source: josm/trunk/src/org/openstreetmap/josm/gui/MainMenu.java@ 6789

Last change on this file since 6789 was 6738, checked in by simon04, 10 years ago

Add "Search for objects by preset" action

This allows to use presets for searching for objects.
SHIFT+F3 displays the preset dialog and after confirmation, the objects matching the preset are selected.

  • Property svn:eol-style set to native
File size: 36.0 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.marktr;
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.Component;
9import java.awt.Toolkit;
10import java.awt.event.KeyEvent;
11import java.util.HashMap;
12import java.util.Map;
13
14import javax.swing.JCheckBoxMenuItem;
15import javax.swing.JMenu;
16import javax.swing.JMenuBar;
17import javax.swing.JMenuItem;
18import javax.swing.JPopupMenu;
19import javax.swing.JSeparator;
20import javax.swing.KeyStroke;
21import javax.swing.event.MenuEvent;
22import javax.swing.event.MenuListener;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.actions.AboutAction;
26import org.openstreetmap.josm.actions.AddNodeAction;
27import org.openstreetmap.josm.actions.AlignInCircleAction;
28import org.openstreetmap.josm.actions.AlignInLineAction;
29import org.openstreetmap.josm.actions.AutoScaleAction;
30import org.openstreetmap.josm.actions.ChangesetManagerToggleAction;
31import org.openstreetmap.josm.actions.CloseChangesetAction;
32import org.openstreetmap.josm.actions.CombineWayAction;
33import org.openstreetmap.josm.actions.CopyAction;
34import org.openstreetmap.josm.actions.CopyCoordinatesAction;
35import org.openstreetmap.josm.actions.CreateCircleAction;
36import org.openstreetmap.josm.actions.CreateMultipolygonAction;
37import org.openstreetmap.josm.actions.DeleteAction;
38import org.openstreetmap.josm.actions.DialogsToggleAction;
39import org.openstreetmap.josm.actions.DistributeAction;
40import org.openstreetmap.josm.actions.DownloadAction;
41import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
42import org.openstreetmap.josm.actions.DownloadReferrersAction;
43import org.openstreetmap.josm.actions.DuplicateAction;
44import org.openstreetmap.josm.actions.ExitAction;
45import org.openstreetmap.josm.actions.ExpertToggleAction;
46import org.openstreetmap.josm.actions.FollowLineAction;
47import org.openstreetmap.josm.actions.FullscreenToggleAction;
48import org.openstreetmap.josm.actions.GpxExportAction;
49import org.openstreetmap.josm.actions.HelpAction;
50import org.openstreetmap.josm.actions.HistoryInfoAction;
51import org.openstreetmap.josm.actions.HistoryInfoWebAction;
52import org.openstreetmap.josm.actions.InfoAction;
53import org.openstreetmap.josm.actions.InfoWebAction;
54import org.openstreetmap.josm.actions.JoinAreasAction;
55import org.openstreetmap.josm.actions.JoinNodeWayAction;
56import org.openstreetmap.josm.actions.JosmAction;
57import org.openstreetmap.josm.actions.JumpToAction;
58import org.openstreetmap.josm.actions.MergeLayerAction;
59import org.openstreetmap.josm.actions.MergeNodesAction;
60import org.openstreetmap.josm.actions.MergeSelectionAction;
61import org.openstreetmap.josm.actions.MirrorAction;
62import org.openstreetmap.josm.actions.MoveAction;
63import org.openstreetmap.josm.actions.MoveNodeAction;
64import org.openstreetmap.josm.actions.NewAction;
65import org.openstreetmap.josm.actions.OpenFileAction;
66import org.openstreetmap.josm.actions.OpenLocationAction;
67import org.openstreetmap.josm.actions.OrthogonalizeAction;
68import org.openstreetmap.josm.actions.OrthogonalizeAction.Undo;
69import org.openstreetmap.josm.actions.PasteAction;
70import org.openstreetmap.josm.actions.PasteTagsAction;
71import org.openstreetmap.josm.actions.PreferenceToggleAction;
72import org.openstreetmap.josm.actions.PreferencesAction;
73import org.openstreetmap.josm.actions.PurgeAction;
74import org.openstreetmap.josm.actions.RedoAction;
75import org.openstreetmap.josm.actions.RestartAction;
76import org.openstreetmap.josm.actions.ReverseWayAction;
77import org.openstreetmap.josm.actions.SaveAction;
78import org.openstreetmap.josm.actions.SaveAsAction;
79import org.openstreetmap.josm.actions.SelectAllAction;
80import org.openstreetmap.josm.actions.SelectNonBranchingWaySequencesAction;
81import org.openstreetmap.josm.actions.SessionLoadAction;
82import org.openstreetmap.josm.actions.SessionSaveAsAction;
83import org.openstreetmap.josm.actions.ShowStatusReportAction;
84import org.openstreetmap.josm.actions.SimplifyWayAction;
85import org.openstreetmap.josm.actions.SplitWayAction;
86import org.openstreetmap.josm.actions.ToggleGPXLinesAction;
87import org.openstreetmap.josm.actions.UnGlueAction;
88import org.openstreetmap.josm.actions.UnJoinNodeWayAction;
89import org.openstreetmap.josm.actions.UndoAction;
90import org.openstreetmap.josm.actions.UnselectAllAction;
91import org.openstreetmap.josm.actions.UpdateDataAction;
92import org.openstreetmap.josm.actions.UpdateModifiedAction;
93import org.openstreetmap.josm.actions.UpdateSelectionAction;
94import org.openstreetmap.josm.actions.UploadAction;
95import org.openstreetmap.josm.actions.UploadSelectionAction;
96import org.openstreetmap.josm.actions.ViewportFollowToggleAction;
97import org.openstreetmap.josm.actions.WireframeToggleAction;
98import org.openstreetmap.josm.actions.ZoomInAction;
99import org.openstreetmap.josm.actions.ZoomOutAction;
100import org.openstreetmap.josm.actions.audio.AudioBackAction;
101import org.openstreetmap.josm.actions.audio.AudioFasterAction;
102import org.openstreetmap.josm.actions.audio.AudioFwdAction;
103import org.openstreetmap.josm.actions.audio.AudioNextAction;
104import org.openstreetmap.josm.actions.audio.AudioPlayPauseAction;
105import org.openstreetmap.josm.actions.audio.AudioPrevAction;
106import org.openstreetmap.josm.actions.audio.AudioSlowerAction;
107import org.openstreetmap.josm.actions.search.SearchAction;
108import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
109import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
110import org.openstreetmap.josm.gui.io.RecentlyOpenedFilesMenu;
111import org.openstreetmap.josm.gui.layer.Layer;
112import org.openstreetmap.josm.gui.mappaint.MapPaintMenu;
113import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
114import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
115import org.openstreetmap.josm.gui.tagging.TaggingPresetSearchAction;
116import org.openstreetmap.josm.gui.tagging.TaggingPresetSearchPrimitiveDialog;
117import org.openstreetmap.josm.tools.ImageProvider;
118import org.openstreetmap.josm.tools.Shortcut;
119
120/**
121 * This is the JOSM main menu bar. It is overwritten to initialize itself and provide all menu
122 * entries as member variables (sort of collect them).
123 *
124 * It also provides possibilities to attach new menu entries (used by plugins).
125 *
126 * @author Immanuel.Scholz
127 */
128public class MainMenu extends JMenuBar {
129
130 /* File menu */
131 /** File -> New Layer **/
132 public final NewAction newAction = new NewAction();
133 /** File -> Open... **/
134 public final OpenFileAction openFile = new OpenFileAction();
135 /** File -> Open Recent > **/
136 public final RecentlyOpenedFilesMenu recentlyOpened = new RecentlyOpenedFilesMenu();
137 /** File -> Open Location... **/
138 public final OpenLocationAction openLocation = new OpenLocationAction();
139 /** File -> Save **/
140 public final SaveAction save = SaveAction.getInstance();
141 /** File -> Save As... **/
142 public final SaveAsAction saveAs = SaveAsAction.getInstance();
143 /** File -> Session > Load Session **/
144 public SessionLoadAction sessionLoad;
145 /** File -> Session > Save Session As... **/
146 public SessionSaveAsAction sessionSaveAs;
147 /** File -> Export to GPX... **/
148 public final GpxExportAction gpxExport = new GpxExportAction();
149 /** File -> Download from OSM... **/
150 public final DownloadAction download = new DownloadAction();
151 /** File -> Download object... **/
152 public final DownloadPrimitiveAction downloadPrimitive = new DownloadPrimitiveAction();
153 /** File -> Download parent ways/relations... **/
154 public final DownloadReferrersAction downloadReferrers = new DownloadReferrersAction();
155 /** File -> Close open changesets... **/
156 public final CloseChangesetAction closeChangesetAction = new CloseChangesetAction();
157 /** File -> Update data **/
158 public final JosmAction update = new UpdateDataAction();
159 /** File -> Update selection **/
160 public final JosmAction updateSelection = new UpdateSelectionAction();
161 /** File -> Update modified **/
162 public final JosmAction updateModified = new UpdateModifiedAction();
163 /** File -> Upload data **/
164 public final JosmAction upload = new UploadAction();
165 /** File -> Upload selection **/
166 public final JosmAction uploadSelection = new UploadSelectionAction();
167 /** File -> Restart **/
168 public final RestartAction restart = new RestartAction();
169 /** File -> Exit **/
170 public final ExitAction exit = new ExitAction();
171
172 /* Edit menu */
173 /** Edit -> Undo... */
174 public final UndoAction undo = new UndoAction();
175 /** Edit -> Redo */
176 public final RedoAction redo = new RedoAction();
177 /** Edit -> Copy */
178 public final CopyAction copy = new CopyAction();
179 /** Edit -> Copy Coordinates */
180 public final JosmAction copyCoordinates = new CopyCoordinatesAction();
181 /** Edit -> Paste */
182 public final PasteAction paste = new PasteAction();
183 /** Edit -> Paste Tags */
184 public final PasteTagsAction pasteTags = new PasteTagsAction();
185 /** Edit -> Duplicate */
186 public final DuplicateAction duplicate = new DuplicateAction();
187 /** Edit -> Delete */
188 public final DeleteAction delete = new DeleteAction();
189 /** Edit -> Purge... */
190 public final JosmAction purge = new PurgeAction();
191 /** Edit -> Merge layer */
192 public final MergeLayerAction merge = new MergeLayerAction();
193 /** Edit -> Merge selection */
194 public final MergeSelectionAction mergeSelected = new MergeSelectionAction();
195 /** Edit -> Search... */
196 public final SearchAction search = new SearchAction();
197 /** Edit -> Preferences */
198 public final PreferencesAction preferences = new PreferencesAction();
199
200 /* View menu */
201 /** View -> Wireframe View */
202 public final WireframeToggleAction wireFrameToggleAction = new WireframeToggleAction();
203 public final JosmAction toggleGPXLines = new ToggleGPXLinesAction();
204 /** View -> Advanced info */
205 public final InfoAction info = new InfoAction();
206 /** View -> Advanced info (web) */
207 public final InfoWebAction infoweb = new InfoWebAction();
208 /** View -> History */
209 public final HistoryInfoAction historyinfo = new HistoryInfoAction();
210 /** View -> History (web) */
211 public final HistoryInfoWebAction historyinfoweb = new HistoryInfoWebAction();
212 /** View -> "Zoom to"... actions */
213 public final Map<String, AutoScaleAction> autoScaleActions = new HashMap<String, AutoScaleAction>();
214 /** View -> Jump to position */
215 public final JumpToAction jumpToAct = new JumpToAction();
216
217 /* Tools menu */
218 /** Tools -> Split Way */
219 public final SplitWayAction splitWay = new SplitWayAction();
220 /** Tools -> Combine Way */
221 public final CombineWayAction combineWay = new CombineWayAction();
222 /** Tools -> Reverse Ways */
223 public final ReverseWayAction reverseWay = new ReverseWayAction();
224 /** Tools -> Simplify Way */
225 public final SimplifyWayAction simplifyWay = new SimplifyWayAction();
226 /** Tools -> Align Nodes in Circle */
227 public final AlignInCircleAction alignInCircle = new AlignInCircleAction();
228 /** Tools -> Align Nodes in Line */
229 public final AlignInLineAction alignInLine = new AlignInLineAction();
230 /** Tools -> Distribute Nodes */
231 public final DistributeAction distribute = new DistributeAction();
232 /** Tools -> Orthogonalize Shape */
233 public final OrthogonalizeAction ortho = new OrthogonalizeAction();
234 /** Orthogonalize undo. Action is not shown in the menu. Only triggered by shortcut */
235 public final Undo orthoUndo = new Undo();
236 /** Tools -> Mirror */
237 public final MirrorAction mirror = new MirrorAction();
238 /** Tools -> Follow line */
239 public final FollowLineAction followLine = new FollowLineAction();
240 /** Tools -> Add Node... */
241 public final AddNodeAction addNode = new AddNodeAction();
242 /** Tools -> Move Node... */
243 public final MoveNodeAction moveNode = new MoveNodeAction();
244 /** Tools -> Create Circle */
245 public final CreateCircleAction createCircle = new CreateCircleAction();
246 /** Tools -> Merge Nodes */
247 public final MergeNodesAction mergeNodes = new MergeNodesAction();
248 /** Tools -> Join Node to Way */
249 public final JoinNodeWayAction joinNodeWay = new JoinNodeWayAction();
250 /** Tools -> Disconnect Node from Way */
251 public final UnJoinNodeWayAction unJoinNodeWay = new UnJoinNodeWayAction();
252 /** Tools -> Unglue Ways */
253 public final UnGlueAction unglueNodes = new UnGlueAction();
254 /** Tools -> Join overlapping Areas */
255 public final JoinAreasAction joinAreas = new JoinAreasAction();
256 /** Tools -> Create multipolygon */
257 public final CreateMultipolygonAction createMultipolygon = new CreateMultipolygonAction(false);
258 /** Tools -> Update multipolygon */
259 public final CreateMultipolygonAction updateMultipolygon = new CreateMultipolygonAction(true);
260
261 /* Selection menu */
262 /** Selection -> Select All */
263 public final SelectAllAction selectAll = new SelectAllAction();
264 /** Selection -> Unselect All */
265 public final UnselectAllAction unselectAll = new UnselectAllAction();
266 /** Selection -> Non-branching way sequences */
267 public final SelectNonBranchingWaySequencesAction nonBranchingWaySequences = new SelectNonBranchingWaySequencesAction();
268
269 /* Audio menu */
270 /** Audio -> Play/Pause */
271 public final JosmAction audioPlayPause = new AudioPlayPauseAction();
272 /** Audio -> Next marker */
273 public final JosmAction audioNext = new AudioNextAction();
274 /** Audio -> Previous Marker */
275 public final JosmAction audioPrev = new AudioPrevAction();
276 /** Audio -> Forward */
277 public final JosmAction audioFwd = new AudioFwdAction();
278 /** Audio -> Back */
279 public final JosmAction audioBack = new AudioBackAction();
280 /** Audio -> Faster */
281 public final JosmAction audioFaster = new AudioFasterAction();
282 /** Audio -> Slower */
283 public final JosmAction audioSlower = new AudioSlowerAction();
284
285 /* Windows Menu */
286 /** Windows -> Changeset Manager */
287 public final ChangesetManagerToggleAction changesetManager = new ChangesetManagerToggleAction();
288
289 /* Help menu */
290 /** Help -> Help */
291 public final HelpAction help = new HelpAction();
292 /** Help -> About */
293 public final AboutAction about = new AboutAction();
294 /** Help -> Show Status Report */
295 public final ShowStatusReportAction statusreport = new ShowStatusReportAction();
296
297 /**
298 * fileMenu contains I/O actions
299 */
300 public final JMenu fileMenu = addMenu(marktr("File"), KeyEvent.VK_F, 0, ht("/Menu/File"));
301 /**
302 * sessionMenu is a submenu of File menu containing all session actions
303 */
304 public final JMenu sessionMenu = new JMenu(tr("Session"));
305 /**
306 * editMenu contains editing actions
307 */
308 public final JMenu editMenu = addMenu(marktr("Edit"), KeyEvent.VK_E, 1, ht("/Menu/Edit"));
309 /**
310 * viewMenu contains display actions (zoom, map styles, etc.)
311 */
312 public final JMenu viewMenu = addMenu(marktr("View"), KeyEvent.VK_V, 2, ht("/Menu/View"));
313 /**
314 * toolsMenu contains different geometry manipulation actions from JOSM core (most used)
315 * The plugins should use other menus
316 */
317 public final JMenu toolsMenu = addMenu(marktr("Tools"), KeyEvent.VK_T, 3, ht("/Menu/Tools"));
318 /**
319 * moreToolsMenu contains geometry-related actions from all the plugins
320 * @since 6082 (moved from Utilsplugin2)
321 */
322 public final JMenu moreToolsMenu = addMenu(marktr("More tools"), KeyEvent.VK_M, 4, ht("/Menu/MoreTools"));
323 /**
324 * dataMenu contains plugin actions that are related to certain tagging schemes (addressing opening hours),
325 * importing external data and using external web APIs
326 * @since 6082
327 */
328 public final JMenu dataMenu = addMenu(marktr("Data"), KeyEvent.VK_D, 5, ht("/Menu/Data"));
329 /**
330 * selectionMenu contains all actions related to selecting different objects
331 * @since 6082 (moved from Utilsplugin2)
332 */
333 public final JMenu selectionMenu = addMenu(marktr("Selection"), KeyEvent.VK_N, 6, ht("/Menu/Selection"));
334 /**
335 * presetsMenu contains presets actions (search, presets tree)
336 */
337 public final JMenu presetsMenu = addMenu(marktr("Presets"), KeyEvent.VK_P, 7, ht("/Menu/Presets"));
338 /**
339 * submenu in Imagery menu that contains plugin-managed additional imagery layers
340 * @since 6097
341 */
342 public final JMenu imagerySubMenu = new JMenu(tr("More..."));
343 /**
344 * imageryMenu contains all imagery-related actions
345 */
346 public final ImageryMenu imageryMenu = addMenu(new ImageryMenu(imagerySubMenu), marktr("Imagery"), KeyEvent.VK_I, 8, ht("/Menu/Imagery"));
347 /**
348 * gpsMenu contains all plugin actions that are related
349 * to using GPS data, including opening, uploading and real-time tracking
350 * @since 6082
351 */
352 public final JMenu gpsMenu = addMenu(marktr("GPS"), KeyEvent.VK_G, 9, ht("/Menu/GPS"));
353 /** the window menu is split into several groups. The first is for windows that can be opened from
354 * this menu any time, e.g. the changeset editor. The second group is for toggle dialogs and the third
355 * group is for currently open windows that cannot be toggled, e.g. relation editors. It's recommended
356 * to use WINDOW_MENU_GROUP to determine the group integer.
357 */
358 public final JMenu windowMenu = addMenu(marktr("Windows"), KeyEvent.VK_W, 10, ht("/Menu/Windows"));
359 public static enum WINDOW_MENU_GROUP { ALWAYS, TOGGLE_DIALOG, VOLATILE }
360
361 /**
362 * audioMenu contains all audio-related actions. Be careful, this menu is not guaranteed to be displayed at all
363 */
364 public JMenu audioMenu = null;
365 /**
366 * helpMenu contains JOSM general actions (Help, About, etc.)
367 */
368 public final JMenu helpMenu = addMenu(marktr("Help"), KeyEvent.VK_H, 11, ht("/Menu/Help"));
369
370 private static final int defaultMenuPos = 11;
371
372 public final JosmAction moveUpAction = new MoveAction(MoveAction.Direction.UP);
373 public final JosmAction moveDownAction = new MoveAction(MoveAction.Direction.DOWN);
374 public final JosmAction moveLeftAction = new MoveAction(MoveAction.Direction.LEFT);
375 public final JosmAction moveRightAction = new MoveAction(MoveAction.Direction.RIGHT);
376
377 public final TaggingPresetSearchAction presetSearchAction = new TaggingPresetSearchAction();
378 public final TaggingPresetSearchPrimitiveDialog.Action presetSearchPrimitiveAction = new TaggingPresetSearchPrimitiveDialog.Action();
379 public final DialogsToggleAction dialogsToggleAction = new DialogsToggleAction();
380 public FullscreenToggleAction fullscreenToggleAction = null;
381
382 /** this menu listener hides unnecessary JSeparators in a menu list but does not remove them.
383 * If at a later time the separators are required, they will be made visible again. Intended
384 * usage is make menus not look broken if separators are used to group the menu and some of
385 * these groups are empty.
386 */
387 public final static MenuListener menuSeparatorHandler = new MenuListener() {
388 @Override
389 public void menuCanceled(MenuEvent arg0) {}
390 @Override
391 public void menuDeselected(MenuEvent arg0) {}
392 @Override
393 public void menuSelected(MenuEvent a) {
394 if(!(a.getSource() instanceof JMenu))
395 return;
396 final JPopupMenu m = ((JMenu) a.getSource()).getPopupMenu();
397 for(int i=0; i < m.getComponentCount()-1; i++) {
398 if(!(m.getComponent(i) instanceof JSeparator)) {
399 continue;
400 }
401 // hide separator if the next menu item is one as well
402 ((JSeparator) m.getComponent(i)).setVisible(!(m.getComponent(i+1) instanceof JSeparator));
403 }
404 // hide separator at the end of the menu
405 if(m.getComponent(m.getComponentCount()-1) instanceof JSeparator) {
406 ((JSeparator) m.getComponent(m.getComponentCount()-1)).setVisible(false);
407 }
408 }
409 };
410
411 /**
412 * @since 6088
413 * @return the default position of tnew top-level menus
414 */
415 public int getDefaultMenuPos() {
416 return defaultMenuPos;
417 }
418
419 /**
420 * Add a JosmAction at the end of a menu.
421 *
422 * This method handles all the shortcut handling. It also makes sure that actions that are
423 * handled by the OS are not duplicated on the menu.
424 * @param menu the menu to add the action to
425 * @param action the action that should get a menu item
426 * @return the created menu item
427 */
428 public static JMenuItem add(JMenu menu, JosmAction action) {
429 return add(menu, action, false);
430 }
431
432 /**
433 * Add a JosmAction at the end of a menu.
434 *
435 * This method handles all the shortcut handling. It also makes sure that actions that are
436 * handled by the OS are not duplicated on the menu.
437 * @param menu the menu to add the action to
438 * @param action the action that should get a menu item
439 * @param isExpert whether the entry should only be visible if the expert mode is activated
440 * @return the created menu item
441 */
442 public static JMenuItem add(JMenu menu, JosmAction action, boolean isExpert) {
443 return add(menu, action, isExpert, null);
444 }
445
446 /**
447 * Add a JosmAction at the end of a menu.
448 *
449 * This method handles all the shortcut handling. It also makes sure that actions that are
450 * handled by the OS are not duplicated on the menu.
451 * @param menu the menu to add the action to
452 * @param action the action that should get a menu item
453 * @param isExpert whether the entry should only be visible if the expert mode is activated
454 * @param index an integer specifying the position at which to add the action
455 * @return the created menu item
456 */
457 public static JMenuItem add(JMenu menu, JosmAction action, boolean isExpert, Integer index) {
458 if (action.getShortcut().getAutomatic())
459 return null;
460 final JMenuItem menuitem;
461 if (index == null) {
462 menuitem = menu.add(action);
463 } else {
464 menuitem = menu.insert(action, index);
465 }
466 if (isExpert) {
467 ExpertToggleAction.addVisibilitySwitcher(menuitem);
468 }
469 KeyStroke ks = action.getShortcut().getKeyStroke();
470 if (ks != null) {
471 menuitem.setAccelerator(ks);
472 }
473 // some menus are hidden before they are populated with some items by plugins
474 if (!menu.isVisible()) menu.setVisible(true);
475 return menuitem;
476 }
477
478 /**
479 * Add the JosmAction {@code actionToBeInserted} directly below {@code existingMenuEntryAction}.
480 *
481 * This method handles all the shortcut handling. It also makes sure that actions that are
482 * handled by the OS are not duplicated on the menu.
483 * @param menu the menu to add the action to
484 * @param actionToBeInserted the action that should get a menu item directly below {@code existingMenuEntryAction}
485 * @param isExpert whether the entry should only be visible if the expert mode is activated
486 * @param existingMenuEntryAction an action already added to the menu {@code menu}, the action {@code actionToBeInserted} is added directly below
487 * @return the created menu item
488 */
489 public static JMenuItem addAfter(JMenu menu, JosmAction actionToBeInserted, boolean isExpert, JosmAction existingMenuEntryAction) {
490 int i = 0;
491 for (Component c : menu.getMenuComponents()) {
492 if (c instanceof JMenuItem && ((JMenuItem) c).getAction() == existingMenuEntryAction) {
493 break;
494 }
495 i++;
496 }
497 return add(menu, actionToBeInserted, isExpert, i + 1);
498 }
499
500 /**
501 * Add a JosmAction to a menu.
502 *
503 * This method handles all the shortcut handling. It also makes sure that actions that are
504 * handled by the OS are not duplicated on the menu.
505 * @param menu to add the action to
506 * @param action the action that should get a menu item
507 * @param group the item should be added to. Groups are split by a separator.
508 * 0 is the first group, -1 will add the item to the end.
509 * @return The created menu item
510 */
511 public static <E extends Enum<E>> JMenuItem add(JMenu menu, JosmAction action, Enum<E> group) {
512 if (action.getShortcut().getAutomatic())
513 return null;
514 int i = getInsertionIndexForGroup(menu, group.ordinal());
515 JMenuItem menuitem = (JMenuItem) menu.add(new JMenuItem(action), i);
516 KeyStroke ks = action.getShortcut().getKeyStroke();
517 if (ks != null) {
518 menuitem.setAccelerator(ks);
519 }
520 return menuitem;
521 }
522
523 /**
524 * Add a JosmAction to a menu and automatically prints accelerator if available.
525 * Also adds a checkbox that may be toggled.
526 * @param menu to add the action to
527 * @param action the action that should get a menu item
528 * @param group the item should be added to. Groups are split by a separator. Use
529 * one of the enums that are defined for some of the menus to tell in which
530 * group the item should go.
531 * @return The created menu item
532 */
533 public static <E extends Enum<E>> JCheckBoxMenuItem addWithCheckbox(JMenu menu, JosmAction action, Enum<E> group) {
534 int i = getInsertionIndexForGroup(menu, group.ordinal());
535 final JCheckBoxMenuItem mi = (JCheckBoxMenuItem) menu.add(new JCheckBoxMenuItem(action), i);
536 final KeyStroke ks = action.getShortcut().getKeyStroke();
537 if (ks != null) {
538 mi.setAccelerator(ks);
539 }
540 return mi;
541 }
542
543 /** finds the correct insertion index for a given group and adds separators if necessary */
544 private static int getInsertionIndexForGroup(JMenu menu, int group) {
545 if(group < 0)
546 return -1;
547 // look for separator that *ends* the group (or stop at end of menu)
548 int i;
549 for(i=0; i < menu.getItemCount() && group >= 0; i++) {
550 if(menu.getItem(i) == null) {
551 group--;
552 }
553 }
554 // insert before separator that ends the group
555 if(group < 0) {
556 i--;
557 }
558 // not enough separators have been found, add them
559 while(group > 0) {
560 menu.addSeparator();
561 group--;
562 i++;
563 }
564 return i;
565 }
566
567 public JMenu addMenu(String name, int mnemonicKey, int position, String relativeHelpTopic) {
568 final JMenu menu = new JMenu(tr(name));
569 int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
570 int menuItemHeight = new JMenu().add(newAction).getPreferredSize().height;
571 MenuScroller.setScrollerFor(menu, screenHeight / menuItemHeight);
572 return addMenu(menu, name, mnemonicKey, position, relativeHelpTopic);
573 }
574
575 public <T extends JMenu> T addMenu(T menu, String name, int mnemonicKey, int position, String relativeHelpTopic) {
576 Shortcut.registerShortcut("menu:" + name, tr("Menu: {0}", tr(name)), mnemonicKey,
577 Shortcut.MNEMONIC).setMnemonic(menu);
578 add(menu, position);
579 menu.putClientProperty("help", relativeHelpTopic);
580 return menu;
581 }
582
583 /**
584 * Constructs a new {@code MainMenu}.
585 */
586 public MainMenu() {
587 JMenuItem current;
588
589 moreToolsMenu.setVisible(false);
590 dataMenu.setVisible(false);
591 gpsMenu.setVisible(false);
592
593 add(fileMenu, newAction);
594 add(fileMenu, openFile);
595 fileMenu.add(recentlyOpened);
596 add(fileMenu, openLocation);
597 fileMenu.addSeparator();
598 add(fileMenu, save);
599 add(fileMenu, saveAs);
600 sessionMenu.setToolTipText(tr("Save and load the current session (list of layers, etc.)"));
601 sessionMenu.setIcon(ImageProvider.get("session"));
602 sessionSaveAs = new SessionSaveAsAction();
603 sessionLoad = new SessionLoadAction();
604 add(sessionMenu, sessionSaveAs);
605 add(sessionMenu, sessionLoad);
606 fileMenu.add(sessionMenu);
607 ExpertToggleAction.addVisibilitySwitcher(sessionMenu);
608 add(fileMenu, gpxExport, true);
609 fileMenu.addSeparator();
610 add(fileMenu, download);
611 add(fileMenu, downloadPrimitive);
612 add(fileMenu, downloadReferrers);
613 add(fileMenu, update);
614 add(fileMenu, updateSelection);
615 add(fileMenu, updateModified);
616 fileMenu.addSeparator();
617 add(fileMenu, upload);
618 add(fileMenu, uploadSelection);
619 Component sep = new JPopupMenu.Separator();
620 fileMenu.add(sep);
621 ExpertToggleAction.addVisibilitySwitcher(sep);
622 add(fileMenu, closeChangesetAction, true);
623 fileMenu.addSeparator();
624 add(fileMenu, restart);
625 add(fileMenu, exit);
626
627 add(editMenu, undo);
628 Main.main.undoRedo.addCommandQueueListener(undo);
629 add(editMenu, redo);
630 Main.main.undoRedo.addCommandQueueListener(redo);
631 editMenu.addSeparator();
632 add(editMenu, copy);
633 add(editMenu, copyCoordinates, true);
634 add(editMenu, paste);
635 add(editMenu, pasteTags);
636 add(editMenu, duplicate);
637 add(editMenu, delete);
638 add(editMenu, purge, true);
639 editMenu.addSeparator();
640 add(editMenu,merge);
641 add(editMenu,mergeSelected);
642 editMenu.addSeparator();
643 add(editMenu, search);
644 add(editMenu, presetSearchPrimitiveAction);
645 editMenu.addSeparator();
646 add(editMenu, preferences);
647
648 // -- wireframe toggle action
649 final JCheckBoxMenuItem wireframe = new JCheckBoxMenuItem(wireFrameToggleAction);
650 viewMenu.add(wireframe);
651 wireframe.setAccelerator(wireFrameToggleAction.getShortcut().getKeyStroke());
652 wireFrameToggleAction.addButtonModel(wireframe.getModel());
653
654 viewMenu.add(new MapPaintMenu());
655 viewMenu.addSeparator();
656 add(viewMenu, new ZoomInAction());
657 add(viewMenu, new ZoomOutAction());
658 viewMenu.addSeparator();
659 for (String mode : AutoScaleAction.MODES) {
660 AutoScaleAction autoScaleAction = new AutoScaleAction(mode);
661 autoScaleActions.put(mode, autoScaleAction);
662 add(viewMenu, autoScaleAction);
663 }
664
665 // -- viewport follow toggle action
666 ViewportFollowToggleAction viewportFollowToggleAction = new ViewportFollowToggleAction();
667 final JCheckBoxMenuItem vft = new JCheckBoxMenuItem(viewportFollowToggleAction);
668 ExpertToggleAction.addVisibilitySwitcher(vft);
669 viewMenu.add(vft);
670 vft.setAccelerator(viewportFollowToggleAction.getShortcut().getKeyStroke());
671 viewportFollowToggleAction.addButtonModel(vft.getModel());
672
673 if(!Main.applet && Main.platform.canFullscreen()) {
674 // -- fullscreen toggle action
675 fullscreenToggleAction = new FullscreenToggleAction();
676 final JCheckBoxMenuItem fullscreen = new JCheckBoxMenuItem(fullscreenToggleAction);
677 viewMenu.addSeparator();
678 viewMenu.add(fullscreen);
679 fullscreen.setAccelerator(fullscreenToggleAction.getShortcut().getKeyStroke());
680 fullscreenToggleAction.addButtonModel(fullscreen.getModel());
681 }
682
683 // -- dialogs panel toggle action
684 final JCheckBoxMenuItem dialogsToggle = new JCheckBoxMenuItem(dialogsToggleAction);
685 dialogsToggle.setAccelerator(dialogsToggleAction.getShortcut().getKeyStroke());
686 dialogsToggleAction.addButtonModel(dialogsToggle.getModel());
687 viewMenu.add(dialogsToggle);
688
689 add(viewMenu, jumpToAct, true);
690 viewMenu.addSeparator();
691 add(viewMenu, info);
692 add(viewMenu, infoweb);
693 add(viewMenu, historyinfo);
694 add(viewMenu, historyinfoweb);
695 viewMenu.addSeparator();
696 viewMenu.add(new PreferenceToggleAction(tr("Edit toolbar"),
697 tr("Toggles the visibility of the edit toolbar (i.e., the vertical tool)"),
698 "sidetoolbar.visible", true).getCheckbox());
699 // -- expert mode toggle action
700 final JCheckBoxMenuItem expertItem = new JCheckBoxMenuItem(ExpertToggleAction.getInstance());
701 viewMenu.add(expertItem);
702 ExpertToggleAction.getInstance().addButtonModel(expertItem.getModel());
703
704 add(presetsMenu, presetSearchAction);
705 add(presetsMenu, presetSearchPrimitiveAction);
706 add(presetsMenu, PreferencesAction.forPreferenceSubTab(tr("Preset preferences"),
707 tr("Click to open the tagging presets tab in the preferences"), TaggingPresetPreference.class));
708 presetsMenu.addSeparator();
709
710 add(imageryMenu, PreferencesAction.forPreferenceTab(tr("Imagery preferences"),
711 tr("Click to open the imagery tab in the preferences"), ImageryPreference.class));
712
713 add(selectionMenu, selectAll);
714 add(selectionMenu, unselectAll);
715 add(selectionMenu, nonBranchingWaySequences);
716
717 add(toolsMenu, splitWay);
718 add(toolsMenu, combineWay);
719 toolsMenu.addSeparator();
720 add(toolsMenu, reverseWay);
721 add(toolsMenu, simplifyWay);
722 toolsMenu.addSeparator();
723 add(toolsMenu, alignInCircle);
724 add(toolsMenu, alignInLine);
725 add(toolsMenu, distribute);
726 add(toolsMenu, ortho);
727 add(toolsMenu, mirror, true);
728 toolsMenu.addSeparator();
729 add(toolsMenu, followLine, true);
730 add(toolsMenu, addNode, true);
731 add(toolsMenu, moveNode, true);
732 add(toolsMenu, createCircle);
733 toolsMenu.addSeparator();
734 add(toolsMenu, mergeNodes);
735 add(toolsMenu, joinNodeWay);
736 add(toolsMenu, unJoinNodeWay);
737 add(toolsMenu, unglueNodes);
738 toolsMenu.addSeparator();
739 add(toolsMenu, joinAreas);
740 add(toolsMenu, createMultipolygon);
741 add(toolsMenu, updateMultipolygon);
742
743 // -- changeset manager toggle action
744 final JCheckBoxMenuItem mi = MainMenu.addWithCheckbox(windowMenu, changesetManager,
745 MainMenu.WINDOW_MENU_GROUP.ALWAYS);
746 changesetManager.addButtonModel(mi.getModel());
747
748 if (!Main.pref.getBoolean("audio.menuinvisible", false)) {
749 showAudioMenu(true);
750 }
751
752 Main.pref.addPreferenceChangeListener(new PreferenceChangedListener() {
753 @Override
754 public void preferenceChanged(PreferenceChangeEvent e) {
755 if (e.getKey().equals("audio.menuinvisible")) {
756 showAudioMenu(!Boolean.parseBoolean(e.getNewValue().toString()));
757 }
758 }
759 });
760
761 helpMenu.add(statusreport);
762
763 current = helpMenu.add(help); // FIXME why is help not a JosmAction?
764 current.setAccelerator(Shortcut.registerShortcut("system:help", tr("Help"), KeyEvent.VK_F1,
765 Shortcut.DIRECT).getKeyStroke());
766 add(helpMenu, about);
767
768
769 windowMenu.addMenuListener(menuSeparatorHandler);
770
771 new PresetsMenuEnabler(presetsMenu).refreshEnabled();
772 }
773
774 protected void showAudioMenu(boolean showMenu) {
775 if (showMenu && audioMenu == null) {
776 audioMenu = addMenu(marktr("Audio"), KeyEvent.VK_U, defaultMenuPos, ht("/Menu/Audio"));
777 add(audioMenu, audioPlayPause);
778 add(audioMenu, audioNext);
779 add(audioMenu, audioPrev);
780 add(audioMenu, audioFwd);
781 add(audioMenu, audioBack);
782 add(audioMenu, audioSlower);
783 add(audioMenu, audioFaster);
784 validate();
785 } else if (!showMenu && audioMenu != null) {
786 remove(audioMenu);
787 audioMenu.removeAll();
788 audioMenu = null;
789 validate();
790 }
791 }
792
793 static class PresetsMenuEnabler implements MapView.LayerChangeListener {
794 private JMenu presetsMenu;
795 public PresetsMenuEnabler(JMenu presetsMenu) {
796 MapView.addLayerChangeListener(this);
797 this.presetsMenu = presetsMenu;
798 }
799 /**
800 * Refreshes the enabled state
801 */
802 protected void refreshEnabled() {
803 presetsMenu.setEnabled(Main.main.hasEditLayer());
804 }
805
806 @Override
807 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
808 refreshEnabled();
809 }
810
811 @Override
812 public void layerAdded(Layer newLayer) {
813 refreshEnabled();
814 }
815
816 @Override
817 public void layerRemoved(Layer oldLayer) {
818 refreshEnabled();
819 }
820 }
821}
Note: See TracBrowser for help on using the repository browser.