source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java@ 16438

Last change on this file since 16438 was 16438, checked in by simon04, 5 years ago

see #19251 - Java 8: use Stream

  • Property svn:eol-style set to native
File size: 30.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.GridBagConstraints;
11import java.awt.GridBagLayout;
12import java.awt.event.ActionEvent;
13import java.awt.event.MouseAdapter;
14import java.awt.event.MouseEvent;
15import java.io.IOException;
16import java.net.MalformedURLException;
17import java.net.URL;
18import java.util.ArrayList;
19import java.util.HashMap;
20import java.util.HashSet;
21import java.util.List;
22import java.util.Map;
23import java.util.Objects;
24import java.util.Optional;
25import java.util.Set;
26import java.util.function.BiConsumer;
27import java.util.function.Consumer;
28import java.util.function.Function;
29
30import javax.swing.AbstractAction;
31import javax.swing.Box;
32import javax.swing.JButton;
33import javax.swing.JLabel;
34import javax.swing.JOptionPane;
35import javax.swing.JPanel;
36import javax.swing.JScrollPane;
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.table.DefaultTableCellRenderer;
43import javax.swing.table.DefaultTableModel;
44import javax.swing.table.TableColumnModel;
45
46import org.openstreetmap.gui.jmapviewer.Coordinate;
47import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
48import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
49import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
50import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
51import org.openstreetmap.josm.data.imagery.ImageryInfo;
52import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
53import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryCategory;
54import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
55import org.openstreetmap.josm.data.imagery.Shape;
56import org.openstreetmap.josm.data.preferences.NamedColorProperty;
57import org.openstreetmap.josm.gui.MainApplication;
58import org.openstreetmap.josm.gui.bbox.JosmMapViewer;
59import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
60import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
61import org.openstreetmap.josm.gui.util.GuiHelper;
62import org.openstreetmap.josm.gui.widgets.FilterField;
63import org.openstreetmap.josm.gui.widgets.HtmlPanel;
64import org.openstreetmap.josm.gui.widgets.JosmEditorPane;
65import org.openstreetmap.josm.spi.preferences.Config;
66import org.openstreetmap.josm.tools.GBC;
67import org.openstreetmap.josm.tools.ImageProvider;
68import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
69import org.openstreetmap.josm.tools.LanguageInfo;
70import org.openstreetmap.josm.tools.Logging;
71
72/**
73 * A panel displaying imagery providers.
74 * @since 15115 (extracted from ImageryPreferences)
75 */
76public class ImageryProvidersPanel extends JPanel {
77 // Public JTables and JosmMapViewer
78 /** The table of active providers **/
79 public final JTable activeTable;
80 /** The table of default providers **/
81 public final JTable defaultTable;
82 /** The filter of default providers **/
83 private final FilterField defaultFilter;
84 /** The selection listener synchronizing map display with table of default providers **/
85 private final transient DefListSelectionListener defaultTableListener;
86 /** The map displaying imagery bounds of selected default providers **/
87 public final JosmMapViewer defaultMap;
88
89 // Public models
90 /** The model of active providers **/
91 public final ImageryLayerTableModel activeModel;
92 /** The model of default providers **/
93 public final ImageryDefaultLayerTableModel defaultModel;
94
95 // Public JToolbars
96 /** The toolbar on the right of active providers **/
97 public final JToolBar activeToolbar;
98 /** The toolbar on the middle of the panel **/
99 public final JToolBar middleToolbar;
100 /** The toolbar on the right of default providers **/
101 public final JToolBar defaultToolbar;
102
103 // Private members
104 private final PreferenceTabbedPane gui;
105 private final transient ImageryLayerInfo layerInfo;
106
107 /**
108 * class to render the URL information of Imagery source
109 * @since 8065
110 */
111 private static class ImageryURLTableCellRenderer extends DefaultTableCellRenderer {
112
113 private static final NamedColorProperty IMAGERY_BACKGROUND_COLOR = new NamedColorProperty(
114 marktr("Imagery Background: Default"),
115 new Color(200, 255, 200));
116
117 private final transient List<ImageryInfo> layers;
118
119 ImageryURLTableCellRenderer(List<ImageryInfo> layers) {
120 this.layers = layers;
121 }
122
123 @Override
124 public Component getTableCellRendererComponent(JTable table, Object value, boolean
125 isSelected, boolean hasFocus, int row, int column) {
126 JLabel label = (JLabel) super.getTableCellRendererComponent(
127 table, value, isSelected, hasFocus, row, column);
128 GuiHelper.setBackgroundReadable(label, UIManager.getColor("Table.background"));
129 if (value != null) { // Fix #8159
130 if (layers.stream().anyMatch(l -> Objects.equals(l.getExtendedUrl(), value.toString()))) {
131 GuiHelper.setBackgroundReadable(label, IMAGERY_BACKGROUND_COLOR.get());
132 }
133 label.setToolTipText((String) value);
134 }
135 return label;
136 }
137 }
138
139 /**
140 * class to render an information of Imagery source
141 * @param <T> type of information
142 */
143 private static class ImageryTableCellRenderer<T> extends DefaultTableCellRenderer {
144 private final Function<T, Object> mapper;
145 private final Function<T, String> tooltip;
146 private final BiConsumer<T, JLabel> decorator;
147
148 ImageryTableCellRenderer(Function<T, Object> mapper, Function<T, String> tooltip, BiConsumer<T, JLabel> decorator) {
149 this.mapper = mapper;
150 this.tooltip = tooltip;
151 this.decorator = decorator;
152 }
153
154 @Override
155 @SuppressWarnings("unchecked")
156 public final Component getTableCellRendererComponent(JTable table, Object value, boolean
157 isSelected, boolean hasFocus, int row, int column) {
158 T obj = (T) value;
159 JLabel label = (JLabel) super.getTableCellRendererComponent(
160 table, mapper.apply(obj), isSelected, hasFocus, row, column);
161 GuiHelper.setBackgroundReadable(label,
162 isSelected ? UIManager.getColor("Table.selectionBackground") : UIManager.getColor("Table.background"));
163 if (obj != null) {
164 label.setToolTipText(tooltip.apply(obj));
165 if (decorator != null) {
166 decorator.accept(obj, label);
167 }
168 }
169 return label;
170 }
171 }
172
173 /**
174 * class to render the category information of Imagery source
175 */
176 private static class ImageryCategoryTableCellRenderer extends ImageryProvidersPanel.ImageryTableCellRenderer<ImageryCategory> {
177 ImageryCategoryTableCellRenderer() {
178 super(cat -> null, cat -> tr("Imagery category: {0}", cat.getDescription()),
179 (cat, label) -> label.setIcon(cat.getIcon(ImageSizes.TABLE)));
180 }
181 }
182
183 /**
184 * class to render the country information of Imagery source
185 */
186 private static class ImageryCountryTableCellRenderer extends ImageryProvidersPanel.ImageryTableCellRenderer<String> {
187 ImageryCountryTableCellRenderer() {
188 super(code -> code, ImageryInfo::getLocalizedCountry, null);
189 }
190 }
191
192 /**
193 * class to render the name information of Imagery source
194 */
195 private static class ImageryNameTableCellRenderer extends ImageryProvidersPanel.ImageryTableCellRenderer<ImageryInfo> {
196 ImageryNameTableCellRenderer() {
197 super(info -> info == null ? null : info.getName(), ImageryInfo::getToolTipText, null);
198 }
199 }
200
201 /**
202 * Constructs a new {@code ImageryProvidersPanel}.
203 * @param gui The parent preference tab pane
204 * @param layerInfoArg The list of imagery entries to display
205 */
206 public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) {
207 super(new GridBagLayout());
208 this.gui = gui;
209 this.layerInfo = layerInfoArg;
210 this.activeModel = new ImageryLayerTableModel();
211
212 activeTable = new JTable(activeModel) {
213 @Override
214 public String getToolTipText(MouseEvent e) {
215 java.awt.Point p = e.getPoint();
216 try {
217 return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
218 } catch (ArrayIndexOutOfBoundsException ex) {
219 Logging.debug(ex);
220 return null;
221 }
222 }
223 };
224 activeTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
225
226 defaultModel = new ImageryDefaultLayerTableModel();
227 defaultTable = new JTable(defaultModel);
228 defaultTable.setAutoCreateRowSorter(true);
229 defaultFilter = new FilterField().filter(defaultTable, defaultModel);
230
231 defaultModel.addTableModelListener(e -> activeTable.repaint());
232 activeModel.addTableModelListener(e -> defaultTable.repaint());
233
234 TableColumnModel mod = defaultTable.getColumnModel();
235 mod.getColumn(3).setPreferredWidth(775);
236 mod.getColumn(3).setCellRenderer(new ImageryURLTableCellRenderer(layerInfo.getLayers()));
237 mod.getColumn(2).setPreferredWidth(475);
238 mod.getColumn(2).setCellRenderer(new ImageryNameTableCellRenderer());
239 mod.getColumn(1).setCellRenderer(new ImageryCountryTableCellRenderer());
240 mod.getColumn(0).setPreferredWidth(50);
241 mod.getColumn(0).setCellRenderer(new ImageryCategoryTableCellRenderer());
242 mod.getColumn(0).setPreferredWidth(50);
243
244 mod = activeTable.getColumnModel();
245 mod.getColumn(1).setPreferredWidth(800);
246 mod.getColumn(1).setCellRenderer(new ImageryURLTableCellRenderer(layerInfo.getAllDefaultLayers()));
247 mod.getColumn(0).setPreferredWidth(200);
248
249 RemoveEntryAction remove = new RemoveEntryAction();
250 activeTable.getSelectionModel().addListSelectionListener(remove);
251
252 add(new JLabel(tr("Available default entries:")), GBC.std().insets(5, 5, 0, 0));
253 add(new JLabel(tr("Boundaries of selected imagery entries:")), GBC.eol().insets(5, 5, 0, 0));
254
255 // Add default item list
256 JPanel defaultPane = new JPanel(new GridBagLayout());
257 JScrollPane scrolldef = new JScrollPane(defaultTable);
258 scrolldef.setPreferredSize(new Dimension(200, 200));
259 defaultPane.add(defaultFilter, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
260 defaultPane.add(scrolldef, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.BOTH));
261 add(defaultPane, GBC.std().fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
262
263 // Add default item map
264 defaultMap = new JosmMapViewer();
265 defaultMap.setTileSource(SlippyMapBBoxChooser.DefaultOsmTileSourceProvider.get()); // for attribution
266 defaultMap.addMouseListener(new MouseAdapter() {
267 @Override
268 public void mouseClicked(MouseEvent e) {
269 if (e.getButton() == MouseEvent.BUTTON1) {
270 defaultMap.getAttribution().handleAttribution(e.getPoint(), true);
271 }
272 }
273 });
274 defaultMap.setZoomControlsVisible(false);
275 defaultMap.setMinimumSize(new Dimension(100, 200));
276 add(defaultMap, GBC.std().fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
277
278 defaultTableListener = new DefListSelectionListener();
279 defaultTable.getSelectionModel().addListSelectionListener(defaultTableListener);
280
281 defaultToolbar = new JToolBar(JToolBar.VERTICAL);
282 defaultToolbar.setFloatable(false);
283 defaultToolbar.setBorderPainted(false);
284 defaultToolbar.setOpaque(false);
285 defaultToolbar.add(new ReloadAction());
286 add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
287
288 HtmlPanel help = new HtmlPanel(tr("New default entries can be added in the <a href=\"{0}\">Wiki</a>.",
289 Config.getUrls().getJOSMWebsite()+"/wiki/Maps"));
290 help.enableClickableHyperlinks();
291 add(help, GBC.eol().insets(10, 0, 0, 0).fill(GBC.HORIZONTAL));
292
293 ActivateAction activate = new ActivateAction();
294 defaultTable.getSelectionModel().addListSelectionListener(activate);
295 JButton btnActivate = new JButton(activate);
296
297 middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
298 middleToolbar.setFloatable(false);
299 middleToolbar.setBorderPainted(false);
300 middleToolbar.setOpaque(false);
301 middleToolbar.add(btnActivate);
302 add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 5, 5, 0));
303
304 add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
305
306 add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0));
307 JScrollPane scroll = new JScrollPane(activeTable);
308 add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5));
309 scroll.setPreferredSize(new Dimension(200, 200));
310
311 activeToolbar = new JToolBar(JToolBar.VERTICAL);
312 activeToolbar.setFloatable(false);
313 activeToolbar.setBorderPainted(false);
314 activeToolbar.setOpaque(false);
315 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMS));
316 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.TMS));
317 activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMTS));
318 activeToolbar.add(remove);
319 add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5));
320 }
321
322 // Listener of default providers list selection
323 private final class DefListSelectionListener implements ListSelectionListener {
324 // The current drawn rectangles and polygons
325 private final Map<Integer, MapRectangle> mapRectangles;
326 private final Map<Integer, List<MapPolygon>> mapPolygons;
327
328 private DefListSelectionListener() {
329 this.mapRectangles = new HashMap<>();
330 this.mapPolygons = new HashMap<>();
331 }
332
333 private void clearMap() {
334 defaultMap.removeAllMapRectangles();
335 defaultMap.removeAllMapPolygons();
336 mapRectangles.clear();
337 mapPolygons.clear();
338 }
339
340 @Override
341 public void valueChanged(ListSelectionEvent e) {
342 // First index can be set to -1 when the list is refreshed, so discard all map rectangles and polygons
343 if (e.getFirstIndex() == -1) {
344 clearMap();
345 } else if (!e.getValueIsAdjusting()) {
346 // Only process complete (final) selection events
347 for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) {
348 if (i < defaultTable.getRowCount()) {
349 updateBoundsAndShapes(defaultTable.convertRowIndexToModel(i));
350 }
351 }
352 // Cleanup residual selected bounds which may have disappeared after a filter
353 cleanupResidualBounds();
354 // If needed, adjust map to show all map rectangles and polygons
355 if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
356 defaultMap.setDisplayToFitMapElements(false, true, true);
357 defaultMap.zoomOut();
358 }
359 }
360 }
361
362 /**
363 * update bounds and shapes for a new entry
364 * @param i model index
365 */
366 private void updateBoundsAndShapes(int i) {
367 ImageryBounds bounds = defaultModel.getRow(i).getBounds();
368 if (bounds != null) {
369 int viewIndex = defaultTable.convertRowIndexToView(i);
370 List<Shape> shapes = bounds.getShapes();
371 if (shapes != null && !shapes.isEmpty()) {
372 if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
373 if (!mapPolygons.containsKey(i)) {
374 List<MapPolygon> list = new ArrayList<>();
375 mapPolygons.put(i, list);
376 // Add new map polygons
377 for (Shape shape : shapes) {
378 MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
379 list.add(polygon);
380 defaultMap.addMapPolygon(polygon);
381 }
382 }
383 } else if (mapPolygons.containsKey(i)) {
384 // Remove previously drawn map polygons
385 for (MapPolygon polygon : mapPolygons.get(i)) {
386 defaultMap.removeMapPolygon(polygon);
387 }
388 mapPolygons.remove(i);
389 }
390 // Only display bounds when no polygons (shapes) are defined for this provider
391 } else {
392 if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
393 if (!mapRectangles.containsKey(i)) {
394 // Add new map rectangle
395 Coordinate topLeft = new Coordinate(bounds.getMaxLat(), bounds.getMinLon());
396 Coordinate bottomRight = new Coordinate(bounds.getMinLat(), bounds.getMaxLon());
397 MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight);
398 mapRectangles.put(i, rectangle);
399 defaultMap.addMapRectangle(rectangle);
400 }
401 } else if (mapRectangles.containsKey(i)) {
402 // Remove previously drawn map rectangle
403 defaultMap.removeMapRectangle(mapRectangles.get(i));
404 mapRectangles.remove(i);
405 }
406 }
407 }
408 }
409
410 private <T> void doCleanupResidualBounds(Map<Integer, T> map, Consumer<T> removalEffect) {
411 for (Integer i : map.keySet()) {
412 int viewIndex = defaultTable.convertRowIndexToView(i);
413 if (!defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
414 removalEffect.accept(map.remove(i));
415 }
416 }
417 }
418
419 private void cleanupResidualBounds() {
420 doCleanupResidualBounds(mapPolygons, l -> l.forEach(defaultMap::removeMapPolygon));
421 doCleanupResidualBounds(mapRectangles, defaultMap::removeMapRectangle);
422 }
423 }
424
425 private class NewEntryAction extends AbstractAction {
426
427 private final ImageryInfo.ImageryType type;
428
429 NewEntryAction(ImageryInfo.ImageryType type) {
430 putValue(NAME, type.toString());
431 putValue(SHORT_DESCRIPTION, tr("Add a new {0} entry by entering the URL", type.toString()));
432 String icon = /* ICON(dialogs/) */ "add";
433 switch (type) {
434 case WMS:
435 icon = /* ICON(dialogs/) */ "add_wms";
436 break;
437 case TMS:
438 icon = /* ICON(dialogs/) */ "add_tms";
439 break;
440 case WMTS:
441 icon = /* ICON(dialogs/) */ "add_wmts";
442 break;
443 default:
444 break;
445 }
446 new ImageProvider("dialogs", icon).getResource().attachImageIcon(this, true);
447 this.type = type;
448 }
449
450 @Override
451 public void actionPerformed(ActionEvent evt) {
452 final AddImageryPanel p;
453 switch (type) {
454 case WMS:
455 p = new AddWMSLayerPanel();
456 break;
457 case TMS:
458 p = new AddTMSLayerPanel();
459 break;
460 case WMTS:
461 p = new AddWMTSLayerPanel();
462 break;
463 default:
464 throw new IllegalStateException("Type " + type + " not supported");
465 }
466
467 final AddImageryDialog addDialog = new AddImageryDialog(gui, p);
468 addDialog.showDialog();
469
470 if (addDialog.getValue() == 1) {
471 try {
472 activeModel.addRow(p.getImageryInfo());
473 } catch (IllegalArgumentException ex) {
474 if (ex.getMessage() == null || ex.getMessage().isEmpty())
475 throw ex;
476 else {
477 JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
478 ex.getMessage(), tr("Error"),
479 JOptionPane.ERROR_MESSAGE);
480 }
481 }
482 }
483 }
484 }
485
486 private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
487
488 /**
489 * Constructs a new {@code RemoveEntryAction}.
490 */
491 RemoveEntryAction() {
492 putValue(NAME, tr("Remove"));
493 putValue(SHORT_DESCRIPTION, tr("Remove entry"));
494 new ImageProvider("dialogs", "delete").getResource().attachImageIcon(this, true);
495 updateEnabledState();
496 }
497
498 protected final void updateEnabledState() {
499 setEnabled(activeTable.getSelectedRowCount() > 0);
500 }
501
502 @Override
503 public void valueChanged(ListSelectionEvent e) {
504 updateEnabledState();
505 }
506
507 @Override
508 public void actionPerformed(ActionEvent e) {
509 Integer i;
510 while ((i = activeTable.getSelectedRow()) != -1) {
511 activeModel.removeRow(i);
512 }
513 }
514 }
515
516 private class ActivateAction extends AbstractAction implements ListSelectionListener {
517
518 /**
519 * Constructs a new {@code ActivateAction}.
520 */
521 ActivateAction() {
522 putValue(NAME, tr("Activate"));
523 putValue(SHORT_DESCRIPTION, tr("Copy selected default entries from the list above into the list below."));
524 new ImageProvider("preferences", "activate-down").getResource().attachImageIcon(this, true);
525 }
526
527 protected void updateEnabledState() {
528 setEnabled(defaultTable.getSelectedRowCount() > 0);
529 }
530
531 @Override
532 public void valueChanged(ListSelectionEvent e) {
533 updateEnabledState();
534 }
535
536 @Override
537 public void actionPerformed(ActionEvent e) {
538 int[] lines = defaultTable.getSelectedRows();
539 if (lines.length == 0) {
540 JOptionPane.showMessageDialog(
541 gui,
542 tr("Please select at least one row to copy."),
543 tr("Information"),
544 JOptionPane.INFORMATION_MESSAGE);
545 return;
546 }
547
548 Set<String> acceptedEulas = new HashSet<>();
549
550 outer:
551 for (int line : lines) {
552 ImageryInfo info = defaultModel.getRow(defaultTable.convertRowIndexToModel(line));
553
554 // Check if an entry with exactly the same values already exists
555 for (int j = 0; j < activeModel.getRowCount(); j++) {
556 if (info.equalsBaseValues(activeModel.getRow(j))) {
557 // Select the already existing row so the user has
558 // some feedback in case an entry exists
559 activeTable.getSelectionModel().setSelectionInterval(j, j);
560 activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true));
561 continue outer;
562 }
563 }
564
565 String eulaURL = info.getEulaAcceptanceRequired();
566 // If set and not already accepted, ask for EULA acceptance
567 if (eulaURL != null && !acceptedEulas.contains(eulaURL)) {
568 if (confirmEulaAcceptance(gui, eulaURL)) {
569 acceptedEulas.add(eulaURL);
570 } else {
571 continue outer;
572 }
573 }
574
575 activeModel.addRow(new ImageryInfo(info));
576 int lastLine = activeModel.getRowCount() - 1;
577 activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
578 activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true));
579 }
580 }
581 }
582
583 private class ReloadAction extends AbstractAction {
584
585 /**
586 * Constructs a new {@code ReloadAction}.
587 */
588 ReloadAction() {
589 putValue(SHORT_DESCRIPTION, tr("Update default entries"));
590 new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this, true);
591 }
592
593 @Override
594 public void actionPerformed(ActionEvent evt) {
595 layerInfo.loadDefaults(true, MainApplication.worker, false);
596 defaultModel.fireTableDataChanged();
597 defaultTable.getSelectionModel().clearSelection();
598 defaultTableListener.clearMap();
599 /* loading new file may change active layers */
600 activeModel.fireTableDataChanged();
601 }
602 }
603
604 /**
605 * The table model for imagery layer list
606 */
607 public class ImageryLayerTableModel extends DefaultTableModel {
608 /**
609 * Constructs a new {@code ImageryLayerTableModel}.
610 */
611 public ImageryLayerTableModel() {
612 setColumnIdentifiers(new String[] {tr("Menu Name"), tr("Imagery URL")});
613 }
614
615 /**
616 * Returns the imagery info at the given row number.
617 * @param row The row number
618 * @return The imagery info at the given row number
619 */
620 public ImageryInfo getRow(int row) {
621 return layerInfo.getLayers().get(row);
622 }
623
624 /**
625 * Adds a new imagery info as the last row.
626 * @param i The imagery info to add
627 */
628 public void addRow(ImageryInfo i) {
629 layerInfo.add(i);
630 int p = getRowCount() - 1;
631 fireTableRowsInserted(p, p);
632 }
633
634 @Override
635 public void removeRow(int i) {
636 layerInfo.remove(getRow(i));
637 fireTableRowsDeleted(i, i);
638 }
639
640 @Override
641 public int getRowCount() {
642 return layerInfo.getLayers().size();
643 }
644
645 @Override
646 public Object getValueAt(int row, int column) {
647 ImageryInfo info = layerInfo.getLayers().get(row);
648 switch (column) {
649 case 0:
650 return info.getName();
651 case 1:
652 return info.getExtendedUrl();
653 default:
654 throw new ArrayIndexOutOfBoundsException(Integer.toString(column));
655 }
656 }
657
658 @Override
659 public void setValueAt(Object o, int row, int column) {
660 if (layerInfo.getLayers().size() <= row) return;
661 ImageryInfo info = layerInfo.getLayers().get(row);
662 switch (column) {
663 case 0:
664 info.setName((String) o);
665 info.clearId();
666 break;
667 case 1:
668 info.setExtendedUrl((String) o);
669 info.clearId();
670 break;
671 default:
672 throw new ArrayIndexOutOfBoundsException(Integer.toString(column));
673 }
674 }
675 }
676
677 /**
678 * The table model for the default imagery layer list
679 */
680 public class ImageryDefaultLayerTableModel extends DefaultTableModel {
681 /**
682 * Constructs a new {@code ImageryDefaultLayerTableModel}.
683 */
684 public ImageryDefaultLayerTableModel() {
685 setColumnIdentifiers(new String[]{"", "", tr("Menu Name (Default)"), tr("Imagery URL (Default)")});
686 }
687
688 /**
689 * Returns the imagery info at the given row number.
690 * @param row The row number
691 * @return The imagery info at the given row number
692 */
693 public ImageryInfo getRow(int row) {
694 return layerInfo.getAllDefaultLayers().get(row);
695 }
696
697 @Override
698 public int getRowCount() {
699 return layerInfo.getAllDefaultLayers().size();
700 }
701
702 @Override
703 public Class<?> getColumnClass(int columnIndex) {
704 switch (columnIndex) {
705 case 0:
706 return ImageryCategory.class;
707 case 1:
708 return String.class;
709 case 2:
710 return ImageryInfo.class;
711 case 3:
712 return String.class;
713 default:
714 return super.getColumnClass(columnIndex);
715 }
716 }
717
718 @Override
719 public Object getValueAt(int row, int column) {
720 ImageryInfo info = layerInfo.getAllDefaultLayers().get(row);
721 switch (column) {
722 case 0:
723 return Optional.ofNullable(info.getImageryCategory()).orElse(ImageryCategory.OTHER);
724 case 1:
725 return info.getCountryCode();
726 case 2:
727 return info;
728 case 3:
729 return info.getExtendedUrl();
730 default:
731 return null;
732 }
733 }
734
735 @Override
736 public boolean isCellEditable(int row, int column) {
737 return false;
738 }
739 }
740
741 private static boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
742 URL url;
743 try {
744 url = new URL(eulaUrl.replaceAll("\\{lang\\}", LanguageInfo.getWikiLanguagePrefix()));
745 JosmEditorPane htmlPane;
746 try {
747 htmlPane = new JosmEditorPane(url);
748 } catch (IOException e1) {
749 Logging.trace(e1);
750 // give a second chance with a default Locale 'en'
751 try {
752 url = new URL(eulaUrl.replaceAll("\\{lang\\}", ""));
753 htmlPane = new JosmEditorPane(url);
754 } catch (IOException e2) {
755 Logging.debug(e2);
756 JOptionPane.showMessageDialog(gui, tr("EULA license URL not available: {0}", eulaUrl));
757 return false;
758 }
759 }
760 Box box = Box.createVerticalBox();
761 htmlPane.setEditable(false);
762 JScrollPane scrollPane = new JScrollPane(htmlPane);
763 scrollPane.setPreferredSize(new Dimension(400, 400));
764 box.add(scrollPane);
765 int option = JOptionPane.showConfirmDialog(MainApplication.getMainFrame(), box, tr("Please abort if you are not sure"),
766 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
767 if (option == JOptionPane.YES_OPTION)
768 return true;
769 } catch (MalformedURLException e2) {
770 JOptionPane.showMessageDialog(gui, tr("Malformed URL for the EULA licence: {0}", eulaUrl));
771 }
772 return false;
773 }
774}
Note: See TracBrowser for help on using the repository browser.