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