source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java@ 4007

Last change on this file since 4007 was 4007, checked in by bastiK, 13 years ago

see #6150 mapcss - extended functionality for instruction text: ... (patch by Gubaer)

  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.io.InputStream;
8import java.io.InputStreamReader;
9import java.util.ArrayList;
10import java.util.Arrays;
11import java.util.Collection;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.concurrent.CopyOnWriteArrayList;
15
16import javax.swing.ImageIcon;
17import javax.swing.SwingUtilities;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.gui.PleaseWaitRunnable;
21import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
22import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
23import org.openstreetmap.josm.gui.preferences.MapPaintPreference.MapPaintPrefMigration;
24import org.openstreetmap.josm.gui.preferences.SourceEntry;
25import org.openstreetmap.josm.gui.progress.ProgressMonitor;
26import org.openstreetmap.josm.io.MirroredInputStream;
27import org.openstreetmap.josm.tools.ImageProvider;
28
29/**
30 * This class manages the ElemStyles instance. The object you get with
31 * getStyles() is read only, any manipulation happens via one of
32 * the wrapper methods here. (readFromPreferences, moveStyles, ...)
33 *
34 * On change, mapPaintSylesUpdated() is fired for all listeners.
35 */
36public class MapPaintStyles {
37
38 private static ElemStyles styles = new ElemStyles();
39
40 public static ElemStyles getStyles()
41 {
42 return styles;
43 }
44
45 /**
46 * Value holder for a reference to a tag name. A style instruction
47 * <pre>
48 * text: a_tag_name;
49 * </pre>
50 * results in a tag reference for the tag <tt>a_tag_name</tt> in the
51 * style cascade.
52 */
53 public static class TagKeyReference {
54 public final String key;
55 public TagKeyReference(String key){
56 this.key = key;
57 }
58
59 @Override
60 public String toString() {
61 return "TagKeyReference{" + "key='" + key + "'}";
62 }
63 }
64
65 public static class IconReference {
66
67 public final String iconName;
68 public final StyleSource source;
69
70 public IconReference(String iconName, StyleSource source) {
71 this.iconName = iconName;
72 this.source = source;
73 }
74
75 @Override
76 public String toString() {
77 return "IconReference{" + "iconName='" + iconName + "' source='" + source.getDisplayString() + "'}";
78 }
79 }
80
81 public static ImageIcon getIcon(IconReference ref, boolean sanitize) {
82 String namespace = ref.source.getPrefName();
83 ImageIcon i = ImageProvider.getIfAvailable(getIconSourceDirs(ref.source), "mappaint."+namespace, null, ref.iconName, ref.source.zipIcons, sanitize);
84 if(i == null)
85 {
86 System.out.println("Mappaint style \""+namespace+"\" icon \"" + ref.iconName + "\" not found.");
87 return null;
88 }
89 return i;
90 }
91
92 /**
93 * No icon with the given name was found, show a dummy icon instead
94 * @return the icon misc/no_icon.png, in descending priority:
95 * - relative to source file
96 * - from user icon paths
97 * - josm's default icon
98 * can be null if the defaults are turned off by user
99 */
100 public static ImageIcon getNoIcon_Icon(StyleSource source, boolean sanitize) {
101 return ImageProvider.getIfAvailable(getIconSourceDirs(source), "mappaint."+source.getPrefName(), null, "misc/no_icon.png", source.zipIcons, sanitize);
102 }
103
104 private static List<String> getIconSourceDirs(StyleSource source) {
105 List<String> dirs = new LinkedList<String>();
106
107 String sourceDir = source.getLocalSourceDir();
108 if (sourceDir != null) {
109 dirs.add(sourceDir);
110 }
111
112 Collection<String> prefIconDirs = Main.pref.getCollection("mappaint.icon.sources");
113 for(String fileset : prefIconDirs)
114 {
115 String[] a;
116 if(fileset.indexOf("=") >= 0) {
117 a = fileset.split("=", 2);
118 } else {
119 a = new String[] {"", fileset};
120 }
121
122 /* non-prefixed path is generic path, always take it */
123 if(a[0].length() == 0 || source.getPrefName().equals(a[0])) {
124 dirs.add(a[1]);
125 }
126 }
127
128 if (Main.pref.getBoolean("mappaint.icon.enable-defaults", true)) {
129 /* don't prefix icon path, as it should be generic */
130 dirs.add("resource://images/styles/standard/");
131 dirs.add("resource://images/styles/");
132 }
133
134 return dirs;
135 }
136
137 public static void readFromPreferences() {
138 styles.clear();
139
140 Collection<? extends SourceEntry> sourceEntries = MapPaintPrefMigration.INSTANCE.get();
141
142 for (SourceEntry entry : sourceEntries) {
143 StyleSource source = fromSourceEntry(entry);
144 if (source != null) {
145 styles.add(source);
146 }
147 }
148 for (StyleSource source : styles.getStyleSources()) {
149 source.loadStyleSource();
150 }
151
152 fireMapPaintSylesUpdated();
153 }
154
155 private static StyleSource fromSourceEntry(SourceEntry entry) {
156 MirroredInputStream in = null;
157 try {
158 in = new MirroredInputStream(entry.url);
159 InputStream zip = in.getZipEntry("xml", "style");
160 if (zip != null)
161 return new XmlStyleSource(entry);
162 zip = in.getZipEntry("mapcss", "style");
163 if (zip != null)
164 return new MapCSSStyleSource(entry);
165 if (entry.url.toLowerCase().endsWith(".mapcss"))
166 return new MapCSSStyleSource(entry);
167 if (entry.url.toLowerCase().endsWith(".xml"))
168 return new XmlStyleSource(entry);
169 else {
170 InputStreamReader reader = new InputStreamReader(in);
171 WHILE: while (true) {
172 int c = reader.read();
173 switch (c) {
174 case -1:
175 break WHILE;
176 case ' ':
177 case '\t':
178 case '\n':
179 case '\r':
180 continue;
181 case '<':
182 return new XmlStyleSource(entry);
183 default:
184 return new MapCSSStyleSource(entry);
185 }
186 }
187 System.err.println("Warning: Could not detect style type. Using default (xml).");
188 return new XmlStyleSource(entry);
189 }
190 } catch (IOException e) {
191 System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", entry.url, e.toString()));
192 e.printStackTrace();
193 } finally {
194 try {
195 if (in != null) {
196 in.close();
197 }
198 } catch (IOException ex) {
199 }
200 }
201 return null;
202 }
203
204 /**
205 * reload styles
206 * preferences are the same, but the file source may have changed
207 * @param sel the indices of styles to reload
208 */
209 public static void reloadStyles(final int... sel) {
210 List<StyleSource> toReload = new ArrayList<StyleSource>();
211 List<StyleSource> data = styles.getStyleSources();
212 for (int i : sel) {
213 toReload.add(data.get(i));
214 }
215 Main.worker.submit(new MapPaintStyleLoader(toReload));
216 }
217
218 public static class MapPaintStyleLoader extends PleaseWaitRunnable {
219 private boolean canceled;
220 private List<StyleSource> sources;
221
222 public MapPaintStyleLoader(List<StyleSource> sources) {
223 super(tr("Reloading style sources"));
224 this.sources = sources;
225 }
226
227 @Override
228 protected void cancel() {
229 canceled = true;
230 }
231
232 @Override
233 protected void finish() {
234 SwingUtilities.invokeLater(new Runnable() {
235 @Override
236 public void run() {
237 fireMapPaintSylesUpdated();
238 styles.clearCached();
239 Main.map.mapView.preferenceChanged(null);
240 Main.map.mapView.repaint();
241 }
242 });
243 }
244
245 @Override
246 protected void realRun() {
247 ProgressMonitor monitor = getProgressMonitor();
248 monitor.setTicksCount(sources.size());
249 for (StyleSource s : sources) {
250 if (canceled)
251 return;
252 monitor.subTask(tr("loading style ''{0}''...", s.getDisplayString()));
253 s.loadStyleSource();
254 monitor.worked(1);
255 }
256 }
257 }
258
259 /**
260 * Move position of entries in the current list of StyleSources
261 * @param sele The indices of styles to be moved.
262 * @param delta The number of lines it should move. positive int moves
263 * down and negative moves up.
264 */
265 public static void moveStyles(int[] sel, int delta) {
266 if (!canMoveStyles(sel, delta))
267 return;
268 int[] selSorted = Arrays.copyOf(sel, sel.length);
269 Arrays.sort(selSorted);
270 List<StyleSource> data = new ArrayList<StyleSource>(styles.getStyleSources());
271 for (int row: selSorted) {
272 StyleSource t1 = data.get(row);
273 StyleSource t2 = data.get(row + delta);
274 data.set(row, t2);
275 data.set(row + delta, t1);
276 }
277 styles.setStyleSources(data);
278 MapPaintPrefMigration.INSTANCE.put(data);
279 fireMapPaintSylesUpdated();
280 styles.clearCached();
281 Main.map.mapView.repaint();
282 }
283
284 public static boolean canMoveStyles(int[] sel, int i) {
285 if (sel.length == 0)
286 return false;
287 int[] selSorted = Arrays.copyOf(sel, sel.length);
288 Arrays.sort(selSorted);
289
290 if (i < 0) // Up
291 return selSorted[0] >= -i;
292 else if (i > 0) // Down
293 return selSorted[selSorted.length-1] <= styles.getStyleSources().size() - 1 - i;
294 else
295 return true;
296 }
297
298 public static void toggleStyleActive(int... sel) {
299 List<StyleSource> data = styles.getStyleSources();
300 for (int p : sel) {
301 StyleSource s = data.get(p);
302 s.active = !s.active;
303 }
304 MapPaintPrefMigration.INSTANCE.put(data);
305 if (sel.length == 1) {
306 fireMapPaintStyleEntryUpdated(sel[0]);
307 } else {
308 fireMapPaintSylesUpdated();
309 }
310 styles.clearCached();
311 Main.map.mapView.repaint();
312 }
313
314 public static void addStyle(SourceEntry entry) {
315 StyleSource source = fromSourceEntry(entry);
316 if (source != null) {
317 styles.add(source);
318 source.loadStyleSource();
319 MapPaintPrefMigration.INSTANCE.put(styles.getStyleSources());
320 fireMapPaintSylesUpdated();
321 styles.clearCached();
322 Main.map.mapView.repaint();
323 }
324 }
325
326 /***********************************
327 * MapPaintSylesUpdateListener & related code
328 * (get informed when the list of MapPaint StyleSources changes)
329 */
330
331 public interface MapPaintSylesUpdateListener {
332 public void mapPaintStylesUpdated();
333 public void mapPaintStyleEntryUpdated(int idx);
334 }
335
336 protected static final CopyOnWriteArrayList<MapPaintSylesUpdateListener> listeners
337 = new CopyOnWriteArrayList<MapPaintSylesUpdateListener>();
338
339 public static void addMapPaintSylesUpdateListener(MapPaintSylesUpdateListener listener) {
340 if (listener != null) {
341 listeners.addIfAbsent(listener);
342 }
343 }
344
345 public static void removeMapPaintSylesUpdateListener(MapPaintSylesUpdateListener listener) {
346 listeners.remove(listener);
347 }
348
349 public static void fireMapPaintSylesUpdated() {
350 for (MapPaintSylesUpdateListener l : listeners) {
351 l.mapPaintStylesUpdated();
352 }
353 }
354
355 public static void fireMapPaintStyleEntryUpdated(int idx) {
356 for (MapPaintSylesUpdateListener l : listeners) {
357 l.mapPaintStyleEntryUpdated(idx);
358 }
359 }
360}
Note: See TracBrowser for help on using the repository browser.