001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences; 003 004import java.io.File; 005import java.util.Objects; 006import java.util.regex.Matcher; 007import java.util.regex.Pattern; 008 009import org.openstreetmap.josm.Main; 010 011/** 012 * A source entry primarily used to save the user's selection of mappaint styles, 013 * but also for preset sources or validator rules. 014 * @since 3796 015 */ 016public class SourceEntry { 017 018 /** 019 * A URL can be anything that CachedFile understands, i.e. 020 * a local file, http://, or a file from the current jar 021 */ 022 public String url; 023 024 /** 025 * Indicates, that {@link #url} is a zip file and the resource is 026 * inside the zip file. 027 */ 028 public boolean isZip; 029 030 /** 031 * If {@link #isZip} is true, denotes the path inside the zip file. 032 */ 033 public String zipEntryPath; 034 035 /** 036 * Name is used as a namespace for color preferences and (currently) only 037 * one file with a name can be loaded at a time. Additional styles must 038 * either have the same name as the main style or no name at all. 039 * If no name is provided, it will be set to the default value "standard". 040 * The name can also be given in the xml file as attribute for the rules tag. 041 * (This overrides the name given in the preferences, otherwise both 042 * methods are equivalent.) 043 */ 044 public String name; 045 046 /** 047 * A title that can be used as menu entry. 048 */ 049 public String title; 050 051 /** 052 * active is a boolean flag that can be used to turn the source on or off at runtime. 053 */ 054 public boolean active; 055 056 /** 057 * Constructs a new {@code SourceEntry}. 058 * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands 059 * @param isZip if url is a zip file and the resource is inside the zip file 060 * @param zipEntryPath If {@code isZip} is {@code true}, denotes the path inside the zip file 061 * @param name Source name 062 * @param title title that can be used as menu entry 063 * @param active boolean flag that can be used to turn the source on or off at runtime 064 * @see #url 065 * @see #isZip 066 * @see #zipEntryPath 067 * @see #name 068 * @see #title 069 * @see #active 070 */ 071 public SourceEntry(String url, boolean isZip, String zipEntryPath, String name, String title, boolean active) { 072 this.url = url; 073 this.isZip = isZip; 074 this.zipEntryPath = "".equals(zipEntryPath) ? null : zipEntryPath; 075 this.name = "".equals(name) ? null : name; 076 this.title = "".equals(title) ? null : title; 077 this.active = active; 078 } 079 080 /** 081 * Constructs a new {@code SourceEntry}. 082 * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands 083 * @param name Source name 084 * @param title title that can be used as menu entry 085 * @param active boolean flag that can be used to turn the source on or off at runtime 086 * @see #url 087 * @see #name 088 * @see #title 089 * @see #active 090 */ 091 public SourceEntry(String url, String name, String title, Boolean active) { 092 this(url, false, null, name, title, active); 093 } 094 095 /** 096 * Constructs a new {@code SourceEntry}. 097 * @param e existing source entry to copy 098 */ 099 public SourceEntry(SourceEntry e) { 100 this.url = e.url; 101 this.isZip = e.isZip; 102 this.zipEntryPath = e.zipEntryPath; 103 this.name = e.name; 104 this.title = e.title; 105 this.active = e.active; 106 } 107 108 @Override 109 public boolean equals(Object obj) { 110 if (obj == null || getClass() != obj.getClass()) 111 return false; 112 final SourceEntry other = (SourceEntry) obj; 113 return Objects.equals(other.url, url) && 114 other.isZip == isZip && 115 Objects.equals(other.zipEntryPath, zipEntryPath) && 116 Objects.equals(other.name, name) && 117 Objects.equals(other.title, title) && 118 other.active == active; 119 } 120 121 @Override 122 public int hashCode() { 123 int hash = 5; 124 hash = 89 * hash + (this.url != null ? this.url.hashCode() : 0); 125 hash = 89 * hash + (this.isZip ? 1 : 0); 126 hash = 89 * hash + (this.zipEntryPath != null ? this.zipEntryPath.hashCode() : 0); 127 hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0); 128 hash = 89 * hash + (this.title != null ? this.title.hashCode() : 0); 129 hash = 89 * hash + (this.active ? 1 : 0); 130 return hash; 131 } 132 133 @Override 134 public String toString() { 135 return title != null ? title : url; 136 } 137 138 /** 139 * String to show in menus and error messages. 140 * @return Usually the shortdescription, but can be the file name 141 * if no shortdescription is available. 142 */ 143 public String getDisplayString() { 144 if (title != null) 145 return title; 146 else 147 return getFileNamePart(); 148 } 149 150 /** 151 * Extracts file part from url, e.g.: 152 * <code>http://www.test.com/file.xml?format=text --> file.xml</code> 153 * @return The filename part of the URL 154 */ 155 public String getFileNamePart() { 156 Pattern p = Pattern.compile("([^/\\\\]*?)([?].*)?$"); 157 Matcher m = p.matcher(url); 158 if (m.find()) { 159 return m.group(1); 160 } else { 161 Main.warn("Unexpected URL format: "+url); 162 return url; 163 } 164 } 165 166 /** 167 * the name / identifier that should be used to save custom color values 168 * and similar stuff to the preference file 169 * @return the identifier; never null. Usually the result is "standard" 170 */ 171 public String getPrefName() { 172 return name == null ? "standard" : name; 173 } 174 175 /** 176 * Determines if this source denotes a file on a local filesystem. 177 * @return {@code true} if the source is a local file 178 */ 179 public boolean isLocal() { 180 if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("resource://")) 181 return false; 182 return true; 183 } 184 185 /** 186 * Return the source directory, only for local files. 187 * @return The source directory, or {@code null} if this file isn't local, or does not have a parent 188 * @since 7276 189 */ 190 public File getLocalSourceDir() { 191 if (!isLocal()) 192 return null; 193 return new File(url).getParentFile(); 194 } 195 196 /** 197 * Returns the parent directory of the resource inside the zip file. 198 * 199 * @return the parent directory of the resource inside the zip file, 200 * "." if zipEntryPath is a top level file; null, if zipEntryPath is null 201 */ 202 public String getZipEntryDirName() { 203 if (zipEntryPath == null) return null; 204 File file = new File(zipEntryPath); 205 File dir = file.getParentFile(); 206 if (dir == null) return "."; 207 String path = dir.getPath(); 208 if (!"/".equals(File.separator)) { 209 path = path.replace(File.separator, "/"); 210 } 211 return path; 212 } 213}