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 /** 060 * Constructs a new, active {@link StyleSource}. 061 * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands 062 * @param name The name for this StyleSource 063 * @param title The title that can be used as menu entry 064 */ 065 public StyleSource(String url, String name, String title) { 066 super(url, name, title, true); 067 } 068 069 /** 070 * Constructs a new {@link StyleSource} 071 * @param entry The entry to copy the data (url, name, ...) from. 072 */ 073 public StyleSource(SourceEntry entry) { 074 super(entry); 075 } 076 077 /** 078 * Apply style to osm primitive. 079 * 080 * Adds properties to a MultiCascade. All active {@link StyleSource}s add 081 * their properties on after the other. At a later stage, concrete painting 082 * primitives (lines, icons, text, ...) are derived from the MultiCascade. 083 * @param mc the current MultiCascade, empty for the first StyleSource 084 * @param osm the primitive 085 * @param scale the map scale 086 * @param pretendWayIsClosed For styles that require the way to be closed, 087 * we pretend it is. This is useful for generating area styles from the (segmented) 088 * outer ways of a multipolygon. 089 */ 090 public abstract void apply(MultiCascade mc, OsmPrimitive osm, double scale, boolean pretendWayIsClosed); 091 092 /** 093 * Loads the style source. 094 */ 095 public abstract void loadStyleSource(); 096 097 /** 098 * Returns a new {@code InputStream} to the style source. When finished, {@link #closeSourceInputStream(InputStream)} must be called. 099 * @return A new {@code InputStream} to the style source that must be closed by the caller 100 * @throws IOException if any I/O error occurs. 101 * @see #closeSourceInputStream(InputStream) 102 */ 103 public abstract InputStream getSourceInputStream() throws IOException; 104 105 /** 106 * Returns a new {@code CachedFile} to the local file containing style source (can be a text file or an archive). 107 * @return A new {@code CachedFile} to the local file containing style source 108 * @throws IOException if any I/O error occurs. 109 * @since 7081 110 */ 111 public abstract CachedFile getCachedFile() throws IOException; 112 113 /** 114 * Closes the source input stream previously returned by {@link #getSourceInputStream()} and other linked resources, if applicable. 115 * @param is The source input stream that must be closed 116 * @see #getSourceInputStream() 117 * @since 6289 118 */ 119 public void closeSourceInputStream(InputStream is) { 120 Utils.close(is); 121 } 122 123 public void logError(Throwable e) { 124 errors.add(e); 125 } 126 127 public Collection<Throwable> getErrors() { 128 return Collections.unmodifiableCollection(errors); 129 } 130 131 /** 132 * Initialize the class. 133 */ 134 protected void init() { 135 errors.clear(); 136 imageIconProvider = null; 137 icon = null; 138 } 139 140 /** 141 * Image provider for default icon. 142 * 143 * @return image provider for default styles icon 144 * @see #getIconProvider() 145 * @since 8097 146 */ 147 private static synchronized ImageProvider getDefaultIconProvider() { 148 if (defaultIconProvider == null) { 149 defaultIconProvider = new ImageProvider("dialogs/mappaint", "pencil"); 150 } 151 return defaultIconProvider; 152 } 153 154 /** 155 * Image provider for source icon. Uses default icon, when not else available. 156 * 157 * @return image provider for styles icon 158 * @see #getIconProvider() 159 * @since 8097 160 */ 161 protected ImageProvider getSourceIconProvider() { 162 if (imageIconProvider == null) { 163 if (icon != null) { 164 imageIconProvider = MapPaintStyles.getIconProvider(new IconReference(icon, this), true); 165 } 166 if (imageIconProvider == null) { 167 imageIconProvider = getDefaultIconProvider(); 168 } 169 } 170 return imageIconProvider; 171 } 172 173 /** 174 * Image provider for source icon. 175 * 176 * @return image provider for styles icon 177 * @since 8097 178 */ 179 public final ImageProvider getIconProvider() { 180 ImageProvider i = getSourceIconProvider(); 181 if (!getErrors().isEmpty()) { 182 i = new ImageProvider(i).addOverlay(new ImageOverlay(new ImageProvider("dialogs/mappaint/error_small"))); 183 } 184 return i; 185 } 186 187 /** 188 * Image for source icon. 189 * 190 * @return styles icon for display 191 */ 192 public final ImageIcon getIcon() { 193 return getIconProvider().setMaxSize(ImageProvider.ImageSizes.MENU).get(); 194 } 195 196 /** 197 * Return text to display as ToolTip. 198 * 199 * @return tooltip text containing error status 200 */ 201 public String getToolTipText() { 202 if (errors.isEmpty()) 203 return null; 204 else 205 return trn("There was an error when loading this style. Select ''Info'' from the right click menu for details.", 206 "There were {0} errors when loading this style. Select ''Info'' from the right click menu for details.", 207 errors.size(), errors.size()); 208 } 209 210 public Color getBackgroundColorOverride() { 211 return null; 212 } 213}