Changeset 3796 in josm for trunk/src/org
- Timestamp:
- 2011-01-21T12:42:29+01:00 (14 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
r3719 r3796 16 16 17 17 import org.openstreetmap.josm.Main; 18 import org.openstreetmap.josm.gui.preferences.SourceEntry; 19 import org.openstreetmap.josm.gui.preferences.MapPaintPreference.MapPaintPrefMigration; 18 20 import org.openstreetmap.josm.io.MirroredInputStream; 19 21 import org.openstreetmap.josm.tools.ImageProvider; … … 71 73 } 72 74 73 Collection<String> files = Main.pref.getCollection("mappaint.style.sources", Collections.<String>emptySet()); 74 if (Main.pref.getBoolean("mappaint.style.enable-defaults", true)) { 75 LinkedList<String> f = new LinkedList<String>(); 76 f.add("resource://data/elemstyles.xml"); 77 f.addAll(files); 78 files = f; 79 } 75 Collection<? extends SourceEntry> sourceEntries = (new MapPaintPrefMigration()).get(); 80 76 81 for (String file : files) { 82 String[] a = null; 77 for (SourceEntry entry : sourceEntries) { 83 78 try { 84 if (file.indexOf("=") >= 0) { 85 a = file.split("=", 2); 86 } else { 87 a = new String[] { null, file }; 88 } 89 XmlObjectParser parser = new XmlObjectParser(new ElemStyleHandler(a[0])); 90 MirroredInputStream in = new MirroredInputStream(a[1]); 79 XmlObjectParser parser = new XmlObjectParser(new ElemStyleHandler(entry.name)); 80 MirroredInputStream in = new MirroredInputStream(entry.url); 91 81 InputStream zip = in.getZipEntry("xml","style"); 92 82 InputStreamReader ins; … … 103 93 } 104 94 } catch(IOException e) { 105 System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", a[1], e.toString()));95 System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", entry.url, e.toString())); 106 96 e.printStackTrace(); 107 97 } catch(SAXParseException e) { 108 System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: [{1}:{2}] {3}", a[1], e.getLineNumber(), e.getColumnNumber(), e.getMessage()));98 System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: [{1}:{2}] {3}", entry.url, e.getLineNumber(), e.getColumnNumber(), e.getMessage())); 109 99 e.printStackTrace(); 110 100 } catch(SAXException e) { 111 System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: {1}", a[1], e.getMessage()));101 System.err.println(tr("Warning: failed to parse Mappaint styles from ''{0}''. Error was: {1}", entry.url, e.getMessage())); 112 102 e.printStackTrace(); 113 103 } -
trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java
r3467 r3796 2 2 package org.openstreetmap.josm.gui.preferences; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 6 7 import java.awt.GridBagLayout; 8 import java.util.Arrays; 7 9 import java.util.Collection; 10 import java.util.Collections; 11 import java.util.List; 8 12 import java.util.TreeSet; 9 13 … … 20 24 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 21 25 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 26 import org.openstreetmap.josm.gui.preferences.StyleSourceEditor.StyleSourceInfo; 22 27 import org.openstreetmap.josm.tools.GBC; 23 28 … … 40 45 Main.pref.getBoolean("mappaint.icon.enable-defaults", true)); 41 46 42 sources = new StyleSourceEditor("mappaint.style.sources", "mappaint.icon.sources", 43 "http://josm.openstreetmap.de/styles"); 47 sources = new MapPaintSourceEditor(); 44 48 45 49 Collection<String> styles = new TreeSet<String>(MapPaintStyles.getStyles().getStyleNames()); … … 60 64 final JPanel panel = new JPanel(new GridBagLayout()); 61 65 panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 )); 62 panel.add(enableDefault, GBC.std().insets(5,5,5,0));63 panel.add(enableIconDefault, GBC.eol().insets(5,5,5,0));64 66 65 67 panel.add(new JLabel(tr("Used style")), GBC.std().insets(5,5,0,5)); … … 68 70 69 71 panel.add(sources, GBC.eol().fill(GBC.BOTH)); 72 panel.add(enableIconDefault, GBC.eol().insets(11,2,5,0)); 73 70 74 gui.mapcontent.addTab(tr("Map Paint Styles"), panel); 71 75 … … 84 88 } 85 89 90 class MapPaintSourceEditor extends StyleSourceEditor { 91 92 final private String iconpref = "mappaint.icon.sources"; 93 94 public MapPaintSourceEditor() { 95 super("http://josm.openstreetmap.de/styles"); 96 } 97 98 @Override 99 public Collection<? extends SourceEntry> getInitialSourcesList() { 100 return (new MapPaintPrefMigration()).get(); 101 } 102 103 @Override 104 public boolean finish() { 105 List<SourceEntry> activeStyles = activeStylesModel.getStyles(); 106 107 boolean changed = (new MapPaintPrefMigration()).put(activeStyles); 108 109 if (tblIconPaths != null) { 110 List<String> iconPaths = iconPathsModel.getIconPaths(); 111 112 if (!iconPaths.isEmpty()) { 113 if (Main.pref.putCollection(iconpref, iconPaths)) { 114 changed = true; 115 } 116 } else if (Main.pref.putCollection(iconpref, null)) { 117 changed = true; 118 } 119 } 120 return changed; 121 } 122 123 @Override 124 public Collection<StyleSourceInfo> getDefault() { 125 return (new MapPaintPrefMigration()).getDefault(); 126 } 127 128 @Override 129 public Collection<String> getInitialIconPathsList() { 130 return Main.pref.getCollection(iconpref, null); 131 } 132 133 @Override 134 public String getStr(I18nString ident) { 135 switch (ident) { 136 case AVAILABLE_SOURCES: 137 return tr("Available styles:"); 138 case ACTIVE_SOURCES: 139 return tr("Active styles:"); 140 case NEW_SOURCE_ENTRY: 141 return tr("New style entry:"); 142 case REMOVE_SOURCE_TOOLTIP: 143 return tr("Remove the selected styles from the list of active styles"); 144 case EDIT_SOURCE_TOOLTIP: 145 return tr("Edit the filename or URL for the selected active style"); 146 case ACTIVATE_TOOLTIP: 147 return tr("Add the selected available styles to the list of active styles"); 148 case RELOAD_ALL_AVAILABLE: 149 return marktr("Reloads the list of available styles from ''{0}''"); 150 case LOADING_SOURCES_FROM: 151 return marktr("Loading style sources from ''{0}''"); 152 case FAILED_TO_LOAD_SOURCES_FROM: 153 return marktr("<html>Failed to load the list of style sources from<br>" 154 + "''{0}''.<br>" 155 + "<br>" 156 + "Details (untranslated):<br>{1}</html>"); 157 case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC: 158 return "/Preferences/Styles#FailedToLoadStyleSources"; 159 case ILLEGAL_FORMAT_OF_ENTRY: 160 return marktr("Warning: illegal format of entry in style list ''{0}''. Got ''{1}''"); 161 default: throw new AssertionError(); 162 } 163 } 164 165 } 166 86 167 public boolean ok() { 87 168 Boolean restart = Main.pref.put("mappaint.style.enable-defaults", enableDefault.isSelected()); … … 112 193 MapPaintStyles.readFromPreferences(); 113 194 } 195 196 public static class MapPaintPrefMigration extends StyleSourceEditor.SourcePrefMigration { 197 198 public MapPaintPrefMigration() { 199 super("mappaint.style.sources", 200 "mappaint.style.enable-defaults", 201 "mappaint.style.sources-list"); 202 } 203 204 @Override 205 public Collection<StyleSourceInfo> getDefault() { 206 StyleSourceInfo i = new StyleSourceInfo("elemstyles.xml", "resource://data/elemstyles.xml"); 207 i.name = "standard"; 208 i.shortdescription = tr("Internal Style"); 209 i.description = tr("Internal style to be used as base for runtime switchable overlay styles"); 210 return Collections.singletonList(i); 211 } 212 213 @Override 214 public Collection<String> serialize(SourceEntry entry) { 215 return Arrays.asList(new String[] {entry.url, entry.name, entry.shortdescription, Boolean.toString(entry.active)}); 216 } 217 218 @Override 219 public SourceEntry deserialize(List<String> entryStr) { 220 if (entryStr.size() < 4) 221 return null; 222 String url = entryStr.get(0); 223 String name = entryStr.get(1); 224 String shortdescription = entryStr.get(2); 225 boolean active = Boolean.parseBoolean(entryStr.get(3)); 226 return new SourceEntry(url, name, shortdescription, active); 227 } 228 } 114 229 } -
trunk/src/org/openstreetmap/josm/gui/preferences/StyleSourceEditor.java
r3754 r3796 4 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 import static org.openstreetmap.josm.tools.Utils.equal; 6 7 7 8 import java.awt.Component; 9 import java.awt.Dimension; 10 import java.awt.Font; 8 11 import java.awt.GridBagConstraints; 9 12 import java.awt.GridBagLayout; 13 import java.awt.Insets; 10 14 import java.awt.event.ActionEvent; 11 15 import java.awt.event.FocusAdapter; 12 16 import java.awt.event.FocusEvent; 13 17 import java.awt.event.KeyEvent; 18 import java.awt.event.MouseAdapter; 14 19 import java.awt.event.MouseEvent; 15 20 import java.io.BufferedReader; … … 34 39 import javax.swing.AbstractAction; 35 40 import javax.swing.BorderFactory; 41 import javax.swing.Box; 36 42 import javax.swing.DefaultListModel; 37 43 import javax.swing.DefaultListSelectionModel; … … 55 61 import javax.swing.event.ListSelectionEvent; 56 62 import javax.swing.event.ListSelectionListener; 63 import javax.swing.event.TableModelEvent; 64 import javax.swing.event.TableModelListener; 57 65 import javax.swing.table.AbstractTableModel; 66 import javax.swing.table.DefaultTableCellRenderer; 58 67 import javax.swing.table.TableCellEditor; 68 import javax.swing.table.TableCellRenderer; 59 69 60 70 import org.openstreetmap.josm.Main; 71 import org.openstreetmap.josm.gui.ExtendedDialog; 61 72 import org.openstreetmap.josm.gui.HelpAwareOptionPane; 62 73 import org.openstreetmap.josm.gui.PleaseWaitRunnable; … … 68 79 import org.xml.sax.SAXException; 69 80 70 public class StyleSourceEditor extends JPanel { 71 private JTable tblActiveStyles; 72 private ActiveStylesModel activeStylesModel; 73 private JList lstAvailableStyles; 74 private AvailableStylesListModel availableStylesModel; 75 private JTable tblIconPaths = null; 76 private IconPathTableModel iconPathsModel; 77 private String pref; 78 private String iconpref; 79 private boolean stylesInitiallyLoaded; 80 private String availableStylesUrl; 81 public abstract class StyleSourceEditor extends JPanel { 82 83 protected JTable tblActiveStyles; 84 protected ActiveStylesModel activeStylesModel; 85 protected JList lstAvailableStyles; 86 protected AvailableStylesListModel availableStylesModel; 87 protected JTable tblIconPaths = null; 88 protected IconPathTableModel iconPathsModel; 89 protected boolean stylesInitiallyLoaded; 90 protected String availableStylesUrl; 81 91 82 92 /** 83 * 84 * @param stylesPreferencesKey the preferences key with the list of active style sources (filenames and URLs) 85 * @param iconsPreferenceKey the preference key with the list of icon sources (can be null) 93 * constructor 86 94 * @param availableStylesUrl the URL to the list of available style sources 87 95 */ 88 public StyleSourceEditor( String stylesPreferencesKey, String iconsPreferenceKey,final String availableStylesUrl) {96 public StyleSourceEditor(final String availableStylesUrl) { 89 97 90 98 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel(); 99 lstAvailableStyles = new JList(availableStylesModel = new AvailableStylesListModel(selectionModel)); 100 lstAvailableStyles.setSelectionModel(selectionModel); 101 lstAvailableStyles.setCellRenderer(new StyleSourceCellRenderer()); 102 this.availableStylesUrl = availableStylesUrl; 103 104 selectionModel = new DefaultListSelectionModel(); 91 105 tblActiveStyles = new JTable(activeStylesModel = new ActiveStylesModel(selectionModel)); 92 106 tblActiveStyles.putClientProperty("terminateEditOnFocusLost", true); 93 107 tblActiveStyles.setSelectionModel(selectionModel); 94 108 tblActiveStyles.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 109 tblActiveStyles.setShowGrid(false); 110 tblActiveStyles.setIntercellSpacing(new Dimension(0, 0)); 95 111 tblActiveStyles.setTableHeader(null); 96 tblActiveStyles. getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor(true));97 tblActiveStyles.setRowHeight(20);98 activeStylesModel.setActiveStyles(Main.pref.getCollection(stylesPreferencesKey, null));99 100 selectionModel = new DefaultListSelectionModel();101 lstAvailableStyles = new JList(availableStylesModel =new AvailableStylesListModel(selectionModel));102 lstAvailableStyles.setSelectionModel(selectionModel);103 lstAvailableStyles.setCellRenderer(new StyleSourceCellRenderer());104 this.availableStylesUrl = availableStylesUrl;105 106 this.pref = stylesPreferencesKey;107 this.iconpref = iconsPreferenceKey;108 109 EditActiveStyleAction editActiveStyleAction = new EditActiveStyleAction();112 tblActiveStyles.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 113 SourceEntryRenderer sourceEntryRenderer = new SourceEntryRenderer(); 114 tblActiveStyles.getColumnModel().getColumn(0).setCellRenderer(sourceEntryRenderer); 115 activeStylesModel.addTableModelListener(new TableModelListener() { 116 // Force swing to show horizontal scrollbars for the JTable 117 // Yes, this is a little ugly, but should work 118 @Override 119 public void tableChanged(TableModelEvent e) { 120 adjustColumnWidth(tblActiveStyles, 0); 121 } 122 }); 123 activeStylesModel.setActiveStyles(getInitialSourcesList()); 124 125 final EditActiveStyleAction editActiveStyleAction = new EditActiveStyleAction(); 110 126 tblActiveStyles.getSelectionModel().addListSelectionListener(editActiveStyleAction); 127 tblActiveStyles.addMouseListener(new MouseAdapter() { 128 @Override 129 public void mouseClicked(MouseEvent e) { 130 if (e.getClickCount() == 2) { 131 int row = tblActiveStyles.rowAtPoint(e.getPoint()); 132 if (row < 0 || row >= tblActiveStyles.getRowCount()) 133 return; 134 editActiveStyleAction.actionPerformed(null); 135 } 136 } 137 }); 111 138 112 139 RemoveActiveStylesAction removeActiveStylesAction = new RemoveActiveStylesAction(); … … 121 148 setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); 122 149 setLayout(new GridBagLayout()); 123 add(new JLabel(tr("Active styles:")), GBC.eol().insets(11, 5, 5, 0)); 150 151 GridBagConstraints gbc = new GridBagConstraints(); 152 gbc.gridx = 0; 153 gbc.gridy = 0; 154 gbc.weightx = 0.5; 155 gbc.gridwidth = 2; 156 gbc.anchor = GBC.WEST; 157 gbc.insets = new Insets(5, 11, 0, 0); 158 159 add(new JLabel(getStr(I18nString.AVAILABLE_SOURCES)), gbc); 160 161 gbc.gridx = 2; 162 gbc.insets = new Insets(5, 0, 0, 6); 163 164 add(new JLabel(getStr(I18nString.ACTIVE_SOURCES)), gbc); 165 166 gbc.gridwidth = 1; 167 gbc.gridx = 0; 168 gbc.gridy++; 169 gbc.weighty = 0.8; 170 gbc.fill = GBC.BOTH; 171 gbc.anchor = GBC.CENTER; 172 gbc.insets = new Insets(0, 11, 0, 0); 173 174 JScrollPane sp1 = new JScrollPane(lstAvailableStyles); 175 add(sp1, gbc); 176 177 gbc.gridx = 1; 178 gbc.weightx = 0.0; 179 gbc.fill = GBC.VERTICAL; 180 gbc.insets = new Insets(0, 0, 0, 0); 181 182 JToolBar middleTB = new JToolBar(); 183 middleTB.setFloatable(false); 184 middleTB.setBorderPainted(false); 185 middleTB.setOpaque(false); 186 middleTB.add(Box.createHorizontalGlue()); 187 middleTB.add(activate); 188 middleTB.add(Box.createHorizontalGlue()); 189 add(middleTB, gbc); 190 191 gbc.gridx++; 192 gbc.weightx = 0.5; 193 gbc.fill = GBC.BOTH; 194 124 195 JScrollPane sp = new JScrollPane(tblActiveStyles); 125 add(sp, GBC.std().insets(10, 0, 3, 0).fill(GBC.BOTH));196 add(sp, gbc); 126 197 sp.setColumnHeaderView(null); 198 199 gbc.gridx++; 200 gbc.weightx = 0.0; 201 gbc.fill = GBC.VERTICAL; 202 gbc.insets = new Insets(0, 0, 0, 6); 127 203 128 204 JToolBar sideButtonTB = new JToolBar(JToolBar.VERTICAL); … … 133 209 sideButtonTB.add(editActiveStyleAction); 134 210 sideButtonTB.add(removeActiveStylesAction); 135 add(sideButtonTB, GBC.eol().insets(0, 0, 10, 0).fill(GBC.VERTICAL)); 136 137 JToolBar bottomButtonTB = new JToolBar(); 138 bottomButtonTB.setFloatable(false); 139 bottomButtonTB.setBorderPainted(false); 140 bottomButtonTB.setOpaque(false); 141 bottomButtonTB.add(activate); 142 add(bottomButtonTB, GBC.eol().insets(12, 4, 5, 4).fill(GBC.HORIZONTAL)); 143 144 add(new JLabel(tr("Available styles (from {0}):", availableStylesUrl)), GBC.eol().insets(11, 0, 5, 0)); 145 add(new JScrollPane(lstAvailableStyles), GBC.std().insets(10, 0, 3, 0).fill(GBC.BOTH)); 146 147 sideButtonTB = new JToolBar(JToolBar.VERTICAL); 148 sideButtonTB.setFloatable(false); 149 sideButtonTB.setBorderPainted(false); 150 sideButtonTB.setOpaque(false); 151 sideButtonTB.add(new ReloadStylesAction(availableStylesUrl)); 152 add(sideButtonTB, GBC.eol().insets(0, 0, 10, 0).fill(GBC.VERTICAL)); 153 154 if (iconsPreferenceKey != null) { 155 selectionModel = new DefaultListSelectionModel(); 156 tblIconPaths = new JTable(iconPathsModel = new IconPathTableModel(selectionModel)); 157 tblIconPaths.setSelectionModel(selectionModel); 158 tblIconPaths.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 159 tblIconPaths.setTableHeader(null); 160 tblIconPaths.getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor(false)); 161 tblIconPaths.setRowHeight(20); 162 iconPathsModel.setIconPaths(Main.pref.getCollection(iconsPreferenceKey, null)); 163 164 EditIconPathAction editIconPathAction = new EditIconPathAction(); 165 tblIconPaths.getSelectionModel().addListSelectionListener(editIconPathAction); 166 167 RemoveIconPathAction removeIconPathAction = new RemoveIconPathAction(); 168 tblIconPaths.getSelectionModel().addListSelectionListener(removeIconPathAction); 169 tblIconPaths.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "delete"); 170 tblIconPaths.getActionMap().put("delete", removeIconPathAction); 171 172 add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(5, 10, 5, 10)); 173 add(new JLabel(tr("Icon paths:")), GBC.eol().insets(11, 0, 5, 0)); 174 add(sp = new JScrollPane(tblIconPaths), GBC.std().insets(10, 0, 3, 0).fill(GBC.BOTH)); 175 sp.setColumnHeaderView(null); 176 sideButtonTB = new JToolBar(JToolBar.VERTICAL); 177 sideButtonTB.setFloatable(false); 178 sideButtonTB.setBorderPainted(false); 179 sideButtonTB.setOpaque(false); 180 add(sideButtonTB, GBC.eol().insets(0, 0, 10, 0).fill(GBC.VERTICAL)); 181 sideButtonTB.add(new NewIconPathAction()); 182 sideButtonTB.add(editIconPathAction); 183 sideButtonTB.add(removeIconPathAction); 184 } 211 add(sideButtonTB, gbc); 212 213 gbc.gridx = 0; 214 gbc.gridy++; 215 gbc.weighty = 0.0; 216 gbc.weightx = 0.5; 217 gbc.fill = GBC.HORIZONTAL; 218 gbc.anchor = GBC.WEST; 219 gbc.insets = new Insets(0, 11, 0, 0); 220 221 JToolBar bottomLeftTB = new JToolBar(JToolBar.VERTICAL); 222 bottomLeftTB.setFloatable(false); 223 bottomLeftTB.setBorderPainted(false); 224 bottomLeftTB.setOpaque(false); 225 bottomLeftTB.add(new ReloadStylesAction(availableStylesUrl)); 226 middleTB.add(Box.createHorizontalGlue()); 227 add(bottomLeftTB, gbc); 228 229 gbc.gridx = 2; 230 gbc.anchor = GBC.CENTER; 231 gbc.insets = new Insets(0, 0, 0, 0); 232 233 JToolBar bottomRightTB = new JToolBar(); 234 bottomRightTB.setFloatable(false); 235 bottomRightTB.setBorderPainted(false); 236 bottomRightTB.setOpaque(false); 237 bottomRightTB.add(Box.createHorizontalGlue()); 238 bottomRightTB.add(new JButton(new ResetAction())); 239 add(bottomRightTB, gbc); 240 241 /*** 242 * Icon configuration 243 **/ 244 245 selectionModel = new DefaultListSelectionModel(); 246 tblIconPaths = new JTable(iconPathsModel = new IconPathTableModel(selectionModel)); 247 tblIconPaths.setSelectionModel(selectionModel); 248 tblIconPaths.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 249 tblIconPaths.setTableHeader(null); 250 tblIconPaths.getColumnModel().getColumn(0).setCellEditor(new FileOrUrlCellEditor(false)); 251 tblIconPaths.setRowHeight(20); 252 tblIconPaths.putClientProperty("terminateEditOnFocusLost", true); 253 iconPathsModel.setIconPaths(getInitialIconPathsList()); 254 255 EditIconPathAction editIconPathAction = new EditIconPathAction(); 256 tblIconPaths.getSelectionModel().addListSelectionListener(editIconPathAction); 257 258 RemoveIconPathAction removeIconPathAction = new RemoveIconPathAction(); 259 tblIconPaths.getSelectionModel().addListSelectionListener(removeIconPathAction); 260 tblIconPaths.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "delete"); 261 tblIconPaths.getActionMap().put("delete", removeIconPathAction); 262 263 gbc.gridx = 0; 264 gbc.gridy++; 265 gbc.weightx = 1.0; 266 gbc.gridwidth = GBC.REMAINDER; 267 gbc.insets = new Insets(8, 11, 8, 6); 268 269 add(new JSeparator(), gbc); 270 271 gbc.gridy++; 272 gbc.insets = new Insets(0, 11, 0, 6); 273 274 add(new JLabel(tr("Icon paths:")), gbc); 275 276 gbc.gridy++; 277 gbc.weighty = 0.2; 278 gbc.gridwidth = 3; 279 gbc.fill = GBC.BOTH; 280 gbc.insets = new Insets(0, 11, 0, 0); 281 282 add(sp = new JScrollPane(tblIconPaths), gbc); 283 sp.setColumnHeaderView(null); 284 285 gbc.gridx = 3; 286 gbc.gridwidth = 1; 287 gbc.weightx = 0.0; 288 gbc.fill = GBC.VERTICAL; 289 gbc.insets = new Insets(0, 0, 0, 6); 290 291 JToolBar sideButtonTBIcons = new JToolBar(JToolBar.VERTICAL); 292 sideButtonTBIcons.setFloatable(false); 293 sideButtonTBIcons.setBorderPainted(false); 294 sideButtonTBIcons.setOpaque(false); 295 sideButtonTBIcons.add(new NewIconPathAction()); 296 sideButtonTBIcons.add(editIconPathAction); 297 sideButtonTBIcons.add(removeIconPathAction); 298 add(sideButtonTBIcons, gbc); 299 } 300 301 /** 302 * Load the list of source entries that the user has configured. 303 */ 304 abstract public Collection<? extends SourceEntry> getInitialSourcesList(); 305 306 /** 307 * Load the list of configured icon paths. 308 */ 309 abstract public Collection<String> getInitialIconPathsList(); 310 311 /** 312 * Get the default list of entries (used when resetting the list). 313 */ 314 abstract public Collection<StyleSourceInfo> getDefault(); 315 316 /** 317 * Save the settings after user clicked "Ok". 318 * @return true if restart is required 319 */ 320 abstract public boolean finish(); 321 322 /** 323 * Provide the GUI strings. (There are differences for MapPaint and Preset) 324 */ 325 abstract protected String getStr(I18nString ident); 326 327 /** 328 * Identifiers for strings that need to be provided. 329 */ 330 protected enum I18nString { AVAILABLE_SOURCES, ACTIVE_SOURCES, NEW_SOURCE_ENTRY, 331 REMOVE_SOURCE_TOOLTIP, EDIT_SOURCE_TOOLTIP, ACTIVATE_TOOLTIP, RELOAD_ALL_AVAILABLE, 332 LOADING_SOURCES_FROM, FAILED_TO_LOAD_SOURCES_FROM, FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC, 333 ILLEGAL_FORMAT_OF_ENTRY } 334 335 /** 336 * adjust the preferred width of column col to the maximum preferred width of the cells 337 * requires JTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 338 */ 339 private static void adjustColumnWidth(JTable tbl, int col) { 340 int maxwidth = 0; 341 for (int row=0; row<tbl.getRowCount(); row++) { 342 TableCellRenderer tcr = tbl.getCellRenderer(row, col); 343 Object val = tbl.getValueAt(row, col); 344 Component comp = tcr.getTableCellRendererComponent(tbl, val, false, false, row, col); 345 maxwidth = Math.max(comp.getPreferredSize().width, maxwidth); 346 } 347 tbl.getColumnModel().getColumn(col).setPreferredWidth(maxwidth); 185 348 } 186 349 187 350 public boolean hasActiveStylesChanged() { 188 return !activeStylesModel.getStyles().equals(Main.pref.getCollection(pref, Collections.<String>emptyList())); 189 } 190 191 public Collection<String> getActiveStyles() { 351 Collection<? extends SourceEntry> prev = getInitialSourcesList(); 352 List<SourceEntry> cur = activeStylesModel.getStyles(); 353 if (prev.size() != cur.size()) 354 return true; 355 Iterator<? extends SourceEntry> p = prev.iterator(); 356 Iterator<SourceEntry> c = cur.iterator(); 357 while (p.hasNext()) { 358 SourceEntry pe = p.next(); 359 SourceEntry ce = c.next(); 360 if (!equal(pe.url, ce.url) || !equal(pe.name, ce.name) || pe.active != ce.active) 361 return true; 362 } 363 return false; 364 } 365 366 public Collection<SourceEntry> getActiveStyles() { 192 367 return activeStylesModel.getStyles(); 193 368 } 194 369 195 public void removeSource(String source) { 196 activeStylesModel.remove(source); 197 } 198 199 public boolean finish() { 200 boolean changed = false; 201 List<String> activeStyles = activeStylesModel.getStyles(); 202 203 if (activeStyles.size() > 0) { 204 if (Main.pref.putCollection(pref, activeStyles)) { 205 changed = true; 206 } 207 } else if (Main.pref.putCollection(pref, null)) { 208 changed = true; 209 } 210 211 if (tblIconPaths != null) { 212 List<String> iconPaths = iconPathsModel.getIconPaths(); 213 214 if (!iconPaths.isEmpty()) { 215 if (Main.pref.putCollection(iconpref, iconPaths)) { 216 changed = true; 217 } 218 } else if (Main.pref.putCollection(iconpref, null)) { 219 changed = true; 220 } 221 } 222 return changed; 370 public void removeSources(Collection<Integer> idxs) { 371 activeStylesModel.removeIdxs(idxs); 223 372 } 224 373 … … 234 383 } 235 384 236 static class AvailableStylesListModel extends DefaultListModel {385 protected static class AvailableStylesListModel extends DefaultListModel { 237 386 private ArrayList<StyleSourceInfo> data; 238 387 private DefaultListSelectionModel selectionModel; … … 286 435 } 287 436 288 static class ActiveStylesModel extends AbstractTableModel {289 private ArrayList<String> data;437 protected static class ActiveStylesModel extends AbstractTableModel { 438 private List<SourceEntry> data; 290 439 private DefaultListSelectionModel selectionModel; 291 440 292 441 public ActiveStylesModel(DefaultListSelectionModel selectionModel) { 293 442 this.selectionModel = selectionModel; 294 this.data = new ArrayList<S tring>();443 this.data = new ArrayList<SourceEntry>(); 295 444 } 296 445 … … 303 452 } 304 453 305 public Object getValueAt(int rowIndex, int columnIndex) { 454 @Override 455 public SourceEntry getValueAt(int rowIndex, int columnIndex) { 306 456 return data.get(rowIndex); 307 457 } … … 309 459 @Override 310 460 public boolean isCellEditable(int rowIndex, int columnIndex) { 311 return true;461 return false; 312 462 } 313 463 … … 317 467 } 318 468 319 public void setActiveStyles(Collection<String> styles) { 469 public void setActiveStyles(Collection<? extends SourceEntry> sources) { 470 //abstract public Collection<? extends StyleSourceEntry> getInitialStyleSources(); 320 471 data.clear(); 321 if (styles !=null) { 322 data.addAll(styles); 323 } 324 sort(); 472 if (sources != null) { 473 data.addAll(sources); 474 } 325 475 fireTableDataChanged(); 326 476 } 327 477 328 public void addStyle(S tringstyle) {478 public void addStyle(SourceEntry style) { 329 479 if (style == null) return; 330 480 data.add(style); 331 sort();332 481 fireTableDataChanged(); 333 482 int idx = data.indexOf(style); … … 340 489 if (style == null) return; 341 490 if (pos < 0 || pos >= getRowCount()) return; 342 data.set(pos, style); 491 data.get(pos).url = style; 492 fireTableDataChanged(); 493 int idx = data.indexOf(style); 494 if (idx >= 0) { 495 selectionModel.setSelectionInterval(idx, idx); 496 } 497 } 498 499 public void removeSelected() { 500 Iterator<SourceEntry> it = data.iterator(); 501 int i=0; 502 while(it.hasNext()) { 503 it.next(); 504 if (selectionModel.isSelectedIndex(i)) { 505 it.remove(); 506 } 507 i++; 508 } 509 fireTableDataChanged(); 510 } 511 512 public void removeIdxs(Collection<Integer> idxs) { 513 List<SourceEntry> newData = new ArrayList<SourceEntry>(); 514 for (int i=0; i<data.size(); ++i) { 515 if (!idxs.contains(i)) { 516 newData.add(data.get(i)); 517 } 518 } 519 data = newData; 520 fireTableDataChanged(); 521 } 522 523 public void addStylesFromSources(List<StyleSourceInfo> sources) { 524 if (sources == null) return; 525 for (StyleSourceInfo info: sources) { 526 data.add(new SourceEntry(info.url, info.name, info.getDisplayName(), true)); 527 } 528 fireTableDataChanged(); 529 selectionModel.clearSelection(); 530 for (StyleSourceInfo info: sources) { 531 int pos = data.indexOf(info); 532 if (pos >=0) { 533 selectionModel.addSelectionInterval(pos, pos); 534 } 535 } 536 } 537 538 public List<SourceEntry> getStyles() { 539 return new ArrayList<SourceEntry>(data); 540 } 541 } 542 543 public static class StyleSourceInfo extends SourceEntry { 544 public String simpleFileName; 545 public String version; 546 public String author; 547 public String link; 548 public String description; 549 550 public StyleSourceInfo(String simpleFileName, String url) { 551 super(url, null, null, true); 552 this.simpleFileName = simpleFileName; 553 version = author = link = description = shortdescription = null; 554 } 555 556 /** 557 * @return string representation for GUI list or menu entry 558 */ 559 public String getDisplayName() { 560 return shortdescription == null ? simpleFileName : shortdescription; 561 } 562 563 public String getTooltip() { 564 String s = tr("Short Description: {0}", getDisplayName()) + "<br>" + tr("URL: {0}", url); 565 if (author != null) { 566 s += "<br>" + tr("Author: {0}", author); 567 } 568 if (link != null) { 569 s += "<br>" + tr("Webpage: {0}", link); 570 } 571 if (description != null) { 572 s += "<br>" + tr("Description: {0}", description); 573 } 574 if (version != null) { 575 s += "<br>" + tr("Version: {0}", version); 576 } 577 return "<html>" + s + "</html>"; 578 } 579 580 @Override 581 public String toString() { 582 return "<html><b>" + getDisplayName() + "</b> (" + url + ")</html>"; 583 } 584 } 585 586 protected class EditSourceEntryDialog extends ExtendedDialog { 587 588 /** 589 * We call this text field "name", but it is actually the shortdescription. 590 */ 591 private JTextField tfName; 592 private JTextField tfURL; 593 594 public EditSourceEntryDialog(Component parent, String title, SourceEntry e) { 595 super(parent, 596 title, 597 new String[] {tr("Ok"), tr("Cancel")}); 598 599 JPanel p = new JPanel(new GridBagLayout()); 600 601 tfName = new JTextField(60); 602 p.add(new JLabel(tr("Name (optional):")), GBC.std().insets(15, 0, 5, 5)); 603 p.add(tfName, GBC.eol().insets(0, 0, 5, 5)); 604 605 tfURL = new JTextField(60); 606 p.add(new JLabel(tr("URL / File:")), GBC.std().insets(15, 0, 5, 0)); 607 p.add(tfURL, GBC.std().insets(0, 0, 5, 0)); 608 JButton fileChooser = new JButton(new LaunchFileChooserAction()); 609 fileChooser.setMargin(new Insets(0, 0, 0, 0)); 610 p.add(fileChooser, GBC.eol().insets(0, 0, 5, 0)); 611 612 if (e != null) { 613 if (e.shortdescription != null) { 614 tfName.setText(e.shortdescription); 615 } 616 tfURL.setText(e.url); 617 } 618 619 setButtonIcons(new String[] {"ok", "cancel"}); 620 setContent(p); 621 } 622 623 class LaunchFileChooserAction extends AbstractAction { 624 public LaunchFileChooserAction() { 625 putValue(SMALL_ICON, ImageProvider.get("open")); 626 putValue(SHORT_DESCRIPTION, tr("Launch a file chooser to select a file")); 627 } 628 629 protected void prepareFileChooser(String url, JFileChooser fc) { 630 if (url == null || url.trim().length() == 0) return; 631 URL sourceUrl = null; 632 try { 633 sourceUrl = new URL(url); 634 } catch(MalformedURLException e) { 635 File f = new File(url); 636 if (f.isFile()) { 637 f = f.getParentFile(); 638 } 639 if (f != null) { 640 fc.setCurrentDirectory(f); 641 } 642 return; 643 } 644 if (sourceUrl.getProtocol().startsWith("file")) { 645 File f = new File(sourceUrl.getPath()); 646 if (f.isFile()) { 647 f = f.getParentFile(); 648 } 649 if (f != null) { 650 fc.setCurrentDirectory(f); 651 } 652 } 653 } 654 655 public void actionPerformed(ActionEvent e) { 656 JFileChooser fc= new JFileChooser(); 657 prepareFileChooser(tfURL.getText(), fc); 658 int ret = fc.showOpenDialog(JOptionPane.getFrameForComponent(StyleSourceEditor.this)); 659 if (ret != JFileChooser.APPROVE_OPTION) 660 return; 661 tfURL.setText(fc.getSelectedFile().toString()); 662 } 663 } 664 665 public String getShortdescription() { 666 return tfName.getText(); 667 } 668 669 public String getURL() { 670 return tfURL.getText(); 671 } 672 } 673 674 class NewActiveStyleAction extends AbstractAction { 675 public NewActiveStyleAction() { 676 putValue(NAME, tr("New")); 677 putValue(SHORT_DESCRIPTION, tr("Add a filename or an URL of an active style")); 678 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add")); 679 } 680 681 public void actionPerformed(ActionEvent evt) { 682 EditSourceEntryDialog editEntryDialog = new EditSourceEntryDialog( 683 StyleSourceEditor.this, 684 getStr(I18nString.NEW_SOURCE_ENTRY), 685 null); 686 editEntryDialog.showDialog(); 687 if (editEntryDialog.getValue() == 1) { 688 activeStylesModel.addStyle(new SourceEntry( 689 editEntryDialog.getURL(), 690 null, editEntryDialog.getShortdescription(), true)); 691 activeStylesModel.fireTableDataChanged(); 692 } 693 } 694 } 695 696 class RemoveActiveStylesAction extends AbstractAction implements ListSelectionListener { 697 698 public RemoveActiveStylesAction() { 699 putValue(NAME, tr("Remove")); 700 putValue(SHORT_DESCRIPTION, getStr(I18nString.REMOVE_SOURCE_TOOLTIP)); 701 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete")); 702 updateEnabledState(); 703 } 704 705 protected void updateEnabledState() { 706 setEnabled(tblActiveStyles.getSelectedRowCount() > 0); 707 } 708 709 public void valueChanged(ListSelectionEvent e) { 710 updateEnabledState(); 711 } 712 713 public void actionPerformed(ActionEvent e) { 714 activeStylesModel.removeSelected(); 715 } 716 } 717 718 class EditActiveStyleAction extends AbstractAction implements ListSelectionListener { 719 public EditActiveStyleAction() { 720 putValue(NAME, tr("Edit")); 721 putValue(SHORT_DESCRIPTION, getStr(I18nString.EDIT_SOURCE_TOOLTIP)); 722 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit")); 723 updateEnabledState(); 724 } 725 726 protected void updateEnabledState() { 727 setEnabled(tblActiveStyles.getSelectedRowCount() == 1); 728 } 729 730 public void valueChanged(ListSelectionEvent e) { 731 updateEnabledState(); 732 } 733 734 public void actionPerformed(ActionEvent evt) { 735 int pos = tblActiveStyles.getSelectedRow(); 736 if (pos < 0 || pos >= tblActiveStyles.getRowCount()) 737 return; 738 739 SourceEntry e = activeStylesModel.getValueAt(pos, 0); 740 741 EditSourceEntryDialog editEntryDialog = new EditSourceEntryDialog( 742 StyleSourceEditor.this, tr("Edit source entry:"), e); 743 editEntryDialog.showDialog(); 744 if (editEntryDialog.getValue() == 1) { 745 if (e.shortdescription != null || !equal(editEntryDialog.getShortdescription(), "")) { 746 e.shortdescription = editEntryDialog.getShortdescription(); 747 if (equal(e.shortdescription, "")) { 748 e.shortdescription = null; 749 } 750 } 751 e.url = editEntryDialog.getURL(); 752 activeStylesModel.fireTableCellUpdated(pos, 0); 753 } 754 } 755 } 756 757 class ActivateStylesAction extends AbstractAction implements ListSelectionListener { 758 public ActivateStylesAction() { 759 putValue(SHORT_DESCRIPTION, getStr(I18nString.ACTIVATE_TOOLTIP)); 760 putValue(SMALL_ICON, ImageProvider.get("preferences", "activatestyle")); 761 updateEnabledState(); 762 } 763 764 protected void updateEnabledState() { 765 setEnabled(lstAvailableStyles.getSelectedIndices().length > 0); 766 } 767 768 public void valueChanged(ListSelectionEvent e) { 769 updateEnabledState(); 770 } 771 772 public void actionPerformed(ActionEvent e) { 773 List<StyleSourceInfo> styleSources = availableStylesModel.getSelected(); 774 activeStylesModel.addStylesFromSources(styleSources); 775 } 776 } 777 778 class ResetAction extends AbstractAction { 779 780 public ResetAction() { 781 putValue(NAME, tr("Reset")); 782 putValue(SHORT_DESCRIPTION, tr("Reset to default")); 783 putValue(SMALL_ICON, ImageProvider.get("preferences", "reset")); 784 } 785 786 public void actionPerformed(ActionEvent e) { 787 activeStylesModel.setActiveStyles(getDefault()); 788 } 789 } 790 791 class ReloadStylesAction extends AbstractAction { 792 private String url; 793 public ReloadStylesAction(String url) { 794 putValue(NAME, tr("Reload")); 795 putValue(SHORT_DESCRIPTION, tr(getStr(I18nString.RELOAD_ALL_AVAILABLE), url)); 796 putValue(SMALL_ICON, ImageProvider.get("dialogs/refresh")); 797 this.url = url; 798 } 799 800 public void actionPerformed(ActionEvent e) { 801 MirroredInputStream.cleanup(url); 802 reloadAvailableStyles(url); 803 } 804 } 805 806 protected static class IconPathTableModel extends AbstractTableModel { 807 private ArrayList<String> data; 808 private DefaultListSelectionModel selectionModel; 809 810 public IconPathTableModel(DefaultListSelectionModel selectionModel) { 811 this.selectionModel = selectionModel; 812 this.data = new ArrayList<String>(); 813 } 814 815 public int getColumnCount() { 816 return 1; 817 } 818 819 public int getRowCount() { 820 return data == null ? 0 : data.size(); 821 } 822 823 public Object getValueAt(int rowIndex, int columnIndex) { 824 return data.get(rowIndex); 825 } 826 827 @Override 828 public boolean isCellEditable(int rowIndex, int columnIndex) { 829 return true; 830 } 831 832 @Override 833 public void setValueAt(Object aValue, int rowIndex, int columnIndex) { 834 updatePath(rowIndex, (String)aValue); 835 } 836 837 public void setIconPaths(Collection<String> styles) { 838 data.clear(); 839 if (styles !=null) { 840 data.addAll(styles); 841 } 343 842 sort(); 344 843 fireTableDataChanged(); 345 int idx = data.indexOf(style); 844 } 845 846 public void addPath(String path) { 847 if (path == null) return; 848 data.add(path); 849 sort(); 850 fireTableDataChanged(); 851 int idx = data.indexOf(path); 852 if (idx >= 0) { 853 selectionModel.setSelectionInterval(idx, idx); 854 } 855 } 856 857 public void updatePath(int pos, String path) { 858 if (path == null) return; 859 if (pos < 0 || pos >= getRowCount()) return; 860 data.set(pos, path); 861 sort(); 862 fireTableDataChanged(); 863 int idx = data.indexOf(path); 346 864 if (idx >= 0) { 347 865 selectionModel.setSelectionInterval(idx, idx); … … 360 878 } 361 879 fireTableDataChanged(); 362 } 363 364 public void remove(String source) { 365 data.remove(source); 366 fireTableDataChanged(); 880 selectionModel.clearSelection(); 367 881 } 368 882 … … 382 896 } 383 897 384 public void addStylesFromSources(List<StyleSourceInfo> sources) {385 if (sources == null) return;386 for (StyleSourceInfo info: sources) {387 data.add(info.url);388 }389 sort();390 fireTableDataChanged();391 selectionModel.clearSelection();392 for (StyleSourceInfo info: sources) {393 int pos = data.indexOf(info.url);394 if (pos >=0) {395 selectionModel.addSelectionInterval(pos, pos);396 }397 }398 }399 400 public List<String> getStyles() {401 return new ArrayList<String>(data);402 }403 404 public String getStyle(int pos) {405 return data.get(pos);406 }407 }408 409 public static class StyleSourceInfo {410 String version;411 String name;412 String url;413 String author;414 String link;415 String description;416 String shortdescription;417 418 public StyleSourceInfo(String name, String url) {419 this.name = name;420 this.url = url;421 version = author = link = description = shortdescription = null;422 }423 424 public String getName() {425 return shortdescription == null ? name : shortdescription;426 }427 428 public String getTooltip() {429 String s = tr("Short Description: {0}", getName()) + "<br>" + tr("URL: {0}", url);430 if (author != null) {431 s += "<br>" + tr("Author: {0}", author);432 }433 if (link != null) {434 s += "<br>" + tr("Webpage: {0}", link);435 }436 if (description != null) {437 s += "<br>" + tr("Description: {0}", description);438 }439 if (version != null) {440 s += "<br>" + tr("Version: {0}", version);441 }442 return "<html>" + s + "</html>";443 }444 445 @Override446 public String toString() {447 return getName() + " (" + url + ")";448 }449 }450 451 class NewActiveStyleAction extends AbstractAction {452 public NewActiveStyleAction() {453 putValue(NAME, tr("New"));454 putValue(SHORT_DESCRIPTION, tr("Add a filename or an URL of an active style"));455 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));456 }457 458 public void actionPerformed(ActionEvent e) {459 activeStylesModel.addStyle("");460 tblActiveStyles.requestFocusInWindow();461 tblActiveStyles.editCellAt(activeStylesModel.getRowCount()-1, 0);462 }463 }464 465 class RemoveActiveStylesAction extends AbstractAction implements ListSelectionListener {466 467 public RemoveActiveStylesAction() {468 putValue(NAME, tr("Remove"));469 putValue(SHORT_DESCRIPTION, tr("Remove the selected styles from the list of active styles"));470 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));471 updateEnabledState();472 }473 474 protected void updateEnabledState() {475 setEnabled(tblActiveStyles.getSelectedRowCount() > 0);476 }477 478 public void valueChanged(ListSelectionEvent e) {479 updateEnabledState();480 }481 482 public void actionPerformed(ActionEvent e) {483 activeStylesModel.removeSelected();484 }485 }486 487 class EditActiveStyleAction extends AbstractAction implements ListSelectionListener {488 public EditActiveStyleAction() {489 putValue(NAME, tr("Edit"));490 putValue(SHORT_DESCRIPTION, tr("Edit the filename or URL for the selected active style"));491 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));492 updateEnabledState();493 }494 495 protected void updateEnabledState() {496 setEnabled(tblActiveStyles.getSelectedRowCount() == 1);497 }498 499 public void valueChanged(ListSelectionEvent e) {500 updateEnabledState();501 }502 503 public void actionPerformed(ActionEvent e) {504 int pos = tblActiveStyles.getSelectedRow();505 tblActiveStyles.editCellAt(pos, 0);506 }507 }508 509 class ActivateStylesAction extends AbstractAction implements ListSelectionListener {510 public ActivateStylesAction() {511 putValue(NAME, tr("Activate"));512 putValue(SHORT_DESCRIPTION, tr("Add the selected available styles to the list of active styles"));513 putValue(SMALL_ICON, ImageProvider.get("preferences", "activatestyle"));514 updateEnabledState();515 }516 517 protected void updateEnabledState() {518 setEnabled(lstAvailableStyles.getSelectedIndices().length > 0);519 }520 521 public void valueChanged(ListSelectionEvent e) {522 updateEnabledState();523 }524 525 public void actionPerformed(ActionEvent e) {526 List<StyleSourceInfo> styleSources = availableStylesModel.getSelected();527 activeStylesModel.addStylesFromSources(styleSources);528 }529 }530 531 class ReloadStylesAction extends AbstractAction {532 private String url;533 public ReloadStylesAction(String url) {534 putValue(NAME, tr("Reload"));535 putValue(SHORT_DESCRIPTION, tr("Reloads the list of available styles from ''{0}''", url));536 putValue(SMALL_ICON, ImageProvider.get("dialogs/refresh"));537 this.url = url;538 }539 540 public void actionPerformed(ActionEvent e) {541 MirroredInputStream.cleanup(url);542 reloadAvailableStyles(url);543 }544 }545 546 static class IconPathTableModel extends AbstractTableModel {547 private ArrayList<String> data;548 private DefaultListSelectionModel selectionModel;549 550 public IconPathTableModel(DefaultListSelectionModel selectionModel) {551 this.selectionModel = selectionModel;552 this.data = new ArrayList<String>();553 }554 555 public int getColumnCount() {556 return 1;557 }558 559 public int getRowCount() {560 return data == null ? 0 : data.size();561 }562 563 public Object getValueAt(int rowIndex, int columnIndex) {564 return data.get(rowIndex);565 }566 567 @Override568 public boolean isCellEditable(int rowIndex, int columnIndex) {569 return true;570 }571 572 @Override573 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {574 updatePath(rowIndex, (String)aValue);575 }576 577 public void setIconPaths(Collection<String> styles) {578 data.clear();579 if (styles !=null) {580 data.addAll(styles);581 }582 sort();583 fireTableDataChanged();584 }585 586 public void addPath(String path) {587 if (path == null) return;588 data.add(path);589 sort();590 fireTableDataChanged();591 int idx = data.indexOf(path);592 if (idx >= 0) {593 selectionModel.setSelectionInterval(idx, idx);594 }595 }596 597 public void updatePath(int pos, String path) {598 if (path == null) return;599 if (pos < 0 || pos >= getRowCount()) return;600 data.set(pos, path);601 sort();602 fireTableDataChanged();603 int idx = data.indexOf(path);604 if (idx >= 0) {605 selectionModel.setSelectionInterval(idx, idx);606 }607 }608 609 public void removeSelected() {610 Iterator<String> it = data.iterator();611 int i=0;612 while(it.hasNext()) {613 it.next();614 if (selectionModel.isSelectedIndex(i)) {615 it.remove();616 }617 i++;618 }619 fireTableDataChanged();620 selectionModel.clearSelection();621 }622 623 protected void sort() {624 Collections.sort(625 data,626 new Comparator<String>() {627 public int compare(String o1, String o2) {628 if (o1.equals("") && o2.equals(""))629 return 0;630 if (o1.equals("")) return 1;631 if (o2.equals("")) return -1;632 return o1.compareTo(o2);633 }634 }635 );636 }637 638 898 public List<String> getIconPaths() { 639 899 return new ArrayList<String>(data); … … 711 971 setEnabled(list.isEnabled()); 712 972 setFont(list.getFont()); 973 setFont(getFont().deriveFont(Font.PLAIN)); 713 974 setOpaque(true); 714 975 setToolTipText(((StyleSourceInfo) value).getTooltip()); … … 723 984 724 985 public StyleSourceLoader(String url) { 725 super(tr( "Loading style sources from ''{0}''", url));986 super(tr(getStr(I18nString.LOADING_SOURCES_FROM), url)); 726 987 this.url = url; 727 988 } … … 745 1006 String emsg = e.getMessage() != null ? e.getMessage() : e.toString(); 746 1007 emsg = emsg.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); 747 String msg = tr("<html>Failed to load the list of style sources from<br>" 748 + "''{0}''.<br>" 749 + "<br>" 750 + "Details (untranslated):<br>{1}</html>", 751 url, emsg 752 ); 1008 String msg = tr(getStr(I18nString.FAILED_TO_LOAD_SOURCES_FROM), url, emsg); 753 1009 754 1010 HelpAwareOptionPane.showOptionDialog( … … 757 1013 tr("Error"), 758 1014 JOptionPane.ERROR_MESSAGE, 759 ht( "/Preferences/Styles#FailedToLoadStyleSources")1015 ht(getStr(I18nString.FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC)) 760 1016 ); 761 1017 } … … 766 1022 String lang = LanguageInfo.getLanguageCodeXML(); 767 1023 try { 768 StyleSourceInfo i = new StyleSourceInfo("elemstyles.xml", "resource://data/elemstyles.xml"); 769 i.shortdescription = tr("Internal style"); 770 i.description = tr("Internal style to be used as base for runtime switchable overlay styles"); 771 styles.add(i); 1024 styles.addAll(getDefault()); 772 1025 MirroredInputStream stream = new MirroredInputStream(url); 773 1026 InputStreamReader r; … … 789 1042 Matcher m = Pattern.compile("^\t([^:]+): *(.+)$").matcher(line); 790 1043 if (! m.matches()) { 791 System.err.println(tr( "Warning: illegal format of entry in style list ''{0}''. Got ''{1}''", url, line));1044 System.err.println(tr(getStr(I18nString.ILLEGAL_FORMAT_OF_ENTRY), url, line)); 792 1045 continue; 793 1046 } … … 805 1058 } else if ("shortdescription".equals(key) && last.shortdescription == null) { 806 1059 last.shortdescription = value; 1060 } else if ("name".equals(key) && last.name == null) { 1061 last.name = value; 807 1062 } else if ((lang + "author").equals(key)) { 808 1063 last.author = value; … … 821 1076 styles.add(last = new StyleSourceInfo(m.group(1), m.group(2))); 822 1077 } else { 823 System.err.println(tr( "Warning: illegal format of entry in style list ''{0}''. Got ''{1}''", url, line));1078 System.err.println(tr(getStr(I18nString.ILLEGAL_FORMAT_OF_ENTRY), url, line)); 824 1079 } 825 1080 } … … 835 1090 } 836 1091 availableStylesModel.setStyleSources(styles); 1092 } 1093 } 1094 1095 class SourceEntryRenderer extends DefaultTableCellRenderer { 1096 @Override 1097 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 1098 SourceEntry se = (SourceEntry) value; 1099 JLabel label = (JLabel)super.getTableCellRendererComponent(table, 1100 fromSourceEntry(se), isSelected, hasFocus, row, column); 1101 return label; 1102 } 1103 1104 private String fromSourceEntry(SourceEntry entry) { 1105 StringBuilder s = new StringBuilder("<html><b>"); 1106 if (entry.shortdescription != null) { 1107 s.append(entry.shortdescription).append("</b> ("); 1108 } 1109 s.append(entry.url); 1110 if (entry.name != null) { 1111 s.append(")"); 1112 } 1113 s.append("</html>"); 1114 return s.toString(); 837 1115 } 838 1116 } … … 995 1273 } 996 1274 1275 1276 /** 1277 * Convert mappaint and preset source preferences from a simple list to 1278 * array with one line for each source entry. 1279 * 1280 * MapPaint: 1281 * 1282 * Old format 1283 * key: mappaint.style.sources 1284 * value: list of "<name>=<url>" pairs. The "<name>=" part is optional. 1285 * The style is always active. 1286 * default: empty list 1287 * 1288 * key: mappaint.style.enable-defaults 1289 * value: if true, the default style "resource://data/elemstyles.xml" should 1290 * be loaded. 1291 * default: true 1292 * 1293 * New format 1294 * key: mappaint.style.sources-list 1295 * value: each line is a list with entries: url, name, shortdescription, active 1296 * default: 1297 * One line: "resource://data/elemstyles.xml", "standard", tr("Internal Style"), true 1298 * 1299 * Tagging Preset: 1300 * 1301 * the same, but "name" and "active" are not needed and omitted 1302 * 1303 */ 1304 abstract public static class SourcePrefMigration { 1305 1306 private final String oldPref; 1307 private final String oldPrefEnableDefaults; 1308 private final String pref; 1309 1310 public SourcePrefMigration(String oldPref, String oldPrefEnableDefaults, String pref) { 1311 this.oldPref = oldPref; 1312 this.oldPrefEnableDefaults = oldPrefEnableDefaults; 1313 this.pref = pref; 1314 } 1315 1316 abstract public Collection<StyleSourceInfo> getDefault(); 1317 1318 abstract public Collection<String> serialize(SourceEntry entry); 1319 1320 abstract public SourceEntry deserialize(List<String> entryStr); 1321 1322 public List<SourceEntry> get() { 1323 List<SourceEntry> entries = readNewFormatImpl(); 1324 if (entries == null) { 1325 1326 entries = readOldFormat(); 1327 put(entries); 1328 return entries; 1329 } 1330 return entries; 1331 } 1332 1333 public boolean put(Collection<? extends SourceEntry> entries) { 1334 boolean changed = false; 1335 if (entries.isEmpty()) { 1336 changed |= Main.pref.put(pref + "._empty_", true); 1337 changed |= Main.pref.putArray(pref, null); 1338 } else { 1339 Collection<Collection<String>> setting = new ArrayList<Collection<String>>(); 1340 for (SourceEntry e : entries) { 1341 setting.add(serialize(e)); 1342 } 1343 changed |= Main.pref.put(pref + "._empty_", null); 1344 changed |= Main.pref.putArray(pref, setting); 1345 } 1346 return changed; 1347 } 1348 1349 public List<SourceEntry> readOldFormat() { 1350 List<SourceEntry> result = new ArrayList<SourceEntry>(); 1351 if (Main.pref.getBoolean(oldPrefEnableDefaults, true)) { 1352 result.addAll(getDefault()); 1353 } 1354 1355 List<String> lines = new LinkedList<String>(Main.pref.getCollection(oldPref)); 1356 for (String line : lines) { 1357 String[] a = null; 1358 if (line.indexOf("=") >= 0) { 1359 a = line.split("=", 2); 1360 } else { 1361 a = new String[] { null, line }; 1362 } 1363 result.add(new SourceEntry(a[1], a[0], null, true)); 1364 } 1365 1366 return result; 1367 } 1368 1369 public Collection<? extends SourceEntry> readNewFormat() { 1370 List<SourceEntry> entries = readNewFormatImpl(); 1371 if (entries == null) { 1372 return getDefault(); 1373 } 1374 return entries; 1375 } 1376 1377 private List<SourceEntry> readNewFormatImpl() { 1378 List<SourceEntry> entries = new ArrayList<SourceEntry>(); 1379 Collection<Collection<String>> mappaintSrc = Main.pref.getArray(pref, null); 1380 if (mappaintSrc == null || mappaintSrc.isEmpty()) { 1381 if (Main.pref.getBoolean(pref + "._empty_", false)) { 1382 return Collections.<SourceEntry>emptyList(); 1383 } 1384 return null; 1385 } 1386 1387 for (Collection<String> sourcePref : mappaintSrc) { 1388 SourceEntry e = deserialize(new ArrayList<String>(sourcePref)); 1389 if (e != null) { 1390 entries.add(e); 1391 } 1392 } 1393 return entries; 1394 } 1395 } 1396 997 1397 } -
trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
r3534 r3796 2 2 package org.openstreetmap.josm.gui.preferences; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 … … 7 8 import java.io.IOException; 8 9 import java.util.ArrayList; 10 import java.util.Arrays; 9 11 import java.util.Collection; 12 import java.util.Collections; 10 13 import java.util.HashMap; 11 14 import java.util.List; … … 25 28 import org.openstreetmap.josm.gui.ExtendedDialog; 26 29 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener; 30 import org.openstreetmap.josm.gui.preferences.StyleSourceEditor.StyleSourceInfo; 27 31 import org.openstreetmap.josm.gui.tagging.TaggingPreset; 28 32 import org.openstreetmap.josm.gui.tagging.TaggingPresetMenu; … … 44 48 private StyleSourceEditor sources; 45 49 private JCheckBox sortMenu; 46 private JCheckBox enableDefault;47 48 50 49 51 private ValidationListener validationListener = new ValidationListener() { 50 52 public boolean validatePreferences() { 51 53 if (sources.hasActiveStylesChanged()) { 52 List<String> sourcesToRemove = new ArrayList<String>(); 54 List<Integer> sourcesToRemove = new ArrayList<Integer>(); 55 int i = -1; 53 56 SOURCES: 54 for (String source: sources.getActiveStyles()) { 57 for (SourceEntry source: sources.getActiveStyles()) { 58 i++; 55 59 boolean canLoad = false; 56 60 try { 57 TaggingPreset.readAll(source , false);61 TaggingPreset.readAll(source.url, false); 58 62 canLoad = true; 59 63 } catch (IOException e) { … … 66 70 continue SOURCES; 67 71 case 2: 68 sourcesToRemove.add( source);72 sourcesToRemove.add(i); 69 73 continue SOURCES; 70 74 default: … … 78 82 79 83 try { 80 TaggingPreset.readAll(source , true);84 TaggingPreset.readAll(source.url, true); 81 85 } catch (IOException e) { 82 86 // Should not happen, but at least show message … … 117 121 continue SOURCES; 118 122 case JOptionPane.NO_OPTION: 119 sourcesToRemove.add( source);123 sourcesToRemove.add(i); 120 124 continue SOURCES; 121 125 default: … … 124 128 } 125 129 } 126 for (String toRemove:sourcesToRemove) { 127 sources.removeSource(toRemove); 128 } 130 sources.removeSources(sourcesToRemove); 129 131 return true; 130 132 } else … … 136 138 sortMenu = new JCheckBox(tr("Sort presets menu"), 137 139 Main.pref.getBoolean("taggingpreset.sortmenu", false)); 138 enableDefault = new JCheckBox(tr("Enable built-in defaults"),139 Main.pref.getBoolean("taggingpreset.enable-defaults", true));140 140 141 141 final JPanel panel = new JPanel(new GridBagLayout()); 142 142 panel.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 )); 143 143 panel.add(sortMenu, GBC.eol().insets(5,5,5,0)); 144 panel.add(enableDefault, GBC.eol().insets(5,0,5,0)); 145 sources = new StyleSourceEditor("taggingpreset.sources", "taggingpreset.icon.sources", 146 "http://josm.openstreetmap.de/presets"); 144 sources = new TaggingPresetSourceEditor(); 147 145 panel.add(sources, GBC.eol().fill(GBC.BOTH)); 148 146 gui.mapcontent.addTab(tr("Tagging Presets"), panel); … … 163 161 } 164 162 163 class TaggingPresetSourceEditor extends StyleSourceEditor { 164 165 final private String iconpref = "taggingpreset.icon.sources"; 166 167 public TaggingPresetSourceEditor() { 168 super("http://josm.openstreetmap.de/presets"); 169 } 170 171 @Override 172 public Collection<? extends SourceEntry> getInitialSourcesList() { 173 return (new PresetPrefMigration()).get(); 174 } 175 176 @Override 177 public boolean finish() { 178 List<SourceEntry> activeStyles = activeStylesModel.getStyles(); 179 180 boolean changed = (new PresetPrefMigration()).put(activeStyles); 181 182 if (tblIconPaths != null) { 183 List<String> iconPaths = iconPathsModel.getIconPaths(); 184 185 if (!iconPaths.isEmpty()) { 186 if (Main.pref.putCollection(iconpref, iconPaths)) { 187 changed = true; 188 } 189 } else if (Main.pref.putCollection(iconpref, null)) { 190 changed = true; 191 } 192 } 193 return changed; 194 } 195 196 @Override 197 public Collection<StyleSourceInfo> getDefault() { 198 return (new PresetPrefMigration()).getDefault(); 199 } 200 201 @Override 202 public Collection<String> getInitialIconPathsList() { 203 return Main.pref.getCollection(iconpref, null); 204 } 205 206 @Override 207 public String getStr(I18nString ident) { 208 switch (ident) { 209 case AVAILABLE_SOURCES: 210 return tr("Available presets:"); 211 case ACTIVE_SOURCES: 212 return tr("Active presets:"); 213 case NEW_SOURCE_ENTRY: 214 return tr("New preset entry:"); 215 case REMOVE_SOURCE_TOOLTIP: 216 return tr("Remove the selected presets from the list of active presets"); 217 case EDIT_SOURCE_TOOLTIP: 218 return tr("Edit the filename or URL for the selected active preset"); 219 case ACTIVATE_TOOLTIP: 220 return tr("Add the selected available presets to the list of active presets"); 221 case RELOAD_ALL_AVAILABLE: 222 return marktr("Reloads the list of available presets from ''{0}''"); 223 case LOADING_SOURCES_FROM: 224 return marktr("Loading preset sources from ''{0}''"); 225 case FAILED_TO_LOAD_SOURCES_FROM: 226 return marktr("<html>Failed to load the list of preset sources from<br>" 227 + "''{0}''.<br>" 228 + "<br>" 229 + "Details (untranslated):<br>{1}</html>"); 230 case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC: 231 return "/Preferences/Presets#FailedToLoadPresetSources"; 232 case ILLEGAL_FORMAT_OF_ENTRY: 233 return marktr("Warning: illegal format of entry in preset list ''{0}''. Got ''{1}''"); 234 default: throw new AssertionError(); 235 } 236 } 237 } 238 165 239 public boolean ok() { 166 boolean restart = Main.pref.put("taggingpreset.enable-defaults", 167 enableDefault.getSelectedObjects() != null); 168 if(Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null)) { 169 restart = true; 170 } 171 if(sources.finish()) { 172 restart = true; 173 } 240 boolean restart = Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null); 241 restart |= sources.finish(); 242 174 243 return restart; 175 244 } … … 217 286 } 218 287 } 288 289 public static class PresetPrefMigration extends StyleSourceEditor.SourcePrefMigration { 290 291 public PresetPrefMigration() { 292 super("taggingpreset.sources", 293 "taggingpreset.enable-defaults", 294 "taggingpreset.sources-list"); 295 } 296 297 @Override 298 public Collection<StyleSourceInfo> getDefault() { 299 StyleSourceInfo i = new StyleSourceInfo("defaultpresets.xml", "resource://data/defaultpresets.xml"); 300 i.shortdescription = tr("Internal Preset"); 301 i.description = tr("The default preset for JOSM"); 302 return Collections.singletonList(i); 303 } 304 305 @Override 306 public Collection<String> serialize(SourceEntry entry) { 307 return Arrays.asList(new String[] {entry.url, entry.shortdescription}); 308 } 309 310 @Override 311 public SourceEntry deserialize(List<String> entryStr) { 312 if (entryStr.size() < 2) 313 return null; 314 String url = entryStr.get(0); 315 String shortdescription = entryStr.get(1); 316 return new SourceEntry(url, null, shortdescription, true); 317 } 318 } 219 319 } -
trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
r3794 r3796 64 64 import org.openstreetmap.josm.gui.layer.Layer; 65 65 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 66 import org.openstreetmap.josm.gui.preferences.SourceEntry; 67 import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference.PresetPrefMigration; 66 68 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField; 67 69 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority; … … 1228 1230 LinkedList<String> sources = new LinkedList<String>(); 1229 1231 1230 if(Main.pref.getBoolean("taggingpreset.enable-defaults", true)) {1231 sources.add( "resource://data/defaultpresets.xml");1232 } 1233 sources.addAll(Main.pref.getCollection("taggingpreset.sources", new LinkedList<String>())); 1232 for (SourceEntry e : (new PresetPrefMigration()).get()) { 1233 sources.add(e.url); 1234 } 1235 1234 1236 return sources; 1235 1237 } -
trunk/src/org/openstreetmap/josm/tools/Utils.java
r3711 r3796 29 29 30 30 /** 31 * for convenience: test whether 2 objects are either both null or a.equals(b) 32 */ 33 public static <T> boolean equal(T a, T b) { 34 if (a == null && b == null) 35 return true; 36 return (a != null && a.equals(b)); 37 } 38 39 /** 31 40 * return the modulus in the range [0, n) 32 41 */
Note:
See TracChangeset
for help on using the changeset viewer.