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

Last change on this file was 19176, checked in by taylor.smock, 7 weeks ago

Fix #11487: Have josm render data to tiles

This adds a new rendering method that renders async. This avoids blocking the UI.

Where this is useful:

  • Large datasets (think county or country level)

Where this is not useful:

  • Micromapping -- the tiles aren't being rendered exactly where they should be and there are some minor rendering artifacts.

Known issues:

  • Some tiles aren't exactly where they should be (off by a pixel or two -- by default, we use the old render method at z16+)
  • Rendering of tiles is slow -- there is some prework done to render tiles in batches. The primary reason rendering is slow is we are effectively rendering 25 total tiles (to avoid movement of text, we render 2 tiles in each directory and only keep the middle one)
  • Due to the above speed issue, hovering over an object will cause the highlight to render in slowly.

New advanced preferences:

  • mappaint.fast_render.tile_size -- controls the number of pixels in a tile
  • mappaint.fast_render.zlevel -- controls the maximum z level at which tiles are generated
  • Property svn:eol-style set to native
File size: 46.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trc;
7
8import java.awt.Component;
9import java.awt.GraphicsEnvironment;
10import java.awt.event.KeyEvent;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collection;
14import java.util.EnumMap;
15import java.util.List;
16import java.util.Locale;
17import java.util.Map;
18import java.util.Objects;
19import java.util.Optional;
20
21import javax.swing.JCheckBoxMenuItem;
22import javax.swing.JMenu;
23import javax.swing.JMenuBar;
24import javax.swing.JMenuItem;
25import javax.swing.JPopupMenu;
26import javax.swing.JSeparator;
27import javax.swing.KeyStroke;
28import javax.swing.event.MenuEvent;
29import javax.swing.event.MenuListener;
30
31import org.openstreetmap.josm.actions.AboutAction;
32import org.openstreetmap.josm.actions.AddNodeAction;
33import org.openstreetmap.josm.actions.AlignInCircleAction;
34import org.openstreetmap.josm.actions.AlignInLineAction;
35import org.openstreetmap.josm.actions.AutoScaleAction;
36import org.openstreetmap.josm.actions.AutoScaleAction.AutoScaleMode;
37import org.openstreetmap.josm.actions.ChangesetManagerToggleAction;
38import org.openstreetmap.josm.actions.CloseChangesetAction;
39import org.openstreetmap.josm.actions.CombineWayAction;
40import org.openstreetmap.josm.actions.CopyAction;
41import org.openstreetmap.josm.actions.CopyCoordinatesAction;
42import org.openstreetmap.josm.actions.CopyUrlAction;
43import org.openstreetmap.josm.actions.CreateCircleAction;
44import org.openstreetmap.josm.actions.CreateMultipolygonAction;
45import org.openstreetmap.josm.actions.DeleteAction;
46import org.openstreetmap.josm.actions.DeleteLayerAction;
47import org.openstreetmap.josm.actions.DialogsToggleAction;
48import org.openstreetmap.josm.actions.DistributeAction;
49import org.openstreetmap.josm.actions.DownloadAction;
50import org.openstreetmap.josm.actions.DownloadAlongWayAction;
51import org.openstreetmap.josm.actions.DownloadNotesInViewAction;
52import org.openstreetmap.josm.actions.DownloadOsmInViewAction;
53import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
54import org.openstreetmap.josm.actions.DownloadReferrersAction;
55import org.openstreetmap.josm.actions.DrawBoundariesOfDownloadedDataAction;
56import org.openstreetmap.josm.actions.DuplicateAction;
57import org.openstreetmap.josm.actions.ExitAction;
58import org.openstreetmap.josm.actions.ExpertToggleAction;
59import org.openstreetmap.josm.actions.FollowLineAction;
60import org.openstreetmap.josm.actions.FullscreenToggleAction;
61import org.openstreetmap.josm.actions.GpxExportAction;
62import org.openstreetmap.josm.actions.HelpAction;
63import org.openstreetmap.josm.actions.HistoryInfoAction;
64import org.openstreetmap.josm.actions.HistoryInfoWebAction;
65import org.openstreetmap.josm.actions.InfoAction;
66import org.openstreetmap.josm.actions.InfoWebAction;
67import org.openstreetmap.josm.actions.InvertSelectionAction;
68import org.openstreetmap.josm.actions.JoinAreasAction;
69import org.openstreetmap.josm.actions.JoinNodeWayAction;
70import org.openstreetmap.josm.actions.JosmAction;
71import org.openstreetmap.josm.actions.JumpToAction;
72import org.openstreetmap.josm.actions.MergeLayerAction;
73import org.openstreetmap.josm.actions.MergeNodesAction;
74import org.openstreetmap.josm.actions.MergeSelectionAction;
75import org.openstreetmap.josm.actions.MirrorAction;
76import org.openstreetmap.josm.actions.MoveAction;
77import org.openstreetmap.josm.actions.MoveNodeAction;
78import org.openstreetmap.josm.actions.NewAction;
79import org.openstreetmap.josm.actions.OpenFileAction;
80import org.openstreetmap.josm.actions.OpenLocationAction;
81import org.openstreetmap.josm.actions.OrthogonalizeAction;
82import org.openstreetmap.josm.actions.OrthogonalizeAction.Undo;
83import org.openstreetmap.josm.actions.PasteAction;
84import org.openstreetmap.josm.actions.PasteAtSourcePositionAction;
85import org.openstreetmap.josm.actions.PasteTagsAction;
86import org.openstreetmap.josm.actions.PreferenceToggleAction;
87import org.openstreetmap.josm.actions.PreferencesAction;
88import org.openstreetmap.josm.actions.PurgeAction;
89import org.openstreetmap.josm.actions.RedoAction;
90import org.openstreetmap.josm.actions.ReorderImageryLayersAction;
91import org.openstreetmap.josm.actions.ReportBugAction;
92import org.openstreetmap.josm.actions.RestartAction;
93import org.openstreetmap.josm.actions.ReverseWayAction;
94import org.openstreetmap.josm.actions.SaveAction;
95import org.openstreetmap.josm.actions.SaveAsAction;
96import org.openstreetmap.josm.actions.SearchNotesDownloadAction;
97import org.openstreetmap.josm.actions.SelectAllAction;
98import org.openstreetmap.josm.actions.SelectNonBranchingWaySequencesAction;
99import org.openstreetmap.josm.actions.SelectSharedChildObjectsAction;
100import org.openstreetmap.josm.actions.SessionSaveAction;
101import org.openstreetmap.josm.actions.SessionSaveAsAction;
102import org.openstreetmap.josm.actions.ShowStatusReportAction;
103import org.openstreetmap.josm.actions.SimplifyWayAction;
104import org.openstreetmap.josm.actions.SplitWayAction;
105import org.openstreetmap.josm.actions.TaggingPresetSearchAction;
106import org.openstreetmap.josm.actions.TiledRenderToggleAction;
107import org.openstreetmap.josm.actions.UnGlueAction;
108import org.openstreetmap.josm.actions.UnJoinNodeWayAction;
109import org.openstreetmap.josm.actions.UndoAction;
110import org.openstreetmap.josm.actions.UnselectAllAction;
111import org.openstreetmap.josm.actions.UpdateDataAction;
112import org.openstreetmap.josm.actions.UpdateModifiedAction;
113import org.openstreetmap.josm.actions.UpdateSelectionAction;
114import org.openstreetmap.josm.actions.UploadAction;
115import org.openstreetmap.josm.actions.UploadSelectionAction;
116import org.openstreetmap.josm.actions.ViewportFollowToggleAction;
117import org.openstreetmap.josm.actions.WireframeToggleAction;
118import org.openstreetmap.josm.actions.ZoomInAction;
119import org.openstreetmap.josm.actions.ZoomOutAction;
120import org.openstreetmap.josm.actions.audio.AudioBackAction;
121import org.openstreetmap.josm.actions.audio.AudioFasterAction;
122import org.openstreetmap.josm.actions.audio.AudioFwdAction;
123import org.openstreetmap.josm.actions.audio.AudioNextAction;
124import org.openstreetmap.josm.actions.audio.AudioPlayPauseAction;
125import org.openstreetmap.josm.actions.audio.AudioPrevAction;
126import org.openstreetmap.josm.actions.audio.AudioSlowerAction;
127import org.openstreetmap.josm.actions.mapmode.MapMode;
128import org.openstreetmap.josm.actions.search.SearchAction;
129import org.openstreetmap.josm.data.UndoRedoHandler;
130import org.openstreetmap.josm.gui.dialogs.MenuItemSearchDialog;
131import org.openstreetmap.josm.gui.io.OnlineResourceMenu;
132import org.openstreetmap.josm.gui.io.RecentlyOpenedFilesMenu;
133import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
134import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
135import org.openstreetmap.josm.gui.layer.geoimage.WikimediaCommonsLoader.WikimediaCommonsLoadImagesAction;
136import org.openstreetmap.josm.gui.mappaint.MapPaintMenu;
137import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
138import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetSearchPrimitiveDialog;
139import org.openstreetmap.josm.spi.preferences.Config;
140import org.openstreetmap.josm.tools.ImageProvider;
141import org.openstreetmap.josm.tools.PlatformManager;
142import org.openstreetmap.josm.tools.Shortcut;
143
144/**
145 * This is the JOSM main menu bar. It is overwritten to initialize itself and provide all menu
146 * entries as member variables (sort of collect them).
147 * <p>
148 * It also provides possibilities to attach new menu entries (used by plugins).
149 *
150 * @author Immanuel.Scholz
151 */
152public class MainMenu extends JMenuBar {
153
154 /**
155 * The possible item groups of the Windows menu.
156 * @see MainMenu#addWithCheckbox
157 */
158 public enum WINDOW_MENU_GROUP {
159 /** Entries always displayed, at the top */
160 ALWAYS,
161 /** Entries displayed only for visible toggle dialogs */
162 TOGGLE_DIALOG,
163 /** Volatile entries displayed at the end */
164 VOLATILE
165 }
166
167 /* File menu */
168 /** File / New Layer **/
169 public final NewAction newAction = new NewAction();
170 /** File / Open... **/
171 public final OpenFileAction openFile = new OpenFileAction();
172 /** File / Open Recent &gt; **/
173 public final RecentlyOpenedFilesMenu recentlyOpened = new RecentlyOpenedFilesMenu();
174 /** File / Open Location... **/
175 public final OpenLocationAction openLocation = new OpenLocationAction();
176 /** File / Delete Layer **/
177 public final DeleteLayerAction deleteLayerAction = new DeleteLayerAction();
178 /** File / Save **/
179 public final SaveAction save = SaveAction.getInstance();
180 /** File / Save As... **/
181 public final SaveAsAction saveAs = SaveAsAction.getInstance();
182 /** File / Session &gt; Save Session **/
183 public final SessionSaveAction sessionSave = SessionSaveAction.getInstance();
184 /** File / Session &gt; Save Session As... **/
185 public final SessionSaveAsAction sessionSaveAs = new SessionSaveAsAction();
186 /** File / Export to GPX... **/
187 public final GpxExportAction gpxExport = new GpxExportAction();
188 /** File / Download from OSM... **/
189 public final DownloadAction download = new DownloadAction();
190 /** File / Download in current view **/
191 public final DownloadOsmInViewAction downloadInView = new DownloadOsmInViewAction();
192 /** File / Download object... **/
193 public final DownloadPrimitiveAction downloadPrimitive = new DownloadPrimitiveAction();
194 /** File / Download notes in current view **/
195 public final DownloadNotesInViewAction downloadNotesInView = DownloadNotesInViewAction.newActionWithNoteIcon();
196 /** File / Search Notes... **/
197 public final SearchNotesDownloadAction searchNotes = new SearchNotesDownloadAction();
198 /** File / Download parent ways/relations... **/
199 public final DownloadReferrersAction downloadReferrers = new DownloadReferrersAction();
200 /** File / Close open changesets... **/
201 public final CloseChangesetAction closeChangesetAction = new CloseChangesetAction();
202 /** File / Update data **/
203 public final JosmAction update = new UpdateDataAction();
204 /** File / Update selection **/
205 public final JosmAction updateSelection = new UpdateSelectionAction();
206 /** File / Update modified **/
207 public final JosmAction updateModified = new UpdateModifiedAction();
208 /** File / Upload data **/
209 public final JosmAction upload = new UploadAction();
210 /** File / Upload selection **/
211 public final JosmAction uploadSelection = new UploadSelectionAction();
212 /** File / Restart **/
213 public final RestartAction restart = new RestartAction();
214 /** File / Exit **/
215 public final ExitAction exit = new ExitAction();
216
217 /* Edit menu */
218 /** Edit / Undo... */
219 public final UndoAction undo = new UndoAction();
220 /** Edit / Redo */
221 public final RedoAction redo = new RedoAction();
222 /** Edit / Copy */
223 public final CopyAction copy = new CopyAction();
224 /** Edit / Copy URLs*/
225 public final CopyUrlAction copyUrl = new CopyUrlAction();
226 /** Edit / Copy Coordinates */
227 public final JosmAction copyCoordinates = new CopyCoordinatesAction();
228 /** Edit / Paste */
229 public final PasteAction paste = new PasteAction();
230 /** Edit / Paste at source */
231 private final PasteAtSourcePositionAction pasteAtSource = new PasteAtSourcePositionAction();
232 /** Edit / Paste Tags */
233 public final PasteTagsAction pasteTags = new PasteTagsAction();
234 /** Edit / Duplicate */
235 public final DuplicateAction duplicate = new DuplicateAction();
236 /** Edit / Delete */
237 public final DeleteAction delete = new DeleteAction();
238 /** Edit / Purge... */
239 public final JosmAction purge = new PurgeAction();
240 /** Edit / Merge layer */
241 public final MergeLayerAction merge = new MergeLayerAction();
242 /** Edit / Merge selection */
243 public final MergeSelectionAction mergeSelected = new MergeSelectionAction();
244 /** Edit / Search... */
245 public final SearchAction search = new SearchAction();
246 /** Edit / Preferences */
247 public final PreferencesAction preferences = new PreferencesAction();
248
249 /* View menu */
250 /** View / Wireframe View */
251 public final WireframeToggleAction wireFrameToggleAction = new WireframeToggleAction();
252 /** View / Tiled Rendering */
253 public final TiledRenderToggleAction tiledRenderToggleAction = new TiledRenderToggleAction();
254 /** View / Hatch area outside download */
255 public final DrawBoundariesOfDownloadedDataAction drawBoundariesOfDownloadedDataAction = new DrawBoundariesOfDownloadedDataAction();
256 /** View / Advanced info */
257 public final InfoAction info = new InfoAction();
258 /** View / Advanced info (web) */
259 public final InfoWebAction infoweb = new InfoWebAction();
260 /** View / History */
261 public final HistoryInfoAction historyinfo = new HistoryInfoAction();
262 /** View / History (web) */
263 public final HistoryInfoWebAction historyinfoweb = new HistoryInfoWebAction();
264 /** View / "Zoom to"... actions */
265 public final Map<AutoScaleMode, AutoScaleAction> autoScaleActions = new EnumMap<>(AutoScaleMode.class);
266 /** View / Jump to position */
267 public final JumpToAction jumpToAct = new JumpToAction();
268
269 /* Tools menu */
270 /** Tools / Split Way */
271 public final SplitWayAction splitWay = new SplitWayAction();
272 /** Tools / Combine Way */
273 public final CombineWayAction combineWay = new CombineWayAction();
274 /** Tools / Reverse Ways */
275 public final ReverseWayAction reverseWay = new ReverseWayAction();
276 /** Tools / Simplify Way */
277 public final SimplifyWayAction simplifyWay = new SimplifyWayAction();
278 /** Tools / Align Nodes in Circle */
279 public final AlignInCircleAction alignInCircle = new AlignInCircleAction();
280 /** Tools / Align Nodes in Line */
281 public final AlignInLineAction alignInLine = new AlignInLineAction();
282 /** Tools / Distribute Nodes */
283 public final DistributeAction distribute = new DistributeAction();
284 /** Tools / Orthogonalize Shape */
285 public final OrthogonalizeAction ortho = new OrthogonalizeAction();
286 /** Orthogonalize undo. Action is not shown in the menu. Only triggered by shortcut */
287 public final Undo orthoUndo = new Undo();
288 /** Tools / Mirror */
289 public final MirrorAction mirror = new MirrorAction();
290 /** Tools / Follow line */
291 public final FollowLineAction followLine = new FollowLineAction();
292 /** Tools / Add Node... */
293 public final AddNodeAction addNode = new AddNodeAction();
294 /** Tools / Move Node... */
295 public final MoveNodeAction moveNode = new MoveNodeAction();
296 /** Tools / Create Circle */
297 public final CreateCircleAction createCircle = new CreateCircleAction();
298 /** Tools / Merge Nodes */
299 public final MergeNodesAction mergeNodes = new MergeNodesAction();
300 /** Tools / Join Node to Way */
301 public final JoinNodeWayAction joinNodeWay = JoinNodeWayAction.createJoinNodeToWayAction();
302 /** Tools / Join Way to Node */
303 public final JoinNodeWayAction moveNodeOntoWay = JoinNodeWayAction.createMoveNodeOntoWayAction();
304 /** Tools / Disconnect Node from Way */
305 public final UnJoinNodeWayAction unJoinNodeWay = new UnJoinNodeWayAction();
306 /** Tools / Unglue Ways */
307 public final UnGlueAction unglueNodes = new UnGlueAction();
308 /** Tools / Join overlapping Areas */
309 public final JoinAreasAction joinAreas = new JoinAreasAction();
310 /** Tools / Create multipolygon */
311 public final CreateMultipolygonAction createMultipolygon = new CreateMultipolygonAction(false);
312 /** Tools / Update multipolygon */
313 public final CreateMultipolygonAction updateMultipolygon = new CreateMultipolygonAction(true);
314 /** Tools / Download along way */
315 public final DownloadAlongWayAction downloadAlongWay = new DownloadAlongWayAction();
316
317 /* Selection menu */
318 /** Selection / Select All */
319 public final SelectAllAction selectAll = new SelectAllAction();
320 /** Selection / Unselect All */
321 public final UnselectAllAction unselectAll = new UnselectAllAction();
322 /** Selection / Invert Selection */
323 public final InvertSelectionAction invertSelection = new InvertSelectionAction();
324 /** Selection / Non-branching way sequences */
325 public final SelectNonBranchingWaySequencesAction nonBranchingWaySequences = new SelectNonBranchingWaySequencesAction();
326 /** Selection / Shared Child Objects */
327 public final SelectSharedChildObjectsAction sharedChildObjects = new SelectSharedChildObjectsAction();
328
329 /* Audio menu */
330 /** Audio / Play/Pause */
331 public final JosmAction audioPlayPause = new AudioPlayPauseAction();
332 /** Audio / Next marker */
333 public final JosmAction audioNext = new AudioNextAction();
334 /** Audio / Previous Marker */
335 public final JosmAction audioPrev = new AudioPrevAction();
336 /** Audio / Forward */
337 public final JosmAction audioFwd = new AudioFwdAction();
338 /** Audio / Back */
339 public final JosmAction audioBack = new AudioBackAction();
340 /** Audio / Faster */
341 public final JosmAction audioFaster = new AudioFasterAction();
342 /** Audio / Slower */
343 public final JosmAction audioSlower = new AudioSlowerAction();
344
345 /* Windows Menu */
346 /** Windows / Changeset Manager */
347 public final ChangesetManagerToggleAction changesetManager = new ChangesetManagerToggleAction();
348
349 /* Help menu */
350 /** Help / Help */
351 public final HelpAction help = new HelpAction();
352 /** Help / About */
353 public final AboutAction about = new AboutAction();
354 /** Help / Show Status Report */
355 public final ShowStatusReportAction statusreport = new ShowStatusReportAction();
356 /** Help / Report bug */
357 public final ReportBugAction reportbug = new ReportBugAction();
358
359 /**
360 * fileMenu contains I/O actions
361 */
362 public final JMenu fileMenu = addMenu("File", /* I18N: mnemonic: F */ trc("menu", "File"), KeyEvent.VK_F, 0, ht("/Menu/File"));
363 /**
364 * editMenu contains editing actions
365 */
366 public final JMenu editMenu = addMenu("Edit", /* I18N: mnemonic: E */ trc("menu", "Edit"), KeyEvent.VK_E, 1, ht("/Menu/Edit"));
367 /**
368 * viewMenu contains display actions (zoom, map styles, etc.)
369 */
370 public final JMenu viewMenu = addMenu("View", /* I18N: mnemonic: V */ trc("menu", "View"), KeyEvent.VK_V, 2, ht("/Menu/View"));
371 /**
372 * modeMenu contains map modes
373 */
374 public final JMenu modeMenu = addMenu(new ModeMenu(), /* I18N: mnemonic: M */ trc("menu", "Mode"), KeyEvent.VK_M, 3, ht("/Menu/Mode"));
375 /**
376 * toolsMenu contains different geometry manipulation actions from JOSM core (most used)
377 * The plugins should use other menus
378 */
379 public final JMenu toolsMenu = addMenu("Tools", /* I18N: mnemonic: T */ trc("menu", "Tools"), KeyEvent.VK_T, 4, ht("/Menu/Tools"));
380 /**
381 * moreToolsMenu contains geometry-related actions from all the plugins
382 * @since 6082 (moved from Utilsplugin2)
383 */
384 // CHECKSTYLE.OFF: LineLength
385 public final JMenu moreToolsMenu = addMenu("More tools", /* I18N: mnemonic: O */ trc("menu", "More tools"), KeyEvent.VK_O, 5, ht("/Menu/MoreTools"));
386 /**
387 * dataMenu contains plugin actions that are related to certain tagging schemes (addressing opening hours),
388 * importing external data and using external web APIs
389 * @since 6082
390 */
391 public final JMenu dataMenu = addMenu("Data", /* I18N: mnemonic: D */ trc("menu", "Data"), KeyEvent.VK_D, 6, ht("/Menu/Data"));
392 /**
393 * selectionMenu contains all actions related to selecting different objects
394 * @since 6082 (moved from Utilsplugin2)
395 */
396 public final JMenu selectionMenu = addMenu("Selection", /* I18N: mnemonic: N */ trc("menu", "Selection"), KeyEvent.VK_N, 7, ht("/Menu/Selection"));
397 /**
398 * presetsMenu contains presets actions (search, presets tree)
399 */
400 public final JMenu presetsMenu = addMenu("Presets", /* I18N: mnemonic: P */ trc("menu", "Presets"), KeyEvent.VK_P, 8, ht("/Menu/Presets"));
401 /**
402 * submenu in Imagery menu that contains plugin-managed additional imagery layers
403 * @since 6097
404 */
405 public final JMenu imagerySubMenu = new JMenu(tr("More..."));
406 /**
407 * imageryMenu contains all imagery-related actions
408 */
409 public final ImageryMenu imageryMenu = addMenu(new ImageryMenu(imagerySubMenu), /* untranslated name */ "Imagery", KeyEvent.VK_I, 9, ht("/Menu/Imagery"));
410 /**
411 * gpsMenu contains all plugin actions that are related
412 * to using GPS data, including opening, uploading and real-time tracking
413 * @since 6082
414 */
415 public final JMenu gpsMenu = addMenu("GPS", /* I18N: mnemonic: G */ trc("menu", "GPS"), KeyEvent.VK_G, 10, ht("/Menu/GPS"));
416 /** the window menu is split into several groups. The first is for windows that can be opened from
417 * this menu any time, e.g. the changeset editor. The second group is for toggle dialogs and the third
418 * group is for currently open windows that cannot be toggled, e.g. relation editors. It's recommended
419 * to use WINDOW_MENU_GROUP to determine the group integer.
420 */
421 public final WindowMenu windowMenu = addMenu(new WindowMenu(), /* untranslated name */ "Windows", KeyEvent.VK_W, 11, ht("/Menu/Windows"));
422 // CHECKSTYLE.ON: LineLength
423
424 /**
425 * audioMenu contains all audio-related actions. Be careful, this menu is not guaranteed to be displayed at all
426 */
427 public JMenu audioMenu;
428 /**
429 * helpMenu contains JOSM general actions (Help, About, etc.)
430 */
431 public final JMenu helpMenu = addMenu("Help", /* I18N: mnemonic: H */ trc("menu", "Help"), KeyEvent.VK_H, 12, ht("/Menu/Help"));
432
433 private static final int defaultMenuPos = 12;
434
435 /** Move the selection up */
436 public final JosmAction moveUpAction = new MoveAction(MoveAction.Direction.UP);
437 /** Move the selection down */
438 public final JosmAction moveDownAction = new MoveAction(MoveAction.Direction.DOWN);
439 /** Move the selection left */
440 public final JosmAction moveLeftAction = new MoveAction(MoveAction.Direction.LEFT);
441 /** Move the selection right */
442 public final JosmAction moveRightAction = new MoveAction(MoveAction.Direction.RIGHT);
443
444 /** Reorder imagery layers */
445 public final ReorderImageryLayersAction reorderImageryLayersAction = new ReorderImageryLayersAction();
446
447 /** Search tagging presets */
448 public final TaggingPresetSearchAction presetSearchAction = new TaggingPresetSearchAction();
449 /** Search objects by their tagging preset */
450 public final TaggingPresetSearchPrimitiveDialog.Action presetSearchPrimitiveAction = new TaggingPresetSearchPrimitiveDialog.Action();
451 /** Toggle visibility of dialogs panel */
452 public final DialogsToggleAction dialogsToggleAction = new DialogsToggleAction();
453 /** Toggle the full-screen mode */
454 public FullscreenToggleAction fullscreenToggleAction;
455
456 /** this menu listener hides unnecessary JSeparators in a menu list but does not remove them.
457 * If at a later time the separators are required, they will be made visible again. Intended
458 * usage is make menus not look broken if separators are used to group the menu and some of
459 * these groups are empty.
460 */
461 public static final MenuListener menuSeparatorHandler = new MenuListener() {
462 @Override
463 public void menuCanceled(MenuEvent e) {
464 // Do nothing
465 }
466
467 @Override
468 public void menuDeselected(MenuEvent e) {
469 // Do nothing
470 }
471
472 @Override
473 public void menuSelected(MenuEvent a) {
474 if (!(a.getSource() instanceof JMenu))
475 return;
476 final JPopupMenu m = ((JMenu) a.getSource()).getPopupMenu();
477 for (int i = 0; i < m.getComponentCount()-1; i++) {
478 // hide separator if the next menu item is one as well
479 if (m.getComponent(i) instanceof JSeparator && m.getComponent(i + 1) instanceof JSeparator) {
480 m.getComponent(i).setVisible(false);
481 }
482 }
483 // hide separator at the end of the menu
484 if (m.getComponent(m.getComponentCount() - 1) instanceof JSeparator) {
485 m.getComponent(m.getComponentCount() - 1).setVisible(false);
486 }
487 }
488 };
489
490 /**
491 * Returns the default position of new top-level menus.
492 * @return the default position of new top-level menus
493 * @since 6088
494 */
495 public int getDefaultMenuPos() {
496 return defaultMenuPos;
497 }
498
499 /**
500 * Add a JosmAction at the end of a menu.
501 * <p>
502 * This method handles all the shortcut handling. It also makes sure that actions that are
503 * handled by the OS are not duplicated on the menu.
504 * @param menu the menu to add the action to
505 * @param action the action that should get a menu item
506 * @return the created menu item
507 */
508 public static JMenuItem add(JMenu menu, JosmAction action) {
509 return add(menu, action, false);
510 }
511
512 /**
513 * Add a JosmAction at the end of a menu.
514 * <p>
515 * This method handles all the shortcut handling. It also makes sure that actions that are
516 * handled by the OS are not duplicated on the menu.
517 * @param menu the menu to add the action to
518 * @param action the action that should get a menu item
519 * @param isExpert whether the entry should only be visible if the expert mode is activated
520 * @return the created menu item
521 */
522 public static JMenuItem add(JMenu menu, JosmAction action, boolean isExpert) {
523 return add(menu, action, isExpert, null);
524 }
525
526 /**
527 * Add a JosmAction at the end of a menu.
528 * <p>
529 * This method handles all the shortcut handling. It also makes sure that actions that are
530 * handled by the OS are not duplicated on the menu.
531 * @param menu the menu to add the action to
532 * @param action the action that should get a menu item
533 * @param isExpert whether the entry should only be visible if the expert mode is activated
534 * @param index an integer specifying the position at which to add the action
535 * @return the created menu item
536 */
537 public static JMenuItem add(JMenu menu, JosmAction action, boolean isExpert, Integer index) {
538 if (action.getShortcut().isAutomatic())
539 return null;
540 final JMenuItem menuitem;
541 if (index == null) {
542 menuitem = menu.add(action);
543 } else {
544 menuitem = menu.insert(action, index);
545 }
546 if (isExpert) {
547 ExpertToggleAction.addVisibilitySwitcher(menuitem);
548 }
549 KeyStroke ks = action.getShortcut().getKeyStroke();
550 if (ks != null) {
551 menuitem.setAccelerator(ks);
552 }
553 // some menus are hidden before they are populated with some items by plugins
554 if (!menu.isVisible()) menu.setVisible(true);
555 return menuitem;
556 }
557
558 /**
559 * Add the JosmAction {@code actionToBeInserted} directly below {@code existingMenuEntryAction}.
560 * <p>
561 * This method handles all the shortcut handling. It also makes sure that actions that are
562 * handled by the OS are not duplicated on the menu.
563 * @param menu the menu to add the action to
564 * @param actionToBeInserted the action that should get a menu item directly below {@code existingMenuEntryAction}
565 * @param isExpert whether the entry should only be visible if the expert mode is activated
566 * @param existingMenuEntryAction an action already added to the menu {@code menu},
567 * the action {@code actionToBeInserted} is added directly below
568 * @return the created menu item
569 */
570 public static JMenuItem addAfter(JMenu menu, JosmAction actionToBeInserted, boolean isExpert, JosmAction existingMenuEntryAction) {
571 int i = 0;
572 for (Component c : menu.getMenuComponents()) {
573 if (c instanceof JMenuItem && ((JMenuItem) c).getAction() == existingMenuEntryAction) {
574 break;
575 }
576 i++;
577 }
578 return add(menu, actionToBeInserted, isExpert, i + 1);
579 }
580
581 /**
582 * Add a JosmAction to a menu.
583 * <p>
584 * This method handles all the shortcut handling. It also makes sure that actions that are
585 * handled by the OS are not duplicated on the menu.
586 * @param <E> group item enum type
587 * @param menu to add the action to
588 * @param action the action that should get a menu item
589 * @param group the item should be added to. Groups are split by a separator. null will add the item to the end.
590 * @return The created menu item
591 */
592 public static <E extends Enum<E>> JMenuItem add(JMenu menu, JosmAction action, Enum<E> group) {
593 if (action.getShortcut().isAutomatic())
594 return null;
595 int i = group != null ? getInsertionIndexForGroup(menu, group.ordinal(), false) : -1;
596 JMenuItem menuitem = (JMenuItem) menu.add(new JMenuItem(action), i);
597 KeyStroke ks = action.getShortcut().getKeyStroke();
598 if (ks != null) {
599 menuitem.setAccelerator(ks);
600 }
601 return menuitem;
602 }
603
604 /**
605 * Add a JosmAction to a menu and automatically prints accelerator if available.
606 * Also adds a checkbox that may be toggled.
607 * @param <E> group enum item type
608 * @param menu to add the action to
609 * @param action the action that should get a menu item
610 * @param group the item should be added to. Groups are split by a separator. Use
611 * one of the enums that are defined for some of the menus to tell in which
612 * group the item should go.
613 * @return The created menu item
614 */
615 public static <E extends Enum<E>> JCheckBoxMenuItem addWithCheckbox(JMenu menu, JosmAction action, Enum<E> group) {
616 return addWithCheckbox(menu, action, group, false, false);
617 }
618
619 /**
620 * Add a JosmAction to a menu and automatically prints accelerator if available.
621 * Also adds a checkbox that may be toggled.
622 * @param <E> group enum item type
623 * @param menu to add the action to
624 * @param action the action that should get a menu item
625 * @param group the item should be added to. Groups are split by a separator. Use
626 * one of the enums that are defined for some of the menus to tell in which
627 * group the item should go. null will add the item to the end.
628 * @param isEntryExpert whether the entry should only be visible if the expert mode is activated
629 * @param isGroupSeparatorExpert whether the group separator should only be visible if the expert mode is activated
630 * @return The created menu item
631 * @since 15633
632 */
633 public static <E extends Enum<E>> JCheckBoxMenuItem addWithCheckbox(JMenu menu, JosmAction action, Enum<E> group,
634 boolean isEntryExpert, boolean isGroupSeparatorExpert) {
635 int i = group != null ? getInsertionIndexForGroup(menu, group.ordinal(), isGroupSeparatorExpert) : -1;
636 return addWithCheckbox(menu, action, i, isEntryExpert);
637 }
638
639 /**
640 * Add a JosmAction to a menu and automatically prints accelerator if available.
641 * Also adds a checkbox that may be toggled.
642 * @param <E> group enum item type
643 * @param menu to add the action to
644 * @param action the action that should get a menu item
645 * @param i the item position in the menu. -1 will add the item to the end.
646 * @param isEntryExpert whether the entry should only be visible if the expert mode is activated
647 * @return The created menu item
648 * @since 15655
649 */
650 public static <E extends Enum<E>> JCheckBoxMenuItem addWithCheckbox(JMenu menu, JosmAction action, int i, boolean isEntryExpert) {
651 final JCheckBoxMenuItem mi = new JCheckBoxMenuItem(action);
652 final KeyStroke ks = action.getShortcut().getKeyStroke();
653 if (ks != null) {
654 mi.setAccelerator(ks);
655 }
656 if (isEntryExpert) {
657 ExpertToggleAction.addVisibilitySwitcher(mi);
658 }
659 return (JCheckBoxMenuItem) menu.add(mi, i);
660 }
661
662 /**
663 * Finds the correct insertion index for a given group and adds separators if necessary
664 * @param menu menu
665 * @param group group number
666 * @param isGroupSeparatorExpert whether the added separators should only be visible if the expert mode is activated
667 * @return correct insertion index
668 */
669 private static int getInsertionIndexForGroup(JMenu menu, int group, boolean isGroupSeparatorExpert) {
670 if (group < 0)
671 return -1;
672 // look for separator that *ends* the group (or stop at end of menu)
673 int i;
674 for (i = 0; i < menu.getItemCount() && group >= 0; i++) {
675 if (menu.getItem(i) == null) {
676 group--;
677 }
678 }
679 // insert before separator that ends the group
680 if (group < 0) {
681 i--;
682 }
683 // not enough separators have been found, add them
684 while (group > 0) {
685 menu.addSeparator();
686 if (isGroupSeparatorExpert) {
687 ExpertToggleAction.addVisibilitySwitcher(menu.getMenuComponent(menu.getMenuComponentCount() - 1));
688 }
689 group--;
690 i++;
691 }
692 return i;
693 }
694
695 /**
696 * Creates a menu and adds it on the given position to the main menu.
697 *
698 * @param name the untranslated name (used as identifier for shortcut registration)
699 * @param translatedName the translated menu name (use {@code I18n.trc("menu", name)} to allow better internationalization
700 * @param mnemonicKey the mnemonic key to register
701 * @param position the position in the main menu
702 * @param relativeHelpTopic the relative help topic
703 * @return the newly created menu
704 */
705 public JMenu addMenu(String name, String translatedName, int mnemonicKey, int position, String relativeHelpTopic) {
706 final JMenu menu = new JMenu(translatedName);
707 if (!GraphicsEnvironment.isHeadless()) {
708 MenuScroller.setScrollerFor(menu);
709 }
710 return addMenu(menu, name, mnemonicKey, position, relativeHelpTopic);
711 }
712
713 /**
714 * Adds the given menu on the given position to the main menu.
715 * @param <T> menu type
716 *
717 * @param menu the menu to add
718 * @param name the untranslated name (used as identifier for shortcut registration)
719 * @param mnemonicKey the mnemonic key to register
720 * @param position the position in the main menu
721 * @param relativeHelpTopic the relative help topic
722 * @return the given {@code }menu}
723 */
724 public <T extends JMenu> T addMenu(T menu, String name, int mnemonicKey, int position, String relativeHelpTopic) {
725 Shortcut.registerShortcut("menu:" + name, tr("Menu: {0}", name), mnemonicKey,
726 Shortcut.MNEMONIC).setMnemonic(menu);
727 add(menu, position);
728 menu.putClientProperty("help", relativeHelpTopic);
729 return menu;
730 }
731
732 /**
733 * Initialize the main menu.
734 * @since 10340
735 */
736 // CHECKSTYLE.OFF: ExecutableStatementCountCheck
737 public void initialize() {
738 moreToolsMenu.setVisible(false);
739 dataMenu.setVisible(false);
740 gpsMenu.setVisible(false);
741
742 add(fileMenu, newAction);
743 add(fileMenu, openFile);
744 fileMenu.add(recentlyOpened);
745 add(fileMenu, openLocation);
746 add(fileMenu, deleteLayerAction);
747 fileMenu.addSeparator();
748 add(fileMenu, save);
749 add(fileMenu, saveAs);
750 add(fileMenu, sessionSave);
751 add(fileMenu, sessionSaveAs);
752 add(fileMenu, gpxExport, true);
753 fileMenu.addSeparator();
754 add(fileMenu, download);
755 add(fileMenu, downloadInView, true);
756 add(fileMenu, downloadAlongWay);
757 add(fileMenu, downloadPrimitive);
758 add(fileMenu, searchNotes);
759 add(fileMenu, downloadNotesInView);
760 add(fileMenu, new WikimediaCommonsLoadImagesAction());
761 add(fileMenu, downloadReferrers);
762 add(fileMenu, update);
763 add(fileMenu, updateSelection);
764 add(fileMenu, updateModified);
765 fileMenu.addSeparator();
766 add(fileMenu, upload);
767 add(fileMenu, uploadSelection);
768 Component sep = new JPopupMenu.Separator();
769 fileMenu.add(sep);
770 ExpertToggleAction.addVisibilitySwitcher(sep);
771 add(fileMenu, closeChangesetAction, true);
772 fileMenu.addSeparator();
773 fileMenu.add(new OnlineResourceMenu());
774 add(fileMenu, restart);
775 add(fileMenu, exit);
776
777 add(editMenu, undo);
778 UndoRedoHandler.getInstance().addCommandQueueListener(undo);
779 add(editMenu, redo);
780 UndoRedoHandler.getInstance().addCommandQueueListener(redo);
781 editMenu.addSeparator();
782 add(editMenu, copy);
783 add(editMenu, copyCoordinates, true);
784 add(editMenu, copyUrl, true);
785 add(editMenu, paste);
786 add(editMenu, pasteAtSource, true);
787 add(editMenu, pasteTags);
788 add(editMenu, duplicate);
789 add(editMenu, delete);
790 add(editMenu, purge, true);
791 editMenu.addSeparator();
792 add(editMenu, merge);
793 add(editMenu, mergeSelected);
794 editMenu.addSeparator();
795 add(editMenu, search);
796 add(editMenu, presetSearchPrimitiveAction);
797 editMenu.addSeparator();
798 add(editMenu, preferences);
799
800 // -- wireframe toggle action
801 final JCheckBoxMenuItem wireframe = new JCheckBoxMenuItem(wireFrameToggleAction);
802 viewMenu.add(wireframe);
803 wireframe.setAccelerator(wireFrameToggleAction.getShortcut().getKeyStroke());
804 wireFrameToggleAction.addButtonModel(wireframe.getModel());
805 // -- tiled render toggle action -- not intended to be permanently an "Expert" mode option
806 final JCheckBoxMenuItem tiledRender = new JCheckBoxMenuItem(tiledRenderToggleAction);
807 viewMenu.add(tiledRender);
808 tiledRenderToggleAction.addButtonModel(tiledRender.getModel());
809 ExpertToggleAction.addVisibilitySwitcher(tiledRender);
810 // -- hatch toggle action
811 final JCheckBoxMenuItem hatchAreaOutsideDownloadMenuItem = drawBoundariesOfDownloadedDataAction.getCheckbox();
812 viewMenu.add(hatchAreaOutsideDownloadMenuItem);
813 ExpertToggleAction.addVisibilitySwitcher(hatchAreaOutsideDownloadMenuItem);
814
815 viewMenu.add(new MapPaintMenu());
816 viewMenu.addSeparator();
817 add(viewMenu, new ZoomInAction());
818 add(viewMenu, new ZoomOutAction());
819 viewMenu.addSeparator();
820 for (AutoScaleMode mode : AutoScaleMode.values()) {
821 AutoScaleAction autoScaleAction = new AutoScaleAction(mode);
822 autoScaleActions.put(mode, autoScaleAction);
823 add(viewMenu, autoScaleAction);
824 }
825
826 // -- viewport follow toggle action
827 ViewportFollowToggleAction viewportFollowToggleAction = new ViewportFollowToggleAction();
828 final JCheckBoxMenuItem vft = new JCheckBoxMenuItem(viewportFollowToggleAction);
829 ExpertToggleAction.addVisibilitySwitcher(vft);
830 viewMenu.add(vft);
831 vft.setAccelerator(viewportFollowToggleAction.getShortcut().getKeyStroke());
832 viewportFollowToggleAction.addButtonModel(vft.getModel());
833
834 if (PlatformManager.getPlatform().canFullscreen()) {
835 // -- fullscreen toggle action
836 fullscreenToggleAction = new FullscreenToggleAction();
837 final JCheckBoxMenuItem fullscreen = new JCheckBoxMenuItem(fullscreenToggleAction);
838 viewMenu.addSeparator();
839 viewMenu.add(fullscreen);
840 fullscreen.setAccelerator(fullscreenToggleAction.getShortcut().getKeyStroke());
841 fullscreenToggleAction.addButtonModel(fullscreen.getModel());
842 }
843
844 add(viewMenu, jumpToAct, true);
845 viewMenu.addSeparator();
846 add(viewMenu, info);
847 add(viewMenu, infoweb);
848 add(viewMenu, historyinfo);
849 add(viewMenu, historyinfoweb);
850 viewMenu.addSeparator();
851 viewMenu.add(new PreferenceToggleAction(tr("Main toolbar"),
852 new ImageProvider("dialogs/main_toolbar.svg"),
853 tr("Toggles the visibility of the main toolbar (i.e., the horizontal toolbar)"),
854 MapFrame.TOOLBAR_VISIBLE).getCheckbox());
855 viewMenu.add(new PreferenceToggleAction(tr("Edit toolbar"),
856 new ImageProvider("dialogs/edit_toolbar.svg"),
857 tr("Toggles the visibility of the edit toolbar (i.e., the vertical tool)"),
858 MapFrame.SIDE_TOOLBAR_VISIBLE).getCheckbox());
859 // -- dialogs panel toggle action
860 final JCheckBoxMenuItem dialogsToggle = new JCheckBoxMenuItem(dialogsToggleAction);
861 dialogsToggle.setAccelerator(dialogsToggleAction.getShortcut().getKeyStroke());
862 dialogsToggleAction.addButtonModel(dialogsToggle.getModel());
863 viewMenu.add(dialogsToggle);
864 viewMenu.addSeparator();
865 // -- expert mode toggle action
866 final JCheckBoxMenuItem expertItem = new JCheckBoxMenuItem(ExpertToggleAction.getInstance());
867 viewMenu.add(expertItem);
868 ExpertToggleAction.getInstance().addButtonModel(expertItem.getModel());
869
870 add(imageryMenu, reorderImageryLayersAction);
871 add(imageryMenu, PreferencesAction.forPreferenceTab(tr("Imagery preferences..."),
872 tr("Click to open the imagery tab in the preferences"), ImageryPreference.class));
873
874 add(selectionMenu, selectAll);
875 add(selectionMenu, unselectAll);
876 add(selectionMenu, invertSelection, true);
877 add(selectionMenu, nonBranchingWaySequences);
878 add(selectionMenu, sharedChildObjects, true);
879
880 add(toolsMenu, splitWay);
881 add(toolsMenu, combineWay);
882 toolsMenu.addSeparator();
883 add(toolsMenu, reverseWay);
884 add(toolsMenu, simplifyWay);
885 toolsMenu.addSeparator();
886 add(toolsMenu, alignInCircle);
887 add(toolsMenu, alignInLine);
888 add(toolsMenu, distribute);
889 add(toolsMenu, ortho);
890 add(toolsMenu, mirror, true);
891 toolsMenu.addSeparator();
892 add(toolsMenu, followLine, true);
893 add(toolsMenu, addNode, true);
894 add(toolsMenu, moveNode, true);
895 add(toolsMenu, createCircle);
896 toolsMenu.addSeparator();
897 add(toolsMenu, mergeNodes);
898 add(toolsMenu, joinNodeWay);
899 add(toolsMenu, moveNodeOntoWay);
900 add(toolsMenu, unJoinNodeWay);
901 add(toolsMenu, unglueNodes);
902 toolsMenu.addSeparator();
903 add(toolsMenu, joinAreas);
904 add(toolsMenu, createMultipolygon);
905 add(toolsMenu, updateMultipolygon);
906
907 // -- changeset manager toggle action
908 final JCheckBoxMenuItem mi = MainMenu.addWithCheckbox(windowMenu, changesetManager,
909 WINDOW_MENU_GROUP.ALWAYS, true, false);
910 changesetManager.addButtonModel(mi.getModel());
911
912 if (!Config.getPref().getBoolean("audio.menuinvisible", false)) {
913 showAudioMenu(true);
914 }
915
916 Config.getPref().addPreferenceChangeListener(e -> {
917 if ("audio.menuinvisible".equals(e.getKey())) {
918 showAudioMenu(!Boolean.parseBoolean(e.getNewValue().toString()));
919 }
920 });
921
922 add(helpMenu, new MenuItemSearchDialog.Action());
923 helpMenu.addSeparator();
924 add(helpMenu, statusreport);
925 add(helpMenu, reportbug);
926 helpMenu.addSeparator();
927
928 add(helpMenu, help);
929 add(helpMenu, about);
930
931 windowMenu.addMenuListener(menuSeparatorHandler);
932
933 new EditLayerMenuEnabler(Arrays.asList(modeMenu, toolsMenu, moreToolsMenu, selectionMenu));
934 }
935 // CHECKSTYLE.ON: ExecutableStatementCountCheck
936
937 /**
938 * Search main menu for items with {@code textToFind} in title.
939 * @param textToFind The text to find
940 * @param skipPresets whether to skip the {@link #presetsMenu} in the search
941 * @return not null list of found menu items.
942 */
943 public List<JMenuItem> findMenuItems(String textToFind, boolean skipPresets) {
944 // Explicitly use default locale in this case, because we're looking for translated strings
945 textToFind = textToFind.toLowerCase(Locale.getDefault());
946 List<JMenuItem> result = new ArrayList<>();
947 for (int i = 0; i < getMenuCount(); i++) {
948 if (getMenu(i) != null && (!skipPresets || presetsMenu != getMenu(i))) {
949 findMenuItems(getMenu(i), textToFind, result);
950 }
951 }
952 return result;
953 }
954
955 /**
956 * Returns the {@link JCheckBoxMenuItem} for the given {@link MapMode}.
957 * @param mode map mode
958 * @return the {@code JCheckBoxMenuItem} for the given {@code MapMode}
959 * @since 15438
960 */
961 public Optional<JCheckBoxMenuItem> findMapModeMenuItem(MapMode mode) {
962 return Arrays.stream(modeMenu.getMenuComponents())
963 .filter(JCheckBoxMenuItem.class::isInstance)
964 .map(JCheckBoxMenuItem.class::cast)
965 .filter(m -> Objects.equals(mode, m.getAction()))
966 .findFirst();
967 }
968
969 /**
970 * Recursive walker for menu items. Only menu items with action are selected. If menu item
971 * contains {@code textToFind} it's appended to result.
972 * @param menu menu in which search will be performed
973 * @param textToFind The text to find
974 * @param result resulting list of menu items
975 */
976 private static void findMenuItems(final JMenu menu, final String textToFind, final List<JMenuItem> result) {
977 for (int i = 0; i < menu.getItemCount(); i++) {
978 JMenuItem menuItem = menu.getItem(i);
979 if (menuItem == null) continue;
980
981 // Explicitly use default locale in this case, because we're looking for translated strings
982 if (menuItem.getAction() != null && menuItem.getText().toLowerCase(Locale.getDefault()).contains(textToFind)) {
983 result.add(menuItem);
984 }
985
986 // Go recursive if needed
987 if (menuItem instanceof JMenu) {
988 findMenuItems((JMenu) menuItem, textToFind, result);
989 }
990 }
991 }
992
993 protected void showAudioMenu(boolean showMenu) {
994 if (showMenu && audioMenu == null) {
995 audioMenu = addMenu("Audio", /* I18N: mnemonic: U */ trc("menu", "Audio"), KeyEvent.VK_U, defaultMenuPos, ht("/Menu/Audio"));
996 add(audioMenu, audioPlayPause);
997 add(audioMenu, audioNext);
998 add(audioMenu, audioPrev);
999 add(audioMenu, audioFwd);
1000 add(audioMenu, audioBack);
1001 add(audioMenu, audioSlower);
1002 add(audioMenu, audioFaster);
1003 validate();
1004 } else if (!showMenu && audioMenu != null) {
1005 remove(audioMenu);
1006 audioMenu.removeAll();
1007 audioMenu = null;
1008 validate();
1009 }
1010 }
1011
1012 static class EditLayerMenuEnabler implements ActiveLayerChangeListener {
1013 private final Collection<JMenu> menus;
1014
1015 EditLayerMenuEnabler(Collection<JMenu> menus) {
1016 this.menus = Objects.requireNonNull(menus);
1017 MainApplication.getLayerManager().addAndFireActiveLayerChangeListener(this);
1018 }
1019
1020 @Override
1021 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
1022 menus.forEach(m -> m.setEnabled(e.getSource().getEditLayer() != null));
1023 }
1024 }
1025}
Note: See TracBrowser for help on using the repository browser.