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

Last change on this file since 2683 was 2657, checked in by jttt, 14 years ago

Cache list of used tags in properties dialog (faster adding of keys in large datasets)

  • 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).destroy();
190 }
191 for (int i = 0; i < toolBarToggle.getComponentCount(); ++i)
192 if (toolBarToggle.getComponent(i) instanceof Destroyable) {
193 ((Destroyable)toolBarToggle).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) return;
202 try {
203 statusLine.thread.interrupt();
204 } catch (Exception e) {}
205 }
206
207 public Action getDefaultButtonAction() {
208 return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
209 }
210
211 /**
212 * Open all ToggleDialogs that have their preferences property set. Close all others.
213 */
214 public void initializeDialogsPane() {
215 dialogsPanel.initialize(allDialogs);
216 }
217
218 /**
219 *
220 */
221 public void tearDownDialogsPane() {
222 dialogsPanel.tearDown();
223 }
224
225 /**
226 * Call this to add new toggle dialogs to the left button-list
227 * @param dlg The toggle dialog. It must not be in the list already.
228 */
229 public IconToggleButton addToggleDialog(ToggleDialog dlg) {
230 IconToggleButton button = new IconToggleButton(dlg.getToggleAction());
231 toolBarToggle.add(button);
232 allDialogs.add(dlg);
233 if (dialogsPanel.initialized) {
234 dialogsPanel.add(dlg);
235 }
236 return button;
237 }
238
239 public void addMapMode(IconToggleButton b) {
240 toolBarActions.add(b);
241 toolGroup.add(b);
242 }
243
244 /**
245 * Fires an property changed event "visible".
246 */
247 @Override public void setVisible(boolean aFlag) {
248 boolean old = isVisible();
249 super.setVisible(aFlag);
250 if (old != aFlag) {
251 firePropertyChange("visible", old, aFlag);
252 }
253 }
254
255 /**
256 * Change the operating map mode for the view. Will call unregister on the
257 * old MapMode and register on the new one.
258 * @param mapMode The new mode to set.
259 */
260 public void selectMapMode(MapMode newMapMode) {
261 MapMode oldMapMode = this.mapMode;
262 if (newMapMode == oldMapMode)
263 return;
264 if (oldMapMode != null) {
265 oldMapMode.exitMode();
266 }
267 this.mapMode = newMapMode;
268 newMapMode.enterMode();
269 fireMapModeChanged(oldMapMode, newMapMode);
270 }
271
272 /**
273 * Fill the given panel by adding all necessary components to the different
274 * locations.
275 *
276 * @param panel The container to fill. Must have an BorderLayout.
277 */
278 public void fillPanel(Container panel) {
279 panel.add(this, BorderLayout.CENTER);
280 JToolBar jb = new JToolBar(JToolBar.VERTICAL);
281 jb.setFloatable(false);
282 jb.add(toolBarActions);
283 jb.addSeparator(new Dimension(0,10));
284 jb.add(toolBarToggle);
285 if(Main.pref.getBoolean("sidetoolbar.visible", true))
286 {
287 if(Main.pref.getBoolean("sidetoolbar.scrollable", true)) {
288 final ScrollViewport svp = new ScrollViewport(jb, ScrollViewport.VERTICAL_DIRECTION);
289 panel.add(svp, BorderLayout.WEST);
290 jb.addMouseWheelListener(new MouseWheelListener() {
291 public void mouseWheelMoved(MouseWheelEvent e) {
292 svp.scroll(0,e.getUnitsToScroll() * 5);
293 }
294 });
295 } else {
296 panel.add(jb, BorderLayout.WEST);
297 }
298 }
299 if (statusLine != null && Main.pref.getBoolean("statusline.visible", true)) {
300 panel.add(statusLine, BorderLayout.SOUTH);
301 }
302 }
303
304 /**
305 * Replies the instance of a toggle dialog of type <code>type</code> managed by this
306 * map frame
307 *
308 * @param <T>
309 * @param type the class of the toggle dialog, i.e. UserListDialog.class
310 * @return the instance of a toggle dialog of type <code>type</code> managed by this
311 * map frame; null, if no such dialog exists
312 *
313 */
314 public <T> T getToggleDialog(Class<T> type) {
315 return dialogsPanel.getToggleDialog(type);
316 }
317
318 /**
319 * Returns the current width of the (possibly resized) toggle dialog area
320 */
321 public int getToggleDlgWidth() {
322 return dialogsPanel.getWidth();
323 }
324
325 /**
326 * Interface to notify listeners of the change of the mapMode.
327 */
328 public interface MapModeChangeListener {
329 void mapModeChange(MapMode oldMapMode, MapMode newMapMode);
330 }
331
332 /**
333 * the mapMode listeners
334 */
335 private static final CopyOnWriteArrayList<MapModeChangeListener> mapModeChangeListeners = new CopyOnWriteArrayList<MapModeChangeListener>();
336 /**
337 * Adds a mapMode change listener
338 *
339 * @param listener the listener. Ignored if null or already registered.
340 */
341 public static void addMapModeChangeListener(MapModeChangeListener listener) {
342 if (listener != null) {
343 mapModeChangeListeners.addIfAbsent(listener);
344 }
345 }
346 /**
347 * Removes a mapMode change listener
348 *
349 * @param listener the listener. Ignored if null or already registered.
350 */
351 public static void removeMapModeChangeListener(MapModeChangeListener listener) {
352 mapModeChangeListeners.remove(listener);
353 }
354
355 protected static void fireMapModeChanged(MapMode oldMapMode, MapMode newMapMode) {
356 for (MapModeChangeListener l : mapModeChangeListeners) {
357 l.mapModeChange(oldMapMode, newMapMode);
358 }
359 }
360}
Note: See TracBrowser for help on using the repository browser.