Ticket #13001: patch-main-add-map-content.patch
File patch-main-add-map-content.patch, 43.3 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/Main.java
diff --git a/src/org/openstreetmap/josm/Main.java b/src/org/openstreetmap/josm/Main.java index 99dd688..81fc031 100644
a b import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask; 61 61 import org.openstreetmap.josm.actions.downloadtasks.DownloadTask; 62 62 import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler; 63 63 import org.openstreetmap.josm.actions.mapmode.DrawAction; 64 import org.openstreetmap.josm.actions.mapmode.MapMode;65 64 import org.openstreetmap.josm.actions.search.SearchAction; 66 65 import org.openstreetmap.josm.data.Bounds; 67 66 import org.openstreetmap.josm.data.Preferences; … … import org.openstreetmap.josm.data.projection.ProjectionChangeListener; 79 78 import org.openstreetmap.josm.data.validation.OsmValidator; 80 79 import org.openstreetmap.josm.gui.GettingStarted; 81 80 import org.openstreetmap.josm.gui.MainApplication.Option; 81 import org.openstreetmap.josm.gui.MainFrame; 82 82 import org.openstreetmap.josm.gui.MainMenu; 83 import org.openstreetmap.josm.gui.MainPanel; 83 84 import org.openstreetmap.josm.gui.MapFrame; 84 85 import org.openstreetmap.josm.gui.MapFrameListener; 85 import org.openstreetmap.josm.gui.MapView;86 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;87 86 import org.openstreetmap.josm.gui.help.HelpUtil; 88 87 import org.openstreetmap.josm.gui.io.SaveLayersDialog; 89 88 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; 90 89 import org.openstreetmap.josm.gui.layer.Layer; 91 import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;92 import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;93 import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;94 import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;95 90 import org.openstreetmap.josm.gui.layer.MainLayerManager; 96 91 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 97 92 import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener; … … public abstract class Main { 194 189 * The MapFrame. Use {@link Main#setMapFrame} to set or clear it. 195 190 * <p> 196 191 * There should be no need to access this to access any map data. Use {@link #layerManager} instead. 192 * 193 * @see MainPanel 197 194 */ 198 195 public static MapFrame map; 199 196 … … public abstract class Main { 235 232 236 233 /** 237 234 * The MOTD Layer. 235 * @deprecated Do not access this. It will be removed soon. You should not need to access the GettingStarted panel. 238 236 */ 239 public final GettingStarted gettingStarted = new GettingStarted(); 240 241 private static final Collection<MapFrameListener> mapFrameListeners = new ArrayList<>(); 237 @Deprecated 238 public final GettingStarted gettingStarted = mainPanel.getGettingStarted(); 242 239 243 240 protected static final Map<String, Throwable> NETWORK_ERRORS = new HashMap<>(); 244 241 … … public abstract class Main { 253 250 */ 254 251 public static int logLevel = 3; 255 252 253 /** 254 * The real main panel. Thies field may be removed any time and made private to {@link MainFrame} 255 * @see #panel 256 */ 257 protected static final MainPanel mainPanel = new MainPanel(getLayerManager()); 258 256 259 private static void rememberWarnErrorMsg(String msg) { 257 260 // Only remember first line of message 258 261 int idx = msg.indexOf('\n'); … … public abstract class Main { 509 512 510 513 /** 511 514 * Set or clear (if passed <code>null</code>) the map. 515 * <p> 516 * To be removed any time 512 517 * @param map The map to set {@link Main#map} to. Can be null. 518 * @deprecated This is done automatically by {@link MainPanel} 513 519 */ 520 @Deprecated 514 521 public final void setMapFrame(final MapFrame map) { 515 MapFrame old = Main.map; 516 panel.setVisible(false); 517 panel.removeAll(); 518 if (map != null) { 519 map.fillPanel(panel); 520 } else { 521 old.destroy(); 522 panel.add(gettingStarted, BorderLayout.CENTER); 523 } 524 panel.setVisible(true); 525 redoUndoListener.commandChanged(0, 0); 526 527 Main.map = map; 528 529 // Notify map frame listeners, mostly plugins. 530 if ((map == null) == (old == null)) { 531 Main.warn("Replacing the map frame. This is not expected by some plugins and should not happen."); 532 } 533 for (MapFrameListener listener : mapFrameListeners) { 534 MapView.fireDeprecatedListenerOnAdd = true; 535 listener.mapFrameInitialized(old, map); 536 MapView.fireDeprecatedListenerOnAdd = false; 537 } 538 if (map == null && currentProgressMonitor != null) { 539 currentProgressMonitor.showForegroundDialog(); 540 } 522 Main.warn("setMapFrame call was ignored."); 541 523 } 542 524 543 525 /** 544 526 * Remove the specified layer from the map. If it is the last layer, 545 527 * remove the map as well. 528 * <p> 529 * To be removed end of 2016 546 530 * @param layer The layer to remove 531 * @deprecated You can remove the layer using {@link #getLayerManager()} 547 532 */ 533 @Deprecated 548 534 public final synchronized void removeLayer(final Layer layer) { 549 535 if (map != null) { 550 536 getLayerManager().removeLayer(layer); 551 if (isDisplayingMapView() && getLayerManager().getLayers().isEmpty()) {552 setMapFrame(null);553 }554 537 } 555 538 } 556 539 … … public abstract class Main { 574 557 */ 575 558 public Main() { 576 559 main = this; 577 getLayerManager().addLayerChangeListener(new LayerChangeListener() {560 mainPanel.addAndFireMapFrameListener(new MapFrameListener() { 578 561 @Override 579 public void layerAdded(LayerAddEvent e) { 580 Layer layer = e.getAddedLayer(); 581 if (map == null) { 582 Main.main.createMapFrame(layer, null); 583 Main.map.setVisible(true); 584 } 585 ProjectionBounds viewProjectionBounds = layer.getViewProjectionBounds(); 586 if (viewProjectionBounds != null) { 587 Main.map.mapView.scheduleZoomTo(new ViewportData(viewProjectionBounds)); 588 } 562 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 563 redoUndoListener.commandChanged(0, 0); 589 564 } 590 591 @Override592 public void layerRemoving(LayerRemoveEvent e) {593 // empty594 }595 596 @Override597 public void layerOrderChanged(LayerOrderChangeEvent e) {598 //empty599 }600 601 565 }); 602 566 } 603 567 … … public abstract class Main { 797 761 * Add a new layer to the map. 798 762 * 799 763 * If no map exists, create one. 764 * <p> 765 * To be removed end of 2016 800 766 * 801 767 * @param layer the layer 802 768 * 803 769 * @see #addLayer(Layer, ProjectionBounds) 804 770 * @see #addLayer(Layer, ViewportData) 771 * @deprecated You can add the layer to the layer manager: {@link #getLayerManager()} 805 772 */ 773 @Deprecated 806 774 public final void addLayer(final Layer layer) { 807 addLayer(layer, layer.getViewProjectionBounds());775 addLayer(layer, (ViewportData) null); 808 776 } 809 777 810 778 /** … … public abstract class Main { 830 798 */ 831 799 public final void addLayer(Layer layer, ViewportData viewport) { 832 800 getLayerManager().addLayer(layer); 833 if (viewport != null) { 801 if (viewport != null && Main.map.mapView != null) { 802 // MapView may be null in headless mode here. 834 803 Main.map.mapView.scheduleZoomTo(viewport); 835 804 } 836 805 } 837 806 838 807 /** 839 808 * Creates the map frame. Call only in EDT Thread. 809 * <p> 810 * To be removed any time 840 811 * @param firstLayer The first layer that was added. 841 812 * @param viewportData The initial viewport. Can be <code>null</code> to be automatically computed. 813 * @deprecated Not supported. MainPanel does this automatically. 842 814 */ 815 @Deprecated 843 816 public synchronized void createMapFrame(Layer firstLayer, ViewportData viewportData) { 844 817 GuiHelper.assertCallFromEdt(); 845 MapFrame mapFrame = new MapFrame(contentPanePrivate, viewportData); 846 setMapFrame(mapFrame); 847 if (firstLayer != null) { 848 mapFrame.selectMapMode((MapMode) mapFrame.getDefaultButtonAction(), firstLayer); 849 } 850 mapFrame.initializeDialogsPane(); 851 // bootstrapping problem: make sure the layer list dialog is going to 852 // listen to change events of the very first layer 853 // 854 if (firstLayer != null) { 855 firstLayer.addPropertyChangeListener(LayerListDialog.getInstance().getModel()); 856 } 818 Main.error("createMapFrame() not supported any more."); 857 819 } 858 820 859 821 /** 860 822 * Replies <code>true</code> if there is an edit layer 823 * <p> 824 * To be removed end of 2016 861 825 * 862 826 * @return <code>true</code> if there is an edit layer 827 * @deprecated You can get the edit layer using the layer manager and then check if it is not null: {@link #getLayerManager()} 863 828 */ 829 @Deprecated 864 830 public boolean hasEditLayer() { 865 831 if (getEditLayer() == null) return false; 866 832 return true; … … public abstract class Main { 868 834 869 835 /** 870 836 * Replies the current edit layer 837 * <p> 838 * To be removed end of 2016 871 839 * 872 840 * @return the current edit layer. <code>null</code>, if no current edit layer exists 841 * @deprecated You can get the edit layer using the layer manager: {@link #getLayerManager()} 873 842 */ 843 @Deprecated 874 844 public OsmDataLayer getEditLayer() { 875 if (!isDisplayingMapView()) return null;876 845 return getLayerManager().getEditLayer(); 877 846 } 878 847 879 848 /** 880 849 * Replies the current data set. 850 * <p> 851 * To be removed end of 2016 881 852 * 882 853 * @return the current data set. <code>null</code>, if no current data set exists 854 * @deprecated You can get the data set using the layer manager: {@link #getLayerManager()} 883 855 */ 856 @Deprecated 884 857 public DataSet getCurrentDataSet() { 885 if (!hasEditLayer()) return null; 886 return getEditLayer().data; 858 return getLayerManager().getEditDataSet(); 887 859 } 888 860 889 861 /** … … public abstract class Main { 907 879 908 880 /** 909 881 * Returns the currently active layer 882 * <p> 883 * To be removed end of 2016 910 884 * 911 885 * @return the currently active layer. <code>null</code>, if currently no active layer exists 886 * @deprecated You can get the layer using the layer manager: {@link #getLayerManager()} 912 887 */ 888 @Deprecated 913 889 public Layer getActiveLayer() { 914 if (!isDisplayingMapView()) return null;915 890 return getLayerManager().getActiveLayer(); 916 891 } 917 892 … … public abstract class Main { 976 951 /** 977 952 * Global panel. 978 953 */ 979 public static final JPanel panel = new JPanel(new BorderLayout());954 public static final JPanel panel = mainPanel; 980 955 981 956 private final CommandQueueListener redoUndoListener = new CommandQueueListener() { 982 957 @Override … … public abstract class Main { 1162 1137 map.rememberToggleDialogWidth(); 1163 1138 } 1164 1139 // Remove all layers because somebody may rely on layerRemoved events (like AutosaveTask) 1165 if (Main.isDisplayingMapView()) { 1166 Collection<Layer> layers = new ArrayList<>(getLayerManager().getLayers()); 1167 for (Layer l: layers) { 1168 Main.main.removeLayer(l); 1169 } 1170 } 1140 getLayerManager().resetState(); 1171 1141 try { 1172 1142 pref.saveDefaults(); 1173 1143 } catch (IOException ex) { … … public abstract class Main { 1653 1623 * @return {@code true} if the listeners collection changed as a result of the call 1654 1624 */ 1655 1625 public static boolean addMapFrameListener(MapFrameListener listener, boolean fireWhenMapViewPresent) { 1656 boolean changed = listener != null && mapFrameListeners.add(listener); 1657 if (fireWhenMapViewPresent && changed && map != null) { 1658 listener.mapFrameInitialized(null, map); 1626 if (fireWhenMapViewPresent) { 1627 return mainPanel.addAndFireMapFrameListener(listener); 1628 } else { 1629 return mainPanel.addMapFrameListener(listener); 1659 1630 } 1660 return changed;1661 1631 } 1662 1632 1663 1633 /** … … public abstract class Main { 1667 1637 * @since 5957 1668 1638 */ 1669 1639 public static boolean addMapFrameListener(MapFrameListener listener) { 1670 return addMapFrameListener(listener, false);1640 return mainPanel.addMapFrameListener(listener); 1671 1641 } 1672 1642 1673 1643 /** … … public abstract class Main { 1677 1647 * @since 5957 1678 1648 */ 1679 1649 public static boolean removeMapFrameListener(MapFrameListener listener) { 1680 return listener != null && mapFrameListeners.remove(listener);1650 return mainPanel.removeMapFrameListener(listener); 1681 1651 } 1682 1652 1683 1653 /** -
src/org/openstreetmap/josm/actions/SessionLoadAction.java
diff --git a/src/org/openstreetmap/josm/actions/SessionLoadAction.java b/src/org/openstreetmap/josm/actions/SessionLoadAction.java index cd390f2..6d2b2ee 100644
a b public class SessionLoadAction extends DiskAccessAction { 124 124 125 125 private void addLayers() { 126 126 if (layers != null && !layers.isEmpty()) { 127 Layer firstLayer = layers.get(0);128 127 boolean noMap = Main.map == null; 129 if (noMap) {130 Main.main.createMapFrame(firstLayer, viewport);131 }132 128 for (Layer l : layers) { 133 129 if (canceled) 134 130 return; 135 Main. main.addLayer(l, (ViewportData) null);131 Main.getLayerManager().addLayer(l); 136 132 } 137 133 if (active != null) { 138 134 Main.getLayerManager().setActiveLayer(active); 139 135 } 140 136 if (noMap) { 141 Main.map. setVisible(true);137 Main.map.mapView.scheduleZoomTo(viewport); 142 138 } 143 139 } 144 140 } -
src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
diff --git a/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java b/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java index 024b189..33d467a 100644
a b import java.util.regex.Pattern; 12 12 import org.openstreetmap.josm.Main; 13 13 import org.openstreetmap.josm.data.Bounds; 14 14 import org.openstreetmap.josm.data.Bounds.ParseMethod; 15 import org.openstreetmap.josm.data.ViewportData; 15 16 import org.openstreetmap.josm.data.gpx.GpxData; 16 17 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 17 18 import org.openstreetmap.josm.gui.layer.GpxLayer; … … public class DownloadGpsTask extends AbstractDownloadTask<GpxData> { 140 141 private <L extends Layer> L addOrMergeLayer(L layer, L mergeLayer) { 141 142 if (layer == null) return null; 142 143 if (newLayer || mergeLayer == null) { 143 if (Main.main != null) { 144 Main.main.addLayer(layer); 145 } 144 Main.getLayerManager().addLayer(layer); 146 145 return layer; 147 146 } else { 148 147 mergeLayer.mergeFrom(layer); 148 mergeLayer.invalidate(); 149 149 if (Main.map != null) { 150 Main.map. repaint();150 Main.map.mapView.scheduleZoomTo(new ViewportData(layer.getViewProjectionBounds())); 151 151 } 152 152 return mergeLayer; 153 153 } -
src/org/openstreetmap/josm/gui/MainApplication.java
diff --git a/src/org/openstreetmap/josm/gui/MainApplication.java b/src/org/openstreetmap/josm/gui/MainApplication.java index 5727fa5..58ebfc2 100644
a b public class MainApplication extends Main { 316 316 317 317 initApplicationPreferences(); 318 318 319 // Can only be called after preferences are initialized. 320 // We can move this to MainPanel constructor as soon as noone depends on Main#panel any more. 321 GuiHelper.runInEDTAndWait(new Runnable() { 322 @Override 323 public void run() { 324 mainPanel.updateContent(); 325 } 326 }); 327 319 328 Policy.setPolicy(new Policy() { 320 329 // Permissions for plug-ins loaded when josm is started via webstart 321 330 private PermissionCollection pc; … … public class MainApplication extends Main { 398 407 WindowGeometry geometry = WindowGeometry.mainWindow("gui.geometry", 399 408 args.containsKey(Option.GEOMETRY) ? args.get(Option.GEOMETRY).iterator().next() : null, 400 409 !args.containsKey(Option.NO_MAXIMIZE) && Main.pref.getBoolean("gui.maximized", false)); 401 final MainFrame mainFrame = new MainFrame(contentPanePrivate, geometry);410 final MainFrame mainFrame = new MainFrame(contentPanePrivate, mainPanel, geometry); 402 411 Main.parent = mainFrame; 403 412 404 413 if (args.containsKey(Option.LOAD_PREFERENCES)) { -
src/org/openstreetmap/josm/gui/MainFrame.java
diff --git a/src/org/openstreetmap/josm/gui/MainFrame.java b/src/org/openstreetmap/josm/gui/MainFrame.java index 75ac489..7b5a654 100644
a b import org.openstreetmap.josm.tools.WindowGeometry; 39 39 * @since 10340 40 40 */ 41 41 public class MainFrame extends JFrame { 42 protected transient WindowGeometry geometry;43 protected int windowState = JFrame.NORMAL;44 private MainMenu menu;45 46 42 private final transient LayerStateChangeListener updateTitleOnLayerStateChange = new LayerStateChangeListener() { 47 43 @Override 48 44 public void uploadDiscouragedChanged(OsmDataLayer layer, boolean newValue) { … … public class MainFrame extends JFrame { 51 47 }; 52 48 53 49 private final transient PropertyChangeListener updateTitleOnSaveChange = new PropertyChangeListener() { 54 55 50 @Override 56 51 public void propertyChange(PropertyChangeEvent evt) { 57 52 if (evt.getPropertyName().equals(OsmDataLayer.REQUIRES_SAVE_TO_DISK_PROP) … … public class MainFrame extends JFrame { 62 57 } 63 58 }; 64 59 60 protected transient WindowGeometry geometry; 61 protected int windowState = JFrame.NORMAL; 62 private MainMenu menu; 63 65 64 /** 66 65 * Create a new main window. 67 66 */ 68 67 public MainFrame() { 69 this(new JPanel(), new WindowGeometry(new Rectangle(10, 10, 500, 500)));68 this(new JPanel(), new MainPanel(Main.getLayerManager()), new WindowGeometry(new Rectangle(10, 10, 500, 500))); 70 69 } 71 70 72 71 /** 73 * Create a new main window. 72 * Create a new main window. The parameters will be removed in the future. 74 73 * @param contentPanePrivate The content 74 * @param mainPanel The main panel. 75 75 * @param geometry The inital geometry to use. 76 76 */ 77 public MainFrame(Container contentPanePrivate, WindowGeometry geometry) {77 public MainFrame(Container contentPanePrivate, MainPanel mainPanel, WindowGeometry geometry) { 78 78 super(); 79 79 this.geometry = geometry; 80 80 setContentPane(contentPanePrivate); … … public class MainFrame extends JFrame { 119 119 refreshTitle(); 120 120 121 121 getContentPane().add(Main.panel, BorderLayout.CENTER); 122 Main.panel.add(Main.main.gettingStarted, BorderLayout.CENTER);123 122 menu.initialize(); 124 123 } 125 124 -
new file src/org/openstreetmap/josm/gui/MainPanel.java
diff --git a/src/org/openstreetmap/josm/gui/MainPanel.java b/src/org/openstreetmap/josm/gui/MainPanel.java new file mode 100644 index 0000000..c81f3e4
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui; 3 4 import java.awt.BorderLayout; 5 import java.util.List; 6 import java.util.concurrent.CopyOnWriteArrayList; 7 8 import javax.swing.JPanel; 9 import javax.swing.SwingUtilities; 10 11 import org.openstreetmap.josm.Main; 12 import org.openstreetmap.josm.actions.mapmode.MapMode; 13 import org.openstreetmap.josm.gui.layer.Layer; 14 import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent; 15 import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener; 16 import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent; 17 import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; 18 import org.openstreetmap.josm.gui.layer.MainLayerManager; 19 import org.openstreetmap.josm.gui.util.GuiHelper; 20 21 /** 22 * This is the content panel inside the {@link MainFrame}. It displays the content the user is working with. 23 * <p> 24 * If there is no active layer, there is no content displayed. As soon as there are active layers, the {@link MapFrame} is displayed. 25 * 26 * @author Michael Zangl 27 * @since xxx 28 */ 29 public class MainPanel extends JPanel { 30 private MapFrame map; 31 // Needs to be lazy because we need to wait for preferences to set up. 32 private GettingStarted gettingStarted; 33 private final CopyOnWriteArrayList<MapFrameListener> mapFrameListeners = new CopyOnWriteArrayList<>(); 34 private final transient MainLayerManager layerManager; 35 36 /** 37 * Create a new main panel 38 * @param layerManager The layer manager to use to display the content. 39 */ 40 public MainPanel(MainLayerManager layerManager) { 41 super(new BorderLayout()); 42 this.layerManager = layerManager; 43 reAddListeners(); 44 } 45 46 /** 47 * Update the content of this {@link MainFrame} to either display the map or display the welcome screen. 48 */ 49 protected void updateContent() { 50 GuiHelper.assertCallFromEdt(); 51 MapFrame old = map; 52 boolean showMap = !layerManager.getLayers().isEmpty(); 53 if (old != null && showMap) { 54 // no state change 55 return; 56 } 57 58 // remove old content 59 setVisible(false); 60 removeAll(); 61 if (old != null) { 62 old.destroy(); 63 } 64 65 // create new content 66 if (showMap) { 67 map = createNewMapFrame(); 68 } else { 69 map = null; 70 Main.map = map; 71 add(getGettingStarted(), BorderLayout.CENTER); 72 } 73 setVisible(true); 74 75 if (old == null && !showMap) { 76 // listeners may not be able to handle this... 77 return; 78 } 79 80 // Notify map frame listeners, mostly plugins. 81 for (MapFrameListener listener : mapFrameListeners) { 82 MapView.fireDeprecatedListenerOnAdd = true; 83 listener.mapFrameInitialized(old, map); 84 MapView.fireDeprecatedListenerOnAdd = false; 85 } 86 if (map == null && Main.currentProgressMonitor != null) { 87 Main.currentProgressMonitor.showForegroundDialog(); 88 } 89 } 90 91 private MapFrame createNewMapFrame() { 92 MapFrame mapFrame = new MapFrame(null, null); 93 // Required by many components. 94 Main.map = mapFrame; 95 96 mapFrame.fillPanel(this); 97 98 //TODO: Move this to some better place 99 List<Layer> layers = Main.getLayerManager().getLayers(); 100 if (!layers.isEmpty()) { 101 mapFrame.selectMapMode((MapMode) mapFrame.getDefaultButtonAction(), layers.get(0)); 102 } 103 mapFrame.initializeDialogsPane(); 104 mapFrame.setVisible(true); 105 return mapFrame; 106 } 107 108 /** 109 * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes. 110 * <p> 111 * It will fire an initial mapFrameInitialized event 112 * when the MapFrame is present. Otherwise will only fire when the MapFrame is created 113 * or destroyed. 114 * @param listener The MapFrameListener 115 * @return {@code true} if the listeners collection changed as a result of the call. 116 * @since xxx 117 */ 118 public boolean addAndFireMapFrameListener(MapFrameListener listener) { 119 boolean changed = addMapFrameListener(listener); 120 if (changed && map != null) { 121 listener.mapFrameInitialized(null, map); 122 } 123 return changed; 124 } 125 126 /** 127 * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes 128 * @param listener The MapFrameListener 129 * @return {@code true} if the listeners collection changed as a result of the call 130 * @since xxx 131 */ 132 public boolean addMapFrameListener(MapFrameListener listener) { 133 return listener != null && mapFrameListeners.add(listener); 134 } 135 136 /** 137 * Unregisters the given {@code MapFrameListener} from MapFrame changes 138 * @param listener The MapFrameListener 139 * @return {@code true} if the listeners collection changed as a result of the call 140 * @since xxx 141 */ 142 public boolean removeMapFrameListener(MapFrameListener listener) { 143 return listener != null && mapFrameListeners.remove(listener); 144 } 145 146 /** 147 * Gets the {@link GettingStarted} panel. 148 * @return The panel. 149 */ 150 public GettingStarted getGettingStarted() { 151 if (gettingStarted == null) { 152 gettingStarted = new GettingStarted(); 153 } 154 return gettingStarted; 155 } 156 157 /** 158 * Re-adds the layer listeners. Never call this in production, only needed for testing. 159 */ 160 public void reAddListeners() { 161 layerManager.addLayerChangeListener(new LayerChangeListener() { 162 @Override 163 public void layerAdded(LayerAddEvent e) { 164 updateContent(); 165 } 166 167 @Override 168 public void layerRemoving(final LayerRemoveEvent e) { 169 // Delay main.map removal until after all listeners are finished. 170 // Some components rely on this and e.g. get the MapView that way. 171 SwingUtilities.invokeLater(new Runnable() { 172 @Override 173 public void run() { 174 updateContent(); 175 } 176 }); 177 } 178 179 @Override 180 public void layerOrderChanged(LayerOrderChangeEvent e) { 181 // ignored 182 } 183 }); 184 } 185 } -
src/org/openstreetmap/josm/gui/MapFrame.java
diff --git a/src/org/openstreetmap/josm/gui/MapFrame.java b/src/org/openstreetmap/josm/gui/MapFrame.java index b0a4335..e3ab5cc 100644
a b public class MapFrame extends JPanel implements Destroyable, ActiveLayerChangeLi 187 187 188 188 /** 189 189 * Constructs a new {@code MapFrame}. 190 * @param contentPane The content pane used to register shortcuts in its 191 * {@link javax.swing.InputMap} and {@link javax.swing.ActionMap} 190 * @param contentPane Ignored. Main content pane is used. 192 191 * @param viewportData the initial viewport of the map. Can be null, then 193 192 * the viewport is derived from the layer data. 194 193 */ -
src/org/openstreetmap/josm/gui/MapMover.java
diff --git a/src/org/openstreetmap/josm/gui/MapMover.java b/src/org/openstreetmap/josm/gui/MapMover.java index 377580f..d745f1b 100644
a b import java.awt.event.KeyEvent; 10 10 import java.awt.event.MouseAdapter; 11 11 import java.awt.event.MouseEvent; 12 12 import java.awt.event.MouseWheelEvent; 13 import java.util.ArrayList; 13 14 14 15 import javax.swing.AbstractAction; 15 import javax.swing.ActionMap;16 import javax.swing.InputMap;17 import javax.swing.JComponent;18 16 import javax.swing.JPanel; 19 import javax.swing.KeyStroke;20 17 21 18 import org.openstreetmap.gui.jmapviewer.JMapViewer; 22 19 import org.openstreetmap.josm.Main; … … import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener; 26 23 import org.openstreetmap.josm.data.coor.EastNorth; 27 24 import org.openstreetmap.josm.data.preferences.BooleanProperty; 28 25 import org.openstreetmap.josm.tools.Destroyable; 26 import org.openstreetmap.josm.tools.Pair; 29 27 import org.openstreetmap.josm.tools.Shortcut; 30 28 31 29 /** … … public class MapMover extends MouseAdapter implements Destroyable { 63 61 private final String action; 64 62 65 63 ZoomerAction(String action) { 64 this(action, "MapMover.Zoomer." + action); 65 } 66 67 public ZoomerAction(String action, String name) { 66 68 this.action = action; 69 putValue(NAME, name); 67 70 } 68 71 69 72 @Override … … public class MapMover extends MouseAdapter implements Destroyable { 106 109 * The map to move around. 107 110 */ 108 111 private final NavigatableComponent nc; 109 private final JPanel contentPane;110 112 111 113 private boolean movementInPlace; 112 114 115 private final ArrayList<Pair<ZoomerAction, Shortcut>> registeredShortcuts = new ArrayList<>(); 116 113 117 /** 114 118 * Constructs a new {@code MapMover}. 115 119 * @param navComp the navigatable component 116 * @param contentPane the content pane120 * @param contentPane Ignored. The main action map is used. 117 121 */ 118 122 public MapMover(NavigatableComponent navComp, JPanel contentPane) { 119 123 this.nc = navComp; 120 this.contentPane = contentPane;121 124 nc.addMouseListener(this); 122 125 nc.addMouseMotionListener(this); 123 126 nc.addMouseWheelListener(this); 124 127 125 if (contentPane != null) { 126 // CHECKSTYLE.OFF: LineLength 127 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 128 Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.CTRL).getKeyStroke(), 129 "MapMover.Zoomer.right"); 130 contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right")); 131 132 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 133 Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.CTRL).getKeyStroke(), 134 "MapMover.Zoomer.left"); 135 contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left")); 136 137 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 138 Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.CTRL).getKeyStroke(), 139 "MapMover.Zoomer.up"); 140 contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up")); 141 142 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 143 Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.CTRL).getKeyStroke(), 144 "MapMover.Zoomer.down"); 145 contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down")); 146 // CHECKSTYLE.ON: LineLength 147 148 // see #10592 - Disable these alternate shortcuts on OS X because of conflict with system shortcut 149 if (!Main.isPlatformOsx()) { 150 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 151 Shortcut.registerShortcut("view:zoominalternate", 152 tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.CTRL).getKeyStroke(), 153 "MapMover.Zoomer.in"); 154 contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(",")); 155 156 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( 157 Shortcut.registerShortcut("view:zoomoutalternate", 158 tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.CTRL).getKeyStroke(), 159 "MapMover.Zoomer.out"); 160 contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction(".")); 161 } 128 registerActionShortcut(new ZoomerAction("right"), 129 Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.CTRL)); 130 131 registerActionShortcut(new ZoomerAction("left"), 132 Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.CTRL)); 133 134 registerActionShortcut(new ZoomerAction("up"), 135 Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.CTRL)); 136 registerActionShortcut(new ZoomerAction("down"), 137 Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.CTRL)); 138 139 // see #10592 - Disable these alternate shortcuts on OS X because of conflict with system shortcut 140 if (!Main.isPlatformOsx()) { 141 registerActionShortcut(new ZoomerAction(",", "MapMover.Zoomer.in"), 142 Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.CTRL)); 143 144 registerActionShortcut(new ZoomerAction(".", "MapMover.Zoomer.out"), 145 Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.CTRL)); 162 146 } 163 147 } 164 148 149 private void registerActionShortcut(ZoomerAction action, Shortcut shortcut) { 150 Main.registerActionShortcut(action, shortcut); 151 registeredShortcuts.add(new Pair<>(action, shortcut)); 152 } 153 165 154 /** 166 155 * If the right (and only the right) mouse button is pressed, move the map. 167 156 */ … … public class MapMover extends MouseAdapter implements Destroyable { 269 258 270 259 @Override 271 260 public void destroy() { 272 if (this.contentPane != null) { 273 InputMap inputMap = contentPane.getInputMap(); 274 KeyStroke[] inputKeys = inputMap.keys(); 275 if (inputKeys != null) { 276 for (KeyStroke key : inputKeys) { 277 Object binding = inputMap.get(key); 278 if (binding instanceof String && ((String) binding).startsWith("MapMover.")) { 279 inputMap.remove(key); 280 } 281 } 282 } 283 ActionMap actionMap = contentPane.getActionMap(); 284 Object[] actionsKeys = actionMap.keys(); 285 if (actionsKeys != null) { 286 for (Object key : actionsKeys) { 287 if (key instanceof String && ((String) key).startsWith("MapMover.")) { 288 actionMap.remove(key); 289 } 290 } 291 } 261 for (Pair<ZoomerAction, Shortcut> shortcut : registeredShortcuts) { 262 Main.unregisterActionShortcut(shortcut.a, shortcut.b); 292 263 } 293 264 } 294 265 } -
src/org/openstreetmap/josm/gui/MapView.java
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java index 1415463..03166a0 100644
a b import java.util.Set; 31 31 import java.util.concurrent.CopyOnWriteArrayList; 32 32 33 33 import javax.swing.AbstractButton; 34 import javax.swing.ActionMap;35 import javax.swing.InputMap;36 34 import javax.swing.JComponent; 37 35 import javax.swing.JPanel; 38 36 … … import org.openstreetmap.josm.actions.mapmode.MapMode; 41 39 import org.openstreetmap.josm.data.Bounds; 42 40 import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent; 43 41 import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener; 42 import org.openstreetmap.josm.data.ProjectionBounds; 44 43 import org.openstreetmap.josm.data.SelectionChangedListener; 45 44 import org.openstreetmap.josm.data.ViewportData; 46 45 import org.openstreetmap.josm.data.coor.EastNorth; … … LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener { 494 493 /** 495 494 * Constructs a new {@code MapView}. 496 495 * @param layerManager The layers to display. 497 * @param contentPane The content pane used to register shortcuts in its 498 * {@link InputMap} and {@link ActionMap} 496 * @param contentPane Ignored. Main content pane is used. 499 497 * @param viewportData the initial viewport of the map. Can be null, then 500 498 * the viewport is derived from the layer data. 501 499 * @since 10279 … … LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener { 599 597 playHeadMarker = PlayHeadMarker.create(); 600 598 } 601 599 600 ProjectionBounds viewProjectionBounds = layer.getViewProjectionBounds(); 601 if (viewProjectionBounds != null) { 602 scheduleZoomTo(new ViewportData(viewProjectionBounds)); 603 } 604 602 605 layer.addPropertyChangeListener(this); 603 606 Main.addProjectionChangeListener(layer); 604 607 invalidatedListener.addTo(layer); -
src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
diff --git a/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java index f2ef962..c7b9ade 100644
a b public class LayerListDialog extends ToggleDialog { 330 330 @Override 331 331 public void showNotify() { 332 332 layerManager.addActiveLayerChangeListener(activateLayerAction); 333 layerManager.addLayerChangeListener(model );333 layerManager.addLayerChangeListener(model, true); 334 334 layerManager.addAndFireActiveLayerChangeListener(model); 335 335 model.populate(); 336 336 } 337 337 338 338 @Override 339 339 public void hideNotify() { 340 layerManager.removeLayerChangeListener(model );340 layerManager.removeLayerChangeListener(model, true); 341 341 layerManager.removeActiveLayerChangeListener(model); 342 342 layerManager.removeActiveLayerChangeListener(activateLayerAction); 343 343 } -
src/org/openstreetmap/josm/gui/layer/LayerManager.java
diff --git a/src/org/openstreetmap/josm/gui/layer/LayerManager.java b/src/org/openstreetmap/josm/gui/layer/LayerManager.java index 16fbfd4..4484702 100644
a b public class LayerManager { 89 89 */ 90 90 public static class LayerRemoveEvent extends LayerManagerEvent { 91 91 private final Layer removedLayer; 92 private final boolean lastLayer; 92 93 93 94 LayerRemoveEvent(LayerManager source, Layer removedLayer) { 94 95 super(source); 95 96 this.removedLayer = removedLayer; 97 this.lastLayer = source.getLayers().size() == 1; 96 98 } 97 99 98 100 /** … … public class LayerManager { 102 104 public Layer getRemovedLayer() { 103 105 return removedLayer; 104 106 } 107 108 /** 109 * Check if the layer that was removed is the last layer in the list. 110 * @return <code>true</code> if this was the last layer. 111 */ 112 public boolean isLastLayer() { 113 return lastLayer; 114 } 105 115 } 106 116 107 117 /** … … public class LayerManager { 346 356 l.layerOrderChanged(e); 347 357 } 348 358 } 359 360 /** 361 * Reset all layer manager state. This includes removing all layers and then unregistering all listeners 362 */ 363 public void resetState() { 364 // some layer remove listeners remove other layers. 365 while (!getLayers().isEmpty()) { 366 removeLayer(getLayers().get(0)); 367 } 368 369 layerChangeListeners.clear(); 370 } 349 371 } -
src/org/openstreetmap/josm/gui/layer/MainLayerManager.java
diff --git a/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java b/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java index cf7418a..47856fe 100644
a b public class MainLayerManager extends LayerManager { 312 312 } 313 313 return ret; 314 314 } 315 316 @Override 317 public void resetState() { 318 // active and edit layer are unset automatically 319 super.resetState(); 320 321 activeLayerChangeListeners.clear(); 322 } 315 323 } -
src/org/openstreetmap/josm/io/NoteImporter.java
diff --git a/src/org/openstreetmap/josm/io/NoteImporter.java b/src/org/openstreetmap/josm/io/NoteImporter.java index da40198..af84702 100644
a b import org.openstreetmap.josm.actions.ExtensionFileFilter; 13 13 import org.openstreetmap.josm.data.notes.Note; 14 14 import org.openstreetmap.josm.gui.layer.NoteLayer; 15 15 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 16 import org.openstreetmap.josm.gui.util.GuiHelper;17 16 import org.xml.sax.SAXException; 18 17 19 18 /** … … public class NoteImporter extends FileImporter { 37 36 } 38 37 try (InputStream is = Compression.getUncompressedFileInputStream(file)) { 39 38 final NoteLayer layer = loadLayer(is, file, file.getName(), progressMonitor); 40 if (Main.map == null || !Main.getLayerManager().containsLayer(layer)) { 41 GuiHelper.runInEDT(new Runnable() { 42 @Override 43 public void run() { 44 Main.main.addLayer(layer); 45 } 46 }); 39 if (!Main.getLayerManager().containsLayer(layer)) { 40 Main.getLayerManager().addLayer(layer); 47 41 } 48 42 } catch (SAXException e) { 49 43 Main.error("error opening up notes file"); -
test/unit/org/openstreetmap/josm/io/NoteImporterTest.java
diff --git a/test/unit/org/openstreetmap/josm/io/NoteImporterTest.java b/test/unit/org/openstreetmap/josm/io/NoteImporterTest.java index 8e0c9a1..90f0905 100644
a b import static org.junit.Assert.assertTrue; 6 6 7 7 import java.io.File; 8 8 9 import org.junit.Rule; 9 10 import org.junit.Test; 10 11 import org.openstreetmap.josm.Main; 11 12 import org.openstreetmap.josm.TestUtils; 12 import org.openstreetmap.josm. gui.layer.Layer;13 import org.openstreetmap.josm.testutils.JOSMTestRules; 13 14 14 15 /** 15 16 * Unit tests of {@link NoteImporter} class. … … import org.openstreetmap.josm.gui.layer.Layer; 17 18 public class NoteImporterTest { 18 19 19 20 /** 21 * Use the test rules to remove any layers and reset state. 22 */ 23 @Rule 24 public final JOSMTestRules rules = new JOSMTestRules(); 25 26 /** 20 27 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/12531">Bug #12531</a>. 21 28 */ 22 29 @Test 23 30 public void testTicket12531() { 24 if (Main.map != null) { 25 for (Layer l: Main.getLayerManager().getLayers()) { 26 Main.getLayerManager().removeLayer(l); 27 } 28 Main.main.setMapFrame(null); 29 } 31 Main.getLayerManager().resetState(); 30 32 assertNull(Main.map); 31 33 assertTrue(new NoteImporter().importDataHandleExceptions( 32 34 new File(TestUtils.getRegressionDataFile(12531, "notes.osn")), null)); -
test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
diff --git a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java index 2531d0e..39dae30 100644
a b import org.junit.runners.model.InitializationError; 12 12 import org.junit.runners.model.Statement; 13 13 import org.openstreetmap.josm.Main; 14 14 import org.openstreetmap.josm.data.projection.Projections; 15 import org.openstreetmap.josm.gui.layer.MainLayerManager;16 15 import org.openstreetmap.josm.gui.util.GuiHelper; 17 16 import org.openstreetmap.josm.io.OsmApi; 18 17 import org.openstreetmap.josm.io.OsmApiInitializationException; … … public class JOSMTestRules implements TestRule { 222 221 } 223 222 }); 224 223 // Remove all layers 225 MainLayerManager lm = Main.getLayerManager(); 226 while (!lm.getLayers().isEmpty()) { 227 lm.removeLayer(lm.getLayers().get(0)); 228 } 224 Main.getLayerManager().resetState(); 229 225 230 226 // TODO: Remove global listeners and other global state. 231 227 Main.pref = null;