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 }