Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "appmenumodel.h"
23 :
24 : #include "log.h"
25 : #include "rcommand/commandtypes.h"
26 : #include "types/translatablestring.h"
27 :
28 : #include "muse_framework_config.h"
29 :
30 : #ifdef MUSE_MODULE_WORKSPACE
31 : #include "workspace/qml/Muse/Workspace/workspacesmenumodel.h"
32 : #endif
33 :
34 : #include "notation/inotation.h"
35 : #include "notation/inotationundostack.h"
36 : #include "notationscene/notationcommands.h"
37 :
38 : #include "appshell/appshellcommands.h"
39 : #include "project/projectcommands.h"
40 : #include "notationscene/notationcommands.h"
41 : #include "playback/playbackcommands.h"
42 : #include "palette/palettecommands.h"
43 : #include "dockwindow_v2/dockcommands.h"
44 : #include "update/updatecommands.h"
45 : #include "diagnostics/diagnosticscommands.h"
46 : #include "musesampler/musesamplercommands.h"
47 : #include "vst/vstcommands.h"
48 : #include "audio/main/audiocommands.h"
49 : #include "multiwindows/multiwindowscommands.h"
50 : #include "extensions/extensionscommands.h"
51 : #include "testflow/testflowcommands.h"
52 :
53 : using namespace muse;
54 : using namespace mu::appshell;
55 : using namespace muse::ui;
56 : using namespace muse::uicomponents;
57 : using namespace mu::project;
58 : using namespace muse::workspace;
59 : using namespace muse::extensions;
60 : using namespace mu::notation;
61 : using namespace mu::playback;
62 : using namespace mu::palette;
63 : using namespace muse::dock;
64 : using namespace muse::update;
65 : using namespace muse::diagnostics;
66 : using namespace muse::musesampler;
67 : using namespace muse::vst;
68 : using namespace muse::audio;
69 : using namespace muse::mi;
70 : using namespace muse::testflow;
71 :
72 0 : AppMenuModel::AppMenuModel(QObject* parent)
73 0 : : AbstractMenuModel(parent)
74 : {
75 0 : setObjectName("AppMenuModel");
76 :
77 : #ifdef MUSE_MODULE_WORKSPACE
78 0 : m_workspacesMenuModel = std::make_shared<WorkspacesMenuModel>(this);
79 : #endif
80 0 : }
81 :
82 0 : void AppMenuModel::load()
83 : {
84 0 : TRACEFUNC;
85 :
86 0 : AbstractMenuModel::load();
87 :
88 : #ifdef MUSE_MODULE_WORKSPACE
89 0 : m_workspacesMenuModel->load();
90 : #endif
91 :
92 : MenuItemList items {
93 0 : makeFileMenu(),
94 0 : makeEditMenu(),
95 0 : makeViewMenu(),
96 0 : makeAddMenu(),
97 0 : makeFormatMenu(),
98 0 : makeToolsMenu(),
99 0 : makeExtensionsMenu()
100 0 : };
101 :
102 0 : if (globalConfiguration()->devModeEnabled()) {
103 0 : items << makeHelpMenu(false);
104 0 : items << makeDiagnosticsMenu();
105 : } else {
106 0 : items << makeHelpMenu(true);
107 : }
108 :
109 0 : setItems(items);
110 :
111 0 : setupConnections();
112 :
113 : //! NOTE: removes some undesired platform-specific items
114 : //! (such as "Start Dictation" and "Special Characters" on macOS)
115 0 : appMenuModelHook()->onAppMenuInited();
116 0 : }
117 :
118 0 : bool AppMenuModel::isGlobalMenuAvailable()
119 : {
120 0 : return uiConfiguration()->isGlobalMenuAvailable();
121 : }
122 :
123 0 : void AppMenuModel::setupConnections()
124 : {
125 0 : recentFilesController()->recentFilesListChanged().onReceive(this, [this](const RecentFilesChange&) {
126 0 : MenuItem& recentMenuItem = findMenu("menu-file-open");
127 0 : MenuItemList recentSubMenuItems = makeRecentSubMenuItems();
128 0 : recentMenuItem.setSubitems(recentSubMenuItems);
129 0 : recentMenuItem.setEnabled(!recentSubMenuItems.empty());
130 0 : });
131 :
132 : #ifdef MUSE_MODULE_WORKSPACE
133 0 : connect(m_workspacesMenuModel.get(), &WorkspacesMenuModel::itemsChanged, this, [this]() {
134 0 : MenuItem& workspacesItem = findMenu("menu-workspaces");
135 0 : workspacesItem.setSubitems(m_workspacesMenuModel->items());
136 0 : });
137 : #endif
138 :
139 0 : extensionsRegister()->manifestListChanged().onNotify(this, [this]() {
140 0 : MenuItem& pluginsMenu = findMenu("menu-extensions");
141 0 : pluginsMenu.setSubitems(makeExtensionsSubitems());
142 0 : });
143 :
144 0 : extensionsRegister()->enabledChanged().onReceive(this, [this](const ExtensionUri&) {
145 0 : MenuItem& pluginsItem = findMenu("menu-extensions");
146 0 : pluginsItem.setSubitems(makeExtensionsSubitems());
147 0 : });
148 :
149 0 : projectSession()->currentNotationChanged().onNotify(this, [this]() {
150 0 : auto stack = undoStack();
151 0 : if (stack) {
152 0 : stack->stackChanged().onNotify(this, [this]() {
153 0 : updateUndoRedoItems();
154 0 : }, Asyncable::Mode::SetReplace /* FIXME */);
155 : }
156 :
157 0 : updateUndoRedoItems();
158 0 : });
159 0 : }
160 :
161 0 : bool AppMenuModel::isMuseSamplerModuleAdded() const
162 : {
163 : #ifdef MUSE_MODULE_MUSESAMPLER
164 0 : return museSamplerInfo() != nullptr;
165 : #else
166 : return false;
167 : #endif
168 : }
169 :
170 0 : MenuItemList AppMenuModel::makeChordAndFretboardDiagramsItems()
171 : {
172 : MenuItemList items {
173 0 : makeMenuItem(ADD_CHORD_TEXT_COMMAND),
174 0 : makeMenuItem(ADD_FRETBOARD_DIAGRAM_COMMAND),
175 0 : makeSeparator(),
176 0 : makeMenuItem(INSERT_FRETFRAME_COMMAND, TranslatableString("appshell/menu/add/chordandfret", "Fretboard diagram legend"))
177 0 : };
178 :
179 0 : return items;
180 : }
181 :
182 0 : MenuItem* AppMenuModel::makeMenuItem(const muse::rcommand::Command& command, MenuItemRole role)
183 : {
184 0 : MenuItem* item = makeMenuItem(command);
185 0 : item->setRole(role);
186 0 : return item;
187 : }
188 :
189 0 : MenuItem* AppMenuModel::makeFileMenu()
190 : {
191 0 : MenuItemList recentSubMenuItems = makeRecentSubMenuItems();
192 0 : bool openRecentEnabled = !recentSubMenuItems.isEmpty();
193 :
194 : MenuItemList fileItems {
195 0 : makeMenuItem(PROJECT_NEW_COMMAND),
196 0 : makeMenuItem(PROJECT_OPEN_COMMAND),
197 0 : makeMenu(TranslatableString("appshell/menu/file", "Open &recent"), recentSubMenuItems, "menu-file-open", openRecentEnabled),
198 0 : makeMenuItem(PROJECT_CLOSE_COMMAND),
199 0 : makeSeparator(),
200 0 : makeMenuItem(PROJECT_SAVE_COMMAND),
201 0 : makeMenuItem(PROJECT_SAVE_AS_COMMAND),
202 0 : makeMenuItem(PROJECT_SAVE_TO_CLOUD_COMMAND),
203 0 : makeMenu(TranslatableString("appshell/menu/file", "Save o&ther"), {
204 0 : makeMenuItem(PROJECT_SAVE_A_COPY_COMMAND),
205 0 : makeMenuItem(PROJECT_SAVE_SELECTION_COMMAND),
206 : }),
207 0 : makeMenu(TranslatableString("appshell/menu/file", "Pu&blish online"), {
208 0 : makeMenuItem(PROJECT_PUBLISH_COMMAND),
209 0 : makeMenuItem(PROJECT_SHARE_AUDIO_COMMAND),
210 : }),
211 0 : makeSeparator(),
212 0 : makeMenuItem(PROJECT_CONVERT_TO_SCORE_COMMAND),
213 0 : makeMenuItem(PROJECT_EXPORT_COMMAND),
214 0 : makeSeparator(),
215 0 : makeMenuItem(PROJECT_PROPERTIES_COMMAND),
216 0 : makeMenuItem(OPEN_PARTS_COMMAND),
217 0 : makeSeparator(),
218 0 : makeMenuItem(PROJECT_PRINT_COMMAND),
219 0 : makeSeparator(),
220 0 : makeMenuItem(APP_QUIT_COMMAND, MenuItemRole::QuitRole)
221 0 : };
222 :
223 0 : return makeMenu(TranslatableString("appshell/menu/file", "&File"), fileItems, "menu-file");
224 0 : }
225 :
226 0 : MenuItem* AppMenuModel::makeEditMenu()
227 : {
228 : MenuItemList editItems {
229 0 : makeMenuItem(UNDO_COMMAND),
230 0 : makeMenuItem(REDO_COMMAND),
231 0 : makeMenuItem(DOCK_TOGGLE_UNDO_HISTORY_COMMAND),
232 0 : makeSeparator(),
233 0 : makeMenuItem(CUT_COMMAND),
234 0 : makeMenuItem(COPY_COMMAND),
235 0 : makeMenuItem(PASTE_COMMAND),
236 0 : makeMenuItem(PASTE_HALF_COMMAND),
237 0 : makeMenuItem(PASTE_DOUBLE_COMMAND),
238 0 : makeMenuItem(COPY_PASTE_SWAP_COMMAND),
239 0 : makeMenuItem(DELETE_COMMAND),
240 0 : makeSeparator(),
241 0 : makeMenuItem(SELECT_ALL_COMMAND),
242 0 : makeMenuItem(SELECT_SECTION_COMMAND),
243 0 : makeMenuItem(SHOW_SEARCH_COMMAND),
244 0 : makeSeparator(),
245 0 : makeMenuItem(APP_PREFERENCES_COMMAND, MenuItemRole::PreferencesRole)
246 0 : };
247 :
248 0 : return makeMenu(TranslatableString("appshell/menu/edit", "&Edit"), editItems, "menu-edit");
249 0 : }
250 :
251 0 : mu::notation::INotationUndoStackPtr AppMenuModel::undoStack() const
252 : {
253 0 : mu::notation::INotationPtr notation = projectSession()->currentNotation();
254 0 : return notation ? notation->undoStack() : nullptr;
255 0 : }
256 :
257 0 : void AppMenuModel::updateUndoRedoItems()
258 : {
259 0 : auto stack = undoStack();
260 :
261 0 : MenuItem& undoItem = findItem(UNDO_COMMAND);
262 0 : const TranslatableString undoActionName = stack ? stack->topMostUndoActionName() : TranslatableString();
263 0 : undoItem.setTitle(undoActionName.isEmpty()
264 0 : ? TranslatableString("action", "Undo")
265 0 : : TranslatableString("action", "Undo ‘%1’").arg(undoActionName));
266 :
267 0 : MenuItem& redoItem = findItem(REDO_COMMAND);
268 0 : const TranslatableString redoActionName = stack ? stack->topMostRedoActionName() : TranslatableString();
269 0 : redoItem.setTitle(redoActionName.isEmpty()
270 0 : ? TranslatableString("action", "Redo")
271 0 : : TranslatableString("action", "Redo ‘%1’").arg(redoActionName));
272 0 : }
273 :
274 0 : MenuItem* AppMenuModel::makeViewMenu()
275 : {
276 : MenuItemList viewItems {
277 : #ifndef Q_OS_MAC
278 0 : makeMenuItem(APP_FULLSCREEN_COMMAND),
279 : #endif
280 0 : makeMenuItem(DOCK_TOGGLE_PALETTES_COMMAND),
281 0 : makeMenuItem(TOGGLE_MASTER_PALETTE_COMMAND),
282 0 : makeMenuItem(DOCK_TOGGLE_INSTRUMENTS_COMMAND),
283 0 : makeMenuItem(DOCK_TOGGLE_PROPERTIES_COMMAND),
284 0 : makeMenuItem(DOCK_TOGGLE_SELECTION_FILTER_COMMAND),
285 0 : makeMenuItem(DOCK_TOGGLE_UNDO_HISTORY_COMMAND),
286 0 : makeMenuItem(DOCK_TOGGLE_NAVIGATOR_COMMAND),
287 0 : makeMenuItem(DOCK_TOGGLE_BRAILLE_COMMAND),
288 0 : makeMenuItem(DOCK_TOGGLE_TIMELINE_COMMAND),
289 0 : makeMenuItem(DOCK_TOGGLE_MIXER_COMMAND),
290 0 : makeMenuItem(DOCK_TOGGLE_PIANO_KEYBOARD_COMMAND),
291 0 : makeMenuItem(DOCK_TOGGLE_PERCUSSION_COMMAND),
292 0 : makeMenuItem(OPEN_PLAYBACK_SETUP_COMMAND),
293 0 : makeSeparator(),
294 0 : makeMenu(TranslatableString("appshell/menu/view", "&Toolbars"), {
295 0 : makeMenuItem(DOCK_TOGGLE_PLAYBACK_COMMAND),
296 0 : makeMenuItem(DOCK_TOGGLE_NOTEINPUT_COMMAND),
297 0 : makeMenuItem(DOCK_TOGGLE_STATUSBAR_COMMAND)
298 : }, "menu-toolbars"),
299 : #ifdef MUSE_MODULE_WORKSPACE
300 0 : makeMenu(TranslatableString("appshell/menu/view", "W&orkspaces"), m_workspacesMenuModel->items(), "menu-workspaces"),
301 : #endif
302 0 : makeSeparator(),
303 0 : makeMenu(TranslatableString("appshell/menu/view", "&Show"), {
304 0 : makeMenuItem(SHOW_INVISIBLE_COMMAND),
305 0 : makeMenuItem(SHOW_UNPRINTABLE_COMMAND),
306 0 : makeMenuItem(SHOW_FRAMES_COMMAND),
307 0 : makeMenuItem(SHOW_PAGEBORDERS_COMMAND),
308 0 : makeMenuItem(SHOW_IRREGULAR_COMMAND),
309 0 : makeMenuItem(SHOW_SOUNDFLAGS_COMMAND),
310 : }, "menu-show"),
311 0 : makeSeparator(),
312 0 : makeMenuItem(DOCK_RESTORE_DEFAULT_LAYOUT_COMMAND),
313 0 : };
314 :
315 0 : return makeMenu(TranslatableString("appshell/menu/view", "&View"), viewItems, "menu-view");
316 0 : }
317 :
318 0 : MenuItem* AppMenuModel::makeAddMenu()
319 : {
320 : MenuItemList addItems {
321 0 : makeMenu(TranslatableString("appshell/menu/add", "&Notes"), makeNotesItems(), "menu-notes"),
322 0 : makeMenu(TranslatableString("appshell/menu/add", "&Intervals"), makeIntervalsItems(), "menu-intervals"),
323 0 : makeMenu(TranslatableString("appshell/menu/add", "T&uplets"), makeTupletsItems(), "menu-tuplets"),
324 0 : makeSeparator(),
325 0 : makeMenu(TranslatableString("appshell/menu/add", "&Measures"), makeMeasuresItems(), "menu-measures"),
326 0 : makeMenu(TranslatableString("appshell/menu/add", "&Frames"), makeFramesItems(), "menu-frames"),
327 0 : makeMenu(TranslatableString("appshell/menu/add", "&Text"), makeTextItems(), "menu-text"),
328 0 : makeMenu(TranslatableString("appshell/menu/add", "&Lines"), makeLinesItems(), "menu-lines"),
329 0 : makeMenu(TranslatableString("appshell/menu/add", "&Chords and fretboard diagrams"),
330 0 : makeChordAndFretboardDiagramsItems(), "menu-chord-and-frets"),
331 0 : };
332 :
333 0 : return makeMenu(TranslatableString("appshell/menu/add", "&Add"), addItems, "menu-add");
334 0 : }
335 :
336 0 : MenuItem* AppMenuModel::makeFormatMenu()
337 : {
338 : MenuItemList formatItems {
339 0 : makeMenuItem(OPEN_EDIT_STYLE_COMMAND),
340 0 : makeMenuItem(OPEN_PAGE_SETTINGS_COMMAND),
341 0 : makeSeparator(),
342 0 : makeMenuItem(OPEN_BREAKS_COMMAND),
343 0 : makeMenu(TranslatableString("appshell/menu/format", "Str&etch"), {
344 0 : makeMenuItem(STRETCH_INCREASE_COMMAND),
345 0 : makeMenuItem(STRETCH_DECREASE_COMMAND),
346 0 : makeMenuItem(STRETCH_RESET_COMMAND)
347 : }, "menu-stretch"),
348 0 : makeSeparator(),
349 0 : makeMenuItem(RESET_TEXT_STYLE_OVERRIDES_COMMAND),
350 0 : makeMenuItem(RESET_BEAMS_COMMAND),
351 0 : makeMenuItem(RESET_SHAPES_AND_POSITIONS_COMMAND),
352 0 : makeMenuItem(RESET_TO_DEFAULT_LAYOUT_COMMAND),
353 0 : makeSeparator(),
354 0 : makeMenuItem(LOAD_STYLE_COMMAND),
355 0 : makeMenuItem(SAVE_STYLE_COMMAND)
356 0 : };
357 :
358 0 : return makeMenu(TranslatableString("appshell/menu/format", "F&ormat"), formatItems, "menu-format");
359 0 : }
360 :
361 0 : MenuItem* AppMenuModel::makeToolsMenu()
362 : {
363 : MenuItemList toolsItems {
364 0 : makeMenuItem(OPEN_TRANSPOSE_COMMAND),
365 0 : makeSeparator(),
366 0 : makeMenuItem(STAFF_EXPLODE_COMMAND),
367 0 : makeMenuItem(STAFF_IMPLODE_COMMAND),
368 0 : makeMenuItem(OPEN_REALIZECHORDSYMBOLS_COMMAND),
369 0 : makeMenu(TranslatableString("appshell/menu/tools", "&Voices"), {
370 0 : makeMenuItem(SWAP_VOICE_X12_COMMAND),
371 0 : makeMenuItem(SWAP_VOICE_X13_COMMAND),
372 0 : makeMenuItem(SWAP_VOICE_X14_COMMAND),
373 0 : makeMenuItem(SWAP_VOICE_X23_COMMAND),
374 0 : makeMenuItem(SWAP_VOICE_X24_COMMAND),
375 0 : makeMenuItem(SWAP_VOICE_X34_COMMAND)
376 : }, "menu-voices"),
377 0 : makeMenu(TranslatableString("appshell/menu/tools", "&Measures"), {
378 0 : makeMenuItem(SPLIT_MEASURE_COMMAND),
379 0 : makeMenuItem(JOIN_MEASURES_COMMAND)
380 : }, "menu-tools-measures"),
381 0 : makeMenuItem(REMOVE_SELECTED_RANGE_COMMAND),
382 0 : makeSeparator(),
383 0 : makeMenuItem(SLASH_FILL_COMMAND),
384 0 : makeMenuItem(SLASH_RHYTHM_COMMAND),
385 0 : makeSeparator(),
386 0 : makeMenuItem(PITCH_SPELL_SHARPS_COMMAND),
387 0 : makeMenuItem(PITCH_SPELL_FLATS_COMMAND),
388 0 : makeMenu(TranslatableString("appshell/menu/tools", "Enharmonic spelling"), {
389 0 : makeMenuItem(ENHARMONIC_SPELL_BOTH_COMMAND),
390 0 : makeMenuItem(ENHARMONIC_SPELL_CURRENT_COMMAND),
391 0 : makeMenuItem(PITCH_SPELL_COMMAND),
392 : }, "menu-enharmonic-spelling"),
393 0 : makeSeparator(),
394 0 : makeMenuItem(REGROUP_RHYTHMS_COMMAND),
395 0 : makeMenuItem(RESEQUENCE_REHEARSAL_MARKS_COMMAND),
396 0 : makeSeparator(),
397 0 : makeMenuItem(COPY_LYRICS_COMMAND),
398 0 : makeMenuItem(REMOVE_EMPTY_TRAILING_MEASURES_COMMAND),
399 0 : };
400 :
401 0 : return makeMenu(TranslatableString("appshell/menu/tools", "&Tools"), toolsItems, "menu-tools");
402 0 : }
403 :
404 0 : muse::uicomponents::MenuItemList AppMenuModel::makeExtensionsSubitems()
405 : {
406 : MenuItemList subitems {
407 0 : makeMenuItem(APP_EXTENSIONS_COMMAND),
408 0 : };
409 :
410 0 : MenuItemList extensions = makeExtensionsItems();
411 :
412 0 : if (!extensions.empty()) {
413 0 : subitems << makeSeparator();
414 : }
415 :
416 0 : subitems << extensions;
417 0 : return subitems;
418 0 : }
419 :
420 0 : MenuItem* AppMenuModel::makeExtensionsMenu()
421 : {
422 0 : return makeMenu(TranslatableString("appshell/menu/plugins", "E&xtensions"), makeExtensionsSubitems(), "menu-extensions");
423 : }
424 :
425 0 : MenuItem* AppMenuModel::makeHelpMenu(bool addDiagnosticsSubMenu)
426 : {
427 0 : MenuItemList helpItems;
428 :
429 0 : if (updateConfiguration()->isAppUpdatable()) {
430 0 : helpItems << makeMenuItem(UPDATE_CHECK_COMMAND);
431 0 : helpItems << makeSeparator();
432 : }
433 :
434 0 : helpItems << makeMenuItem(APP_ONLINE_HANDBOOK_COMMAND);
435 0 : helpItems << makeMenuItem(APP_ASK_HELP_COMMAND);
436 0 : helpItems << makeSeparator();
437 :
438 0 : if (addDiagnosticsSubMenu) {
439 0 : helpItems << makeDiagnosticsMenu();
440 0 : helpItems << makeSeparator();
441 : }
442 :
443 0 : helpItems << makeMenuItem(APP_ABOUT_MUSESCORE_COMMAND, MenuItemRole::AboutRole);
444 0 : helpItems << makeMenuItem(APP_ABOUT_QT_COMMAND, MenuItemRole::AboutQtRole);
445 0 : helpItems << makeMenuItem(APP_ABOUT_MUSICXML_COMMAND);
446 0 : helpItems << makeMenuItem(APP_ACCESSIBILITY_STATEMENT_COMMAND);
447 0 : helpItems << makeSeparator();
448 :
449 : #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
450 : if (isMuseSamplerModuleAdded()) {
451 : helpItems << makeMenuItem(CLEAR_ONLINESOUNDS_CACHE_COMMAND);
452 : helpItems << makeSeparator();
453 : }
454 : #endif
455 :
456 0 : helpItems << makeMenuItem(APP_REVERT_TO_FACTORY_COMMAND);
457 :
458 0 : return makeMenu(TranslatableString("appshell/menu/help", "&Help"), helpItems, "menu-help");
459 0 : }
460 :
461 0 : MenuItem* AppMenuModel::makeDiagnosticsMenu()
462 : {
463 : MenuItemList items {
464 0 : makeMenuItem(DIAGNOSTICS_SAVE_FILES_COMMAND),
465 0 : makeMenuItem(RELOAD_PLAYBACK_CACHE_COMMAND),
466 0 : makeMenu(TranslatableString("appshell/menu/diagnostics", "&System"), {
467 0 : makeMenuItem(DIAGNOSTICS_SHOW_PATHS_COMMAND),
468 0 : makeMenuItem(DIAGNOSTICS_SHOW_GRAPHICSINFO_COMMAND),
469 0 : makeMenuItem(DIAGNOSTICS_SHOW_PROFILER_COMMAND),
470 : }, "menu-system")
471 0 : };
472 :
473 0 : if (isMuseSamplerModuleAdded()) {
474 : MenuItemList museSamplerItems {
475 0 : makeMenuItem(MUSESAMPLER_CHECK_COMMAND),
476 0 : };
477 :
478 0 : if (globalConfiguration()->devModeEnabled()) {
479 0 : museSamplerItems << makeMenuItem(MUSESAMPLER_RELOAD_COMMAND);
480 : }
481 :
482 0 : items << makeMenu(TranslatableString("appshell/menu/diagnostics", "&MuseSampler"), museSamplerItems, "menu-musesampler");
483 0 : }
484 :
485 0 : if (globalConfiguration()->devModeEnabled()) {
486 : MenuItemList actionsItems {
487 0 : makeMenuItem(DIAGNOSTICS_SHOW_ACTIONS_COMMAND),
488 0 : makeMenuItem(DIAGNOSTICS_SHOW_RCOMMANDS_COMMAND)
489 0 : };
490 :
491 : MenuItemList accessibilityItems {
492 0 : makeMenuItem(DIAGNOSTICS_SHOW_NAVIGATION_TREE_COMMAND),
493 0 : makeMenuItem(DIAGNOSTICS_SHOW_ACCESSIBLE_TREE_COMMAND),
494 0 : makeMenuItem(DIAGNOSTICS_DUMP_ACCESSIBLE_TREE_COMMAND),
495 0 : };
496 :
497 : MenuItemList engravingItems {
498 0 : makeMenuItem(DIAGNOSTICS_SHOW_ENGRAVING_ELEMENTS_COMMAND),
499 0 : makeMenuItem(DIAGNOSTICS_SHOW_ENGRAVING_UNDOSTACK_COMMAND),
500 0 : makeMenuItem(DIAGNOSTICS_SHOW_ENGRAVING_STYLE_COMMAND),
501 0 : makeSeparator(),
502 0 : makeMenuItem(SHOW_ELEMENT_BOUNDING_RECTS_COMMAND),
503 0 : makeMenuItem(COLOR_ELEMENT_SHAPES_COMMAND),
504 0 : makeMenuItem(SHOW_SEGMENT_SHAPES_COMMAND),
505 0 : makeMenuItem(COLOR_SEGMENT_SHAPES_COMMAND),
506 0 : makeMenuItem(SHOW_SKYLINES_COMMAND),
507 0 : makeMenuItem(SHOW_SYSTEM_BOUNDING_RECTS_COMMAND),
508 0 : makeMenuItem(SHOW_ELEMENT_MASKS_COMMAND),
509 0 : makeMenuItem(SHOW_GAP_RESTS_COMMAND),
510 0 : makeMenuItem(SHOW_LINE_ATTACH_POINTS_COMMAND),
511 0 : makeMenuItem(MARK_EMPTY_STAFF_COMMAND),
512 0 : makeMenuItem(SHOW_ORIGIN_AND_COMBINED_COMMAND),
513 0 : makeMenuItem(MARK_CORRUPTED_MEASURES_COMMAND),
514 0 : makeMenuItem(CHECK_FOR_SCORE_CORRUPTIONS_COMMAND)
515 0 : };
516 :
517 : MenuItemList extensionsItems {
518 0 : makeMenuItem(OPEN_APIDUMP_COMMAND),
519 0 : };
520 :
521 : MenuItemList testflowItems {
522 0 : makeMenuItem(TESTFLOW_OPEN_SCRIPTS_COMMAND),
523 0 : };
524 :
525 : #ifdef MUSE_MODULE_VST
526 : MenuItemList vstItems {
527 0 : makeMenuItem(VST_USE_OLDVIEW_COMMAND),
528 0 : makeMenuItem(VST_USE_NEWVIEW_COMMAND),
529 0 : };
530 : #endif
531 :
532 : MenuItemList audioItems {
533 0 : makeMenuItem(AUDIO_DEV_USE_DRIVER_MODE_COMMAND),
534 0 : makeMenuItem(AUDIO_DEV_USE_HYBRID_MODE_COMMAND),
535 0 : };
536 :
537 0 : items << makeMenu(TranslatableString("appshell/menu/diagnostics", "A&ctions"), actionsItems, "menu-diagnostics-actions")
538 0 : << makeMenu(TranslatableString("appshell/menu/diagnostics",
539 0 : "&Accessibility"), accessibilityItems, "menu-diagnostics-accessibility")
540 0 : << makeMenu(TranslatableString("appshell/menu/diagnostics", "&Engraving"), engravingItems, "menu-diagnostics-engraving")
541 0 : << makeMenu(TranslatableString("appshell/menu/diagnostics", "E&xtensions"), extensionsItems, "menu-diagnostics-extensions")
542 0 : << makeMenu(TranslatableString("appshell/menu/diagnostics", "&Testflow"), testflowItems, "menu-diagnostics-testflow");
543 :
544 : #ifdef MUSE_MODULE_VST
545 0 : items << makeMenu(TranslatableString("appshell/menu/diagnostics", "&VST"), vstItems, "menu-diagnostics-vst");
546 : #endif
547 :
548 0 : items << makeMenu(TranslatableString("appshell/menu/diagnostics", "&Audio"), audioItems, "menu-diagnostics-audio")
549 0 : << makeMenuItem(MULTIWINDOWS_DEV_SHOW_INFO_COMMAND);
550 0 : }
551 :
552 0 : return makeMenu(TranslatableString("appshell/menu/diagnostics", "&Diagnostics"), items, "menu-diagnostic");
553 0 : }
554 :
555 0 : MenuItemList AppMenuModel::makeRecentSubMenuItems()
556 : {
557 0 : MenuItemList items;
558 0 : const RecentFilesList& recentFiles = recentFilesController()->recentFilesList();
559 :
560 0 : for (const RecentFile& file : recentFiles) {
561 0 : rcommand::CommandQuery query(PROJECT_OPEN_COMMAND);
562 0 : query.set("url", Val(file.path.toQUrl().toString().toStdString()));
563 0 : query.set("display_name", Val(file.displayNameOverride.toStdString()));
564 :
565 0 : MenuItem* item = new MenuItem(this);
566 0 : item->setCommandQuery(query);
567 0 : item->setTitle(TranslatableString::untranslatable(file.displayName(/*includingExtension*/ true)));
568 0 : item->setSelectable(true);
569 :
570 0 : bool isCloud = projectConfiguration()->isCloudProject(file.path);
571 0 : if (isCloud) {
572 0 : item->setIcon(IconCode::Code::CLOUD);
573 : }
574 :
575 0 : items << item;
576 0 : }
577 :
578 0 : if (!items.empty()) {
579 0 : items << makeSeparator()
580 0 : << makeMenuItem(PROJECT_CLEAR_RECENT_COMMAND);
581 : }
582 :
583 0 : return items;
584 0 : }
585 :
586 0 : MenuItemList AppMenuModel::makeNotesItems()
587 : {
588 : MenuItemList items {
589 0 : makeMenuItem(TOGGLE_NOTE_INPUT_COMMAND),
590 0 : makeSeparator(),
591 0 : makeMenuItem(ENTER_NOTE_C_COMMAND),
592 0 : makeMenuItem(ENTER_NOTE_D_COMMAND),
593 0 : makeMenuItem(ENTER_NOTE_E_COMMAND),
594 0 : makeMenuItem(ENTER_NOTE_F_COMMAND),
595 0 : makeMenuItem(ENTER_NOTE_G_COMMAND),
596 0 : makeMenuItem(ENTER_NOTE_A_COMMAND),
597 0 : makeMenuItem(ENTER_NOTE_B_COMMAND),
598 0 : makeSeparator(),
599 0 : makeMenuItem(ADD_NOTE_C_COMMAND),
600 0 : makeMenuItem(ADD_NOTE_D_COMMAND),
601 0 : makeMenuItem(ADD_NOTE_E_COMMAND),
602 0 : makeMenuItem(ADD_NOTE_F_COMMAND),
603 0 : makeMenuItem(ADD_NOTE_G_COMMAND),
604 0 : makeMenuItem(ADD_NOTE_A_COMMAND),
605 0 : makeMenuItem(ADD_NOTE_B_COMMAND),
606 0 : };
607 :
608 0 : return items;
609 : }
610 :
611 0 : MenuItemList AppMenuModel::makeIntervalsItems()
612 : {
613 : MenuItemList items {
614 0 : makeMenuItem(ADD_INTERVAL_PLUS_1_COMMAND),
615 0 : makeMenuItem(ADD_INTERVAL_PLUS_2_COMMAND),
616 0 : makeMenuItem(ADD_INTERVAL_PLUS_3_COMMAND),
617 0 : makeMenuItem(ADD_INTERVAL_PLUS_4_COMMAND),
618 0 : makeMenuItem(ADD_INTERVAL_PLUS_5_COMMAND),
619 0 : makeMenuItem(ADD_INTERVAL_PLUS_6_COMMAND),
620 0 : makeMenuItem(ADD_INTERVAL_PLUS_7_COMMAND),
621 0 : makeMenuItem(ADD_INTERVAL_PLUS_8_COMMAND),
622 0 : makeMenuItem(ADD_INTERVAL_PLUS_9_COMMAND),
623 0 : makeMenuItem(ADD_INTERVAL_PLUS_10_COMMAND),
624 0 : makeSeparator(),
625 0 : makeMenuItem(ADD_INTERVAL_MINUS_2_COMMAND),
626 0 : makeMenuItem(ADD_INTERVAL_MINUS_3_COMMAND),
627 0 : makeMenuItem(ADD_INTERVAL_MINUS_4_COMMAND),
628 0 : makeMenuItem(ADD_INTERVAL_MINUS_5_COMMAND),
629 0 : makeMenuItem(ADD_INTERVAL_MINUS_6_COMMAND),
630 0 : makeMenuItem(ADD_INTERVAL_MINUS_7_COMMAND),
631 0 : makeMenuItem(ADD_INTERVAL_MINUS_8_COMMAND),
632 0 : makeMenuItem(ADD_INTERVAL_MINUS_9_COMMAND),
633 0 : makeMenuItem(ADD_INTERVAL_MINUS_10_COMMAND)
634 0 : };
635 :
636 0 : return items;
637 : }
638 :
639 0 : MenuItemList AppMenuModel::makeTupletsItems()
640 : {
641 : MenuItemList items {
642 0 : makeMenuItem(ADD_DUPLET_COMMAND),
643 0 : makeMenuItem(ADD_TRIPLET_COMMAND),
644 0 : makeMenuItem(ADD_QUADRUPLET_COMMAND),
645 0 : makeMenuItem(ADD_QUINTUPLET_COMMAND),
646 0 : makeMenuItem(ADD_SEXTUPLET_COMMAND),
647 0 : makeMenuItem(ADD_SEPTUPLET_COMMAND),
648 0 : makeMenuItem(ADD_OCTUPLET_COMMAND),
649 0 : makeMenuItem(ADD_NONUPLET_COMMAND),
650 0 : makeMenuItem(OPEN_TUPLET_CONFIGURE_COMMAND)
651 0 : };
652 :
653 0 : return items;
654 : }
655 :
656 0 : MenuItemList AppMenuModel::makeMeasuresItems()
657 : {
658 : MenuItemList items {
659 0 : makeMenuItem(INSERT_MEASURE_COMMAND),
660 0 : makeMenuItem(APPEND_MEASURE_COMMAND),
661 0 : makeSeparator(),
662 0 : makeMenuItem(INSERT_MEASURES_COMMAND),
663 0 : makeMenuItem(INSERT_MEASURES_AFTER_SELECTION_COMMAND),
664 0 : makeSeparator(),
665 0 : makeMenuItem(INSERT_MEASURES_AT_START_OF_SCORE_COMMAND),
666 0 : makeMenuItem(APPEND_MEASURES_COMMAND)
667 0 : };
668 :
669 0 : return items;
670 : }
671 :
672 0 : MenuItemList AppMenuModel::makeFramesItems()
673 : {
674 : MenuItemList items {
675 0 : makeMenuItem(INSERT_HBOX_COMMAND),
676 0 : makeMenuItem(INSERT_VBOX_COMMAND),
677 0 : makeMenuItem(INSERT_TEXTFRAME_COMMAND),
678 0 : makeMenuItem(INSERT_FRETFRAME_COMMAND),
679 0 : makeSeparator(),
680 0 : makeMenu(TranslatableString("notation", "Insert at end of score"), {
681 0 : makeMenuItem(APPEND_HBOX_COMMAND),
682 0 : makeMenuItem(APPEND_VBOX_COMMAND),
683 0 : makeMenuItem(APPEND_TEXTFRAME_COMMAND),
684 0 : makeMenuItem(APPEND_FRETFRAME_COMMAND)
685 : })
686 0 : };
687 :
688 0 : return items;
689 : }
690 :
691 0 : MenuItemList AppMenuModel::makeTextItems()
692 : {
693 : MenuItemList items {
694 0 : makeMenuItem(ADD_TITLE_TEXT_COMMAND),
695 0 : makeMenuItem(ADD_SUBTITLE_TEXT_COMMAND),
696 0 : makeMenuItem(ADD_COMPOSER_TEXT_COMMAND),
697 0 : makeMenuItem(ADD_LYRICIST_TEXT_COMMAND),
698 0 : makeMenuItem(ADD_PART_TEXT_COMMAND),
699 0 : makeSeparator(),
700 0 : makeMenuItem(ADD_SYSTEM_TEXT_COMMAND),
701 0 : makeMenuItem(ADD_STAFF_TEXT_COMMAND),
702 0 : makeMenuItem(ADD_DYNAMIC_COMMAND),
703 0 : makeMenuItem(ADD_EXPRESSION_TEXT_COMMAND),
704 0 : makeMenuItem(ADD_REHEARSALMARK_TEXT_COMMAND),
705 0 : makeMenuItem(ADD_INSTRUMENT_CHANGE_TEXT_COMMAND),
706 0 : makeMenuItem(ADD_FINGERING_TEXT_COMMAND),
707 0 : makeSeparator(),
708 0 : makeMenuItem(ADD_STICKING_TEXT_COMMAND),
709 0 : makeMenuItem(ADD_CHORD_TEXT_COMMAND),
710 0 : makeMenuItem(ADD_ROMAN_NUMERAL_TEXT_COMMAND),
711 0 : makeMenuItem(ADD_NASHVILLE_NUMBER_TEXT_COMMAND),
712 0 : makeMenuItem(ADD_LYRICS_COMMAND),
713 0 : makeMenuItem(ADD_FIGURED_BASS_COMMAND),
714 0 : makeMenuItem(ADD_TEMPO_COMMAND)
715 0 : };
716 :
717 0 : return items;
718 : }
719 :
720 0 : MenuItemList AppMenuModel::makeLinesItems()
721 : {
722 : MenuItemList items {
723 0 : makeMenuItem(ADD_SLUR_COMMAND),
724 0 : makeMenuItem(ADD_HAIRPIN_COMMAND),
725 0 : makeMenuItem(ADD_HAIRPIN_REVERSE_COMMAND),
726 0 : makeMenuItem(ADD_OTTAVA_8VA_COMMAND),
727 0 : makeMenuItem(ADD_OTTAVA_8VB_COMMAND),
728 0 : makeMenuItem(ADD_NOTELINE_COMMAND)
729 0 : };
730 :
731 0 : return items;
732 : }
733 :
734 0 : MenuItemList AppMenuModel::makeExtensionsItems()
735 : {
736 0 : MenuItemList result;
737 :
738 0 : KnownCategories categories = extensionsRegister()->knownCategories();
739 0 : ManifestList manifests = extensionsRegister()->manifestList(Filter::Enabled);
740 :
741 0 : auto makeMenuItem = [this](const Manifest& m, const Action& a) {
742 0 : rcommand::Command command = makeCommand(m.uri, a.code);
743 0 : return this->makeMenuItem(command);
744 0 : };
745 :
746 0 : auto addMenuItems = [this, makeMenuItem](MenuItemList& items, const Manifest& m) {
747 0 : MenuItemList sub;
748 0 : for (const muse::extensions::Action& a : m.actions) {
749 0 : if (!a.showOnAppmenu) {
750 0 : continue;
751 : }
752 0 : sub << makeMenuItem(m, a);
753 : }
754 :
755 0 : if (sub.empty()) {
756 0 : return;
757 : }
758 :
759 0 : if (sub.size() == 1) {
760 0 : items << sub.at(0);
761 0 : return;
762 : }
763 :
764 0 : items << makeMenu(TranslatableString::untranslatable(m.title), sub);
765 0 : };
766 :
767 0 : std::map<std::string, MenuItemList> categoriesMap;
768 0 : MenuItemList pluginsWithoutCategories;
769 0 : for (const Manifest& m : manifests) {
770 0 : std::string categoryStr = m.category.toStdString();
771 0 : if (!categoryStr.empty()) {
772 0 : if (!muse::contains(categories, categoryStr)) {
773 0 : categories[categoryStr] = TranslatableString("extensions", m.category);
774 : }
775 0 : MenuItemList& items = categoriesMap[categoryStr];
776 0 : addMenuItems(items, m);
777 : } else {
778 0 : addMenuItems(pluginsWithoutCategories, m);
779 : }
780 0 : }
781 :
782 0 : for (const auto& it : categoriesMap) {
783 0 : TranslatableString categoryTitle = muse::value(categories, it.first, {});
784 0 : result << makeMenu(categoryTitle, it.second);
785 0 : }
786 :
787 0 : std::sort(result.begin(), result.end(), [](const MenuItem& l, const MenuItem& r) {
788 0 : return l.translatedTitle() < r.translatedTitle();
789 : });
790 :
791 0 : std::sort(pluginsWithoutCategories.begin(), pluginsWithoutCategories.end(), [](const MenuItem& l, const MenuItem& r) {
792 0 : return l.translatedTitle() < r.translatedTitle();
793 : });
794 :
795 0 : for (MenuItem* plugin : pluginsWithoutCategories) {
796 0 : result << plugin;
797 : }
798 :
799 0 : return result;
800 0 : }
|