source: josm/trunk/src/org/openstreetmap/josm/gui/MapFrame.java@ 2946

Last change on this file since 2946 was 2871, checked in by jttt, 14 years ago

Partially fix situation after last layer removal - most objects still stay in memory but at least there are less references and forgotten listeners

  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1// License: GPL. See LICENSE file for details.
2
3package org.openstreetmap.josm.gui;
4
5import java.awt.BorderLayout;
6import java.awt.Container;
7import java.awt.Dimension;
8import java.awt.event.MouseWheelEvent;
9import java.awt.event.MouseWheelListener;
10import java.util.ArrayList;
11import java.util.List;
12import java.util.concurrent.CopyOnWriteArrayList;
13
14import javax.swing.AbstractButton;
15import javax.swing.Action;
16import javax.swing.BoxLayout;
17import javax.swing.ButtonGroup;
18import javax.swing.JPanel;
19import javax.swing.JSplitPane;
20import javax.swing.JToolBar;
21import javax.swing.border.Border;
22import javax.swing.plaf.basic.BasicSplitPaneDivider;
23import javax.swing.plaf.basic.BasicSplitPaneUI;
24
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.actions.mapmode.DeleteAction;
27import org.openstreetmap.josm.actions.mapmode.DrawAction;
28import org.openstreetmap.josm.actions.mapmode.ExtrudeAction;
29import org.openstreetmap.josm.actions.mapmode.MapMode;
30import org.openstreetmap.josm.actions.mapmode.SelectAction;
31import org.openstreetmap.josm.actions.mapmode.ZoomAction;
32import org.openstreetmap.josm.gui.dialogs.ChangesetDialog;
33import org.openstreetmap.josm.gui.dialogs.CommandStackDialog;
34import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
35import org.openstreetmap.josm.gui.dialogs.DialogsPanel;
36import org.openstreetmap.josm.gui.dialogs.FilterDialog;
37import org.openstreetmap.josm.gui.dialogs.HistoryDialog;
38import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
39import org.openstreetmap.josm.gui.dialogs.RelationListDialog;
40import org.openstreetmap.josm.gui.dialogs.SelectionListDialog;
41import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
42import org.openstreetmap.josm.gui.dialogs.UserListDialog;
43import org.openstreetmap.josm.gui.dialogs.properties.PropertiesDialog;
44import org.openstreetmap.josm.tools.Destroyable;
45
46/**
47 * One Map frame with one dataset behind. This is the container gui class whose
48 * display can be set to the different views.
49 *
50 * @author imi
51 */
52public class MapFrame extends JPanel implements Destroyable {
53
54 /**
55 * The current mode, this frame operates.
56 */
57 public MapMode mapMode;
58 /**
59 * The view control displayed.
60 */
61 public MapView mapView;
62 /**
63 * The toolbar with the action icons. To add new toggle dialog actions, use addToggleDialog
64 * instead of adding directly to this list. To add a new mode use addMapMode.
65 */
66 private JToolBar toolBarActions = new JToolBar(JToolBar.VERTICAL);
67 private JToolBar toolBarToggle = new JToolBar(JToolBar.VERTICAL);
68 /**
69 * The status line below the map
70 */
71 public MapStatus statusLine;
72
73 public ConflictDialog conflictDialog;
74 /**
75 * The dialog that shows all relations and lets the user edit them.
76 */
77 public RelationListDialog relationListDialog;
78 /**
79 * The panel list of all toggle dialog icons. To add new toggle dialog actions, use addToggleDialog
80 * instead of adding directly to this list.
81 */
82 private List<ToggleDialog> allDialogs = new ArrayList<ToggleDialog>();
83 private final DialogsPanel dialogsPanel;
84
85 public final ButtonGroup toolGroup = new ButtonGroup();
86
87 /**
88 * Default width of the toggle dialog area.
89 */
90 public final int DEF_TOGGLE_DLG_WIDTH = 330;
91
92 public MapFrame() {
93 setSize(400,400);
94 setLayout(new BorderLayout());
95
96 mapView = new MapView();
97
98 new FileDrop(mapView);
99
100 // show menu entry
101 Main.main.menu.viewMenu.setVisible(true);
102
103 // toolbar
104 toolBarActions.setFloatable(false);
105 addMapMode(new IconToggleButton(new SelectAction(this)));
106 addMapMode(new IconToggleButton(new DrawAction(this)));
107 addMapMode(new IconToggleButton(new ExtrudeAction(this)));
108 addMapMode(new IconToggleButton(new ZoomAction(this)));
109 addMapMode(new IconToggleButton(new DeleteAction(this)));
110
111 toolGroup.setSelected(((AbstractButton)toolBarActions.getComponent(0)).getModel(), true);
112
113 JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
114 dialogsPanel = new DialogsPanel(splitPane);
115 splitPane.setLeftComponent(mapView);
116 splitPane.setRightComponent(dialogsPanel);
117
118 /**
119 * All additional space goes to the mapView
120 */
121 splitPane.setResizeWeight(1.0);
122
123 /**
124 * Some beautifications.
125 */
126 splitPane.setDividerSize(5);
127 splitPane.setBorder(null);
128 splitPane.setUI(new BasicSplitPaneUI() {
129 @Override
130 public BasicSplitPaneDivider createDefaultDivider() {
131 return new BasicSplitPaneDivider(this) {
132 @Override
133 public void setBorder(Border b) {
134 }
135 };
136 }
137 });
138
139 add(splitPane, BorderLayout.CENTER);
140
141 dialogsPanel.setLayout(new BoxLayout(dialogsPanel, BoxLayout.Y_AXIS));
142 dialogsPanel.setPreferredSize(new Dimension(Main.pref.getInteger("toggleDialogs.width",DEF_TOGGLE_DLG_WIDTH), 0));
143
144 dialogsPanel.setMinimumSize(new Dimension(24, 0));
145 mapView.setMinimumSize(new Dimension(10,0));
146
147 toolBarToggle.setFloatable(false);
148 LayerListDialog.createInstance(this);
149 addToggleDialog(LayerListDialog.getInstance());
150 addToggleDialog(new PropertiesDialog(this));
151 addToggleDialog(new HistoryDialog());
152 addToggleDialog(new SelectionListDialog());
153 if(Main.pref.getBoolean("displayfilter", false)) {
154 addToggleDialog(new FilterDialog());
155 }
156 addToggleDialog(new UserListDialog());
157 addToggleDialog(conflictDialog = new ConflictDialog());
158 addToggleDialog(new CommandStackDialog(this));
159 addToggleDialog(relationListDialog = new RelationListDialog());
160 addToggleDialog(new ChangesetDialog(this));
161
162 // status line below the map
163 statusLine = new MapStatus(this);
164 }
165
166 public void selectSelectTool(boolean onlyIfModeless) {
167 if(onlyIfModeless && !Main.pref.getBoolean("modeless", false))
168 return;
169
170 selectMapMode((MapMode)getDefaultButtonAction());
171 }
172
173 public void selectDrawTool(boolean onlyIfModeless) {
174 if(onlyIfModeless && !Main.pref.getBoolean("modeless", false))
175 return;
176
177 Action drawAction = ((AbstractButton)toolBarActions.getComponent(1)).getAction();
178 selectMapMode((MapMode)drawAction);
179 }
180
181 /**
182 * Called as some kind of destructor when the last layer has been removed.
183 * Delegates the call to all Destroyables within this component (e.g. MapModes)
184 */
185 public void destroy() {
186 dialogsPanel.destroy();
187 for (int i = 0; i < toolBarActions.getComponentCount(); ++i)
188 if (toolBarActions.getComponent(i) instanceof Destroyable) {
189 ((Destroyable)toolBarActions.getComponent(i)).destroy();
190 }
191 for (int i = 0; i < toolBarToggle.getComponentCount(); ++i)
192 if (toolBarToggle.getComponent(i) instanceof Destroyable) {
193 ((Destroyable)toolBarToggle.getComponent(i)).destroy();
194 }
195
196 // remove menu entries
197 Main.main.menu.viewMenu.setVisible(false);
198
199 // MapFrame gets destroyed when the last layer is removed, but the status line background
200 // thread that collects the information doesn't get destroyed automatically.
201 if(statusLine.thread != null) {
202 try {
203 statusLine.thread.interrupt();
204 } catch (Exception e) {
205 e.printStackTrace();
206 }
207 }
208 }
209
210 public Action getDefaultButtonAction() {
211 return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
212 }
213
214 /**
215 * Open all ToggleDialogs that have their preferences property set. Close all others.
216 */
217 public void initializeDialogsPane() {
218 dialogsPanel.initialize(allDialogs);
219 }
220
221 /**
222 * Call this to add new toggle dialogs to the left button-list
223 * @param dlg The toggle dialog. It must not be in the list already.
224 */
225 public IconToggleButton addToggleDialog(ToggleDialog dlg) {
226 IconToggleButton button = new IconToggleButton(dlg.getToggleAction());
227 toolBarToggle.add(button);
228 allDialogs.add(dlg);
229 if (dialogsPanel.initialized) {
230 dialogsPanel.add(dlg);
231 }
232 return button;
233 }
234
235 public void addMapMode(IconToggleButton b) {
236 toolBarActions.add(b);
237 toolGroup.add(b);
238 }
239
240 /**
241 * Fires an property changed event "visible".
242 */
243 @Override public void setVisible(boolean aFlag) {
244 boolean old = isVisible();
245 super.setVisible(aFlag);
246 if (old != aFlag) {
247 firePropertyChange("visible", old, aFlag);
248 }
249 }
250
251 /**
252 * Change the operating map mode for the view. Will call unregister on the
253 * old MapMode and register on the new one.
254 * @param mapMode The new mode to set.
255 */
256 public void selectMapMode(MapMode newMapMode) {
257 MapMode oldMapMode = this.mapMode;
258 if (newMapMode == oldMapMode)
259 return;
260 if (oldMapMode != null) {
261 oldMapMode.exitMode();
262 }
263 this.mapMode = newMapMode;
264 newMapMode.enterMode();
265 fireMapModeChanged(oldMapMode, newMapMode);
266 }
267
268 /**
269 * Fill the given panel by adding all necessary components to the different
270 * locations.
271 *
272 * @param panel The container to fill. Must have an BorderLayout.
273 */
274 public void fillPanel(Container panel) {
275 panel.add(this, BorderLayout.CENTER);
276 JToolBar jb = new JToolBar(JToolBar.VERTICAL);
277 jb.setFloatable(false);
278 jb.add(toolBarActions);
279 jb.addSeparator(new Dimension(0,10));
280 jb.add(toolBarToggle);
281 if(Main.pref.getBoolean("sidetoolbar.visible", true))
282 {
283 if(Main.pref.getBoolean("sidetoolbar.scrollable", true)) {
284 final ScrollViewport svp = new ScrollViewport(jb, ScrollViewport.VERTICAL_DIRECTION);
285 panel.add(svp, BorderLayout.WEST);
286 jb.addMouseWheelListener(new MouseWheelListener() {
287 public void mouseWheelMoved(MouseWheelEvent e) {
288 svp.scroll(0,e.getUnitsToScroll() * 5);
289 }
290 });
291 } else {
292 panel.add(jb, BorderLayout.WEST);
293 }
294 }
295 if (statusLine != null && Main.pref.getBoolean("statusline.visible", true)) {
296 panel.add(statusLine, BorderLayout.SOUTH);
297 }
298 }
299
300 /**
301 * Replies the instance of a toggle dialog of type <code>type</code> managed by this
302 * map frame
303 *
304 * @param <T>
305 * @param type the class of the toggle dialog, i.e. UserListDialog.class
306 * @return the instance of a toggle dialog of type <code>type</code> managed by this
307 * map frame; null, if no such dialog exists
308 *
309 */
310 public <T> T getToggleDialog(Class<T> type) {
311 return dialogsPanel.getToggleDialog(type);
312 }
313
314 /**
315 * Returns the current width of the (possibly resized) toggle dialog area
316 */
317 public int getToggleDlgWidth() {
318 return dialogsPanel.getWidth();
319 }
320
321 /**
322 * Interface to notify listeners of the change of the mapMode.
323 */
324 public interface MapModeChangeListener {
325 void mapModeChange(MapMode oldMapMode, MapMode newMapMode);
326 }
327
328 /**
329 * the mapMode listeners
330 */
331 private static final CopyOnWriteArrayList<MapModeChangeListener> mapModeChangeListeners = new CopyOnWriteArrayList<MapModeChangeListener>();
332 /**
333 * Adds a mapMode change listener
334 *
335 * @param listener the listener. Ignored if null or already registered.
336 */
337 public static void addMapModeChangeListener(MapModeChangeListener listener) {
338 if (listener != null) {
339 mapModeChangeListeners.addIfAbsent(listener);
340 }
341 }
342 /**
343 * Removes a mapMode change listener
344 *
345 * @param listener the listener. Ignored if null or already registered.
346 */
347 public static void removeMapModeChangeListener(MapModeChangeListener listener) {
348 mapModeChangeListeners.remove(listener);
349 }
350
351 protected static void fireMapModeChanged(MapMode oldMapMode, MapMode newMapMode) {
352 for (MapModeChangeListener l : mapModeChangeListeners) {
353 l.mapModeChange(oldMapMode, newMapMode);
354 }
355 }
356}
Note: See TracBrowser for help on using the repository browser.