source: josm/trunk/src/org/openstreetmap/josm/gui/MainPanel.java@ 14903

Last change on this file since 14903 was 14470, checked in by GerdP, 5 years ago

see #17040 Fix various memory leaks
Not sure if this will break Unit tests. Many of them don't work on my PC with a clean copy.

  • Property svn:eol-style set to native
File size: 5.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import java.awt.BorderLayout;
5import java.util.List;
6import java.util.concurrent.CopyOnWriteArrayList;
7
8import javax.swing.JPanel;
9
10import org.openstreetmap.josm.actions.mapmode.MapMode;
11import org.openstreetmap.josm.data.UndoRedoHandler;
12import org.openstreetmap.josm.gui.layer.Layer;
13import org.openstreetmap.josm.gui.layer.MainLayerManager;
14import org.openstreetmap.josm.gui.layer.MainLayerManager.LayerAvailabilityEvent;
15import org.openstreetmap.josm.gui.layer.MainLayerManager.LayerAvailabilityListener;
16import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor;
17import org.openstreetmap.josm.gui.util.GuiHelper;
18
19/**
20 * This is the content panel inside the {@link MainFrame}. It displays the content the user is working with.
21 * <p>
22 * If there is no active layer, there is no content displayed. As soon as there are active layers, the {@link MapFrame} is displayed.
23 *
24 * @author Michael Zangl
25 * @since 10432
26 */
27public class MainPanel extends JPanel {
28 private MapFrame map;
29 // Needs to be lazy because we need to wait for preferences to set up.
30 private GettingStarted gettingStarted;
31 private final CopyOnWriteArrayList<MapFrameListener> mapFrameListeners = new CopyOnWriteArrayList<>();
32 private final transient MainLayerManager layerManager;
33
34 /**
35 * Create a new main panel
36 * @param layerManager The layer manager to use to display the content.
37 */
38 public MainPanel(MainLayerManager layerManager) {
39 super(new BorderLayout());
40 this.layerManager = layerManager;
41 }
42
43 /**
44 * Update the content of this {@link MainFrame} to either display the map or display the welcome screen.
45 * @param showMap If the map should be displayed.
46 */
47 protected synchronized void updateContent(boolean showMap) {
48 GuiHelper.assertCallFromEdt();
49 MapFrame old = map;
50 if (old != null && showMap) {
51 // no state change
52 return;
53 }
54
55 // remove old content
56 setVisible(false);
57 removeAll();
58 if (old != null) {
59 old.destroy();
60 }
61
62 // create new content
63 if (showMap) {
64 map = createNewMapFrame();
65 } else {
66 map = null;
67 MainApplication.map = map;
68 add(getGettingStarted(), BorderLayout.CENTER);
69 UndoRedoHandler.getInstance().clean();
70 }
71 setVisible(true);
72
73 if (old == null && !showMap) {
74 // listeners may not be able to handle this...
75 return;
76 }
77
78 // Notify map frame listeners, mostly plugins.
79 for (MapFrameListener listener : mapFrameListeners) {
80 listener.mapFrameInitialized(old, map);
81 }
82 if (map == null && PleaseWaitProgressMonitor.getCurrent() != null) {
83 PleaseWaitProgressMonitor.getCurrent().showForegroundDialog();
84 }
85 }
86
87 private MapFrame createNewMapFrame() {
88 MapFrame mapFrame = new MapFrame(null);
89 // Required by many components.
90 MainApplication.map = mapFrame;
91
92 mapFrame.fillPanel(this);
93
94 //TODO: Move this to some better place
95 List<Layer> layers = MainApplication.getLayerManager().getLayers();
96 if (!layers.isEmpty()) {
97 mapFrame.selectMapMode((MapMode) mapFrame.getDefaultButtonAction(), layers.get(0));
98 }
99 mapFrame.initializeDialogsPane();
100 mapFrame.setVisible(true);
101 return mapFrame;
102 }
103
104 /**
105 * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes.
106 * <p>
107 * It will fire an initial mapFrameInitialized event
108 * when the MapFrame is present. Otherwise will only fire when the MapFrame is created
109 * or destroyed.
110 * @param listener The MapFrameListener
111 * @return {@code true} if the listeners collection changed as a result of the call.
112 */
113 public synchronized boolean addAndFireMapFrameListener(MapFrameListener listener) {
114 boolean changed = addMapFrameListener(listener);
115 if (changed && map != null) {
116 listener.mapFrameInitialized(null, map);
117 }
118 return changed;
119 }
120
121 /**
122 * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes
123 * @param listener The MapFrameListener
124 * @return {@code true} if the listeners collection changed as a result of the call
125 */
126 public boolean addMapFrameListener(MapFrameListener listener) {
127 return listener != null && mapFrameListeners.add(listener);
128 }
129
130 /**
131 * Unregisters the given {@code MapFrameListener} from MapFrame changes
132 * @param listener The MapFrameListener
133 * @return {@code true} if the listeners collection changed as a result of the call
134 */
135 public boolean removeMapFrameListener(MapFrameListener listener) {
136 return listener != null && mapFrameListeners.remove(listener);
137 }
138
139 /**
140 * Gets the {@link GettingStarted} panel.
141 * @return The panel.
142 */
143 public synchronized GettingStarted getGettingStarted() {
144 if (gettingStarted == null) {
145 gettingStarted = new GettingStarted();
146 }
147 return gettingStarted;
148 }
149
150 /**
151 * Re-adds the layer listeners. Never call this in production, only needed for testing.
152 */
153 public void reAddListeners() {
154 layerManager.addLayerAvailabilityListener(new LayerAvailabilityListener() {
155 @Override
156 public void beforeFirstLayerAdded(LayerAvailabilityEvent e) {
157 updateContent(true);
158 }
159
160 @Override
161 public void afterLastLayerRemoved(LayerAvailabilityEvent e) {
162 updateContent(false);
163 }
164 });
165 GuiHelper.runInEDTAndWait(() -> updateContent(!layerManager.getLayers().isEmpty()));
166 }
167}
Note: See TracBrowser for help on using the repository browser.