mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
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
This commit is contained in:
421
src/blackgui/menus/menuaction.cpp
Normal file
421
src/blackgui/menus/menuaction.cpp
Normal file
@@ -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 <algorithm>
|
||||
|
||||
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<CMenuAction> &actions, QList<CMenuAction> &menus) const
|
||||
{
|
||||
QList<CMenuAction> myActions(this->m_actions.values(key));
|
||||
QList<CMenuAction> 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<CMenuAction> &actions)
|
||||
{
|
||||
for (const CMenuAction &action : actions)
|
||||
{
|
||||
this->addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
QList<QAction *> CMenuActions::getQActions() const
|
||||
{
|
||||
QList<QAction *> 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<CMenuAction>(); };
|
||||
const QList<CMenuAction> allActions(this->m_actions.values(path));
|
||||
QList<CMenuAction> 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<CMenuAction> 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<QAction *> &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<void ()> &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<void ()> &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<void ()> &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<void ()> &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<void ()> &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<void ()> &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<void ()> &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<void ()> &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<QString, QMenu *> subMenus;
|
||||
|
||||
for (const QString &key : keys)
|
||||
{
|
||||
bool addedSeparator = false;
|
||||
const int pd = pathDepth(key);
|
||||
|
||||
QList<CMenuAction> actions;
|
||||
QList<CMenuAction> 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<CMenuAction> CMenuActions::toQList() const
|
||||
{
|
||||
return this->m_actions.values();
|
||||
}
|
||||
|
||||
CMenuActions::operator QList<QAction *>() const
|
||||
{
|
||||
QList<QAction *> 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<CMenuAction> &menus, QMap<QString, QMenu *> &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
|
||||
300
src/blackgui/menus/menuaction.h
Normal file
300
src/blackgui/menus/menuaction.h
Normal file
@@ -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 <QMenu>
|
||||
#include <QAction>
|
||||
#include <QIcon>
|
||||
#include <QMultiMap>
|
||||
|
||||
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<CMenuAction> &actions);
|
||||
|
||||
//! All actions
|
||||
CMenuActions getActions() const { return m_actions.values(); }
|
||||
|
||||
//! QActions
|
||||
QList<QAction *> 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<QAction *> &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<void()> &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<void()> &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<void()> &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<void()> &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<void()> &slot, const QKeySequence &shortcut = 0);
|
||||
|
||||
//! Add action
|
||||
CMenuAction addAction(const QIcon &actionIcon, const QString &text, const QString &path, const BlackMisc::CSlot<void()> &slot, const QKeySequence &shortcut = 0);
|
||||
|
||||
//! Add menu action
|
||||
CMenuAction addAction(const QString &text, const QString &path, const BlackMisc::CSlot<void()> &slot, const QKeySequence &shortcut = 0);
|
||||
|
||||
//! Add menu action
|
||||
CMenuAction addAction(const QString &text, const QString &path, QObject *actionOwner, const BlackMisc::CSlot<void()> &slot, const QKeySequence &shortcut = 0);
|
||||
|
||||
//! Insert the sorted actions to the menu
|
||||
void toQMenu(QMenu &menu, bool separateGroups) const;
|
||||
|
||||
//! To QList
|
||||
QList<CMenuAction> toQList() const;
|
||||
|
||||
//! First action
|
||||
CMenuAction first() const { return toQList().first(); }
|
||||
|
||||
//! Last action
|
||||
CMenuAction last() const { return toQList().last(); }
|
||||
|
||||
//! All actions;
|
||||
operator QList<QAction *>() const;
|
||||
|
||||
//! As QList
|
||||
operator QList<CMenuAction>() 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<QString, CMenuAction> m_actions; //!< actions sorted by path
|
||||
|
||||
//! Split actions into submenus, normal actions and fix order
|
||||
void splitSubMenus(const QString &key, QList<CMenuAction> &actions, QList<CMenuAction> &menus) const;
|
||||
|
||||
static int pathDepth(const QString &path);
|
||||
static QMenu *currentMenuForAction(QMenu &menu, const CMenuAction &menuAction, const QList<CMenuAction> &menus, QMap<QString, QMenu *> &subMenus, const QString &key, int pd);
|
||||
static QString parentPathKey(const QString &cuurentPath);
|
||||
};
|
||||
} // ns
|
||||
} // ns
|
||||
|
||||
#endif // guard
|
||||
@@ -11,7 +11,7 @@
|
||||
#define BLACKGUI_MENUS_MENUDELEGATE_H
|
||||
|
||||
#include "blackmisc/logcategorylist.h"
|
||||
#include <QMenu>
|
||||
#include "blackgui/menus/menuaction.h"
|
||||
#include <QObject>
|
||||
|
||||
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?
|
||||
|
||||
Reference in New Issue
Block a user