001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.preferences.imagery; 003 004 import static org.openstreetmap.josm.tools.I18n.marktr; 005 import static org.openstreetmap.josm.tools.I18n.tr; 006 007 import java.awt.Color; 008 import java.awt.Component; 009 import java.awt.Dimension; 010 import java.awt.FlowLayout; 011 import java.awt.Font; 012 import java.awt.GridBagConstraints; 013 import java.awt.GridBagLayout; 014 import java.awt.event.ActionEvent; 015 import java.awt.event.ActionListener; 016 import java.awt.event.MouseEvent; 017 import java.io.IOException; 018 import java.net.MalformedURLException; 019 import java.net.URL; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.HashSet; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.Set; 026 027 import javax.swing.AbstractAction; 028 import javax.swing.BorderFactory; 029 import javax.swing.Box; 030 import javax.swing.JButton; 031 import javax.swing.JEditorPane; 032 import javax.swing.JLabel; 033 import javax.swing.JOptionPane; 034 import javax.swing.JPanel; 035 import javax.swing.JScrollPane; 036 import javax.swing.JSeparator; 037 import javax.swing.JTabbedPane; 038 import javax.swing.JTable; 039 import javax.swing.JToolBar; 040 import javax.swing.event.ListSelectionEvent; 041 import javax.swing.event.ListSelectionListener; 042 import javax.swing.event.TableModelEvent; 043 import javax.swing.event.TableModelListener; 044 import javax.swing.table.DefaultTableCellRenderer; 045 import javax.swing.table.DefaultTableModel; 046 import javax.swing.table.TableColumnModel; 047 048 import org.openstreetmap.gui.jmapviewer.Coordinate; 049 import org.openstreetmap.gui.jmapviewer.JMapViewer; 050 import org.openstreetmap.gui.jmapviewer.MapPolygonImpl; 051 import org.openstreetmap.gui.jmapviewer.MapRectangleImpl; 052 import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon; 053 import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle; 054 import org.openstreetmap.josm.Main; 055 import org.openstreetmap.josm.data.imagery.ImageryInfo; 056 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds; 057 import org.openstreetmap.josm.data.imagery.ImageryLayerInfo; 058 import org.openstreetmap.josm.data.imagery.OffsetBookmark; 059 import org.openstreetmap.josm.data.imagery.Shape; 060 import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting; 061 import org.openstreetmap.josm.gui.preferences.PreferenceSetting; 062 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory; 063 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 064 import org.openstreetmap.josm.gui.util.GuiHelper; 065 import org.openstreetmap.josm.tools.GBC; 066 import org.openstreetmap.josm.tools.ImageProvider; 067 import org.openstreetmap.josm.tools.LanguageInfo; 068 069 public class ImageryPreference extends DefaultTabPreferenceSetting { 070 public static class Factory implements PreferenceSettingFactory { 071 @Override 072 public PreferenceSetting createPreferenceSetting() { 073 return new ImageryPreference(); 074 } 075 } 076 077 private ImageryPreference() { 078 super("imagery", tr("Imagery Preferences"), tr("Modify list of imagery layers displayed in the Imagery menu")); 079 } 080 081 private ImageryProvidersPanel imageryProviders; 082 private ImageryLayerInfo layerInfo; 083 084 private CommonSettingsPanel commonSettings; 085 private WMSSettingsPanel wmsSettings; 086 private TMSSettingsPanel tmsSettings; 087 088 private void addSettingsSection(final JPanel p, String name, JPanel section) { 089 addSettingsSection(p, name, section, GBC.eol()); 090 } 091 092 private void addSettingsSection(final JPanel p, String name, JPanel section, GBC gbc) { 093 final JLabel lbl = new JLabel(name); 094 lbl.setFont(lbl.getFont().deriveFont(Font.BOLD)); 095 p.add(lbl,GBC.std()); 096 p.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0)); 097 p.add(section, gbc.insets(20,5,0,10)); 098 } 099 100 private Component buildSettingsPanel(final PreferenceTabbedPane gui) { 101 final JPanel p = new JPanel(new GridBagLayout()); 102 p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 103 104 addSettingsSection(p, tr("Common Settings"), commonSettings = new CommonSettingsPanel()); 105 addSettingsSection(p, tr("WMS Settings"), wmsSettings = new WMSSettingsPanel(), 106 GBC.eol().fill(GBC.HORIZONTAL)); 107 addSettingsSection(p, tr("TMS Settings"), tmsSettings = new TMSSettingsPanel(), 108 GBC.eol().fill(GBC.HORIZONTAL)); 109 110 p.add(new JPanel(),GBC.eol().fill(GBC.BOTH)); 111 return new JScrollPane(p); 112 } 113 114 @Override 115 public void addGui(final PreferenceTabbedPane gui) { 116 JPanel p = gui.createPreferenceTab(this); 117 JTabbedPane pane = new JTabbedPane(); 118 layerInfo = new ImageryLayerInfo(ImageryLayerInfo.instance); 119 imageryProviders = new ImageryProvidersPanel(gui, layerInfo); 120 pane.add(imageryProviders); 121 pane.add(buildSettingsPanel(gui)); 122 pane.add(new OffsetBookmarksPanel(gui)); 123 loadSettings(); 124 pane.setTitleAt(0, tr("Imagery providers")); 125 pane.setTitleAt(1, tr("Settings")); 126 pane.setTitleAt(2, tr("Offset bookmarks")); 127 p.add(pane,GBC.std().fill(GBC.BOTH)); 128 } 129 130 public ImageryProvidersPanel getProvidersPanel() { 131 return imageryProviders; 132 } 133 134 private void loadSettings() { 135 commonSettings.loadSettings(); 136 wmsSettings.loadSettings(); 137 tmsSettings.loadSettings(); 138 } 139 140 @Override 141 public boolean ok() { 142 layerInfo.save(); 143 ImageryLayerInfo.instance.clear(); 144 ImageryLayerInfo.instance.load(); 145 Main.main.menu.imageryMenu.refreshImageryMenu(); 146 Main.main.menu.imageryMenu.refreshOffsetMenu(); 147 OffsetBookmark.saveBookmarks(); 148 149 boolean commonRestartRequired = commonSettings.saveSettings(); 150 boolean wmsRestartRequired = wmsSettings.saveSettings(); 151 boolean tmsRestartRequired = tmsSettings.saveSettings(); 152 153 return commonRestartRequired || wmsRestartRequired || tmsRestartRequired; 154 } 155 156 /** 157 * Updates a server URL in the preferences dialog. Used by plugins. 158 * 159 * @param server 160 * The server name 161 * @param url 162 * The server URL 163 */ 164 public void setServerUrl(String server, String url) { 165 for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) { 166 if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString())) { 167 imageryProviders.activeModel.setValueAt(url, i, 1); 168 return; 169 } 170 } 171 imageryProviders.activeModel.addRow(new String[] { server, url }); 172 } 173 174 /** 175 * Gets a server URL in the preferences dialog. Used by plugins. 176 * 177 * @param server 178 * The server name 179 * @return The server URL 180 */ 181 public String getServerUrl(String server) { 182 for (int i = 0; i < imageryProviders.activeModel.getRowCount(); i++) { 183 if (server.equals(imageryProviders.activeModel.getValueAt(i, 0).toString())) 184 return imageryProviders.activeModel.getValueAt(i, 1).toString(); 185 } 186 return null; 187 } 188 189 public static class ImageryProvidersPanel extends JPanel { 190 // Public JTables and JMapViewer 191 public final JTable activeTable; 192 public final JTable defaultTable; 193 public final JMapViewer defaultMap; 194 195 // Public models 196 public final ImageryLayerTableModel activeModel; 197 public final ImageryDefaultLayerTableModel defaultModel; 198 199 // Public JToolbars 200 public final JToolBar activeToolbar; 201 public final JToolBar middleToolbar; 202 public final JToolBar defaultToolbar; 203 204 // Private members 205 private final PreferenceTabbedPane gui; 206 private final ImageryLayerInfo layerInfo; 207 208 private static class ImageryTableCellRenderer extends DefaultTableCellRenderer { 209 210 private List<ImageryInfo> layers; 211 212 public ImageryTableCellRenderer(List<ImageryInfo> layers) { 213 this.layers = layers; 214 } 215 216 @Override 217 public Component getTableCellRendererComponent(JTable table, Object value, boolean 218 isSelected, boolean hasFocus, int row, int column) { 219 JLabel label = (JLabel) super.getTableCellRendererComponent( 220 table, value, isSelected, hasFocus, row, column); 221 label.setBackground(Main.pref.getUIColor("Table.background")); 222 if (isSelected) { 223 label.setForeground(Main.pref.getUIColor("Table.foreground")); 224 } 225 if (value != null) { // Fix #8159 226 String t = value.toString(); 227 for (ImageryInfo l : layers) { 228 if (l.getExtendedUrl().equals(t)) { 229 label.setBackground(Main.pref.getColor( 230 marktr("Imagery Background: Default"), 231 new Color(200,255,200))); 232 break; 233 } 234 } 235 } 236 return label; 237 } 238 } 239 240 public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) { 241 super(new GridBagLayout()); 242 this.gui = gui; 243 this.layerInfo = layerInfoArg; 244 this.activeModel = new ImageryLayerTableModel(); 245 246 activeTable = new JTable(activeModel) { 247 @Override 248 public String getToolTipText(MouseEvent e) { 249 java.awt.Point p = e.getPoint(); 250 return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString(); 251 } 252 }; 253 254 defaultModel = new ImageryDefaultLayerTableModel(); 255 defaultTable = new JTable(defaultModel) { 256 @Override 257 public String getToolTipText(MouseEvent e) { 258 java.awt.Point p = e.getPoint(); 259 return (String) defaultModel.getValueAt(rowAtPoint(p), columnAtPoint(p)); 260 } 261 }; 262 263 defaultModel.addTableModelListener( 264 new TableModelListener() { 265 @Override 266 public void tableChanged(TableModelEvent e) { 267 activeTable.repaint(); 268 } 269 } 270 ); 271 272 activeModel.addTableModelListener( 273 new TableModelListener() { 274 @Override 275 public void tableChanged(TableModelEvent e) { 276 defaultTable.repaint(); 277 } 278 } 279 ); 280 281 TableColumnModel mod = defaultTable.getColumnModel(); 282 mod.getColumn(2).setPreferredWidth(800); 283 mod.getColumn(2).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getLayers())); 284 mod.getColumn(1).setPreferredWidth(400); 285 mod.getColumn(0).setPreferredWidth(50); 286 287 mod = activeTable.getColumnModel(); 288 mod.getColumn(1).setPreferredWidth(800); 289 mod.getColumn(1).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getDefaultLayers())); 290 mod.getColumn(0).setPreferredWidth(200); 291 292 RemoveEntryAction remove = new RemoveEntryAction(); 293 activeTable.getSelectionModel().addListSelectionListener(remove); 294 295 add(new JLabel(tr("Available default entries:")), GBC.eol().insets(5, 5, 0, 0)); 296 // Add default item list 297 JScrollPane scrolldef = new JScrollPane(defaultTable); 298 scrolldef.setPreferredSize(new Dimension(200, 200)); 299 add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0)); 300 301 // Add default item map 302 defaultMap = new JMapViewer(); 303 defaultMap.setZoomContolsVisible(false); 304 defaultMap.setMinimumSize(new Dimension(100, 200)); 305 add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0)); 306 307 defaultTable.getSelectionModel().addListSelectionListener(new DefListSelectionListener()); 308 309 defaultToolbar = new JToolBar(JToolBar.VERTICAL); 310 defaultToolbar.setFloatable(false); 311 defaultToolbar.setBorderPainted(false); 312 defaultToolbar.setOpaque(false); 313 defaultToolbar.add(new ReloadAction()); 314 add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0)); 315 316 ActivateAction activate = new ActivateAction(); 317 defaultTable.getSelectionModel().addListSelectionListener(activate); 318 JButton btnActivate = new JButton(activate); 319 320 middleToolbar = new JToolBar(JToolBar.HORIZONTAL); 321 middleToolbar.setFloatable(false); 322 middleToolbar.setBorderPainted(false); 323 middleToolbar.setOpaque(false); 324 middleToolbar.add(btnActivate); 325 add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 15, 5, 0)); 326 327 add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL)); 328 329 add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0)); 330 JScrollPane scroll = new JScrollPane(activeTable); 331 add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5)); 332 scroll.setPreferredSize(new Dimension(200, 200)); 333 334 activeToolbar = new JToolBar(JToolBar.VERTICAL); 335 activeToolbar.setFloatable(false); 336 activeToolbar.setBorderPainted(false); 337 activeToolbar.setOpaque(false); 338 activeToolbar.add(new NewEntryAction()); 339 //activeToolbar.add(edit); TODO 340 activeToolbar.add(remove); 341 add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5)); 342 343 } 344 345 // Listener of default providers list selection 346 private final class DefListSelectionListener implements ListSelectionListener { 347 // The current drawn rectangles and polygons 348 private final Map<Integer, MapRectangle> mapRectangles; 349 private final Map<Integer, List<MapPolygon>> mapPolygons; 350 351 private DefListSelectionListener() { 352 this.mapRectangles = new HashMap<Integer, MapRectangle>(); 353 this.mapPolygons = new HashMap<Integer, List<MapPolygon>>(); 354 } 355 356 @Override 357 public void valueChanged(ListSelectionEvent e) { 358 // First index is set to -1 when the list is refreshed, so discard all map rectangles and polygons 359 if (e.getFirstIndex() == -1) { 360 defaultMap.removeAllMapRectangles(); 361 defaultMap.removeAllMapPolygons(); 362 mapRectangles.clear(); 363 mapPolygons.clear(); 364 // Only process complete (final) selection events 365 } else if (!e.getValueIsAdjusting()) { 366 for (int i = e.getFirstIndex(); i<=e.getLastIndex(); i++) { 367 updateBoundsAndShapes(i); 368 } 369 // If needed, adjust map to show all map rectangles and polygons 370 if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) { 371 defaultMap.setDisplayToFitMapElements(false, true, true); 372 defaultMap.zoomOut(); 373 } 374 } 375 } 376 377 private void updateBoundsAndShapes(int i) { 378 ImageryBounds bounds = defaultModel.getRow(i).getBounds(); 379 if (bounds != null) { 380 List<Shape> shapes = bounds.getShapes(); 381 if (shapes != null && !shapes.isEmpty()) { 382 if (defaultTable.getSelectionModel().isSelectedIndex(i)) { 383 if (!mapPolygons.containsKey(i)) { 384 List<MapPolygon> list = new ArrayList<MapPolygon>(); 385 mapPolygons.put(i, list); 386 // Add new map polygons 387 for (Shape shape : shapes) { 388 MapPolygon polygon = new MapPolygonImpl(shape.getPoints()); 389 list.add(polygon); 390 defaultMap.addMapPolygon(polygon); 391 } 392 } 393 } else if (mapPolygons.containsKey(i)) { 394 // Remove previously drawn map polygons 395 for (MapPolygon polygon : mapPolygons.get(i)) { 396 defaultMap.removeMapPolygon(polygon); 397 } 398 mapPolygons.remove(i); 399 } 400 // Only display bounds when no polygons (shapes) are defined for this provider 401 } else { 402 if (defaultTable.getSelectionModel().isSelectedIndex(i)) { 403 if (!mapRectangles.containsKey(i)) { 404 // Add new map rectangle 405 Coordinate topLeft = new Coordinate(bounds.getMax().lat(), bounds.getMin().lon()); 406 Coordinate bottomRight = new Coordinate(bounds.getMin().lat(), bounds.getMax().lon()); 407 MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight); 408 mapRectangles.put(i, rectangle); 409 defaultMap.addMapRectangle(rectangle); 410 } 411 } else if (mapRectangles.containsKey(i)) { 412 // Remove previously drawn map rectangle 413 defaultMap.removeMapRectangle(mapRectangles.get(i)); 414 mapRectangles.remove(i); 415 } 416 } 417 } 418 } 419 } 420 421 private class NewEntryAction extends AbstractAction { 422 public NewEntryAction() { 423 putValue(NAME, tr("New")); 424 putValue(SHORT_DESCRIPTION, tr("Add a new WMS/TMS entry by entering the URL")); 425 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add")); 426 } 427 428 public void actionPerformed(ActionEvent evt) { 429 final AddWMSLayerPanel p = new AddWMSLayerPanel(); 430 GuiHelper.prepareResizeableOptionPane(p, new Dimension(250, 350)); 431 int answer = JOptionPane.showConfirmDialog( 432 gui, p, tr("Add Imagery URL"), 433 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); 434 if (answer == JOptionPane.OK_OPTION) { 435 try { 436 activeModel.addRow(p.getImageryInfo()); 437 } catch (IllegalArgumentException ex) { 438 if (ex.getMessage() == null || ex.getMessage().isEmpty()) 439 throw ex; 440 else { 441 JOptionPane.showMessageDialog(Main.parent, 442 ex.getMessage(), tr("Error"), 443 JOptionPane.ERROR_MESSAGE); 444 } 445 } 446 } 447 } 448 } 449 450 private class RemoveEntryAction extends AbstractAction implements ListSelectionListener { 451 452 public RemoveEntryAction() { 453 putValue(NAME, tr("Remove")); 454 putValue(SHORT_DESCRIPTION, tr("Remove entry")); 455 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete")); 456 updateEnabledState(); 457 } 458 459 protected void updateEnabledState() { 460 setEnabled(activeTable.getSelectedRowCount() > 0); 461 } 462 463 @Override 464 public void valueChanged(ListSelectionEvent e) { 465 updateEnabledState(); 466 } 467 468 @Override 469 public void actionPerformed(ActionEvent e) { 470 Integer i; 471 while ((i = activeTable.getSelectedRow()) != -1) { 472 activeModel.removeRow(i); 473 } 474 } 475 } 476 477 private class ActivateAction extends AbstractAction implements ListSelectionListener { 478 public ActivateAction() { 479 putValue(NAME, tr("Activate")); 480 putValue(SHORT_DESCRIPTION, tr("copy selected defaults")); 481 putValue(SMALL_ICON, ImageProvider.get("preferences", "activate-down")); 482 } 483 484 protected void updateEnabledState() { 485 setEnabled(defaultTable.getSelectedRowCount() > 0); 486 } 487 488 @Override 489 public void valueChanged(ListSelectionEvent e) { 490 updateEnabledState(); 491 } 492 493 @Override 494 public void actionPerformed(ActionEvent e) { 495 int[] lines = defaultTable.getSelectedRows(); 496 if (lines.length == 0) { 497 JOptionPane.showMessageDialog( 498 gui, 499 tr("Please select at least one row to copy."), 500 tr("Information"), 501 JOptionPane.INFORMATION_MESSAGE); 502 return; 503 } 504 505 Set<String> acceptedEulas = new HashSet<String>(); 506 507 outer: for (int i = 0; i < lines.length; i++) { 508 ImageryInfo info = defaultModel.getRow(lines[i]); 509 510 // Check if an entry with exactly the same values already 511 // exists 512 for (int j = 0; j < activeModel.getRowCount(); j++) { 513 if (info.equalsBaseValues(activeModel.getRow(j))) { 514 // Select the already existing row so the user has 515 // some feedback in case an entry exists 516 activeTable.getSelectionModel().setSelectionInterval(j, j); 517 activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true)); 518 continue outer; 519 } 520 } 521 522 String eulaURL = info.getEulaAcceptanceRequired(); 523 // If set and not already accepted, ask for EULA acceptance 524 if (eulaURL != null && !acceptedEulas.contains(eulaURL)) { 525 if (confirmEulaAcceptance(gui, eulaURL)) { 526 acceptedEulas.add(eulaURL); 527 } else { 528 continue outer; 529 } 530 } 531 532 activeModel.addRow(new ImageryInfo(info)); 533 int lastLine = activeModel.getRowCount() - 1; 534 activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine); 535 activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true)); 536 } 537 } 538 } 539 540 private class ReloadAction extends AbstractAction { 541 public ReloadAction() { 542 putValue(SHORT_DESCRIPTION, tr("reload defaults")); 543 putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh")); 544 } 545 546 public void actionPerformed(ActionEvent evt) { 547 layerInfo.loadDefaults(true); 548 defaultModel.fireTableDataChanged(); 549 } 550 } 551 552 /** 553 * The table model for imagery layer list 554 */ 555 public class ImageryLayerTableModel extends DefaultTableModel { 556 public ImageryLayerTableModel() { 557 setColumnIdentifiers(new String[] { tr("Menu Name"), tr("Imagery URL")}); 558 } 559 560 public ImageryInfo getRow(int row) { 561 return layerInfo.getLayers().get(row); 562 } 563 564 public void addRow(ImageryInfo i) { 565 layerInfo.add(i); 566 int p = getRowCount() - 1; 567 fireTableRowsInserted(p, p); 568 } 569 570 @Override 571 public void removeRow(int i) { 572 layerInfo.remove(getRow(i)); 573 fireTableRowsDeleted(i, i); 574 } 575 576 @Override 577 public int getRowCount() { 578 return layerInfo.getLayers().size(); 579 } 580 581 @Override 582 public Object getValueAt(int row, int column) { 583 ImageryInfo info = layerInfo.getLayers().get(row); 584 switch (column) { 585 case 0: 586 return info.getName(); 587 case 1: 588 return info.getExtendedUrl(); 589 default: 590 throw new ArrayIndexOutOfBoundsException(); 591 } 592 } 593 594 @Override 595 public void setValueAt(Object o, int row, int column) { 596 if (layerInfo.getLayers().size() <= row) return; 597 ImageryInfo info = layerInfo.getLayers().get(row); 598 switch (column) { 599 case 0: 600 info.setName((String) o); 601 break; 602 case 1: 603 info.setExtendedUrl((String)o); 604 break; 605 default: 606 throw new ArrayIndexOutOfBoundsException(); 607 } 608 } 609 610 @Override 611 public boolean isCellEditable(int row, int column) { 612 return true; 613 } 614 } 615 616 /** 617 * The table model for the default imagery layer list 618 */ 619 public class ImageryDefaultLayerTableModel extends DefaultTableModel { 620 public ImageryDefaultLayerTableModel() { 621 setColumnIdentifiers(new String[]{"", tr("Menu Name (Default)"), tr("Imagery URL (Default)")}); 622 } 623 624 public ImageryInfo getRow(int row) { 625 return layerInfo.getDefaultLayers().get(row); 626 } 627 628 @Override 629 public int getRowCount() { 630 return layerInfo.getDefaultLayers().size(); 631 } 632 633 @Override 634 public Object getValueAt(int row, int column) { 635 ImageryInfo info = layerInfo.getDefaultLayers().get(row); 636 switch (column) { 637 case 0: 638 return info.getCountryCode(); 639 case 1: 640 return info.getName(); 641 case 2: 642 return info.getExtendedUrl(); 643 } 644 return null; 645 } 646 647 @Override 648 public boolean isCellEditable(int row, int column) { 649 return false; 650 } 651 } 652 653 private boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) { 654 URL url = null; 655 try { 656 url = new URL(eulaUrl.replaceAll("\\{lang\\}", LanguageInfo.getWikiLanguagePrefix())); 657 JEditorPane htmlPane = null; 658 try { 659 htmlPane = new JEditorPane(url); 660 } catch (IOException e1) { 661 // give a second chance with a default Locale 'en' 662 try { 663 url = new URL(eulaUrl.replaceAll("\\{lang\\}", "")); 664 htmlPane = new JEditorPane(url); 665 } catch (IOException e2) { 666 JOptionPane.showMessageDialog(gui ,tr("EULA license URL not available: {0}", eulaUrl)); 667 return false; 668 } 669 } 670 Box box = Box.createVerticalBox(); 671 htmlPane.setEditable(false); 672 JScrollPane scrollPane = new JScrollPane(htmlPane); 673 scrollPane.setPreferredSize(new Dimension(400, 400)); 674 box.add(scrollPane); 675 int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"), JOptionPane.YES_NO_OPTION, 676 JOptionPane.WARNING_MESSAGE); 677 if (option == JOptionPane.YES_OPTION) 678 return true; 679 } catch (MalformedURLException e2) { 680 JOptionPane.showMessageDialog(gui ,tr("Malformed URL for the EULA licence: {0}", eulaUrl)); 681 } 682 return false; 683 } 684 } 685 686 static class OffsetBookmarksPanel extends JPanel { 687 List<OffsetBookmark> bookmarks = OffsetBookmark.allBookmarks; 688 OffsetsBookmarksModel model = new OffsetsBookmarksModel(); 689 690 public OffsetBookmarksPanel(final PreferenceTabbedPane gui) { 691 super(new GridBagLayout()); 692 final JTable list = new JTable(model) { 693 @Override 694 public String getToolTipText(MouseEvent e) { 695 java.awt.Point p = e.getPoint(); 696 return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString(); 697 } 698 }; 699 JScrollPane scroll = new JScrollPane(list); 700 add(scroll, GBC.eol().fill(GridBagConstraints.BOTH)); 701 scroll.setPreferredSize(new Dimension(200, 200)); 702 703 TableColumnModel mod = list.getColumnModel(); 704 mod.getColumn(0).setPreferredWidth(150); 705 mod.getColumn(1).setPreferredWidth(200); 706 mod.getColumn(2).setPreferredWidth(300); 707 mod.getColumn(3).setPreferredWidth(150); 708 mod.getColumn(4).setPreferredWidth(150); 709 710 JPanel buttonPanel = new JPanel(new FlowLayout()); 711 712 JButton add = new JButton(tr("Add")); 713 buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0)); 714 add.addActionListener(new ActionListener() { 715 @Override 716 public void actionPerformed(ActionEvent e) { 717 OffsetBookmark b = new OffsetBookmark(Main.getProjection().toCode(),"","",0,0); 718 model.addRow(b); 719 } 720 }); 721 722 JButton delete = new JButton(tr("Delete")); 723 buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0)); 724 delete.addActionListener(new ActionListener() { 725 @Override 726 public void actionPerformed(ActionEvent e) { 727 if (list.getSelectedRow() == -1) { 728 JOptionPane.showMessageDialog(gui, tr("Please select the row to delete.")); 729 } else { 730 Integer i; 731 while ((i = list.getSelectedRow()) != -1) { 732 model.removeRow(i); 733 } 734 } 735 } 736 }); 737 738 add(buttonPanel,GBC.eol()); 739 } 740 741 /** 742 * The table model for imagery offsets list 743 */ 744 class OffsetsBookmarksModel extends DefaultTableModel { 745 public OffsetsBookmarksModel() { 746 setColumnIdentifiers(new String[] { tr("Projection"), tr("Layer"), tr("Name"), tr("Easting"), tr("Northing"),}); 747 } 748 749 public OffsetBookmark getRow(int row) { 750 return bookmarks.get(row); 751 } 752 753 public void addRow(OffsetBookmark i) { 754 bookmarks.add(i); 755 int p = getRowCount() - 1; 756 fireTableRowsInserted(p, p); 757 } 758 759 @Override 760 public void removeRow(int i) { 761 bookmarks.remove(getRow(i)); 762 fireTableRowsDeleted(i, i); 763 } 764 765 @Override 766 public int getRowCount() { 767 return bookmarks.size(); 768 } 769 770 @Override 771 public Object getValueAt(int row, int column) { 772 OffsetBookmark info = bookmarks.get(row); 773 switch (column) { 774 case 0: 775 if (info.projectionCode == null) return ""; 776 return info.projectionCode.toString(); 777 case 1: 778 return info.layerName; 779 case 2: 780 return info.name; 781 case 3: 782 return info.dx; 783 case 4: 784 return info.dy; 785 default: 786 throw new ArrayIndexOutOfBoundsException(); 787 } 788 } 789 790 @Override 791 public void setValueAt(Object o, int row, int column) { 792 OffsetBookmark info = bookmarks.get(row); 793 switch (column) { 794 case 1: 795 info.layerName = o.toString(); 796 break; 797 case 2: 798 info.name = o.toString(); 799 break; 800 case 3: 801 info.dx = Double.parseDouble((String) o); 802 break; 803 case 4: 804 info.dy = Double.parseDouble((String) o); 805 break; 806 default: 807 throw new ArrayIndexOutOfBoundsException(); 808 } 809 } 810 811 @Override 812 public boolean isCellEditable(int row, int column) { 813 return column >= 1; 814 } 815 } 816 } 817 818 public static void initialize() { 819 ImageryLayerInfo.instance.clear(); 820 ImageryLayerInfo.instance.loadDefaults(false); 821 ImageryLayerInfo.instance.load(); 822 OffsetBookmark.loadBookmarks(); 823 Main.main.menu.imageryMenu.refreshImageryMenu(); 824 Main.main.menu.imageryMenu.refreshOffsetMenu(); 825 } 826 }