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 pretendWayIsClosed For styles that require the way to be closed, 073 * we pretend it is. This is useful for generating area styles from the (segmented) 074 * outer ways of a multipolygon. 075 */ 076 public abstract void apply(MultiCascade mc, OsmPrimitive osm, double scale, boolean pretendWayIsClosed); 077 078 /** 079 * Loads the style source. 080 */ 081 public abstract void loadStyleSource(); 082 083 /** 084 * Returns a new {@code InputStream} to the style source. When finished, {@link #closeSourceInputStream(InputStream)} must be called. 085 * @return A new {@code InputStream} to the style source that must be closed by the caller 086 * @throws IOException if any I/O error occurs. 087 * @see #closeSourceInputStream(InputStream) 088 */ 089 public abstract InputStream getSourceInputStream() throws IOException; 090 091 /** 092 * Returns a new {@code CachedFile} to the local file containing style source (can be a text file or an archive). 093 * @return A new {@code CachedFile} to the local file containing style source 094 * @throws IOException if any I/O error occurs. 095 * @since 7081 096 */ 097 public abstract CachedFile getCachedFile() throws IOException; 098 099 /** 100 * Closes the source input stream previously returned by {@link #getSourceInputStream()} and other linked resources, if applicable. 101 * @param is The source input stream that must be closed 102 * @since 6289 103 * @see #getSourceInputStream() 104 */ 105 public void closeSourceInputStream(InputStream is) { 106 Utils.close(is); 107 } 108 109 public void logError(Throwable e) { 110 errors.add(e); 111 } 112 113 public Collection<Throwable> getErrors() { 114 return Collections.unmodifiableCollection(errors); 115 } 116 117 protected void init() { 118 errors.clear(); 119 imageIcon = null; 120 icon = null; 121 } 122 123 private static ImageIcon defaultIcon; 124 125 private static ImageIcon getDefaultIcon() { 126 if (defaultIcon == null) { 127 defaultIcon = ImageProvider.get("dialogs/mappaint", "pencil"); 128 } 129 return defaultIcon; 130 } 131 132 protected ImageIcon getSourceIcon() { 133 if (imageIcon == null) { 134 if (icon != null) { 135 imageIcon = MapPaintStyles.getIcon(new IconReference(icon, this), -1, -1); 136 } 137 if (imageIcon == null) { 138 imageIcon = getDefaultIcon(); 139 } 140 } 141 return imageIcon; 142 } 143 144 public final ImageIcon getIcon() { 145 if (getErrors().isEmpty()) 146 return getSourceIcon(); 147 else 148 return ImageProvider.overlay(getSourceIcon(), 149 ImageProvider.get("dialogs/mappaint/error_small"), 150 ImageProvider.OverlayPosition.SOUTHEAST); 151 } 152 153 public String getToolTipText() { 154 if (errors.isEmpty()) 155 return null; 156 else 157 return trn("There was an error when loading this style. Select ''Info'' from the right click menu for details.", 158 "There were {0} errors when loading this style. Select ''Info'' from the right click menu for details.", 159 errors.size(), errors.size()); 160 } 161 162 public Color getBackgroundColorOverride() { 163 return null; 164 } 165}