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.ImageProvider; 024import org.openstreetmap.josm.tools.Utils; 025 026/** 027 * A mappaint style (abstract class). 028 * 029 * Handles everything from parsing the style definition to application 030 * of the style to an osm primitive. 031 */ 032public abstract class StyleSource extends SourceEntry { 033 034 private List<Throwable> errors = new ArrayList<>(); 035 public File zipIcons; 036 037 private ImageIcon imageIcon; 038 039 /****** 040 * The following fields is additional information found in the header 041 * of the source file. 042 */ 043 044 public String icon; 045 046 /** 047 * List of settings for user customization. 048 */ 049 public final List<StyleSetting> settings = new ArrayList<>(); 050 /** 051 * Values of the settings for efficient lookup. 052 */ 053 public Map<String, Object> settingValues = new HashMap<>(); 054 055 public StyleSource(String url, String name, String title) { 056 super(url, name, title, true); 057 } 058 059 public StyleSource(SourceEntry entry) { 060 super(entry); 061 } 062 063 /** 064 * Apply style to osm primitive. 065 * 066 * Adds properties to a MultiCascade. All active {@link StyleSource}s add 067 * their properties on after the other. At a later stage, concrete painting 068 * primitives (lines, icons, text, ...) are derived from the MultiCascade. 069 * @param mc the current MultiCascade, empty for the first StyleSource 070 * @param osm the primitive 071 * @param scale the map scale 072 * @param multipolyOuterWay support for a very old multipolygon tagging style 073 * where you add the tags both to the outer and the inner way. 074 * However, independent inner way style is also possible. 075 * @param pretendWayIsClosed For styles that require the way to be closed, 076 * we pretend it is. This is useful for generating area styles from the (segmented) 077 * outer ways of a multipolygon. 078 */ 079 public abstract void apply(MultiCascade mc, OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed); 080 081 /** 082 * Loads the style source. 083 */ 084 public abstract void loadStyleSource(); 085 086 /** 087 * Returns a new {@code InputStream} to the style source. When finished, {@link #closeSourceInputStream(InputStream)} must be called. 088 * @return A new {@code InputStream} to the style source that must be closed by the caller 089 * @throws IOException if any I/O error occurs. 090 * @see #closeSourceInputStream(InputStream) 091 */ 092 public abstract InputStream getSourceInputStream() throws IOException; 093 094 /** 095 * Returns a new {@code CachedFile} to the local file containing style source (can be a text file or an archive). 096 * @return A new {@code CachedFile} to the local file containing style source 097 * @throws IOException if any I/O error occurs. 098 * @since 7081 099 */ 100 public abstract CachedFile getCachedFile() throws IOException; 101 102 /** 103 * Closes the source input stream previously returned by {@link #getSourceInputStream()} and other linked resources, if applicable. 104 * @param is The source input stream that must be closed 105 * @since 6289 106 * @see #getSourceInputStream() 107 */ 108 public void closeSourceInputStream(InputStream is) { 109 Utils.close(is); 110 } 111 112 public void logError(Throwable e) { 113 errors.add(e); 114 } 115 116 public Collection<Throwable> getErrors() { 117 return Collections.unmodifiableCollection(errors); 118 } 119 120 protected void init() { 121 errors.clear(); 122 imageIcon = null; 123 icon = null; 124 } 125 126 private static ImageIcon defaultIcon; 127 128 private static ImageIcon getDefaultIcon() { 129 if (defaultIcon == null) { 130 defaultIcon = ImageProvider.get("dialogs/mappaint", "pencil"); 131 } 132 return defaultIcon; 133 } 134 135 protected ImageIcon getSourceIcon() { 136 if (imageIcon == null) { 137 if (icon != null) { 138 imageIcon = MapPaintStyles.getIcon(new IconReference(icon, this), -1, -1); 139 } 140 if (imageIcon == null) { 141 imageIcon = getDefaultIcon(); 142 } 143 } 144 return imageIcon; 145 } 146 147 public final ImageIcon getIcon() { 148 if (getErrors().isEmpty()) 149 return getSourceIcon(); 150 else 151 return ImageProvider.overlay(getSourceIcon(), 152 ImageProvider.get("dialogs/mappaint/error_small"), 153 ImageProvider.OverlayPosition.SOUTHEAST); 154 } 155 156 public String getToolTipText() { 157 if (errors.isEmpty()) 158 return null; 159 else 160 return trn("There was an error when loading this style. Select ''Info'' from the right click menu for details.", 161 "There were {0} errors when loading this style. Select ''Info'' from the right click menu for details.", 162 errors.size(), errors.size()); 163 } 164 165 public Color getBackgroundColorOverride() { 166 return null; 167 } 168}