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