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

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

sonar - squid:AssignmentInSubExpressionCheck - Assignments should not be made from within sub-expressions

  • Property svn:eol-style set to native
File size: 38.0 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.ActionListener;
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.event.TableModelEvent;
44import javax.swing.event.TableModelListener;
45import javax.swing.table.DefaultTableCellRenderer;
46import javax.swing.table.DefaultTableModel;
47import javax.swing.table.TableColumnModel;
48
49import org.openstreetmap.gui.jmapviewer.Coordinate;
50import org.openstreetmap.gui.jmapviewer.JMapViewer;
51import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
52import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
53import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
54import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
55import org.openstreetmap.josm.Main;
56import org.openstreetmap.josm.data.imagery.ImageryInfo;
57import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
58import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
59import org.openstreetmap.josm.data.imagery.OffsetBookmark;
60import org.openstreetmap.josm.data.imagery.Shape;
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 final transient List<ImageryInfo> layers;
245
246 ImageryURLTableCellRenderer(List<ImageryInfo> layers) {
247 this.layers = layers;
248 }
249
250 @Override
251 public Component getTableCellRendererComponent(JTable table, Object value, boolean
252 isSelected, boolean hasFocus, int row, int column) {
253 JLabel label = (JLabel) super.getTableCellRendererComponent(
254 table, value, isSelected, hasFocus, row, column);
255 GuiHelper.setBackgroundReadable(label, UIManager.getColor("Table.background"));
256 if (value != null) { // Fix #8159
257 String t = value.toString();
258 for (ImageryInfo l : layers) {
259 if (l.getExtendedUrl().equals(t)) {
260 GuiHelper.setBackgroundReadable(label, Main.pref.getColor(
261 marktr("Imagery Background: Default"),
262 new Color(200, 255, 200)));
263 break;
264 }
265 }
266 label.setToolTipText((String) value);
267 }
268 return label;
269 }
270 }
271
272 /**
273 * class to render the name information of Imagery source
274 * @since 8064
275 */
276 private static class ImageryNameTableCellRenderer extends DefaultTableCellRenderer {
277 @Override
278 public Component getTableCellRendererComponent(JTable table, Object value, boolean
279 isSelected, boolean hasFocus, int row, int column) {
280 ImageryInfo info = (ImageryInfo) value;
281 JLabel label = (JLabel) super.getTableCellRendererComponent(
282 table, info == null ? null : info.getName(), isSelected, hasFocus, row, column);
283 GuiHelper.setBackgroundReadable(label, UIManager.getColor("Table.background"));
284 if (info != null) {
285 label.setToolTipText(info.getToolTipText());
286 }
287 return label;
288 }
289 }
290
291 /**
292 * Constructs a new {@code ImageryProvidersPanel}.
293 * @param gui The parent preference tab pane
294 * @param layerInfoArg The list of imagery entries to display
295 */
296 public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) {
297 super(new GridBagLayout());
298 this.gui = gui;
299 this.layerInfo = layerInfoArg;
300 this.activeModel = new ImageryLayerTableModel();
301
302 activeTable = new JTable(activeModel) {
303 @Override
304 public String getToolTipText(MouseEvent e) {
305 java.awt.Point p = e.getPoint();
306 return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
307 }
308 };
309 activeTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
310
311 defaultModel = new ImageryDefaultLayerTableModel();
312 defaultTable = new JTable(defaultModel);
313
314 defaultModel.addTableModelListener(
315 new TableModelListener() {
316 @Override
317 public void tableChanged(TableModelEvent e) {
318 activeTable.repaint();
319 }
320 }
321 );
322
323 activeModel.addTableModelListener(
324 new TableModelListener() {
325 @Override
326 public void tableChanged(TableModelEvent e) {
327 defaultTable.repaint();
328 }
329 }
330 );
331
332 TableColumnModel mod = defaultTable.getColumnModel();
333 mod.getColumn(2).setPreferredWidth(800);
334 mod.getColumn(2).setCellRenderer(new ImageryURLTableCellRenderer(layerInfo.getLayers()));
335 mod.getColumn(1).setPreferredWidth(400);
336 mod.getColumn(1).setCellRenderer(new ImageryNameTableCellRenderer());
337 mod.getColumn(0).setPreferredWidth(50);
338
339 mod = activeTable.getColumnModel();
340 mod.getColumn(1).setPreferredWidth(800);
341 mod.getColumn(1).setCellRenderer(new ImageryURLTableCellRenderer(layerInfo.getDefaultLayers()));
342 mod.getColumn(0).setPreferredWidth(200);
343
344 RemoveEntryAction remove = new RemoveEntryAction();
345 activeTable.getSelectionModel().addListSelectionListener(remove);
346
347 add(new JLabel(tr("Available default entries:")), GBC.eol().insets(5, 5, 0, 0));
348 // Add default item list
349 JScrollPane scrolldef = new JScrollPane(defaultTable);
350 scrolldef.setPreferredSize(new Dimension(200, 200));
351 add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
352
353 // Add default item map
354 defaultMap = new JMapViewer();
355 defaultMap.setZoomContolsVisible(false);
356 defaultMap.setMinimumSize(new Dimension(100, 200));
357 add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
358
359 defaultTableListener = new DefListSelectionListener();
360 defaultTable.getSelectionModel().addListSelectionListener(defaultTableListener);
361
362 defaultToolbar = new JToolBar(JToolBar.VERTICAL);
363 defaultToolbar.setFloatable(false);
364 defaultToolbar.setBorderPainted(false);
365 defaultToolbar.setOpaque(false);
366 defaultToolbar.add(new ReloadAction());
367 add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
368
369 ActivateAction activate = new ActivateAction();
370 defaultTable.getSelectionModel().addListSelectionListener(activate);
371 JButton btnActivate = new JButton(activate);
372
373 middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
374 middleToolbar.setFloatable(false);
375 middleToolbar.setBorderPainted(false);
376 middleToolbar.setOpaque(false);
377 middleToolbar.add(btnActivate);
378 add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 15, 5, 0));
379
380 add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
381
382 add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0));
383 JScrollPane scroll = new JScrollPane(activeTable);
384 add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5));
385 scroll.setPreferredSize(new Dimension(200, 200));
386
387 activeToolbar = new JToolBar(JToolBar.VERTICAL);
388 activeToolbar.setFloatable(false);
389 activeToolbar.setBorderPainted(false);
390 activeToolbar.setOpaque(false);
391 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMS));
392 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.TMS));
393 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMTS));
394 //activeToolbar.add(edit); TODO
395 activeToolbar.add(remove);
396 add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5));
397 }
398
399 // Listener of default providers list selection
400 private final class DefListSelectionListener implements ListSelectionListener {
401 // The current drawn rectangles and polygons
402 private final Map<Integer, MapRectangle> mapRectangles;
403 private final Map<Integer, List<MapPolygon>> mapPolygons;
404
405 private DefListSelectionListener() {
406 this.mapRectangles = new HashMap<>();
407 this.mapPolygons = new HashMap<>();
408 }
409
410 private void clearMap() {
411 defaultMap.removeAllMapRectangles();
412 defaultMap.removeAllMapPolygons();
413 mapRectangles.clear();
414 mapPolygons.clear();
415 }
416
417 @Override
418 public void valueChanged(ListSelectionEvent e) {
419 // First index can be set to -1 when the list is refreshed, so discard all map rectangles and polygons
420 if (e.getFirstIndex() == -1) {
421 clearMap();
422 } else if (!e.getValueIsAdjusting()) {
423 // Only process complete (final) selection events
424 for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) {
425 updateBoundsAndShapes(i);
426 }
427 // If needed, adjust map to show all map rectangles and polygons
428 if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
429 defaultMap.setDisplayToFitMapElements(false, true, true);
430 defaultMap.zoomOut();
431 }
432 }
433 }
434
435 private void updateBoundsAndShapes(int i) {
436 ImageryBounds bounds = defaultModel.getRow(i).getBounds();
437 if (bounds != null) {
438 List<Shape> shapes = bounds.getShapes();
439 if (shapes != null && !shapes.isEmpty()) {
440 if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
441 if (!mapPolygons.containsKey(i)) {
442 List<MapPolygon> list = new ArrayList<>();
443 mapPolygons.put(i, list);
444 // Add new map polygons
445 for (Shape shape : shapes) {
446 MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
447 list.add(polygon);
448 defaultMap.addMapPolygon(polygon);
449 }
450 }
451 } else if (mapPolygons.containsKey(i)) {
452 // Remove previously drawn map polygons
453 for (MapPolygon polygon : mapPolygons.get(i)) {
454 defaultMap.removeMapPolygon(polygon);
455 }
456 mapPolygons.remove(i);
457 }
458 // Only display bounds when no polygons (shapes) are defined for this provider
459 } else {
460 if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
461 if (!mapRectangles.containsKey(i)) {
462 // Add new map rectangle
463 Coordinate topLeft = new Coordinate(bounds.getMaxLat(), bounds.getMinLon());
464 Coordinate bottomRight = new Coordinate(bounds.getMinLat(), bounds.getMaxLon());
465 MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight);
466 mapRectangles.put(i, rectangle);
467 defaultMap.addMapRectangle(rectangle);
468 }
469 } else if (mapRectangles.containsKey(i)) {
470 // Remove previously drawn map rectangle
471 defaultMap.removeMapRectangle(mapRectangles.get(i));
472 mapRectangles.remove(i);
473 }
474 }
475 }
476 }
477 }
478
479 private class NewEntryAction extends AbstractAction {
480
481 private final ImageryInfo.ImageryType type;
482
483 NewEntryAction(ImageryInfo.ImageryType type) {
484 putValue(NAME, type.toString());
485 putValue(SHORT_DESCRIPTION, tr("Add a new {0} entry by entering the URL", type.toString()));
486 String icon = /* ICON(dialogs/) */ "add";
487 switch (type) {
488 case WMS:
489 icon = /* ICON(dialogs/) */ "add_wms";
490 break;
491 case TMS:
492 icon = /* ICON(dialogs/) */ "add_tms";
493 break;
494 case WMTS:
495 icon = /* ICON(dialogs/) */ "add_wmts";
496 break;
497 default:
498 break;
499 }
500 putValue(SMALL_ICON, ImageProvider.get("dialogs", icon));
501 this.type = type;
502 }
503
504 @Override
505 public void actionPerformed(ActionEvent evt) {
506 final AddImageryPanel p;
507 switch (type) {
508 case WMS:
509 p = new AddWMSLayerPanel();
510 break;
511 case TMS:
512 p = new AddTMSLayerPanel();
513 break;
514 case WMTS:
515 p = new AddWMTSLayerPanel();
516 break;
517 default:
518 throw new IllegalStateException("Type " + type + " not supported");
519 }
520
521 final AddImageryDialog addDialog = new AddImageryDialog(gui, p);
522 addDialog.showDialog();
523
524 if (addDialog.getValue() == 1) {
525 try {
526 activeModel.addRow(p.getImageryInfo());
527 } catch (IllegalArgumentException ex) {
528 if (ex.getMessage() == null || ex.getMessage().isEmpty())
529 throw ex;
530 else {
531 JOptionPane.showMessageDialog(Main.parent,
532 ex.getMessage(), tr("Error"),
533 JOptionPane.ERROR_MESSAGE);
534 }
535 }
536 }
537 }
538 }
539
540 private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
541
542 /**
543 * Constructs a new {@code RemoveEntryAction}.
544 */
545 RemoveEntryAction() {
546 putValue(NAME, tr("Remove"));
547 putValue(SHORT_DESCRIPTION, tr("Remove entry"));
548 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
549 updateEnabledState();
550 }
551
552 protected final void updateEnabledState() {
553 setEnabled(activeTable.getSelectedRowCount() > 0);
554 }
555
556 @Override
557 public void valueChanged(ListSelectionEvent e) {
558 updateEnabledState();
559 }
560
561 @Override
562 public void actionPerformed(ActionEvent e) {
563 Integer i;
564 while ((i = activeTable.getSelectedRow()) != -1) {
565 activeModel.removeRow(i);
566 }
567 }
568 }
569
570 private class ActivateAction extends AbstractAction implements ListSelectionListener {
571
572 /**
573 * Constructs a new {@code ActivateAction}.
574 */
575 ActivateAction() {
576 putValue(NAME, tr("Activate"));
577 putValue(SHORT_DESCRIPTION, tr("copy selected defaults"));
578 putValue(SMALL_ICON, ImageProvider.get("preferences", "activate-down"));
579 }
580
581 protected void updateEnabledState() {
582 setEnabled(defaultTable.getSelectedRowCount() > 0);
583 }
584
585 @Override
586 public void valueChanged(ListSelectionEvent e) {
587 updateEnabledState();
588 }
589
590 @Override
591 public void actionPerformed(ActionEvent e) {
592 int[] lines = defaultTable.getSelectedRows();
593 if (lines.length == 0) {
594 JOptionPane.showMessageDialog(
595 gui,
596 tr("Please select at least one row to copy."),
597 tr("Information"),
598 JOptionPane.INFORMATION_MESSAGE);
599 return;
600 }
601
602 Set<String> acceptedEulas = new HashSet<>();
603
604 outer:
605 for (int line : lines) {
606 ImageryInfo info = defaultModel.getRow(line);
607
608 // Check if an entry with exactly the same values already exists
609 for (int j = 0; j < activeModel.getRowCount(); j++) {
610 if (info.equalsBaseValues(activeModel.getRow(j))) {
611 // Select the already existing row so the user has
612 // some feedback in case an entry exists
613 activeTable.getSelectionModel().setSelectionInterval(j, j);
614 activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true));
615 continue outer;
616 }
617 }
618
619 String eulaURL = info.getEulaAcceptanceRequired();
620 // If set and not already accepted, ask for EULA acceptance
621 if (eulaURL != null && !acceptedEulas.contains(eulaURL)) {
622 if (confirmEulaAcceptance(gui, eulaURL)) {
623 acceptedEulas.add(eulaURL);
624 } else {
625 continue outer;
626 }
627 }
628
629 activeModel.addRow(new ImageryInfo(info));
630 int lastLine = activeModel.getRowCount() - 1;
631 activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
632 activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true));
633 }
634 }
635 }
636
637 private class ReloadAction extends AbstractAction {
638
639 /**
640 * Constructs a new {@code ReloadAction}.
641 */
642 ReloadAction() {
643 putValue(SHORT_DESCRIPTION, tr("Update default entries"));
644 putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
645 }
646
647 @Override
648 public void actionPerformed(ActionEvent evt) {
649 layerInfo.loadDefaults(true, false, false);
650 defaultModel.fireTableDataChanged();
651 defaultTable.getSelectionModel().clearSelection();
652 defaultTableListener.clearMap();
653 /* loading new file may change active layers */
654 activeModel.fireTableDataChanged();
655 }
656 }
657
658 /**
659 * The table model for imagery layer list
660 */
661 public class ImageryLayerTableModel extends DefaultTableModel {
662 /**
663 * Constructs a new {@code ImageryLayerTableModel}.
664 */
665 public ImageryLayerTableModel() {
666 setColumnIdentifiers(new String[] {tr("Menu Name"), tr("Imagery URL")});
667 }
668
669 /**
670 * Returns the imagery info at the given row number.
671 * @param row The row number
672 * @return The imagery info at the given row number
673 */
674 public ImageryInfo getRow(int row) {
675 return layerInfo.getLayers().get(row);
676 }
677
678 /**
679 * Adds a new imagery info as the last row.
680 * @param i The imagery info to add
681 */
682 public void addRow(ImageryInfo i) {
683 layerInfo.add(i);
684 int p = getRowCount() - 1;
685 fireTableRowsInserted(p, p);
686 }
687
688 @Override
689 public void removeRow(int i) {
690 layerInfo.remove(getRow(i));
691 fireTableRowsDeleted(i, i);
692 }
693
694 @Override
695 public int getRowCount() {
696 return layerInfo.getLayers().size();
697 }
698
699 @Override
700 public Object getValueAt(int row, int column) {
701 ImageryInfo info = layerInfo.getLayers().get(row);
702 switch (column) {
703 case 0:
704 return info.getName();
705 case 1:
706 return info.getExtendedUrl();
707 default:
708 throw new ArrayIndexOutOfBoundsException();
709 }
710 }
711
712 @Override
713 public void setValueAt(Object o, int row, int column) {
714 if (layerInfo.getLayers().size() <= row) return;
715 ImageryInfo info = layerInfo.getLayers().get(row);
716 switch (column) {
717 case 0:
718 info.setName((String) o);
719 info.clearId();
720 break;
721 case 1:
722 info.setExtendedUrl((String) o);
723 info.clearId();
724 break;
725 default:
726 throw new ArrayIndexOutOfBoundsException();
727 }
728 }
729 }
730
731 /**
732 * The table model for the default imagery layer list
733 */
734 public class ImageryDefaultLayerTableModel extends DefaultTableModel {
735 /**
736 * Constructs a new {@code ImageryDefaultLayerTableModel}.
737 */
738 public ImageryDefaultLayerTableModel() {
739 setColumnIdentifiers(new String[]{"", tr("Menu Name (Default)"), tr("Imagery URL (Default)")});
740 }
741
742 /**
743 * Returns the imagery info at the given row number.
744 * @param row The row number
745 * @return The imagery info at the given row number
746 */
747 public ImageryInfo getRow(int row) {
748 return layerInfo.getDefaultLayers().get(row);
749 }
750
751 @Override
752 public int getRowCount() {
753 return layerInfo.getDefaultLayers().size();
754 }
755
756 @Override
757 public Object getValueAt(int row, int column) {
758 ImageryInfo info = layerInfo.getDefaultLayers().get(row);
759 switch (column) {
760 case 0:
761 return info.getCountryCode();
762 case 1:
763 return info;
764 case 2:
765 return info.getExtendedUrl();
766 }
767 return null;
768 }
769
770 @Override
771 public boolean isCellEditable(int row, int column) {
772 return false;
773 }
774 }
775
776 private static boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
777 URL url = null;
778 try {
779 url = new URL(eulaUrl.replaceAll("\\{lang\\}", LanguageInfo.getWikiLanguagePrefix()));
780 JosmEditorPane htmlPane = null;
781 try {
782 htmlPane = new JosmEditorPane(url);
783 } catch (IOException e1) {
784 // give a second chance with a default Locale 'en'
785 try {
786 url = new URL(eulaUrl.replaceAll("\\{lang\\}", ""));
787 htmlPane = new JosmEditorPane(url);
788 } catch (IOException e2) {
789 JOptionPane.showMessageDialog(gui, tr("EULA license URL not available: {0}", eulaUrl));
790 return false;
791 }
792 }
793 Box box = Box.createVerticalBox();
794 htmlPane.setEditable(false);
795 JScrollPane scrollPane = new JScrollPane(htmlPane);
796 scrollPane.setPreferredSize(new Dimension(400, 400));
797 box.add(scrollPane);
798 int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"),
799 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
800 if (option == JOptionPane.YES_OPTION)
801 return true;
802 } catch (MalformedURLException e2) {
803 JOptionPane.showMessageDialog(gui, tr("Malformed URL for the EULA licence: {0}", eulaUrl));
804 }
805 return false;
806 }
807 }
808
809 static class OffsetBookmarksPanel extends JPanel {
810 private final transient List<OffsetBookmark> bookmarks = OffsetBookmark.allBookmarks;
811 private final OffsetsBookmarksModel model = new OffsetsBookmarksModel();
812
813 /**
814 * Constructs a new {@code OffsetBookmarksPanel}.
815 * @param gui the preferences tab pane
816 */
817 OffsetBookmarksPanel(final PreferenceTabbedPane gui) {
818 super(new GridBagLayout());
819 final JTable list = new JTable(model) {
820 @Override
821 public String getToolTipText(MouseEvent e) {
822 java.awt.Point p = e.getPoint();
823 return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
824 }
825 };
826 JScrollPane scroll = new JScrollPane(list);
827 add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
828 scroll.setPreferredSize(new Dimension(200, 200));
829
830 TableColumnModel mod = list.getColumnModel();
831 mod.getColumn(0).setPreferredWidth(150);
832 mod.getColumn(1).setPreferredWidth(200);
833 mod.getColumn(2).setPreferredWidth(300);
834 mod.getColumn(3).setPreferredWidth(150);
835 mod.getColumn(4).setPreferredWidth(150);
836
837 JPanel buttonPanel = new JPanel(new FlowLayout());
838
839 JButton add = new JButton(tr("Add"));
840 buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
841 add.addActionListener(new ActionListener() {
842 @Override
843 public void actionPerformed(ActionEvent e) {
844 OffsetBookmark b = new OffsetBookmark(Main.getProjection().toCode(), "", "", 0, 0);
845 model.addRow(b);
846 }
847 });
848
849 JButton delete = new JButton(tr("Delete"));
850 buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
851 delete.addActionListener(new ActionListener() {
852 @Override
853 public void actionPerformed(ActionEvent e) {
854 if (list.getSelectedRow() == -1) {
855 JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
856 } else {
857 Integer i;
858 while ((i = list.getSelectedRow()) != -1) {
859 model.removeRow(i);
860 }
861 }
862 }
863 });
864
865 add(buttonPanel, GBC.eol());
866 }
867
868 /**
869 * The table model for imagery offsets list
870 */
871 private class OffsetsBookmarksModel extends DefaultTableModel {
872
873 /**
874 * Constructs a new {@code OffsetsBookmarksModel}.
875 */
876 OffsetsBookmarksModel() {
877 setColumnIdentifiers(new String[] {tr("Projection"), tr("Layer"), tr("Name"), tr("Easting"), tr("Northing")});
878 }
879
880 private OffsetBookmark getRow(int row) {
881 return bookmarks.get(row);
882 }
883
884 private void addRow(OffsetBookmark i) {
885 bookmarks.add(i);
886 int p = getRowCount() - 1;
887 fireTableRowsInserted(p, p);
888 }
889
890 @Override
891 public void removeRow(int i) {
892 bookmarks.remove(getRow(i));
893 fireTableRowsDeleted(i, i);
894 }
895
896 @Override
897 public int getRowCount() {
898 return bookmarks.size();
899 }
900
901 @Override
902 public Object getValueAt(int row, int column) {
903 OffsetBookmark info = bookmarks.get(row);
904 switch (column) {
905 case 0:
906 if (info.projectionCode == null) return "";
907 return info.projectionCode;
908 case 1:
909 return info.layerName;
910 case 2:
911 return info.name;
912 case 3:
913 return info.dx;
914 case 4:
915 return info.dy;
916 default:
917 throw new ArrayIndexOutOfBoundsException();
918 }
919 }
920
921 @Override
922 public void setValueAt(Object o, int row, int column) {
923 OffsetBookmark info = bookmarks.get(row);
924 switch (column) {
925 case 1:
926 info.layerName = o.toString();
927 break;
928 case 2:
929 info.name = o.toString();
930 break;
931 case 3:
932 info.dx = Double.parseDouble((String) o);
933 break;
934 case 4:
935 info.dy = Double.parseDouble((String) o);
936 break;
937 default:
938 throw new ArrayIndexOutOfBoundsException();
939 }
940 }
941
942 @Override
943 public boolean isCellEditable(int row, int column) {
944 return column >= 1;
945 }
946 }
947 }
948
949 /**
950 * Initializes imagery preferences.
951 */
952 public static void initialize() {
953 ImageryLayerInfo.instance.load(true);
954 OffsetBookmark.loadBookmarks();
955 Main.main.menu.imageryMenu.refreshImageryMenu();
956 Main.main.menu.imageryMenu.refreshOffsetMenu();
957 }
958}
Note: See TracBrowser for help on using the repository browser.