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

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

mappaint: find images relative to the source file

  • Property svn:eol-style set to native
File size: 10.2 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.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collection;
11import java.util.Collections;
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.SourceEntry;
24import org.openstreetmap.josm.gui.preferences.MapPaintPreference.MapPaintPrefMigration;
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 private static Collection<String> iconDirs;
40
41 public static ElemStyles getStyles()
42 {
43 return styles;
44 }
45
46 public static class IconReference {
47
48 public String iconName;
49 public StyleSource source;
50
51 public IconReference(String iconName, StyleSource source) {
52 this.iconName = iconName;
53 this.source = source;
54 }
55
56 @Override
57 public String toString() {
58 return "IconReference{" + "iconName=" + iconName + " source=" + source.getDisplayString() + '}';
59 }
60 }
61
62 public static ImageIcon getIcon(IconReference ref, boolean sanitize)
63 {
64 String styleName = ref.source.getPrefName();
65 List<String> dirs = new LinkedList<String>();
66 for(String fileset : iconDirs)
67 {
68 String[] a;
69 if(fileset.indexOf("=") >= 0) {
70 a = fileset.split("=", 2);
71 } else {
72 a = new String[] {"", fileset};
73 }
74
75 /* non-prefixed path is generic path, always take it */
76 if(a[0].length() == 0 || styleName.equals(a[0])) {
77 dirs.add(a[1]);
78 }
79 }
80 String sourceDir = ref.source.getLocalSourceDir();
81 if (sourceDir != null) {
82 dirs.add(sourceDir);
83 }
84 ImageIcon i = ImageProvider.getIfAvailable(dirs, "mappaint."+styleName, null, ref.iconName, ref.source.zipIcons, sanitize);
85 if(i == null)
86 {
87 System.out.println("Mappaint style \""+styleName+"\" icon \"" + ref.iconName + "\" not found.");
88 i = ImageProvider.getIfAvailable(dirs, "mappaint."+styleName, null, "misc/no_icon.png");
89 }
90 return i;
91 }
92
93 public static void readFromPreferences() {
94 styles.clear();
95 iconDirs = Main.pref.getCollection("mappaint.icon.sources", Collections.<String>emptySet());
96 if(Main.pref.getBoolean("mappaint.icon.enable-defaults", true))
97 {
98 LinkedList<String> f = new LinkedList<String>(iconDirs);
99 /* don't prefix icon path, as it should be generic */
100 f.add("resource://images/styles/standard/");
101 f.add("resource://images/styles/");
102 iconDirs = f;
103 }
104
105 Collection<? extends SourceEntry> sourceEntries = MapPaintPrefMigration.INSTANCE.get();
106
107 for (SourceEntry entry : sourceEntries) {
108 StyleSource source = fromSourceEntry(entry);
109 if (source != null) {
110 styles.add(source);
111 }
112 }
113 for (StyleSource source : styles.getStyleSources()) {
114 source.loadStyleSource();
115 }
116
117 fireMapPaintSylesUpdated();
118 }
119
120 private static StyleSource fromSourceEntry(SourceEntry entry) {
121 MirroredInputStream in = null;
122 try {
123 in = new MirroredInputStream(entry.url);
124 InputStream zip = in.getZipEntry("xml", "style");
125 if (zip != null) {
126 return new XmlStyleSource(entry);
127 }
128 zip = in.getZipEntry("mapcss", "style");
129 if (zip != null) {
130 return new MapCSSStyleSource(entry);
131 }
132 if (entry.url.toLowerCase().endsWith(".mapcss")) {
133 return new MapCSSStyleSource(entry);
134 } else {
135 return new XmlStyleSource(entry);
136 }
137 } catch (IOException e) {
138 System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", entry.url, e.toString()));
139 e.printStackTrace();
140 } finally {
141 try {
142 if (in != null) {
143 in.close();
144 }
145 } catch (IOException ex) {
146 }
147 }
148 return null;
149 }
150
151 /**
152 * reload styles
153 * preferences are the same, but the file source may have changed
154 * @param sel the indices of styles to reload
155 */
156 public static void reloadStyles(final int... sel) {
157 List<StyleSource> toReload = new ArrayList<StyleSource>();
158 List<StyleSource> data = styles.getStyleSources();
159 for (int i : sel) {
160 toReload.add(data.get(i));
161 }
162 Main.worker.submit(new MapPaintStyleLoader(toReload));
163 }
164
165 public static class MapPaintStyleLoader extends PleaseWaitRunnable {
166 private boolean canceled;
167 private List<StyleSource> sources;
168
169 public MapPaintStyleLoader(List<StyleSource> sources) {
170 super(tr("Reloading style sources"));
171 this.sources = sources;
172 }
173
174 @Override
175 protected void cancel() {
176 canceled = true;
177 }
178
179 @Override
180 protected void finish() {
181 SwingUtilities.invokeLater(new Runnable() {
182 @Override
183 public void run() {
184 fireMapPaintSylesUpdated();
185 styles.clearCached();
186 Main.map.mapView.preferenceChanged(null);
187 Main.map.mapView.repaint();
188 }
189 });
190 }
191
192 @Override
193 protected void realRun() {
194 ProgressMonitor monitor = getProgressMonitor();
195 monitor.setTicksCount(sources.size());
196 for (StyleSource s : sources) {
197 if (canceled)
198 return;
199 monitor.subTask(tr("loading style ''{0}''...", s.getDisplayString()));
200 s.loadStyleSource();
201 monitor.worked(1);
202 }
203 }
204 }
205
206 /**
207 * Move position of entries in the current list of StyleSources
208 * @param sele The indices of styles to be moved.
209 * @param delta The number of lines it should move. positive int moves
210 * down and negative moves up.
211 */
212 public static void moveStyles(int[] sel, int delta) {
213 if (!canMoveStyles(sel, delta))
214 return;
215 int[] selSorted = Arrays.copyOf(sel, sel.length);
216 Arrays.sort(selSorted);
217 List<StyleSource> data = new ArrayList<StyleSource>(styles.getStyleSources());
218 for (int row: selSorted) {
219 StyleSource t1 = data.get(row);
220 StyleSource t2 = data.get(row + delta);
221 data.set(row, t2);
222 data.set(row + delta, t1);
223 }
224 styles.setStyleSources(data);
225 MapPaintPrefMigration.INSTANCE.put(data);
226 fireMapPaintSylesUpdated();
227 styles.clearCached();
228 Main.map.mapView.repaint();
229 }
230
231 public static boolean canMoveStyles(int[] sel, int i) {
232 if (sel.length == 0)
233 return false;
234 int[] selSorted = Arrays.copyOf(sel, sel.length);
235 Arrays.sort(selSorted);
236
237 if (i < 0) { // Up
238 return selSorted[0] >= -i;
239 } else
240 if (i > 0) { // Down
241 return selSorted[selSorted.length-1] <= styles.getStyleSources().size() - 1 - i;
242 } else
243 return true;
244 }
245
246 public static void toggleStyleActive(int... sel) {
247 List<StyleSource> data = styles.getStyleSources();
248 for (int p : sel) {
249 StyleSource s = data.get(p);
250 s.active = !s.active;
251 }
252 MapPaintPrefMigration.INSTANCE.put(data);
253 if (sel.length == 1) {
254 fireMapPaintStyleEntryUpdated(sel[0]);
255 } else {
256 fireMapPaintSylesUpdated();
257 }
258 styles.clearCached();
259 Main.map.mapView.repaint();
260 }
261
262 public static void addStyle(SourceEntry entry) {
263 StyleSource source = fromSourceEntry(entry);
264 if (source != null) {
265 styles.add(source);
266 source.loadStyleSource();
267 MapPaintPrefMigration.INSTANCE.put(styles.getStyleSources());
268 fireMapPaintSylesUpdated();
269 styles.clearCached();
270 Main.map.mapView.repaint();
271 }
272 }
273
274 /***********************************
275 * MapPaintSylesUpdateListener & related code
276 * (get informed when the list of MapPaint StyleSources changes)
277 */
278
279 public interface MapPaintSylesUpdateListener {
280 public void mapPaintStylesUpdated();
281 public void mapPaintStyleEntryUpdated(int idx);
282 }
283
284 protected static final CopyOnWriteArrayList<MapPaintSylesUpdateListener> listeners
285 = new CopyOnWriteArrayList<MapPaintSylesUpdateListener>();
286
287 public static void addMapPaintSylesUpdateListener(MapPaintSylesUpdateListener listener) {
288 if (listener != null) {
289 listeners.addIfAbsent(listener);
290 }
291 }
292
293 public static void removeMapPaintSylesUpdateListener(MapPaintSylesUpdateListener listener) {
294 listeners.remove(listener);
295 }
296
297 public static void fireMapPaintSylesUpdated() {
298 for (MapPaintSylesUpdateListener l : listeners) {
299 l.mapPaintStylesUpdated();
300 }
301 }
302
303 public static void fireMapPaintStyleEntryUpdated(int idx) {
304 for (MapPaintSylesUpdateListener l : listeners) {
305 l.mapPaintStyleEntryUpdated(idx);
306 }
307 }
308}
Note: See TracBrowser for help on using the repository browser.