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

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

sonar - fix various issues

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