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

Last change on this file since 16960 was 16960, checked in by simon04, 4 years ago

see #8334 - Add advanced option to scale the table font

Advanced preference keys gui.scale.table.*

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