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

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

Fix #4500: Various audio controls no longer work

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