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 String t = value.toString(); 222 label.setBackground(Main.pref.getUIColor("Table.background")); 223 if (isSelected) { 224 label.setForeground(Main.pref.getUIColor("Table.foreground")); 225 } 226 for(ImageryInfo l : layers) 227 { 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 return label; 236 } 237 } 238 239 public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfoArg) { 240 super(new GridBagLayout()); 241 this.gui = gui; 242 this.layerInfo = layerInfoArg; 243 this.activeModel = new ImageryLayerTableModel(); 244 245 activeTable = new JTable(activeModel) { 246 @Override 247 public String getToolTipText(MouseEvent e) { 248 java.awt.Point p = e.getPoint(); 249 return activeModel.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString(); 250 } 251 }; 252 253 defaultModel = new ImageryDefaultLayerTableModel(); 254 defaultTable = new JTable(defaultModel) { 255 @Override 256 public String getToolTipText(MouseEvent e) { 257 java.awt.Point p = e.getPoint(); 258 return (String) defaultModel.getValueAt(rowAtPoint(p), columnAtPoint(p)); 259 } 260 }; 261 262 defaultModel.addTableModelListener( 263 new TableModelListener() { 264 @Override 265 public void tableChanged(TableModelEvent e) { 266 activeTable.repaint(); 267 } 268 } 269 ); 270 271 activeModel.addTableModelListener( 272 new TableModelListener() { 273 @Override 274 public void tableChanged(TableModelEvent e) { 275 defaultTable.repaint(); 276 } 277 } 278 ); 279 280 TableColumnModel mod = defaultTable.getColumnModel(); 281 mod.getColumn(2).setPreferredWidth(800); 282 mod.getColumn(2).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getLayers())); 283 mod.getColumn(1).setPreferredWidth(400); 284 mod.getColumn(0).setPreferredWidth(50); 285 286 mod = activeTable.getColumnModel(); 287 mod.getColumn(1).setPreferredWidth(800); 288 mod.getColumn(1).setCellRenderer(new ImageryTableCellRenderer(layerInfo.getDefaultLayers())); 289 mod.getColumn(0).setPreferredWidth(200); 290 291 RemoveEntryAction remove = new RemoveEntryAction(); 292 activeTable.getSelectionModel().addListSelectionListener(remove); 293 294 add(new JLabel(tr("Available default entries:")), GBC.eol().insets(5, 5, 0, 0)); 295 // Add default item list 296 JScrollPane scrolldef = new JScrollPane(defaultTable); 297 scrolldef.setPreferredSize(new Dimension(200, 200)); 298 add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0)); 299 300 // Add default item map 301 defaultMap = new JMapViewer(); 302 defaultMap.setZoomContolsVisible(false); 303 defaultMap.setMinimumSize(new Dimension(100, 200)); 304 add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0)); 305 306 defaultTable.getSelectionModel().addListSelectionListener(new DefListSelectionListener()); 307 308 defaultToolbar = new JToolBar(JToolBar.VERTICAL); 309 defaultToolbar.setFloatable(false); 310 defaultToolbar.setBorderPainted(false); 311 defaultToolbar.setOpaque(false); 312 defaultToolbar.add(new ReloadAction()); 313 add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0)); 314 315 ActivateAction activate = new ActivateAction(); 316 defaultTable.getSelectionModel().addListSelectionListener(activate); 317 JButton btnActivate = new JButton(activate); 318 319 middleToolbar = new JToolBar(JToolBar.HORIZONTAL); 320 middleToolbar.setFloatable(false); 321 middleToolbar.setBorderPainted(false); 322 middleToolbar.setOpaque(false); 323 middleToolbar.add(btnActivate); 324 add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 15, 5, 0)); 325 326 add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL)); 327 328 add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0)); 329 JScrollPane scroll = new JScrollPane(activeTable); 330 add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4).insets(5, 0, 0, 5)); 331 scroll.setPreferredSize(new Dimension(200, 200)); 332 333 activeToolbar = new JToolBar(JToolBar.VERTICAL); 334 activeToolbar.setFloatable(false); 335 activeToolbar.setBorderPainted(false); 336 activeToolbar.setOpaque(false); 337 activeToolbar.add(new NewEntryAction()); 338 //activeToolbar.add(edit); TODO 339 activeToolbar.add(remove); 340 add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5)); 341 342 } 343 344 // Listener of default providers list selection 345 private final class DefListSelectionListener implements ListSelectionListener { 346 // The current drawn rectangles and polygons 347 private final Map<Integer, MapRectangle> mapRectangles; 348 private final Map<Integer, List<MapPolygon>> mapPolygons; 349 350 private DefListSelectionListener() { 351 this.mapRectangles = new HashMap<Integer, MapRectangle>(); 352 this.mapPolygons = new HashMap<Integer, List<MapPolygon>>(); 353 } 354 355 @Override 356 public void valueChanged(ListSelectionEvent e) { 357 // First index is set to -1 when the list is refreshed, so discard all map rectangles and polygons 358 if (e.getFirstIndex() == -1) { 359 defaultMap.removeAllMapRectangles(); 360 defaultMap.removeAllMapPolygons(); 361 mapRectangles.clear(); 362 mapPolygons.clear(); 363 // Only process complete (final) selection events 364 } else if (!e.getValueIsAdjusting()) { 365 for (int i = e.getFirstIndex(); i<=e.getLastIndex(); i++) { 366 updateBoundsAndShapes(i); 367 } 368 // If needed, adjust map to show all map rectangles and polygons 369 if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) { 370 defaultMap.setDisplayToFitMapElements(false, true, true); 371 defaultMap.zoomOut(); 372 } 373 } 374 } 375 376 private void updateBoundsAndShapes(int i) { 377 ImageryBounds bounds = defaultModel.getRow(i).getBounds(); 378 if (bounds != null) { 379 List<Shape> shapes = bounds.getShapes(); 380 if (shapes != null && !shapes.isEmpty()) { 381 if (defaultTable.getSelectionModel().isSelectedIndex(i)) { 382 if (!mapPolygons.containsKey(i)) { 383 List<MapPolygon> list = new ArrayList<MapPolygon>(); 384 mapPolygons.put(i, list); 385 // Add new map polygons 386 for (Shape shape : shapes) { 387 MapPolygon polygon = new MapPolygonImpl(shape.getPoints()); 388 list.add(polygon); 389 defaultMap.addMapPolygon(polygon); 390 } 391 } 392 } else if (mapPolygons.containsKey(i)) { 393 // Remove previously drawn map polygons 394 for (MapPolygon polygon : mapPolygons.get(i)) { 395 defaultMap.removeMapPolygon(polygon); 396 } 397 mapPolygons.remove(i); 398 } 399 // Only display bounds when no polygons (shapes) are defined for this provider 400 } else { 401 if (defaultTable.getSelectionModel().isSelectedIndex(i)) { 402 if (!mapRectangles.containsKey(i)) { 403 // Add new map rectangle 404 Coordinate topLeft = new Coordinate(bounds.getMax().lat(), bounds.getMin().lon()); 405 Coordinate bottomRight = new Coordinate(bounds.getMin().lat(), bounds.getMax().lon()); 406 MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight); 407 mapRectangles.put(i, rectangle); 408 defaultMap.addMapRectangle(rectangle); 409 } 410 } else if (mapRectangles.containsKey(i)) { 411 // Remove previously drawn map rectangle 412 defaultMap.removeMapRectangle(mapRectangles.get(i)); 413 mapRectangles.remove(i); 414 } 415 } 416 } 417 } 418 } 419 420 private class NewEntryAction extends AbstractAction { 421 public NewEntryAction() { 422 putValue(NAME, tr("New")); 423 putValue(SHORT_DESCRIPTION, tr("Add a new WMS/TMS entry by entering the URL")); 424 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add")); 425 } 426 427 public void actionPerformed(ActionEvent evt) { 428 final AddWMSLayerPanel p = new AddWMSLayerPanel(); 429 GuiHelper.prepareResizeableOptionPane(p, new Dimension(250, 350)); 430 int answer = JOptionPane.showConfirmDialog( 431 gui, p, tr("Add Imagery URL"), 432 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); 433 if (answer == JOptionPane.OK_OPTION) { 434 try { 435 activeModel.addRow(p.getImageryInfo()); 436 } catch (IllegalArgumentException ex) { 437 if (ex.getMessage() == null || ex.getMessage().isEmpty()) 438 throw ex; 439 else { 440 JOptionPane.showMessageDialog(Main.parent, 441 ex.getMessage(), tr("Error"), 442 JOptionPane.ERROR_MESSAGE); 443 } 444 } 445 } 446 } 447 } 448 449 private class RemoveEntryAction extends AbstractAction implements ListSelectionListener { 450 451 public RemoveEntryAction() { 452 putValue(NAME, tr("Remove")); 453 putValue(SHORT_DESCRIPTION, tr("Remove entry")); 454 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete")); 455 updateEnabledState(); 456 } 457 458 protected void updateEnabledState() { 459 setEnabled(activeTable.getSelectedRowCount() > 0); 460 } 461 462 @Override 463 public void valueChanged(ListSelectionEvent e) { 464 updateEnabledState(); 465 } 466 467 @Override 468 public void actionPerformed(ActionEvent e) { 469 Integer i; 470 while ((i = activeTable.getSelectedRow()) != -1) { 471 activeModel.removeRow(i); 472 } 473 } 474 } 475 476 private class ActivateAction extends AbstractAction implements ListSelectionListener { 477 public ActivateAction() { 478 putValue(NAME, tr("Activate")); 479 putValue(SHORT_DESCRIPTION, tr("copy selected defaults")); 480 putValue(SMALL_ICON, ImageProvider.get("preferences", "activate-down")); 481 } 482 483 protected void updateEnabledState() { 484 setEnabled(defaultTable.getSelectedRowCount() > 0); 485 } 486 487 @Override 488 public void valueChanged(ListSelectionEvent e) { 489 updateEnabledState(); 490 } 491 492 @Override 493 public void actionPerformed(ActionEvent e) { 494 int[] lines = defaultTable.getSelectedRows(); 495 if (lines.length == 0) { 496 JOptionPane.showMessageDialog( 497 gui, 498 tr("Please select at least one row to copy."), 499 tr("Information"), 500 JOptionPane.INFORMATION_MESSAGE); 501 return; 502 } 503 504 Set<String> acceptedEulas = new HashSet<String>(); 505 506 outer: for (int i = 0; i < lines.length; i++) { 507 ImageryInfo info = defaultModel.getRow(lines[i]); 508 509 // Check if an entry with exactly the same values already 510 // exists 511 for (int j = 0; j < activeModel.getRowCount(); j++) { 512 if (info.equalsBaseValues(activeModel.getRow(j))) { 513 // Select the already existing row so the user has 514 // some feedback in case an entry exists 515 activeTable.getSelectionModel().setSelectionInterval(j, j); 516 activeTable.scrollRectToVisible(activeTable.getCellRect(j, 0, true)); 517 continue outer; 518 } 519 } 520 521 String eulaURL = info.getEulaAcceptanceRequired(); 522 // If set and not already accepted, ask for EULA acceptance 523 if (eulaURL != null && !acceptedEulas.contains(eulaURL)) { 524 if (confirmEulaAcceptance(gui, eulaURL)) { 525 acceptedEulas.add(eulaURL); 526 } else { 527 continue outer; 528 } 529 } 530 531 activeModel.addRow(new ImageryInfo(info)); 532 int lastLine = activeModel.getRowCount() - 1; 533 activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine); 534 activeTable.scrollRectToVisible(activeTable.getCellRect(lastLine, 0, true)); 535 } 536 } 537 } 538 539 private class ReloadAction extends AbstractAction { 540 public ReloadAction() { 541 putValue(SHORT_DESCRIPTION, tr("reload defaults")); 542 putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh")); 543 } 544 545 public void actionPerformed(ActionEvent evt) { 546 layerInfo.loadDefaults(true); 547 defaultModel.fireTableDataChanged(); 548 } 549 } 550 551 /** 552 * The table model for imagery layer list 553 */ 554 public class ImageryLayerTableModel extends DefaultTableModel { 555 public ImageryLayerTableModel() { 556 setColumnIdentifiers(new String[] { tr("Menu Name"), tr("Imagery URL")}); 557 } 558 559 public ImageryInfo getRow(int row) { 560 return layerInfo.getLayers().get(row); 561 } 562 563 public void addRow(ImageryInfo i) { 564 layerInfo.add(i); 565 int p = getRowCount() - 1; 566 fireTableRowsInserted(p, p); 567 } 568 569 @Override 570 public void removeRow(int i) { 571 layerInfo.remove(getRow(i)); 572 fireTableRowsDeleted(i, i); 573 } 574 575 @Override 576 public int getRowCount() { 577 return layerInfo.getLayers().size(); 578 } 579 580 @Override 581 public Object getValueAt(int row, int column) { 582 ImageryInfo info = layerInfo.getLayers().get(row); 583 switch (column) { 584 case 0: 585 return info.getName(); 586 case 1: 587 return info.getExtendedUrl(); 588 default: 589 throw new ArrayIndexOutOfBoundsException(); 590 } 591 } 592 593 @Override 594 public void setValueAt(Object o, int row, int column) { 595 if (layerInfo.getLayers().size() <= row) return; 596 ImageryInfo info = layerInfo.getLayers().get(row); 597 switch (column) { 598 case 0: 599 info.setName((String) o); 600 break; 601 case 1: 602 info.setExtendedUrl((String)o); 603 break; 604 default: 605 throw new ArrayIndexOutOfBoundsException(); 606 } 607 } 608 609 @Override 610 public boolean isCellEditable(int row, int column) { 611 return true; 612 } 613 } 614 615 /** 616 * The table model for the default imagery layer list 617 */ 618 public class ImageryDefaultLayerTableModel extends DefaultTableModel { 619 public ImageryDefaultLayerTableModel() { 620 setColumnIdentifiers(new String[]{"", tr("Menu Name (Default)"), tr("Imagery URL (Default)")}); 621 } 622 623 public ImageryInfo getRow(int row) { 624 return layerInfo.getDefaultLayers().get(row); 625 } 626 627 @Override 628 public int getRowCount() { 629 return layerInfo.getDefaultLayers().size(); 630 } 631 632 @Override 633 public Object getValueAt(int row, int column) { 634 ImageryInfo info = layerInfo.getDefaultLayers().get(row); 635 switch (column) { 636 case 0: 637 return info.getCountryCode(); 638 case 1: 639 return info.getName(); 640 case 2: 641 return info.getExtendedUrl(); 642 } 643 return null; 644 } 645 646 @Override 647 public boolean isCellEditable(int row, int column) { 648 return false; 649 } 650 } 651 652 private boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) { 653 URL url = null; 654 try { 655 url = new URL(eulaUrl.replaceAll("\\{lang\\}", LanguageInfo.getWikiLanguagePrefix())); 656 JEditorPane htmlPane = null; 657 try { 658 htmlPane = new JEditorPane(url); 659 } catch (IOException e1) { 660 // give a second chance with a default Locale 'en' 661 try { 662 url = new URL(eulaUrl.replaceAll("\\{lang\\}", "")); 663 htmlPane = new JEditorPane(url); 664 } catch (IOException e2) { 665 JOptionPane.showMessageDialog(gui ,tr("EULA license URL not available: {0}", eulaUrl)); 666 return false; 667 } 668 } 669 Box box = Box.createVerticalBox(); 670 htmlPane.setEditable(false); 671 JScrollPane scrollPane = new JScrollPane(htmlPane); 672 scrollPane.setPreferredSize(new Dimension(400, 400)); 673 box.add(scrollPane); 674 int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"), JOptionPane.YES_NO_OPTION, 675 JOptionPane.WARNING_MESSAGE); 676 if (option == JOptionPane.YES_OPTION) 677 return true; 678 } catch (MalformedURLException e2) { 679 JOptionPane.showMessageDialog(gui ,tr("Malformed URL for the EULA licence: {0}", eulaUrl)); 680 } 681 return false; 682 } 683 } 684 685 static class OffsetBookmarksPanel extends JPanel { 686 List<OffsetBookmark> bookmarks = OffsetBookmark.allBookmarks; 687 OffsetsBookmarksModel model = new OffsetsBookmarksModel(); 688 689 public OffsetBookmarksPanel(final PreferenceTabbedPane gui) { 690 super(new GridBagLayout()); 691 final JTable list = new JTable(model) { 692 @Override 693 public String getToolTipText(MouseEvent e) { 694 java.awt.Point p = e.getPoint(); 695 return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString(); 696 } 697 }; 698 JScrollPane scroll = new JScrollPane(list); 699 add(scroll, GBC.eol().fill(GridBagConstraints.BOTH)); 700 scroll.setPreferredSize(new Dimension(200, 200)); 701 702 TableColumnModel mod = list.getColumnModel(); 703 mod.getColumn(0).setPreferredWidth(150); 704 mod.getColumn(1).setPreferredWidth(200); 705 mod.getColumn(2).setPreferredWidth(300); 706 mod.getColumn(3).setPreferredWidth(150); 707 mod.getColumn(4).setPreferredWidth(150); 708 709 JPanel buttonPanel = new JPanel(new FlowLayout()); 710 711 JButton add = new JButton(tr("Add")); 712 buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0)); 713 add.addActionListener(new ActionListener() { 714 @Override 715 public void actionPerformed(ActionEvent e) { 716 OffsetBookmark b = new OffsetBookmark(Main.getProjection().toCode(),"","",0,0); 717 model.addRow(b); 718 } 719 }); 720 721 JButton delete = new JButton(tr("Delete")); 722 buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0)); 723 delete.addActionListener(new ActionListener() { 724 @Override 725 public void actionPerformed(ActionEvent e) { 726 if (list.getSelectedRow() == -1) { 727 JOptionPane.showMessageDialog(gui, tr("Please select the row to delete.")); 728 } else { 729 Integer i; 730 while ((i = list.getSelectedRow()) != -1) { 731 model.removeRow(i); 732 } 733 } 734 } 735 }); 736 737 add(buttonPanel,GBC.eol()); 738 } 739 740 /** 741 * The table model for imagery offsets list 742 */ 743 class OffsetsBookmarksModel extends DefaultTableModel { 744 public OffsetsBookmarksModel() { 745 setColumnIdentifiers(new String[] { tr("Projection"), tr("Layer"), tr("Name"), tr("Easting"), tr("Northing"),}); 746 } 747 748 public OffsetBookmark getRow(int row) { 749 return bookmarks.get(row); 750 } 751 752 public void addRow(OffsetBookmark i) { 753 bookmarks.add(i); 754 int p = getRowCount() - 1; 755 fireTableRowsInserted(p, p); 756 } 757 758 @Override 759 public void removeRow(int i) { 760 bookmarks.remove(getRow(i)); 761 fireTableRowsDeleted(i, i); 762 } 763 764 @Override 765 public int getRowCount() { 766 return bookmarks.size(); 767 } 768 769 @Override 770 public Object getValueAt(int row, int column) { 771 OffsetBookmark info = bookmarks.get(row); 772 switch (column) { 773 case 0: 774 if (info.projectionCode == null) return ""; 775 return info.projectionCode.toString(); 776 case 1: 777 return info.layerName; 778 case 2: 779 return info.name; 780 case 3: 781 return info.dx; 782 case 4: 783 return info.dy; 784 default: 785 throw new ArrayIndexOutOfBoundsException(); 786 } 787 } 788 789 @Override 790 public void setValueAt(Object o, int row, int column) { 791 OffsetBookmark info = bookmarks.get(row); 792 switch (column) { 793 case 1: 794 info.layerName = o.toString(); 795 break; 796 case 2: 797 info.name = o.toString(); 798 break; 799 case 3: 800 info.dx = Double.parseDouble((String) o); 801 break; 802 case 4: 803 info.dy = Double.parseDouble((String) o); 804 break; 805 default: 806 throw new ArrayIndexOutOfBoundsException(); 807 } 808 } 809 810 @Override 811 public boolean isCellEditable(int row, int column) { 812 return column >= 1; 813 } 814 } 815 } 816 817 public static void initialize() { 818 ImageryLayerInfo.instance.clear(); 819 ImageryLayerInfo.instance.loadDefaults(false); 820 ImageryLayerInfo.instance.load(); 821 OffsetBookmark.loadBookmarks(); 822 Main.main.menu.imageryMenu.refreshImageryMenu(); 823 Main.main.menu.imageryMenu.refreshOffsetMenu(); 824 } 825 }