001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint;
003
004import static org.openstreetmap.josm.tools.I18n.trn;
005
006import java.awt.Color;
007import java.io.File;
008import java.io.IOException;
009import java.io.InputStream;
010import java.util.ArrayList;
011import java.util.Collection;
012import java.util.Collections;
013import java.util.HashMap;
014import java.util.List;
015import java.util.Map;
016
017import javax.swing.ImageIcon;
018
019import org.openstreetmap.josm.data.osm.OsmPrimitive;
020import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
021import org.openstreetmap.josm.gui.preferences.SourceEntry;
022import org.openstreetmap.josm.io.CachedFile;
023import org.openstreetmap.josm.tools.ImageOverlay;
024import org.openstreetmap.josm.tools.ImageProvider;
025import org.openstreetmap.josm.tools.Utils;
026
027/**
028 * A mappaint style (abstract class).
029 *
030 * Handles everything from parsing the style definition to application
031 * of the style to an osm primitive.
032 */
033public abstract class StyleSource extends SourceEntry {
034
035    private List<Throwable> errors = new ArrayList<>();
036    public File zipIcons;
037
038    /** image provider returning the icon for this style */
039    private ImageProvider imageIconProvider;
040
041    /** image provider returning the default icon */
042    private static ImageProvider defaultIconProvider;
043
044    /******
045     * The following fields is additional information found in the header
046     * of the source file.
047     */
048    public String icon;
049
050    /**
051     * List of settings for user customization.
052     */
053    public final List<StyleSetting> settings = new ArrayList<>();
054    /**
055     * Values of the settings for efficient lookup.
056     */
057    public Map<String, Object> settingValues = new HashMap<>();
058
059    public StyleSource(String url, String name, String title) {
060        super(url, name, title, true);
061    }
062
063    public StyleSource(SourceEntry entry) {
064        super(entry);
065    }
066
067    /**
068     * Apply style to osm primitive.
069     *
070     * Adds properties to a MultiCascade. All active {@link StyleSource}s add
071     * their properties on after the other. At a later stage, concrete painting
072     * primitives (lines, icons, text, ...) are derived from the MultiCascade.
073     * @param mc the current MultiCascade, empty for the first StyleSource
074     * @param osm the primitive
075     * @param scale the map scale
076     * @param pretendWayIsClosed For styles that require the way to be closed,
077     * we pretend it is. This is useful for generating area styles from the (segmented)
078     * outer ways of a multipolygon.
079     */
080    public abstract void apply(MultiCascade mc, OsmPrimitive osm, double scale, boolean pretendWayIsClosed);
081
082    /**
083     * Loads the style source.
084     */
085    public abstract void loadStyleSource();
086
087    /**
088     * Returns a new {@code InputStream} to the style source. When finished, {@link #closeSourceInputStream(InputStream)} must be called.
089     * @return A new {@code InputStream} to the style source that must be closed by the caller
090     * @throws IOException if any I/O error occurs.
091     * @see #closeSourceInputStream(InputStream)
092     */
093    public abstract InputStream getSourceInputStream() throws IOException;
094
095    /**
096     * Returns a new {@code CachedFile} to the local file containing style source (can be a text file or an archive).
097     * @return A new {@code CachedFile} to the local file containing style source
098     * @throws IOException if any I/O error occurs.
099     * @since 7081
100     */
101    public abstract CachedFile getCachedFile() throws IOException;
102
103    /**
104     * Closes the source input stream previously returned by {@link #getSourceInputStream()} and other linked resources, if applicable.
105     * @param is The source input stream that must be closed
106     * @since 6289
107     * @see #getSourceInputStream()
108     */
109    public void closeSourceInputStream(InputStream is) {
110        Utils.close(is);
111    }
112
113    public void logError(Throwable e) {
114        errors.add(e);
115    }
116
117    public Collection<Throwable> getErrors() {
118        return Collections.unmodifiableCollection(errors);
119    }
120
121    /**
122     * Initialize the class.
123     */
124    protected void init() {
125        errors.clear();
126        imageIconProvider = null;
127        icon = null;
128    }
129
130    /**
131     * Image provider for default icon.
132     *
133     * @return image provider for default styles icon
134     * @since 8097
135     * @see #getIconProvider()
136     */
137    private static ImageProvider getDefaultIconProvider() {
138        if (defaultIconProvider == null) {
139            defaultIconProvider = new ImageProvider("dialogs/mappaint", "pencil");
140        }
141        return defaultIconProvider;
142    }
143
144    /**
145     * Image provider for source icon. Uses default icon, when not else available.
146     *
147     * @return image provider for styles icon
148     * @since 8097
149     * @see #getIconProvider()
150     */
151    protected ImageProvider getSourceIconProvider() {
152        if (imageIconProvider == null) {
153            if (icon != null) {
154                imageIconProvider = MapPaintStyles.getIconProvider(new IconReference(icon, this), true);
155            }
156            if (imageIconProvider == null) {
157                imageIconProvider = getDefaultIconProvider();
158            }
159        }
160        return imageIconProvider;
161    }
162
163    /**
164     * Image provider for source icon.
165     *
166     * @return image provider for styles icon
167     * @since 8097
168     */
169    public final ImageProvider getIconProvider() {
170        ImageProvider i = getSourceIconProvider();
171        if (!getErrors().isEmpty()) {
172            i = new ImageProvider(i).addOverlay(new ImageOverlay(new ImageProvider("dialogs/mappaint/error_small")));
173        }
174        return i;
175    }
176
177    /**
178     * Image for source icon.
179     *
180     * @return styles icon for display
181     */
182    public final ImageIcon getIcon() {
183        return getIconProvider().setMaxSize(ImageProvider.ImageSizes.MENU).get();
184    }
185
186    /**
187     * Return text to display as ToolTip.
188     *
189     * @return tooltip text containing error status
190     */
191    public String getToolTipText() {
192        if (errors.isEmpty())
193            return null;
194        else
195            return trn("There was an error when loading this style. Select ''Info'' from the right click menu for details.",
196                    "There were {0} errors when loading this style. Select ''Info'' from the right click menu for details.",
197                    errors.size(), errors.size());
198    }
199
200    public Color getBackgroundColorOverride() {
201        return null;
202    }
203}