source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java@ 11810

Last change on this file since 11810 was 11810, checked in by Don-vip, 7 years ago

sonar - squid:S2325 - "private" methods that don't access instance data should be "static"

  • Property svn:eol-style set to native
File size: 37.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.imagery;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Color;
8import java.awt.Component;
9import java.awt.Dimension;
10import java.awt.FlowLayout;
11import java.awt.Font;
12import java.awt.GraphicsEnvironment;
13import java.awt.GridBagConstraints;
14import java.awt.GridBagLayout;
15import java.awt.event.ActionEvent;
16import java.awt.event.MouseAdapter;
17import java.awt.event.MouseEvent;
18import java.io.IOException;
19import java.net.MalformedURLException;
20import java.net.URL;
21import java.util.ArrayList;
22import java.util.HashMap;
23import java.util.HashSet;
24import java.util.List;
25import java.util.Map;
26import java.util.Set;
27
28import javax.swing.AbstractAction;
29import javax.swing.BorderFactory;
30import javax.swing.Box;
31import javax.swing.JButton;
32import javax.swing.JLabel;
33import javax.swing.JOptionPane;
34import javax.swing.JPanel;
35import javax.swing.JScrollPane;
36import javax.swing.JSeparator;
37import javax.swing.JTabbedPane;
38import javax.swing.JTable;
39import javax.swing.JToolBar;
40import javax.swing.UIManager;
41import javax.swing.event.ListSelectionEvent;
42import javax.swing.event.ListSelectionListener;
43import javax.swing.table.DefaultTableCellRenderer;
44import javax.swing.table.DefaultTableModel;
45import javax.swing.table.TableColumnModel;
46
47import org.openstreetmap.gui.jmapviewer.Coordinate;
48import org.openstreetmap.gui.jmapviewer.JMapViewer;
49import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
50import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
51import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
52import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
53import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
54import org.openstreetmap.josm.Main;
55import org.openstreetmap.josm.data.imagery.ImageryInfo;
56import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
57import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
58import org.openstreetmap.josm.data.imagery.OffsetBookmark;
59import org.openstreetmap.josm.data.imagery.Shape;
60import org.openstreetmap.josm.data.preferences.ColorProperty;
61import org.openstreetmap.josm.gui.download.DownloadDialog;
62import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
63import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
64import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
65import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
66import org.openstreetmap.josm.gui.util.GuiHelper;
67import org.openstreetmap.josm.gui.widgets.JosmEditorPane;
68import org.openstreetmap.josm.tools.GBC;
69import org.openstreetmap.josm.tools.ImageProvider;
70import org.openstreetmap.josm.tools.LanguageInfo;
71
72/**
73 * Imagery preferences, including imagery providers, settings and offsets.
74 * @since 3715
75 */
76public final class ImageryPreference extends DefaultTabPreferenceSetting {
77
78 private ImageryProvidersPanel imageryProviders;
79 private ImageryLayerInfo layerInfo;
80
81 private final CommonSettingsPanel commonSettings = new CommonSettingsPanel();
82 private final WMSSettingsPanel wmsSettings = new WMSSettingsPanel();
83 private final TMSSettingsPanel tmsSettings = new TMSSettingsPanel();
84
85 /**
86 * Factory used to create a new {@code ImageryPreference}.
87 */
88 public static class Factory implements PreferenceSettingFactory {
89 @Override
90 public PreferenceSetting createPreferenceSetting() {
91 return new ImageryPreference();
92 }
93 }
94
95 private ImageryPreference() {
96 super(/* ICON(preferences/) */ "imagery", tr("Imagery Preferences"), tr("Modify list of imagery layers displayed in the Imagery menu"),
97 false, new JTabbedPane());
98 }
99
100 private static void addSettingsSection(final JPanel p, String name, JPanel section) {
101 addSettingsSection(p, name, section, GBC.eol());
102 }
103
104 private static void addSettingsSection(final JPanel p, String name, JPanel section, GBC gbc) {
105 final JLabel lbl = new JLabel(name);
106 lbl.setFont(lbl.getFont().deriveFont(Font.BOLD));
107 lbl.setLabelFor(section);
108 p.add(lbl, GBC.std());
109 p.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
110 p.add(section, gbc.insets(20, 5, 0, 10));
111 }
112
113 private Component buildSettingsPanel() {
114 final JPanel p = new JPanel(new GridBagLayout());
115 p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
116
117 addSettingsSection(p, tr("Common Settings"), commonSettings);
118 addSettingsSection(p, tr("WMS Settings"), wmsSettings,
119 GBC.eol().fill(GBC.HORIZONTAL));
120 addSettingsSection(p, tr("TMS Settings"), tmsSettings,
121 GBC.eol().fill(GBC.HORIZONTAL));
122
123 p.add(new JPanel(), GBC.eol().fill(GBC.BOTH));
124 return GuiHelper.setDefaultIncrement(new JScrollPane(p));
125 }
126
127 @Override
128 public void addGui(final PreferenceTabbedPane gui) {
129 JPanel p = gui.createPreferenceTab(this);
130 JTabbedPane pane = getTabPane();
131 layerInfo = new ImageryLayerInfo(ImageryLayerInfo.instance);
132 imageryProviders = new ImageryProvidersPanel(gui, layerInfo);
133 pane.addTab(tr("Imagery providers"), imageryProviders);
134 pane.addTab(tr("Settings"), buildSettingsPanel());
135 pane.addTab(tr("Offset bookmarks"), new OffsetBookmarksPanel(gui));
136 pane.addTab(tr("Cache contents"), new CacheContentsPanel());
137 loadSettings();
138 p.add(pane, GBC.std().fill(GBC.BOTH));
139 }
140
141 /**
142 * Returns the imagery providers panel.
143 * @return The imagery providers panel.
144 */
145 public ImageryProvidersPanel getProvidersPanel() {
146 return imageryProviders;
147 }
148
149 private void loadSettings() {
150 commonSettings.loadSettings();
151 wmsSettings.loadSettings();
152 tmsSettings.loadSettings();
153 }
154
155 @Override
156 public boolean ok() {
157 layerInfo.save();
158 ImageryLayerInfo.instance.clear();
159 ImageryLayerInfo.instance.load(false);
160 Main.main.menu.imageryMenu.refreshOffsetMenu();
161 OffsetBookmark.saveBookmarks();
162
163 if (!GraphicsEnvironment.isHeadless()) {
164 DownloadDialog.getInstance().refreshTileSources();
165 }
166
167 boolean commonRestartRequired = commonSettings.saveSettings();
168 boolean wmsRestartRequired = wmsSettings.saveSettings();
169 boolean tmsRestartRequired = tmsSettings.saveSettings();
170
171 return commonRestartRequired || wmsRestartRequired || tmsRestartRequired;
172 }
173
174 /**
175 * Updates a server URL in the preferences dialog. Used by plugins.
176 *
177 * @param server
178 * The server name
179 * @param url
180 * The server URL
181 */
182 public void setServerUrl(String server, String url) {
183 for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) {
184 if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString())) {
185 imageryProviders.activeModel.setValueAt(url, i, 1);
186 return;
187 }
188 }
189 imageryProviders.activeModel.addRow(new String[] {server, url});
190 }
191
192 /**
193 * Gets a server URL in the preferences dialog. Used by plugins.
194 *
195 * @param server The server name
196 * @return The server URL
197 */
198 public String getServerUrl(String server) {
199 for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) {
200 if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString()))
201 return imageryProviders.activeModel.getValueAt(i, 1).toString();
202 }
203 return null;
204 }
205
206 /**
207 * A panel displaying imagery providers.
208 */
209 public static class ImageryProvidersPanel extends JPanel {
210 // Public JTables and JMapViewer
211 /** The table of active providers **/
212 public final JTable activeTable;
213 /** The table of default providers **/
214 public final JTable defaultTable;
215 /** The selection listener synchronizing map display with table of default providers **/
216 private final transient DefListSelectionListener defaultTableListener;
217 /** The map displaying imagery bounds of selected default providers **/
218 public final JMapViewer defaultMap;
219
220 // Public models
221 /** The model of active providers **/
222 public final ImageryLayerTableModel activeModel;
223 /** The model of default providers **/
224 public final ImageryDefaultLayerTableModel defaultModel;
225
226 // Public JToolbars
227 /** The toolbar on the right of active providers **/
228 public final JToolBar activeToolbar;
229 /** The toolbar on the middle of the panel **/
230 public final JToolBar middleToolbar;
231 /** The toolbar on the right of default providers **/
232 public final JToolBar defaultToolbar;
233
234 // Private members
235 private final PreferenceTabbedPane gui;
236 private final transient ImageryLayerInfo layerInfo;
237
238 /**
239 * class to render the URL information of Imagery source
240 * @since 8065
241 */
242 private static class ImageryURLTableCellRenderer extends DefaultTableCellRenderer {
243
244 private static final ColorProperty IMAGERY_BACKGROUND_COLOR = new ColorProperty(
245 marktr("Imagery Background: Default"),
246 new Color(200, 255, 200));
247
248 private final transient List<ImageryInfo> layers;
249
250 ImageryURLTableCellRenderer(List<ImageryInfo> layers) {
251 this.layers = layers;
252 }
253
254 @Override
255 public Component getTableCellRendererComponent(JTable table, Object value, boolean
256 isSelected, boolean hasFocus, int row, int column) {
257 JLabel label = (JLabel) super.getTableCellRendererComponent(
258 table, value, isSelected, hasFocus, row, column);
259 GuiHelper.setBackgroundReadable(label, UIManager.getColor("Table.background"));
260 if (value != null) { // Fix #8159
261 String t = value.toString();
262 for (ImageryInfo l : layers) {
263 if (l.getExtendedUrl().equals(t)) {
264 GuiHelper.setBackgroundReadable(label, IMAGERY_BACKGROUND_COLOR.get());
265 break;
266 }
267 }
268 label.setToolTipText((String) value);
269 }
270 return label;
271 }
272 }
273
274 /**
275 * class to render the name information of Imagery source
276 * @since 8064
277 */
278 private static class ImageryNameTableCellRenderer extends DefaultTableCellRenderer {
279 @Override
280 public Component getTableCellRendererComponent(JTable table, Object value, boolean
281 isSelected, boolean hasFocus, int row, int column) {
282 ImageryInfo info = (ImageryInfo) value;
283 JLabel label = (JLabel) super.getTableCellRendererComponent(
284 table, info == null ? null : info.getName(), isSelected, hasFocus, row, column);
285 GuiHelper.setBackgroundReadable(label, UIManager.getColor("Table.background"));
286 if (info != null) {
287 label.setToolTipText(info.getToolTipText());
288 }
289 return label;
290 }
291 }
292
293 /**
294 * Constructs a new {@code ImageryProvidersPanel}.
295 * @param gui The parent preference tab pane
296 * @param layerInfoArg The list of imagery entries to display
297 */
298 public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) {
299 super(new GridBagLayout());
300 this.gui = gui;
301 this.layerInfo = layerInfoArg;
302 this.activeModel = new ImageryLayerTableModel();
303
304 activeTable = new JTable(activeModel) {
305 @Override
306 public String getToolTipText(MouseEvent e) {
307 java.awt.Point p = e.getPoint();
308 return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
309 }
310 };
311 activeTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
312
313 defaultModel = new ImageryDefaultLayerTableModel();
314 defaultTable = new JTable(defaultModel);
315
316 defaultModel.addTableModelListener(e -> activeTable.repaint());
317 activeModel.addTableModelListener(e -> defaultTable.repaint());
318
319 TableColumnModel mod = defaultTable.getColumnModel();
320 mod.getColumn(2).setPreferredWidth(800);
321 mod.getColumn(2).setCellRenderer(new ImageryURLTableCellRenderer(layerInfo.getLayers()));
322 mod.getColumn(1).setPreferredWidth(400);
323 mod.getColumn(1).setCellRenderer(new ImageryNameTableCellRenderer());
324 mod.getColumn(0).setPreferredWidth(50);
325
326 mod = activeTable.getColumnModel();
327 mod.getColumn(1).setPreferredWidth(800);
328 mod.getColumn(1).setCellRenderer(new ImageryURLTableCellRenderer(layerInfo.getAllDefaultLayers()));
329 mod.getColumn(0).setPreferredWidth(200);
330
331 RemoveEntryAction remove = new RemoveEntryAction();
332 activeTable.getSelectionModel().addListSelectionListener(remove);
333
334 add(new JLabel(tr("Available default entries:")), GBC.eol().insets(5, 5, 0, 0));
335 // Add default item list
336 JScrollPane scrolldef = new JScrollPane(defaultTable);
337 scrolldef.setPreferredSize(new Dimension(200, 200));
338 add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
339
340 // Add default item map
341 defaultMap = new JMapViewer();
342 defaultMap.setTileSource(new OsmTileSource.Mapnik()); // for attribution
343 defaultMap.addMouseListener(new MouseAdapter() {
344 @Override
345 public void mouseClicked(MouseEvent e) {
346 if (e.getButton() == MouseEvent.BUTTON1) {
347 defaultMap.getAttribution().handleAttribution(e.getPoint(), true);
348 }
349 }
350 });
351 defaultMap.setZoomContolsVisible(false);
352 defaultMap.setMinimumSize(new Dimension(100, 200));
353 add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
354
355 defaultTableListener = new DefListSelectionListener();
356 defaultTable.getSelectionModel().addListSelectionListener(defaultTableListener);
357
358 defaultToolbar = new JToolBar(JToolBar.VERTICAL);
359 defaultToolbar.setFloatable(false);
360 defaultToolbar.setBorderPainted(false);
361 defaultToolbar.setOpaque(false);
362 defaultToolbar.add(new ReloadAction());
363 add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
364
365 ActivateAction activate = new ActivateAction();
366 defaultTable.getSelectionModel().addListSelectionListener(activate);
367 JButton btnActivate = new JButton(activate);
368
369 middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
370 middleToolbar.setFloatable(false);
371 middleToolbar.setBorderPainted(false);
372 middleToolbar.setOpaque(false);
373 middleToolbar.add(btnActivate);
374 add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 15, 5, 0));
375
376 add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
377
378 add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0));
379 JScrollPane scroll = new JScrollPane(activeTable);
380 add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5));
381 scroll.setPreferredSize(new Dimension(200, 200));
382
383 activeToolbar = new JToolBar(JToolBar.VERTICAL);
384 activeToolbar.setFloatable(false);
385 activeToolbar.setBorderPainted(false);
386 activeToolbar.setOpaque(false);
387 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMS));
388 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.TMS));
389 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMTS));
390 //activeToolbar.add(edit); TODO
391 activeToolbar.add(remove);
392 add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5));
393 }
394
395 // Listener of default providers list selection
396 private final class DefListSelectionListener implements ListSelectionListener {
397 // The current drawn rectangles and polygons
398 private final Map<Integer, MapRectangle> mapRectangles;
399 private final Map<Integer, List<MapPolygon>> mapPolygons;
400
401 private DefListSelectionListener() {
402 this.mapRectangles = new HashMap<>();
403 this.mapPolygons = new HashMap<>();
404 }
405
406 private void clearMap() {
407 defaultMap.removeAllMapRectangles();
408 defaultMap.removeAllMapPolygons();
409 mapRectangles.clear();
410 mapPolygons.clear();
411 }
412
413 @Override
414 public void valueChanged(ListSelectionEvent e) {
415 // First index can be set to -1 when the list is refreshed, so discard all map rectangles and polygons
416 if (e.getFirstIndex() == -1) {
417 clearMap();
418 } else if (!e.getValueIsAdjusting()) {
419 // Only process complete (final) selection events
420 for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) {
421 updateBoundsAndShapes(i);
422 }
423 // If needed, adjust map to show all map rectangles and polygons
424 if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
425 defaultMap.setDisplayToFitMapElements(false, true, true);
426 defaultMap.zoomOut();
427 }
428 }
429 }
430
431 private void updateBoundsAndShapes(int i) {
432 ImageryBounds bounds = defaultModel.getRow(i).getBounds();
433 if (bounds != null) {
434 List<Shape> shapes = bounds.getShapes();
435 if (shapes != null && !shapes.isEmpty()) {
436 if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
437 if (!mapPolygons.containsKey(i)) {
438 List<MapPolygon> list = new ArrayList<>();
439 mapPolygons.put(i, list);
440 // Add new map polygons
441 for (Shape shape : shapes) {
442 MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
443 list.add(polygon);
444 defaultMap.addMapPolygon(polygon);
445 }
446 }
447 } else if (mapPolygons.containsKey(i)) {
448 // Remove previously drawn map polygons
449 for (MapPolygon polygon : mapPolygons.get(i)) {
450 defaultMap.removeMapPolygon(polygon);
451 }
452 mapPolygons.remove(i);
453 }
454 // Only display bounds when no polygons (shapes) are defined for this provider
455 } else {
456 if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
457 if (!mapRectangles.containsKey(i)) {
458 // Add new map rectangle
459 Coordinate topLeft = new Coordinate(bounds.getMaxLat(), bounds.getMinLon());
460 Coordinate bottomRight = new Coordinate(bounds.getMinLat(), bounds.getMaxLon());
461 MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight);
462 mapRectangles.put(i, rectangle);
463 defaultMap.addMapRectangle(rectangle);
464 }
465 } else if (mapRectangles.containsKey(i)) {
466 // Remove previously drawn map rectangle
467 defaultMap.removeMapRectangle(mapRectangles.get(i));
468 mapRectangles.remove(i);
469 }
470 }
471 }
472 }
473 }
474
475 private class NewEntryAction extends AbstractAction {
476
477 private final ImageryInfo.ImageryType type;
478
479 NewEntryAction(ImageryInfo.ImageryType type) {
480 putValue(NAME, type.toString());
481 putValue(SHORT_DESCRIPTION, tr("Add a new {0} entry by entering the URL", type.toString()));
482 String icon = /* ICON(dialogs/) */ "add";
483 switch (type) {
484 case WMS:
485 icon = /* ICON(dialogs/) */ "add_wms";
486 break;
487 case TMS:
488 icon = /* ICON(dialogs/) */ "add_tms";
489 break;
490 case WMTS:
491 icon = /* ICON(dialogs/) */ "add_wmts";
492 break;
493 default:
494 break;
495 }
496 putValue(SMALL_ICON, ImageProvider.get("dialogs", icon));
497 this.type = type;
498 }
499
500 @Override
501 public void actionPerformed(ActionEvent evt) {
502 final AddImageryPanel p;
503 switch (type) {
504 case WMS:
505 p = new AddWMSLayerPanel();
506 break;
507 case TMS:
508 p = new AddTMSLayerPanel();
509 break;
510 case WMTS:
511 p = new AddWMTSLayerPanel();
512 break;
513 default:
514 throw new IllegalStateException("Type " + type + " not supported");
515 }
516
517 final AddImageryDialog addDialog = new AddImageryDialog(gui, p);
518 addDialog.showDialog();
519
520 if (addDialog.getValue() == 1) {
521 try {
522 activeModel.addRow(p.getImageryInfo());
523 } catch (IllegalArgumentException ex) {
524 if (ex.getMessage() == null || ex.getMessage().isEmpty())
525 throw ex;
526 else {
527 JOptionPane.showMessageDialog(Main.parent,
528 ex.getMessage(), tr("Error"),
529 JOptionPane.ERROR_MESSAGE);
530 }
531 }
532 }
533 }
534 }
535
536 private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
537
538 /**
539 * Constructs a new {@code RemoveEntryAction}.
540 */
541 RemoveEntryAction() {
542 putValue(NAME, tr("Remove"));
543 putValue(SHORT_DESCRIPTION, tr("Remove entry"));
544 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
545 updateEnabledState();
546 }
547
548 protected final void updateEnabledState() {
549 setEnabled(activeTable.getSelectedRowCount() > 0);
550 }
551
552 @Override
553 public void valueChanged(ListSelectionEvent e) {
554 updateEnabledState();
555 }
556
557 @Override
558 public void actionPerformed(ActionEvent e) {
559 Integer i;
560 while ((i = activeTable.getSelectedRow()) != -1) {
561 activeModel.removeRow(i);
562 }
563 }
564 }
565
566 private class ActivateAction extends AbstractAction implements ListSelectionListener {
567
568 /**
569 * Constructs a new {@code ActivateAction}.
570 */
571 ActivateAction() {
572 putValue(NAME, tr("Activate"));
573 putValue(SHORT_DESCRIPTION, tr("copy selected defaults"));
574 putValue(SMALL_ICON, ImageProvider.get("preferences", "activate-down"));
575 }
576
577 protected void updateEnabledState() {
578 setEnabled(defaultTable.getSelectedRowCount() > 0);
579 }
580
581 @Override
582 public void valueChanged(ListSelectionEvent e) {
583 updateEnabledState();
584 }
585
586 @Override
587 public void actionPerformed(ActionEvent e) {
588 int[] lines = defaultTable.getSelectedRows();
589 if (lines.length == 0) {
590 JOptionPane.showMessageDialog(
591 gui,
592 tr("Please select at least one row to copy."),
593 tr("Information"),
594 JOptionPane.INFORMATION_MESSAGE);
595 return;
596 }
597
598 Set<String> acceptedEulas = new HashSet<>();
599
600 outer:
601 for (int line : lines) {
602 ImageryInfo info = defaultModel.getRow(line);
603
604 // Check if an entry with exactly the same values already exists
605 for (int j = 0; j < activeModel.getRowCount(); j++) {
606 if (info.equalsBaseValues(activeModel.getRow(j))) {
607 // Select the already existing row so the user has
608 // some feedback in case an entry exists
609 activeTable.getSelectionModel().setSelectionInterval(j, j);
610 activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true));
611 continue outer;
612 }
613 }
614
615 String eulaURL = info.getEulaAcceptanceRequired();
616 // If set and not already accepted, ask for EULA acceptance
617 if (eulaURL != null && !acceptedEulas.contains(eulaURL)) {
618 if (confirmEulaAcceptance(gui, eulaURL)) {
619 acceptedEulas.add(eulaURL);
620 } else {
621 continue outer;
622 }
623 }
624
625 activeModel.addRow(new ImageryInfo(info));
626 int lastLine = activeModel.getRowCount() - 1;
627 activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
628 activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true));
629 }
630 }
631 }
632
633 private class ReloadAction extends AbstractAction {
634
635 /**
636 * Constructs a new {@code ReloadAction}.
637 */
638 ReloadAction() {
639 putValue(SHORT_DESCRIPTION, tr("Update default entries"));
640 putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
641 }
642
643 @Override
644 public void actionPerformed(ActionEvent evt) {
645 layerInfo.loadDefaults(true, false, false);
646 defaultModel.fireTableDataChanged();
647 defaultTable.getSelectionModel().clearSelection();
648 defaultTableListener.clearMap();
649 /* loading new file may change active layers */
650 activeModel.fireTableDataChanged();
651 }
652 }
653
654 /**
655 * The table model for imagery layer list
656 */
657 public class ImageryLayerTableModel extends DefaultTableModel {
658 /**
659 * Constructs a new {@code ImageryLayerTableModel}.
660 */
661 public ImageryLayerTableModel() {
662 setColumnIdentifiers(new String[] {tr("Menu Name"), tr("Imagery URL")});
663 }
664
665 /**
666 * Returns the imagery info at the given row number.
667 * @param row The row number
668 * @return The imagery info at the given row number
669 */
670 public ImageryInfo getRow(int row) {
671 return layerInfo.getLayers().get(row);
672 }
673
674 /**
675 * Adds a new imagery info as the last row.
676 * @param i The imagery info to add
677 */
678 public void addRow(ImageryInfo i) {
679 layerInfo.add(i);
680 int p = getRowCount() - 1;
681 fireTableRowsInserted(p, p);
682 }
683
684 @Override
685 public void removeRow(int i) {
686 layerInfo.remove(getRow(i));
687 fireTableRowsDeleted(i, i);
688 }
689
690 @Override
691 public int getRowCount() {
692 return layerInfo.getLayers().size();
693 }
694
695 @Override
696 public Object getValueAt(int row, int column) {
697 ImageryInfo info = layerInfo.getLayers().get(row);
698 switch (column) {
699 case 0:
700 return info.getName();
701 case 1:
702 return info.getExtendedUrl();
703 default:
704 throw new ArrayIndexOutOfBoundsException();
705 }
706 }
707
708 @Override
709 public void setValueAt(Object o, int row, int column) {
710 if (layerInfo.getLayers().size() <= row) return;
711 ImageryInfo info = layerInfo.getLayers().get(row);
712 switch (column) {
713 case 0:
714 info.setName((String) o);
715 info.clearId();
716 break;
717 case 1:
718 info.setExtendedUrl((String) o);
719 info.clearId();
720 break;
721 default:
722 throw new ArrayIndexOutOfBoundsException();
723 }
724 }
725 }
726
727 /**
728 * The table model for the default imagery layer list
729 */
730 public class ImageryDefaultLayerTableModel extends DefaultTableModel {
731 /**
732 * Constructs a new {@code ImageryDefaultLayerTableModel}.
733 */
734 public ImageryDefaultLayerTableModel() {
735 setColumnIdentifiers(new String[]{"", tr("Menu Name (Default)"), tr("Imagery URL (Default)")});
736 }
737
738 /**
739 * Returns the imagery info at the given row number.
740 * @param row The row number
741 * @return The imagery info at the given row number
742 */
743 public ImageryInfo getRow(int row) {
744 return layerInfo.getAllDefaultLayers().get(row);
745 }
746
747 @Override
748 public int getRowCount() {
749 return layerInfo.getAllDefaultLayers().size();
750 }
751
752 @Override
753 public Object getValueAt(int row, int column) {
754 ImageryInfo info = layerInfo.getAllDefaultLayers().get(row);
755 switch (column) {
756 case 0:
757 return info.getCountryCode();
758 case 1:
759 return info;
760 case 2:
761 return info.getExtendedUrl();
762 }
763 return null;
764 }
765
766 @Override
767 public boolean isCellEditable(int row, int column) {
768 return false;
769 }
770 }
771
772 private static boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
773 URL url = null;
774 try {
775 url = new URL(eulaUrl.replaceAll("\\{lang\\}", LanguageInfo.getWikiLanguagePrefix()));
776 JosmEditorPane htmlPane = null;
777 try {
778 htmlPane = new JosmEditorPane(url);
779 } catch (IOException e1) {
780 Main.trace(e1);
781 // give a second chance with a default Locale 'en'
782 try {
783 url = new URL(eulaUrl.replaceAll("\\{lang\\}", ""));
784 htmlPane = new JosmEditorPane(url);
785 } catch (IOException e2) {
786 Main.debug(e2);
787 JOptionPane.showMessageDialog(gui, tr("EULA license URL not available: {0}", eulaUrl));
788 return false;
789 }
790 }
791 Box box = Box.createVerticalBox();
792 htmlPane.setEditable(false);
793 JScrollPane scrollPane = new JScrollPane(htmlPane);
794 scrollPane.setPreferredSize(new Dimension(400, 400));
795 box.add(scrollPane);
796 int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"),
797 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
798 if (option == JOptionPane.YES_OPTION)
799 return true;
800 } catch (MalformedURLException e2) {
801 JOptionPane.showMessageDialog(gui, tr("Malformed URL for the EULA licence: {0}", eulaUrl));
802 }
803 return false;
804 }
805 }
806
807 static class OffsetBookmarksPanel extends JPanel {
808 private final OffsetsBookmarksModel model = new OffsetsBookmarksModel();
809
810 /**
811 * Constructs a new {@code OffsetBookmarksPanel}.
812 * @param gui the preferences tab pane
813 */
814 OffsetBookmarksPanel(final PreferenceTabbedPane gui) {
815 super(new GridBagLayout());
816 final JTable list = new JTable(model) {
817 @Override
818 public String getToolTipText(MouseEvent e) {
819 java.awt.Point p = e.getPoint();
820 return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
821 }
822 };
823 JScrollPane scroll = new JScrollPane(list);
824 add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
825 scroll.setPreferredSize(new Dimension(200, 200));
826
827 TableColumnModel mod = list.getColumnModel();
828 mod.getColumn(0).setPreferredWidth(150);
829 mod.getColumn(1).setPreferredWidth(200);
830 mod.getColumn(2).setPreferredWidth(300);
831 mod.getColumn(3).setPreferredWidth(150);
832 mod.getColumn(4).setPreferredWidth(150);
833
834 JPanel buttonPanel = new JPanel(new FlowLayout());
835
836 JButton add = new JButton(tr("Add"));
837 buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
838 add.addActionListener(e -> model.addRow(new OffsetBookmark(Main.getProjection().toCode(), "", "", 0, 0)));
839
840 JButton delete = new JButton(tr("Delete"));
841 buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
842 delete.addActionListener(e -> {
843 if (list.getSelectedRow() == -1) {
844 JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
845 } else {
846 Integer i;
847 while ((i = list.getSelectedRow()) != -1) {
848 model.removeRow(i);
849 }
850 }
851 });
852
853 add(buttonPanel, GBC.eol());
854 }
855
856 /**
857 * The table model for imagery offsets list
858 */
859 private static class OffsetsBookmarksModel extends DefaultTableModel {
860
861 /**
862 * Constructs a new {@code OffsetsBookmarksModel}.
863 */
864 OffsetsBookmarksModel() {
865 setColumnIdentifiers(new String[] {tr("Projection"), tr("Layer"), tr("Name"), tr("Easting"), tr("Northing")});
866 }
867
868 private static OffsetBookmark getRow(int row) {
869 return OffsetBookmark.getBookmarkByIndex(row);
870 }
871
872 private void addRow(OffsetBookmark i) {
873 OffsetBookmark.addBookmark(i);
874 int p = getRowCount() - 1;
875 fireTableRowsInserted(p, p);
876 }
877
878 @Override
879 public void removeRow(int i) {
880 OffsetBookmark.removeBookmark(getRow(i));
881 fireTableRowsDeleted(i, i);
882 }
883
884 @Override
885 public int getRowCount() {
886 return OffsetBookmark.getBookmarksSize();
887 }
888
889 @Override
890 public Object getValueAt(int row, int column) {
891 OffsetBookmark info = OffsetBookmark.getBookmarkByIndex(row);
892 switch (column) {
893 case 0:
894 if (info.projectionCode == null) return "";
895 return info.projectionCode;
896 case 1:
897 return info.layerName;
898 case 2:
899 return info.name;
900 case 3:
901 return info.dx;
902 case 4:
903 return info.dy;
904 default:
905 throw new ArrayIndexOutOfBoundsException();
906 }
907 }
908
909 @Override
910 public void setValueAt(Object o, int row, int column) {
911 OffsetBookmark info = OffsetBookmark.getBookmarkByIndex(row);
912 switch (column) {
913 case 1:
914 info.layerName = o.toString();
915 break;
916 case 2:
917 info.name = o.toString();
918 break;
919 case 3:
920 info.dx = Double.parseDouble((String) o);
921 break;
922 case 4:
923 info.dy = Double.parseDouble((String) o);
924 break;
925 default:
926 throw new ArrayIndexOutOfBoundsException();
927 }
928 }
929
930 @Override
931 public boolean isCellEditable(int row, int column) {
932 return column >= 1;
933 }
934 }
935 }
936
937 /**
938 * Initializes imagery preferences.
939 */
940 public static void initialize() {
941 ImageryLayerInfo.instance.load(false);
942 OffsetBookmark.loadBookmarks();
943 Main.main.menu.imageryMenu.refreshImageryMenu();
944 Main.main.menu.imageryMenu.refreshOffsetMenu();
945 }
946}
Note: See TracBrowser for help on using the repository browser.