From 930ebeee30cddf4d08c7173508d844ff3317ecaf Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Tue, 26 Apr 2016 22:27:50 +0200 Subject: [PATCH] refs #648, added a sortable menu action with metadata and changed IMenuDelegate Idea: the menu will be generated as list of menu actions, then finalized before displayed --- src/blackgui/menus/menuaction.cpp | 421 ++++++++++++++++++++++++++++++ src/blackgui/menus/menuaction.h | 300 +++++++++++++++++++++ src/blackgui/menus/menudelegate.h | 15 +- 3 files changed, 725 insertions(+), 11 deletions(-) create mode 100644 src/blackgui/menus/menuaction.cpp create mode 100644 src/blackgui/menus/menuaction.h diff --git a/src/blackgui/menus/menuaction.cpp b/src/blackgui/menus/menuaction.cpp new file mode 100644 index 000000000..950e9b73f --- /dev/null +++ b/src/blackgui/menus/menuaction.cpp @@ -0,0 +1,421 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "menuaction.h" +#include "blackmisc/icons.h" +#include "blackmisc/verify.h" +#include + +using namespace BlackMisc; + +namespace BlackGui +{ + namespace Menus + { + CMenuAction::CMenuAction(const QIcon &icon, const QString &title, const QString &path, bool separator) : + m_icon(icon), m_title(title), m_path(path.trimmed()), m_separator(separator) + { } + + CMenuAction::CMenuAction(const QString &path, bool separator) : + m_path(path.trimmed()), m_separator(separator) + { } + + CMenuAction::CMenuAction(QAction *action, const QString &path, bool separator) : + m_action(action), m_icon(action->icon()), m_title(action->text()), m_path(path.trimmed()), m_separator(separator) + { } + + bool CMenuAction::isCheckableQAction() const + { + if (!this->m_action) { return false; } + return this->m_action->isCheckable(); + } + + void CMenuAction::setActionChecked(bool checked) + { + if (this->m_action) { m_action->setChecked(checked); } + } + + bool CMenuAction::hasNoPathWithSeparator() const + { + return this->m_separator && this->hasNoPath(); + } + + bool CMenuAction::hasNoPath() const + { + return this->m_path.isEmpty() || this->m_path == pathNone(); + } + + QString CMenuAction::getLastPathPart() const + { + if (this->m_path.contains('/')) + { + if (this->m_path.endsWith('/')) { return ""; } + const int i = this->m_path.lastIndexOf('/'); + return this->m_path.mid(i + 1); + } + return ""; + } + + void CMenuActions::splitSubMenus(const QString &key, QList &actions, QList &menus) const + { + QList myActions(this->m_actions.values(key)); + QList checkableActions; + std::reverse(myActions.begin(), myActions.end()); // the order is reverse because of the insert multi value + for (const CMenuAction &action : myActions) + { + if (action.isSubMenu() || !action.getQAction()) + { + menus.append(action); + } + else + { + if (action.isCheckableQAction()) + { + checkableActions.append(action); + } + else + { + actions.append(action); + } + } + } + actions.append(checkableActions); // checkable actions ar end + } + + CMenuActions::CMenuActions(const QList &actions) + { + for (const CMenuAction &action : actions) + { + this->addAction(action); + } + } + + QList CMenuActions::getQActions() const + { + QList qActions; + for (const CMenuAction &a : this->toQList()) + { + qActions.append(a.getQAction()); + } + return qActions; + } + + CMenuActions CMenuActions::getMenuActions(const QString &path) const + { + if (this->m_actions.contains(path)) { return QList(); }; + const QList allActions(this->m_actions.values(path)); + QList menuActions; + for (const CMenuAction &a : allActions) + { + if (a.isSubMenu() || !a.getQAction()) + { + menuActions.append(a); + } + } + return menuActions; + } + + bool CMenuActions::containsMenu(const QString &path) const + { + if (!this->m_actions.contains(path)) { return false; } + return getMenuActions(path).size() > 0; + } + + CMenuAction CMenuActions::addMenu(const QString &title, const QString &path) + { + return this->addMenu(QIcon(), title, path); + } + + CMenuAction CMenuActions::addMenu(const QIcon &icon, const QString &title, const QString &path) + { + CMenuAction menuAction(icon, title, path); + const QList exisitingMenu(this->getMenuActions(path)); + if (!exisitingMenu.isEmpty()) + { + const CMenuAction existing(exisitingMenu.first()); + Q_ASSERT_X(exisitingMenu.size() > 1, Q_FUNC_INFO, "Redundant menu entries"); + Q_ASSERT_X(existing.getTitle() != title, Q_FUNC_INFO, "Title mismatch"); + if (icon.isNull() && existing.hasIcon()) { return existing.getQAction(); } + + //! \todo replace if we have icon now, but not before + //! \todo avoid multiple menu entries + } + + menuAction.setSubMenu(true); + return this->addAction(menuAction); + } + + CMenuAction CMenuActions::addAction(const CMenuAction &menuAction) + { + Q_ASSERT_X(!menuAction.getPath().isEmpty(), Q_FUNC_INFO, "Need path"); + this->m_actions.insertMulti(menuAction.getPath(), menuAction); + return menuAction; + } + + CMenuActions CMenuActions::addActions(const CMenuActions &actions) + { + CMenuAction a; + CMenuActions menuActions; + for (const CMenuAction &action : actions.toQList()) + { + a = this->addAction(action); + menuActions.addAction(a); + } + return menuActions; + } + + CMenuAction CMenuActions::addAction(QAction *action, const QString &path) + { + return this->addAction(CMenuAction(action, path)); + } + + CMenuActions CMenuActions::addActions(const QList &actions, const QString &path) + { + if (actions.isEmpty()) { return CMenuActions(); } + CMenuAction menuAction; + CMenuActions menuActions; + for (QAction *a : actions) + { + menuAction = this->addAction(a, path); + menuActions.addAction(menuAction); + } + return menuActions; + } + + CMenuAction CMenuActions::addAction(QAction *action, const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + if (action) { return this->addAction(action, path); } + return this->addAction(text, path, slot, shortcut); + } + + CMenuAction CMenuActions::addAction(QAction *action, const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + if (action) { return this->addAction(action, path); } + return this->addAction(text, path, actionOwner, slot, shortcut); + } + + CMenuAction CMenuActions::addAction(QAction *action, const QIcon &icon, const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + if (action) { return this->addAction(action, path); } + return this->addAction(icon, text, path, slot, shortcut); + } + + CMenuAction CMenuActions::addAction(QAction *action, const QIcon &icon, const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + if (action) { return this->addAction(action, path); } + Q_ASSERT_X(actionOwner, Q_FUNC_INFO, "Need action owner"); // in this case nullptr as actionOwner is not allowed + return this->addAction(icon, text, path, actionOwner, slot, shortcut); + } + + CMenuAction CMenuActions::addAction(const QString &text, const QString &path, QObject *actionOwner, const QKeySequence &shortcut) + { + return this->addAction(QIcon(), text, path, actionOwner, shortcut); + } + + CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path, QObject *actionOwner, const QKeySequence &shortcut) + { + QAction *action = actionIcon.isNull() ? new QAction(text, actionOwner) : new QAction(actionIcon, text, actionOwner); + action->setShortcut(shortcut); + const CMenuAction ma(action, path); + return this->addAction(ma); + } + + CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + CMenuAction action = this->addAction(actionIcon, text, path, actionOwner, shortcut); + QAction::connect(action.getQAction(), &QAction::triggered, [slot](bool checked) + { + slot(); + Q_UNUSED(checked); + }); + return action; + } + + CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + return this->addAction(actionIcon, text, path, slot.object(), slot, shortcut); + } + + CMenuAction CMenuActions::addAction(const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + return this->addAction(QIcon(), text, path, slot.object(), slot, shortcut); + } + + CMenuAction CMenuActions::addAction(const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut) + { + return this->addAction(QIcon(), text, path, actionOwner, slot, shortcut); + } + + void CMenuActions::toQMenu(QMenu &menu, bool separateGroups) const + { + if (this->m_actions.isEmpty()) { return; } + const QStringList keys(this->m_actions.uniqueKeys()); + QMap subMenus; + + for (const QString &key : keys) + { + bool addedSeparator = false; + const int pd = pathDepth(key); + + QList actions; + QList menus; + this->splitSubMenus(key, actions, menus); + if (actions.isEmpty()) { continue; } + if (!menu.isEmpty() && separateGroups) + { + menu.addSeparator(); + addedSeparator = true; + } + + int noActionsWithoutPath = 0; + QMenu *currentMenu = nullptr; + + // reverse iteration because same key values are inserted and havve reverse order + for (const CMenuAction &menuAction : actions) + { + // create submenu if required + if (!currentMenu) + { + currentMenu = currentMenuForAction(menu, menuAction, menus, subMenus, key, pd); + } + Q_ASSERT_X(currentMenu, Q_FUNC_INFO, "Missing menu"); + Q_ASSERT_X(!menuAction.isSubMenu() && menuAction.getQAction(), Q_FUNC_INFO, "Wrong menu type"); + + if (menuAction.hasNoPath()) + { + noActionsWithoutPath++; + + // separator for unclassfied items + if ((!addedSeparator || noActionsWithoutPath > 1) && menuAction.hasNoPathWithSeparator()) + { + menu.addSeparator(); + addedSeparator = false; + } + } + + // either add to submenu or menu + currentMenu->addAction(menuAction.getQAction()); + + // menu has ownership if there is no other parent + if (menuAction.getQAction() && !menuAction.getQAction()->parent()) + { + menuAction.getQAction()->setParent(&menu); + } + } // actions + + // clean up empty sub menus + if (currentMenu && currentMenu->isEmpty()) + { + menu.removeAction(currentMenu->menuAction()); + } + } // keys + } + + QList CMenuActions::toQList() const + { + return this->m_actions.values(); + } + + CMenuActions::operator QList() const + { + QList qActions; + for (const CMenuAction &a : toQList()) + { + if (!a.getQAction()) { continue; } + qActions.append(a.getQAction()); + } + return qActions; + } + + CMenuAction CMenuActions::addMenuViewOrder() + { + if (this->containsMenu(CMenuAction::pathViewOrder())) { return CMenuAction(); } + return this->addMenu(CIcons::arrowMediumEast16(), "Order", CMenuAction::pathViewOrder()); + } + + CMenuAction CMenuActions::addMenuSimulator() + { + if (this->containsMenu(CMenuAction::pathSimulator())) { return CMenuAction(); } + return this->addMenu(CIcons::appSimulator16(), "Simulator", CMenuAction::pathSimulator()); + } + + CMenuAction CMenuActions::addMenuStash() + { + if (this->containsMenu(CMenuAction::pathStash())) { return CMenuAction(); } + return this->addMenu(CIcons::appDbStash16(), "Stash tools", CMenuAction::pathStash()); + } + + CMenuAction CMenuActions::addMenuStashEditor() + { + if (this->containsMenu(CMenuAction::pathStashEditor())) { return CMenuAction(); } + return this->addMenu(CIcons::appDbStash16(), "Edit models", CMenuAction::pathStashEditor()); + } + + CMenuAction CMenuActions::addMenuDatabase() + { + if (this->containsMenu(CMenuAction::pathViewDatabase())) { CMenuAction(); } + return this->addMenu(CIcons::appDatabase16(), "Database", CMenuAction::pathViewDatabase()); + } + + CMenuAction CMenuActions::addMenuModelSet() + { + if (this->containsMenu(CMenuAction::pathModelSet())) { CMenuAction(); } + return this->addMenu(CIcons::appModels16(), "Model set", CMenuAction::pathModelSet()); + } + + QMenu *CMenuActions::currentMenuForAction(QMenu &menu, const CMenuAction &menuAction, const QList &menus, QMap &subMenus, const QString &key, int pd) + { + if (pd < 1) { return &menu; } + + QMenu *parentMenu = &menu; + if (pd > 1) + { + const QString pk(parentPathKey(key)); + parentMenu = subMenus.value(pk); + BLACK_VERIFY_X(parentMenu, Q_FUNC_INFO, "Missing sub menu"); + if (!parentMenu) { parentMenu = &menu; } + } + + // explicity menu? + QMenu *subMenu = nullptr; + if (menus.isEmpty()) + { + subMenu = parentMenu->addMenu(menuAction.getLastPathPart()); + } + else + { + const CMenuAction menuFound(menus.first()); + subMenu = parentMenu->addMenu(menuFound.getIcon(), menuFound.getTitle()); + } + Q_ASSERT_X(subMenu, Q_FUNC_INFO, "Could not create sub menu"); + + subMenu->setParent(parentMenu); + if (pd > 0 && subMenu) + { + subMenus.insert(key, subMenu); + } + return subMenu; + } + + int CMenuActions::pathDepth(const QString &path) + { + if (path.isEmpty()) { return 0; } + int c = path.count('/'); + return c > 0 ? c : 0; + } + + QString CMenuActions::parentPathKey(const QString ¤tPath) + { + if (!currentPath.contains('/')) { return ""; } + const int i = currentPath.lastIndexOf('/'); + return currentPath.left(i); + } + + } // ns +} // ns diff --git a/src/blackgui/menus/menuaction.h b/src/blackgui/menus/menuaction.h new file mode 100644 index 000000000..c90bfc6cc --- /dev/null +++ b/src/blackgui/menus/menuaction.h @@ -0,0 +1,300 @@ +/* Copyright (C) 2015 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_MENUS_MENUACTION_H +#define BLACKGUI_MENUS_MENUACTION_H + +#include "blackmisc/slot.h" +#include +#include +#include +#include + +namespace BlackGui +{ + namespace Menus + { + /*! + * Wraps a QAction with extra metadata to allow proper sorting for a QMenu + */ + class CMenuAction + { + public: + //! Constructor + CMenuAction(const QIcon &icon, const QString &title, const QString &path = pathNone(), bool separator = false); + + //! Constructor + CMenuAction(const QString &path = pathNone(), bool separator = false); + + //! Constructor + CMenuAction(QAction *action, const QString &path = pathNone(), bool separator = false); + + //! Title + void setTitle(const QString &title) { m_title = title; } + + //! Icon + void setIcon(const QIcon &icon) { m_icon = icon; } + + //! Path + void setPath(const QString &path) { m_path = path; } + + //! Action + QAction *getQAction() const { return m_action; } + + //! Checkable QAction + bool isCheckableQAction() const; + + //! Set a checkable action, QAction::setChecked + void setActionChecked(bool checked); + + //! Path + const QString &getPath() const { return m_path; } + + //! Last part of the path, e.g. "Foo/Bar" -> "Bar" + QString getLastPathPart() const; + + //! Title + const QString &getTitle() const { return m_title; } + + //! Has title? + bool hasTitle() const { return !m_title.isEmpty(); } + + //! Is menu? + bool isSubMenu() const { return m_isMenu; } + + //! Is menu? + void setSubMenu(bool menu) { m_isMenu = menu; } + + //! No path and separator wanted + bool hasNoPathWithSeparator() const; + + //! No path? + bool hasNoPath() const; + + //! Icon + const QIcon &getIcon() const { return m_icon; } + + //! Has icon? + bool hasIcon() const { return !m_icon.isNull(); } + + //! Conversion + operator QAction *() const { return this->m_action; } + + // ---- paths for menus ---- + //! \name Menu path definitions + //! @{ + + //! No key + static const QString &pathNone() { static const QString p("_NONE"); return p; } + + //! Model set + static const QString &pathModelSet() { static const QString p("Custom.10.Model/Model set"); return p; } + + //! Model set, new set + static const QString &pathModelSetNew() { static const QString p("Custom.10.Model/Model set/New set"); return p; } + + //! Simulator sub menu + static const QString &pathSimulator() { static const QString p("Custom.11.Simulator/Simulator"); return p; } + + //! Simulator sub menu reload models + static const QString &pathSimulatorModelsReload() { static const QString p("Custom.11.Simulator/Simulator/Reload models"); return p; } + + //! Stash sub menu + static const QString &pathStash() { static const QString p("Custom.12.Stash/Stash"); return p; } + + //! Stash editor sub menu + static const QString &pathStashEditor() { static const QString p("Custom.13.Stash/Editor"); return p; } + + //! vPilot data + 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; } + + // ---- client ---- + + //! Client COM related + static const QString &pathClientCom() { static const QString p("Client.ATC"); return p; } + + //! Client COM related + 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; } + + //! Database merge + static const QString &pathViewDatabaseMerge() { static const QString p("View.10.Database/Database/Merge"); return p; } + + //! Select add remove + static const QString &pathViewAddRemove() { static const QString p("View.11.AddRemove"); return p; } + + //! View selection mode + static const QString &pathViewSelection() { static const QString p("View.12.Selection/Selection"); return p; } + + //! Order submenus + static const QString &pathViewOrder() { static const QString p("View.13.Order/Order"); return p; } + + //! View resizing + static const QString &pathViewResize() { static const QString p("View.14.Resize"); return p; } + + //! View filter + static const QString &pathViewFilter() { static const QString p("View.15.Filter"); return p; } + + //! View update + static const QString &pathViewUpdates() { static const QString p("View.16.Updates"); return p; } + + //! View load/save + static const QString &pathViewLoadSave() { static const QString p("View.17.LoadSave"); return p; } + + //! @} + + private: + QAction *m_action = nullptr; //!< the action + QIcon m_icon; //!< icon + QString m_title; //!< title + QString m_path; //!< path in menu + bool m_separator = false; //!< separator + bool m_isMenu = false; //!< is menu? + }; + + /*! + * Bunch of CMenuAction objects + */ + class CMenuActions + { + public: + //! Constructor + CMenuActions() {} + + //! Constructor + CMenuActions(const QList &actions); + + //! All actions + CMenuActions getActions() const { return m_actions.values(); } + + //! QActions + QList getQActions() const; + + //! All menu actions + CMenuActions getMenuActions(const QString &path) const; + + //! Menu already available? + bool containsMenu(const QString &path) const; + + //! Empty? + bool isEmpty() const { return m_actions.isEmpty(); } + + //! Elements + int size() const { return m_actions.size(); } + + //! Add a sub menu + CMenuAction addMenu(const QString &title, const QString &path); + + //! Add a sub menu + CMenuAction addMenu(const QIcon &icon, const QString &title, const QString &path); + + //! Add menu action + CMenuAction addAction(const CMenuAction &menuAction); + + //! Add menu actions, returns last valid QAction + CMenuActions addActions(const CMenuActions &actions); + + //! Add menu action + CMenuAction addAction(QAction *action, const QString &path); + + //! Add menu action + CMenuActions addActions(const QList &actions, const QString &path); + + //! Convenience function if method is also kept elsewhere + CMenuAction addAction(QAction *action, const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Convenience function if method is also kept elsewhere + CMenuAction addAction(QAction *action, const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Convenience function if method is also kept elsewhere + CMenuAction addAction(QAction *action, const QIcon &icon, const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Convenience function if method is also kept elsewhere + CMenuAction addAction(QAction *action, const QIcon &icon, const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Add action which still needs to be connected + CMenuAction addAction(const QString &text, const QString &path, QObject *actionOwner, const QKeySequence &shortcut = 0); + + //! Add action which still needs to be connected + CMenuAction addAction(const QIcon &actionIcon, const QString &text, const QString &path, QObject *actionOwner, const QKeySequence &shortcut = 0); + + //! Add action + CMenuAction addAction(const QIcon &actionIcon, const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Add action + CMenuAction addAction(const QIcon &actionIcon, const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Add menu action + CMenuAction addAction(const QString &text, const QString &path, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Add menu action + CMenuAction addAction(const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot &slot, const QKeySequence &shortcut = 0); + + //! Insert the sorted actions to the menu + void toQMenu(QMenu &menu, bool separateGroups) const; + + //! To QList + QList toQList() const; + + //! First action + CMenuAction first() const { return toQList().first(); } + + //! Last action + CMenuAction last() const { return toQList().last(); } + + //! All actions; + operator QList() const; + + //! As QList + operator QList() const { return toQList(); } + + //! \name Add some typical sub menus + //! @{ + + //! View order menu + CMenuAction addMenuViewOrder(); + + //! Simulator menu + CMenuAction addMenuSimulator(); + + //! Stash menu + CMenuAction addMenuStash(); + + //! Stash menu + CMenuAction addMenuStashEditor(); + + //! Database menu + CMenuAction addMenuDatabase(); + + //! Model set menu + CMenuAction addMenuModelSet(); + + //! @} + + private: + QMultiMap m_actions; //!< actions sorted by path + + //! Split actions into submenus, normal actions and fix order + void splitSubMenus(const QString &key, QList &actions, QList &menus) const; + + static int pathDepth(const QString &path); + static QMenu *currentMenuForAction(QMenu &menu, const CMenuAction &menuAction, const QList &menus, QMap &subMenus, const QString &key, int pd); + static QString parentPathKey(const QString &cuurentPath); + }; + } // ns +} // ns + +#endif // guard diff --git a/src/blackgui/menus/menudelegate.h b/src/blackgui/menus/menudelegate.h index ea5c075e7..b7938d019 100644 --- a/src/blackgui/menus/menudelegate.h +++ b/src/blackgui/menus/menudelegate.h @@ -11,7 +11,7 @@ #define BLACKGUI_MENUS_MENUDELEGATE_H #include "blackmisc/logcategorylist.h" -#include +#include "blackgui/menus/menuaction.h" #include using namespace BlackMisc; @@ -29,7 +29,7 @@ namespace BlackGui public: //! Display custom menu - virtual void customMenu(QMenu &menu) const = 0; + virtual void customMenu(CMenuActions &menuActions) = 0; //! Set nested delegate void setNestedDelegate(IMenuDelegate *nestedDelegate) { m_nestedDelegate = nestedDelegate; } @@ -53,17 +53,10 @@ namespace BlackGui QObject(parent), m_separator(separator) {} //! Delegate down one level - void nestedCustomMenu(QMenu &menu) const + void nestedCustomMenu(CMenuActions &menuActions) const { if (!m_nestedDelegate) { return; } - m_nestedDelegate->customMenu(menu); - } - - //! Add separator - virtual void addSeparator(QMenu &menu) const - { - if (!m_separator || menu.isEmpty()) { return; } - menu.addSeparator(); + m_nestedDelegate->customMenu(menuActions); } //! Does the previous (menu) item contain string?