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}