From 1b5888bf82459239fc89db341c3ebdaeaf139d8d Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Tue, 28 Aug 2018 03:55:53 +0200 Subject: [PATCH] Context menu improvements - rneamed some paths, group "model stuff" together - no spearators if same menu key root (such entries belong semantically together) --- .../components/dbmappingcomponent.cpp | 25 +++---- src/blackgui/menus/aircraftmodelmenus.cpp | 8 +-- src/blackgui/menus/menuaction.cpp | 53 +++++++++++---- src/blackgui/menus/menuaction.h | 68 +++++++++++-------- src/blackgui/views/aircraftmodelview.cpp | 6 +- 5 files changed, 99 insertions(+), 61 deletions(-) diff --git a/src/blackgui/components/dbmappingcomponent.cpp b/src/blackgui/components/dbmappingcomponent.cpp index 1f56fb185..ea098eb98 100644 --- a/src/blackgui/components/dbmappingcomponent.cpp +++ b/src/blackgui/components/dbmappingcomponent.cpp @@ -922,15 +922,15 @@ namespace BlackGui menuActions.addMenuStash(); // auto filter in DB views - m_stashFiltering = menuActions.addAction(m_stashFiltering, CIcons::filter16(), "Auto filtering in DB views (on/off)", CMenuAction::pathStash(), this, { mapComp, &CDbMappingComponent::toggleAutoFiltering }); + m_stashFiltering = menuActions.addAction(m_stashFiltering, CIcons::filter16(), "Auto filtering in DB views (on/off)", CMenuAction::pathModelStash(), this, { mapComp, &CDbMappingComponent::toggleAutoFiltering }); m_stashFiltering->setCheckable(true); m_stashFiltering->setChecked(mapComp->m_autoFilterInDbViews); - m_autoStashing = menuActions.addAction(m_autoStashing, CIcons::appDbStash16(), "Auto stashing", CMenuAction::pathStash(), this, { mapComp, &CDbMappingComponent::displayAutoStashingDialog }); - m_autoSimulatorStashing = menuActions.addAction(m_autoSimulatorStashing, CIcons::appDbStash16(), "Cross simulator updating (FSX-P3D-FS9)", CMenuAction::pathStash(), this, { mapComp, &CDbMappingComponent::displayAutoSimulatorStashingDialog }); + m_autoStashing = menuActions.addAction(m_autoStashing, CIcons::appDbStash16(), "Auto stashing", CMenuAction::pathModelStash(), this, { mapComp, &CDbMappingComponent::displayAutoStashingDialog }); + m_autoSimulatorStashing = menuActions.addAction(m_autoSimulatorStashing, CIcons::appDbStash16(), "Cross simulator updating (FSX-P3D-FS9)", CMenuAction::pathModelStash(), this, { mapComp, &CDbMappingComponent::displayAutoSimulatorStashingDialog }); if (mapComp->m_autoStashDialog && mapComp->m_autoStashDialog->isCompleted()) { - menuActions.addAction(CIcons::appDbStash16(), "Last auto stash run", CMenuAction::pathStash(), nullptr, { mapComp->m_autoStashDialog.data(), &CDbAutoStashingComponent::showLastResults }); + menuActions.addAction(CIcons::appDbStash16(), "Last auto stash run", CMenuAction::pathModelStash(), nullptr, { mapComp->m_autoStashDialog.data(), &CDbAutoStashingComponent::showLastResults }); } } else if (mapComp->currentTabIndex() == CDbMappingComponent::TabStash) @@ -948,14 +948,14 @@ namespace BlackGui const int dbModels = sGui->getWebDataServices()->getModelsCount(); if (dbModels > 0 && mapComp->hasStashedModels()) { - menuActions.addMenu(CIcons::appDbStash16(), "Stash", CMenuAction::pathStash()); + menuActions.addMenu(CIcons::appDbStash16(), "Stash", CMenuAction::pathModelStash()); // we have keys and data by which we could delete them from view const QString msgDelete("Delete " + QString::number(dbModels) + " DB model(s) from '" + mapComp->currentTabText() + "'"); - menuActions.addAction(CIcons::delete16(), msgDelete, CMenuAction::pathStash(), nullptr, { mapComp, &CDbMappingComponent::removeDbModelsFromView}); + menuActions.addAction(CIcons::delete16(), msgDelete, CMenuAction::pathModelStash(), nullptr, { mapComp, &CDbMappingComponent::removeDbModelsFromView}); // attribute info - menuActions.addAction(CIcons::info16(), "Show changed attributes", CMenuAction::pathStash(), nullptr, { mapComp, &CDbMappingComponent::showChangedAttributes}); + menuActions.addAction(CIcons::info16(), "Show changed attributes", CMenuAction::pathModelStash(), nullptr, { mapComp, &CDbMappingComponent::showChangedAttributes}); } } @@ -972,7 +972,8 @@ namespace BlackGui { menuActions.addMenuModelSet(); m_menuAction = menuActions.addAction(m_menuAction, CIcons::appModels16(), - "Add to own model set", CMenuAction::pathModelSet(), + "Add to own model set " + CShortcut::toParenthesisString(CShortcut::keyAddToModelSet()), + CMenuAction::pathModelSet(), this, { mapComp, &CDbMappingComponent::ps_addToOwnModelSet }, CShortcut::keyAddToModelSet()); } @@ -996,10 +997,10 @@ namespace BlackGui // stash view and selection menuActions.addMenuStashEditor(); - m_menuActions[0] = menuActions.addAction(m_menuActions[0], CIcons::appAircraftIcao16(), "Current aircraft ICAO", CMenuAction::pathStashEditor(), this, { mapComp, &CDbMappingComponent::applyFormAircraftIcaoData }); - m_menuActions[1] = menuActions.addAction(m_menuActions[1], CIcons::appDistributors16(), "Current distributor", CMenuAction::pathStashEditor(), this, { mapComp, &CDbMappingComponent::applyFormDistributorData }); - m_menuActions[2] = menuActions.addAction(m_menuActions[2], CIcons::appLiveries16(), "Current livery", CMenuAction::pathStashEditor(), this, { mapComp, &CDbMappingComponent::applyFormLiveryData }); - m_menuActions[3] = menuActions.addAction(m_menuActions[3], CIcons::databaseTable16(), "Modify DB model data", CMenuAction::pathStashEditor(), this, { mapComp, &CDbMappingComponent::modifyModelDialog }); + m_menuActions[0] = menuActions.addAction(m_menuActions[0], CIcons::appAircraftIcao16(), "Current aircraft ICAO", CMenuAction::pathModelStashEditor(), this, { mapComp, &CDbMappingComponent::applyFormAircraftIcaoData }); + m_menuActions[1] = menuActions.addAction(m_menuActions[1], CIcons::appDistributors16(), "Current distributor", CMenuAction::pathModelStashEditor(), this, { mapComp, &CDbMappingComponent::applyFormDistributorData }); + m_menuActions[2] = menuActions.addAction(m_menuActions[2], CIcons::appLiveries16(), "Current livery", CMenuAction::pathModelStashEditor(), this, { mapComp, &CDbMappingComponent::applyFormLiveryData }); + m_menuActions[3] = menuActions.addAction(m_menuActions[3], CIcons::databaseTable16(), "Modify DB model data", CMenuAction::pathModelStashEditor(), this, { mapComp, &CDbMappingComponent::modifyModelDialog }); } this->nestedCustomMenu(menuActions); } diff --git a/src/blackgui/menus/aircraftmodelmenus.cpp b/src/blackgui/menus/aircraftmodelmenus.cpp index 35df78350..eb37a5dbf 100644 --- a/src/blackgui/menus/aircraftmodelmenus.cpp +++ b/src/blackgui/menus/aircraftmodelmenus.cpp @@ -184,10 +184,10 @@ namespace BlackGui menuActions.addMenuConsolidateModels(); - m_consolidateAll = menuActions.addAction(m_consolidateAll, CIcons::databaseEdit16(), "All with DB data", CMenuAction::pathViewModelsConsolidate(), { this, &CConsolidateWithDbDataMenu::consolidateData }); + m_consolidateAll = menuActions.addAction(m_consolidateAll, CIcons::databaseEdit16(), "All with DB data", CMenuAction::pathModelConsolidate(), { this, &CConsolidateWithDbDataMenu::consolidateData }); if (mv->hasSelection()) { - m_consolidateSelected = menuActions.addAction(m_consolidateSelected, CIcons::databaseEdit16(), "Selected with DB data", CMenuAction::pathViewModelsConsolidate(), { this, &CConsolidateWithDbDataMenu::consolidateSelectedData }); + m_consolidateSelected = menuActions.addAction(m_consolidateSelected, CIcons::databaseEdit16(), "Selected with DB data", CMenuAction::pathModelConsolidate(), { this, &CConsolidateWithDbDataMenu::consolidateSelectedData }); } this->nestedCustomMenu(menuActions); } @@ -291,10 +291,10 @@ namespace BlackGui menuActions.addMenuConsolidateModels(); - m_consolidateAll = menuActions.addAction(m_consolidateAll, CIcons::appModels16(), "All with simulator models", CMenuAction::pathViewModelsConsolidate(), { this, &CConsolidateWithSimulatorModels::consolidateData }); + m_consolidateAll = menuActions.addAction(m_consolidateAll, CIcons::appModels16(), "All with simulator models", CMenuAction::pathModelConsolidate(), { this, &CConsolidateWithSimulatorModels::consolidateData }); if (mv->hasSelection()) { - m_consolidateSelected = menuActions.addAction(m_consolidateSelected, CIcons::appModels16(), "Selected with simulator models", CMenuAction::pathViewModelsConsolidate(), { this, &CConsolidateWithSimulatorModels::consolidateSelectedData }); + m_consolidateSelected = menuActions.addAction(m_consolidateSelected, CIcons::appModels16(), "Selected with simulator models", CMenuAction::pathModelConsolidate(), { this, &CConsolidateWithSimulatorModels::consolidateSelectedData }); } this->nestedCustomMenu(menuActions); } diff --git a/src/blackgui/menus/menuaction.cpp b/src/blackgui/menus/menuaction.cpp index 3ea1868e3..24bffb7e0 100644 --- a/src/blackgui/menus/menuaction.cpp +++ b/src/blackgui/menus/menuaction.cpp @@ -92,7 +92,7 @@ namespace BlackGui const CMenuAction &CMenuAction::subMenuConsolidateModels() { - static const CMenuAction subdir(CIcons::appModels16(), "Consolidate models", CMenuAction::pathViewModelsConsolidate()); + static const CMenuAction subdir(CIcons::appModels16(), "Consolidate models", CMenuAction::pathModelConsolidate()); return subdir; } @@ -140,7 +140,7 @@ namespace BlackGui } } } - actions.append(checkableActions); // checkable actions ar end + actions.append(checkableActions); // checkable actions at end } CMenuActions::CMenuActions(const QList &actions) @@ -324,17 +324,19 @@ namespace BlackGui void CMenuActions::toQMenu(QMenu &menu, bool separateGroups) const { if (m_actions.isEmpty()) { return; } - const QStringList keys = m_actions.uniqueKeys(); // Sorted ascending + const QStringList keys = m_actions.uniqueKeys(); // Sorted ascending keys, we need a menu for all those keys QMap subMenus; // all sub menus + QString lastKey; + for (const QString &key : keys) { - bool addedSeparator = false; + bool handledSeparator = false; const int pathDepth = CMenuActions::pathDepth(key); // 0 based QList actions; QList menus; - this->splitSubMenus(key, actions, menus); + this->splitSubMenus(key, actions, menus); // splits actions and (sub) menus for that key if (actions.isEmpty()) { // No actions directly for that level @@ -342,8 +344,11 @@ namespace BlackGui } if (!menu.isEmpty() && separateGroups) { - menu.addSeparator(); - addedSeparator = true; + // no separator a) if there is already one b) key roots are the same (such entries belong together) + const bool noSeparator = (!menu.actions().isEmpty() && menu.actions().last()->isSeparator()) || + (isSameKeyRoot(key, lastKey)); + if (!noSeparator) { menu.addSeparator(); } + handledSeparator = true; } int noActionsWithoutPath = 0; @@ -372,10 +377,10 @@ namespace BlackGui noActionsWithoutPath++; // separator for unclassfied items - if ((!addedSeparator || noActionsWithoutPath > 1) && menuAction.hasNoPathWithSeparator()) + if ((!handledSeparator || noActionsWithoutPath > 1) && menuAction.hasNoPathWithSeparator()) { menu.addSeparator(); - addedSeparator = false; + handledSeparator = false; } } @@ -394,6 +399,10 @@ namespace BlackGui { menu.removeAction(currentMenu->menuAction()); } + + // remember last key + lastKey = key; + } // keys } @@ -427,16 +436,16 @@ namespace BlackGui CMenuAction CMenuActions::addMenuStash() { - if (this->containsMenu(CMenuAction::pathStash())) { return CMenuAction(); } + if (this->containsMenu(CMenuAction::pathModelStash())) { return CMenuAction(); } const bool canConnectDb = sGui->getWebDataServices()->hasSuccesfullyConnectedSwiftDb(); const QString txt(canConnectDb ? "Stash tools" : "Stash tools (Warning: no DB!)"); - return this->addMenu(CIcons::appDbStash16(), txt, CMenuAction::pathStash()); + return this->addMenu(CIcons::appDbStash16(), txt, CMenuAction::pathModelStash()); } CMenuAction CMenuActions::addMenuStashEditor() { - if (this->containsMenu(CMenuAction::pathStashEditor())) { return CMenuAction(); } - return this->addMenu(CIcons::appDbStash16(), "Edit models", CMenuAction::pathStashEditor()); + if (this->containsMenu(CMenuAction::pathModelStashEditor())) { return CMenuAction(); } + return this->addMenu(CIcons::appDbStash16(), "Edit models", CMenuAction::pathModelStashEditor()); } CMenuAction CMenuActions::addMenuDatabase() @@ -447,7 +456,7 @@ namespace BlackGui CMenuAction CMenuActions::addMenuConsolidateModels() { - if (this->containsMenu(CMenuAction::pathViewModelsConsolidate())) { CMenuAction(); } + if (this->containsMenu(CMenuAction::pathModelConsolidate())) { CMenuAction(); } return this->addMenu(CMenuAction::subMenuConsolidateModels()); } @@ -517,6 +526,22 @@ namespace BlackGui return currentPath.left(i); } + QString CMenuActions::keyRoot(const QString &key) + { + const int i = key.lastIndexOf('.'); + if (i < 0) { return ""; } + return key.left(i); + } + + bool CMenuActions::isSameKeyRoot(const QString &key1, const QString &key2) + { + const int i1 = key1.lastIndexOf('.'); + if (i1 < 0) { return false; } + const int i2 = key2.lastIndexOf('.'); + if (i2 < 0 || i1 != i2) { return false; } + return key1.left(i1) == key2.left(i2); + } + QMenu *CMenuActions::findUpwardsInMenus(const QString &key, const QMap &menus) { QString k = key; diff --git a/src/blackgui/menus/menuaction.h b/src/blackgui/menus/menuaction.h index b05bbb5dd..f20fdf004 100644 --- a/src/blackgui/menus/menuaction.h +++ b/src/blackgui/menus/menuaction.h @@ -118,88 +118,87 @@ namespace BlackGui //! Path converter into separator static const QString &pathSeparator() { static const QString p("_SEPARATOR"); return p; } - //! Simulator sub menu - static const QString &pathSimulator() { static const QString p("Custom.10.Simulator/Simulator"); return p; } + static const QString &pathSimulator() { static const QString p("Custom.10.Simulator/Simulator"); return p; } //! Simulator sub menu reload models - static const QString &pathSimulatorModelsReload() { static const QString p("Custom.10.Simulator/Simulator/Reload models"); return p; } + static const QString &pathSimulatorModelsReload() { static const QString p("Custom.10.Simulator/Simulator/Reload models"); return p; } //! Simulator sub menu reload models - static const QString &pathSimulatorModelsClearCache() { static const QString p("Custom.10.Simulator/Simulator/Clear model caches"); return p; } + static const QString &pathSimulatorModelsClearCache() { static const QString p("Custom.10.Simulator/Simulator/Clear model caches"); return p; } //! Model - static const QString &pathModel() { static const QString p("Custom.11.Model"); return p; } + static const QString &pathModel() { static const QString p("Custom.11.Model"); return p; } //! Model set - static const QString &pathModelSet() { static const QString p("Custom.11.Model/Model set"); return p; } + static const QString &pathModelSet() { static const QString p("Custom.11.Model/Model set"); return p; } //! Model set, new set - static const QString &pathModelSetNew() { static const QString p("Custom.11.Model/Model set/New set"); return p; } + static const QString &pathModelSetNew() { static const QString p("Custom.11.Model/Model set/New set"); return p; } + + //! Consolidate + static const QString &pathModelConsolidate() { static const QString p("Custom.11.Model/Consolidate"); return p; } //! Stash sub menu - static const QString &pathStash() { static const QString p("Custom.12.Stash/Stash"); return p; } + static const QString &pathModelStash() { static const QString p("Custom.11.Model/Stash/Stash"); return p; } //! Stash editor sub menu - static const QString &pathStashEditor() { static const QString p("Custom.13.Stash/Editor"); return p; } + static const QString &pathModelStashEditor() { static const QString p("Custom.11.Model/Stash/Editor"); return p; } //! vPilot data //! \deprecated vPilot functionality likely to be removed in the future - static const QString &pathVPilot() { static const QString p("Custom.14.vPilot/vPilot"); return p; } + static const QString &pathVPilot() { static const QString p("Custom.14.vPilot/vPilot"); return p; } //! Log functionality - static const QString &pathLog() { static const QString p("Custom15.Log"); return p; } + static const QString &pathLog() { static const QString p("Custom15.Log"); return p; } //! Font menus (font size etc.) - static const QString &pathFont() { static const QString p("Custom20.Font"); return p; } + static const QString &pathFont() { static const QString p("Custom20.Font"); return p; } // ---- client ---- //! Client COM related - static const QString &pathClientCom() { static const QString p("Client.ATC"); return p; } + static const QString &pathClientCom() { static const QString p("Client.ATC"); return p; } //! Client simulation related - static const QString &pathClientSimulation() { static const QString p("Client.Simulation"); return p; } + static const QString &pathClientSimulation() { static const QString p("Client.Simulation"); return p; } // ---- standard view paths -------- //! Database - static const QString &pathViewDatabase() { static const QString p("View.10.Database/Database"); return p; } - - //! Consolidate - static const QString &pathViewModelsConsolidate() { static const QString p("View.11.Models/Consolidate"); return p; } + static const QString &pathViewDatabase() { static const QString p("View.10.Database/Database"); return p; } //! Select add remove - static const QString &pathViewAddRemove() { static const QString p("View.12.AddRemove"); return p; } + static const QString &pathViewAddRemove() { static const QString p("View.12.AddRemove"); return p; } //! View selection mode - static const QString &pathViewSelection() { static const QString p("View.13.Selection/Selection"); return p; } + static const QString &pathViewSelection() { static const QString p("View.13.Selection/Selection"); return p; } //! Order submenus - static const QString &pathViewOrder() { static const QString p("View.14.Order/Order"); return p; } + static const QString &pathViewOrder() { static const QString p("View.14.Order/Order"); return p; } //! View resizing - static const QString &pathViewResize() { static const QString p("View.15.Resize"); return p; } + static const QString &pathViewResize() { static const QString p("View.15.Resize"); return p; } //! View clear highlighting - static const QString &pathViewClearHighlighting() { static const QString p("View.16.ClearHighlight"); return p; } + static const QString &pathViewClearHighlighting() { static const QString p("View.16.ClearHighlight"); return p; } //! View filter - static const QString &pathViewFilter() { static const QString p("View.17.Filter"); return p; } + static const QString &pathViewFilter() { static const QString p("View.17.Filter"); return p; } //! View update - static const QString &pathViewUpdates() { static const QString p("View.18.Updates"); return p; } + static const QString &pathViewUpdates() { static const QString p("View.18.Updates"); return p; } //! View load/save - static const QString &pathViewLoadSave() { static const QString p("View.18.LoadSave"); return p; } + static const QString &pathViewLoadSave() { static const QString p("View.18.LoadSave"); return p; } //! View cut and paste - static const QString &pathViewCutPaste() { static const QString p("View.18.CutPaste"); return p; } + static const QString &pathViewCutPaste() { static const QString p("View.18.CutPaste"); return p; } // ---- nested dock widgets ---- //! Nested dock widget - static const QString &pathDockWidgetNested() { static const QString p("DockWidget.Nested"); return p; } + static const QString &pathDockWidgetNested() { static const QString p("DockWidget.Nested"); return p; } //! @} //! \name Predefined sub sub menus @@ -361,9 +360,22 @@ namespace BlackGui //! Split actions into submenus, normal actions and fix order void splitSubMenus(const QString &key, QList &actions, QList &menus) const; + //! Path depth static int pathDepth(const QString &path); + + //! find current menu for given action static QMenu *currentMenuForAction(QMenu &menu, const CMenuAction &menuAction, const QList &menus, QMap &subMenus, const QString &key, int pd); + + //! Get parent path (one level up) for path static QString parentPath(const QString &cuurentPath); + + //! Root of "Custom.11.Model/Stash/Stash" is "Custom.11" + static QString keyRoot(const QString &key); + + //! Same key root? + static bool isSameKeyRoot(const QString &key1, const QString &key2); + + //! Find key in top level menus static QMenu *findUpwardsInMenus(const QString &key, const QMap &menus); }; } // ns diff --git a/src/blackgui/views/aircraftmodelview.cpp b/src/blackgui/views/aircraftmodelview.cpp index 8b051693d..81fed5a9c 100644 --- a/src/blackgui/views/aircraftmodelview.cpp +++ b/src/blackgui/views/aircraftmodelview.cpp @@ -299,8 +299,8 @@ namespace BlackGui if (!m_menuFlagActions.contains(MenuCanStashModels)) { CMenuActions ma; - ma.addAction(CIcons::appDbStash16(), "Stash selected", CMenuAction::pathStash(), { this, &CAircraftModelView::requestedStash }); - QAction *added = ma.addAction(CIcons::appDbStash16(), "Stashing clears selection (on/off)", CMenuAction::pathStash(), { this, &CAircraftModelView::stashingClearsSelection }); + ma.addAction(CIcons::appDbStash16(), "Stash selected", CMenuAction::pathModelStash(), { this, &CAircraftModelView::requestedStash }); + QAction *added = ma.addAction(CIcons::appDbStash16(), "Stashing clears selection (on/off)", CMenuAction::pathModelStash(), { this, &CAircraftModelView::stashingClearsSelection }); added->setCheckable(true); m_menuFlagActions.insert(MenuCanStashModels, ma); } @@ -321,7 +321,7 @@ namespace BlackGui if (!m_menuFlagActions.contains(MenuHighlightStashed)) { CMenuActions ma; - QAction *added = ma.addAction(CIcons::appDbStash16(), "Highlight stashed (on/off)", CMenuAction::pathStash(), { this, &CAircraftModelView::toggleHighlightStashedModels }); + QAction *added = ma.addAction(CIcons::appDbStash16(), "Highlight stashed (on/off)", CMenuAction::pathModelStash(), { this, &CAircraftModelView::toggleHighlightStashedModels }); added->setCheckable(true); m_menuFlagActions.insert(MenuHighlightStashed, ma); }