001 // License: GPL. Copyright 2007 by Immanuel Scholz and others
002 package org.openstreetmap.josm.gui.preferences.map;
003
004 import static org.openstreetmap.josm.tools.I18n.marktr;
005 import static org.openstreetmap.josm.tools.I18n.tr;
006
007 import java.awt.GridBagLayout;
008 import java.util.ArrayList;
009 import java.util.Arrays;
010 import java.util.Collection;
011 import java.util.HashMap;
012 import java.util.List;
013 import java.util.Map;
014 import java.util.TreeSet;
015
016 import javax.swing.BorderFactory;
017 import javax.swing.JCheckBox;
018 import javax.swing.JPanel;
019 import javax.swing.event.ChangeEvent;
020 import javax.swing.event.ChangeListener;
021
022 import org.openstreetmap.josm.Main;
023 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
024 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
025 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
026 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
027 import org.openstreetmap.josm.gui.preferences.SourceEditor;
028 import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
029 import org.openstreetmap.josm.gui.preferences.SourceEntry;
030 import org.openstreetmap.josm.gui.preferences.SourceProvider;
031 import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
032 import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
033 import org.openstreetmap.josm.tools.GBC;
034 import org.openstreetmap.josm.tools.Predicate;
035 import org.openstreetmap.josm.tools.Utils;
036
037 public class MapPaintPreference implements SubPreferenceSetting {
038 private SourceEditor sources;
039 private JCheckBox enableIconDefault;
040
041 private static final List<SourceProvider> styleSourceProviders = new ArrayList<SourceProvider>();
042
043 public static final boolean registerSourceProvider(SourceProvider provider) {
044 if (provider != null)
045 return styleSourceProviders.add(provider);
046 return false;
047 }
048
049 public static class Factory implements PreferenceSettingFactory {
050 public PreferenceSetting createPreferenceSetting() {
051 return new MapPaintPreference();
052 }
053 }
054
055 public void addGui(final PreferenceTabbedPane gui) {
056 enableIconDefault = new JCheckBox(tr("Enable built-in icon defaults"),
057 Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
058
059 sources = new MapPaintSourceEditor();
060
061 final JPanel panel = new JPanel(new GridBagLayout());
062 panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
063
064 panel.add(sources, GBC.eol().fill(GBC.BOTH));
065 panel.add(enableIconDefault, GBC.eol().insets(11,2,5,0));
066
067 gui.getMapPreference().mapcontent.addTab(tr("Map Paint Styles"), panel);
068
069 // this defers loading of style sources to the first time the tab
070 // with the map paint preferences is selected by the user
071 //
072 gui.getMapPreference().mapcontent.addChangeListener(
073 new ChangeListener() {
074 public void stateChanged(ChangeEvent e) {
075 if (gui.getMapPreference().mapcontent.getSelectedComponent() == panel) {
076 sources.initiallyLoadAvailableSources();
077 }
078 }
079 }
080 );
081 }
082
083 static class MapPaintSourceEditor extends SourceEditor {
084
085 final private String iconpref = "mappaint.icon.sources";
086
087 public MapPaintSourceEditor() {
088 super(true, "http://josm.openstreetmap.de/styles", styleSourceProviders);
089 }
090
091 @Override
092 public Collection<? extends SourceEntry> getInitialSourcesList() {
093 return MapPaintPrefHelper.INSTANCE.get();
094 }
095
096 @Override
097 public boolean finish() {
098 List<SourceEntry> activeStyles = activeSourcesModel.getSources();
099
100 boolean changed = MapPaintPrefHelper.INSTANCE.put(activeStyles);
101
102 if (tblIconPaths != null) {
103 List<String> iconPaths = iconPathsModel.getIconPaths();
104
105 if (!iconPaths.isEmpty()) {
106 if (Main.pref.putCollection(iconpref, iconPaths)) {
107 changed = true;
108 }
109 } else if (Main.pref.putCollection(iconpref, null)) {
110 changed = true;
111 }
112 }
113 return changed;
114 }
115
116 @Override
117 public Collection<ExtendedSourceEntry> getDefault() {
118 return MapPaintPrefHelper.INSTANCE.getDefault();
119 }
120
121 @Override
122 public Collection<String> getInitialIconPathsList() {
123 return Main.pref.getCollection(iconpref, null);
124 }
125
126 @Override
127 public String getStr(I18nString ident) {
128 switch (ident) {
129 case AVAILABLE_SOURCES:
130 return tr("Available styles:");
131 case ACTIVE_SOURCES:
132 return tr("Active styles:");
133 case NEW_SOURCE_ENTRY_TOOLTIP:
134 return tr("Add a new style by entering filename or URL");
135 case NEW_SOURCE_ENTRY:
136 return tr("New style entry:");
137 case REMOVE_SOURCE_TOOLTIP:
138 return tr("Remove the selected styles from the list of active styles");
139 case EDIT_SOURCE_TOOLTIP:
140 return tr("Edit the filename or URL for the selected active style");
141 case ACTIVATE_TOOLTIP:
142 return tr("Add the selected available styles to the list of active styles");
143 case RELOAD_ALL_AVAILABLE:
144 return marktr("Reloads the list of available styles from ''{0}''");
145 case LOADING_SOURCES_FROM:
146 return marktr("Loading style sources from ''{0}''");
147 case FAILED_TO_LOAD_SOURCES_FROM:
148 return marktr("<html>Failed to load the list of style sources from<br>"
149 + "''{0}''.<br>"
150 + "<br>"
151 + "Details (untranslated):<br>{1}</html>");
152 case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC:
153 return "/Preferences/Styles#FailedToLoadStyleSources";
154 case ILLEGAL_FORMAT_OF_ENTRY:
155 return marktr("Warning: illegal format of entry in style list ''{0}''. Got ''{1}''");
156 default: throw new AssertionError();
157 }
158 }
159
160 }
161
162 public boolean ok() {
163 boolean reload = Main.pref.put("mappaint.icon.enable-defaults", enableIconDefault.isSelected());
164 reload |= sources.finish();
165 if (reload) {
166 MapPaintStyles.readFromPreferences();
167 }
168 if (Main.isDisplayingMapView())
169 {
170 MapPaintStyles.getStyles().clearCached();
171 }
172 return false;
173 }
174
175 /**
176 * Initialize the styles
177 */
178 public static void initialize() {
179 MapPaintStyles.readFromPreferences();
180 }
181
182 public static class MapPaintPrefHelper extends SourceEditor.SourcePrefHelper {
183
184 public final static MapPaintPrefHelper INSTANCE = new MapPaintPrefHelper();
185
186 public MapPaintPrefHelper() {
187 super("mappaint.style.entries", "mappaint.style.sources-list");
188 }
189
190 @Override
191 public List<SourceEntry> get() {
192 List<SourceEntry> ls = super.get();
193 if (insertNewDefaults(ls)) {
194 put(ls);
195 }
196 return ls;
197 }
198
199 /**
200 * If the selection of default styles changes in future releases, add
201 * the new entries to the user-configured list. Remember the known URLs,
202 * so an item that was deleted explicitly is not added again.
203 */
204 private boolean insertNewDefaults(List<SourceEntry> list) {
205 boolean changed = false;
206
207 Collection<String> knownDefaults = new TreeSet<String>(Main.pref.getCollection("mappaint.style.known-defaults"));
208
209 Collection<ExtendedSourceEntry> defaults = getDefault();
210 int insertionIdx = 0;
211 for (final SourceEntry def : defaults) {
212 int i = Utils.indexOf(list,
213 new Predicate<SourceEntry>() {
214 @Override
215 public boolean evaluate(SourceEntry se) {
216 return Utils.equal(def.url, se.url);
217 }
218 });
219 if (i == -1 && !knownDefaults.contains(def.url)) {
220 list.add(insertionIdx, def);
221 insertionIdx++;
222 changed = true;
223 } else {
224 if (i >= insertionIdx) {
225 insertionIdx = i + 1;
226 }
227 }
228 }
229
230 for (SourceEntry def : defaults) {
231 knownDefaults.add(def.url);
232 }
233 Main.pref.putCollection("mappaint.style.known-defaults", knownDefaults);
234
235 return changed;
236 }
237
238 @Override
239 public Collection<ExtendedSourceEntry> getDefault() {
240 ExtendedSourceEntry defJOSM = new ExtendedSourceEntry("elemstyles.xml", "resource://styles/standard/elemstyles.xml");
241 defJOSM.active = true;
242 defJOSM.name = "standard";
243 defJOSM.title = tr("JOSM Internal Style");
244 defJOSM.description = tr("Internal style to be used as base for runtime switchable overlay styles");
245 ExtendedSourceEntry defPL2 = new ExtendedSourceEntry("potlatch2.mapcss", "resource://styles/standard/potlatch2.mapcss");
246 defPL2.active = false;
247 defPL2.name = "standard";
248 defPL2.title = tr("Potlatch 2");
249 defPL2.description = tr("the main Potlatch 2 style");
250
251 return Arrays.asList(new ExtendedSourceEntry[] { defJOSM, defPL2 });
252 }
253
254 @Override
255 public Map<String, String> serialize(SourceEntry entry) {
256 Map<String, String> res = new HashMap<String, String>();
257 res.put("url", entry.url);
258 res.put("title", entry.title == null ? "" : entry.title);
259 res.put("active", Boolean.toString(entry.active));
260 if (entry.name != null) {
261 res.put("ptoken", entry.name);
262 }
263 return res;
264 }
265
266 @Override
267 public SourceEntry deserialize(Map<String, String> s) {
268 return new SourceEntry(s.get("url"), s.get("ptoken"), s.get("title"), Boolean.parseBoolean(s.get("active")));
269 }
270
271 @Override
272 public Map<String, String> migrate(Collection<String> old) {
273 List<String> entryStr = new ArrayList<String>(old);
274 if (entryStr.size() < 4)
275 return null;
276 Map<String, String> res = new HashMap<String, String>();
277 res.put("url", entryStr.get(0));
278 res.put("ptoken", entryStr.get(1));
279 res.put("title", entryStr.get(2));
280 res.put("active", entryStr.get(3));
281 return res;
282 }
283 }
284
285 @Override
286 public boolean isExpert() {
287 return false;
288 }
289
290 @Override
291 public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
292 return gui.getMapPreference();
293 }
294 }