diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5ac36f28d..d72165e16 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -30,7 +30,7 @@ add_library( SHARED ${COMMON_FILES} resource/common.qrc - ) +) target_include_directories(${PROJECT_NAME} PUBLIC diff --git a/src/common/actionmanager/action_define.h b/src/common/actionmanager/action_define.h new file mode 100644 index 000000000..cefe6a558 --- /dev/null +++ b/src/common/actionmanager/action_define.h @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef ACTION_DEFINE_H +#define ACTION_DEFINE_H + +#include + +// Menus +constexpr char M_TITLEBAR[] = "IDE.Menu.Titlebar"; // main title menu +constexpr char M_FILE[] = "IDE.Menu.File"; +constexpr char M_EDIT[] = "IDE.Menu.Edit"; +constexpr char M_BUILD[] = "IDE.Menu.Build"; +constexpr char M_DEBUG[] = "IDE.Menu.Debug"; +constexpr char M_TOOLS[] = "IDE.Menu.Tools"; +constexpr char M_TOOLS_BINARY[] = "IDE.Menu.Tools.Binary"; +constexpr char M_TOOLS_REVERSEDEBUG[] = "IDE.Menu.Tools.ReverseDebug"; +constexpr char M_HELP[] = "IDE.Menu.Help"; + +// Contexts +constexpr char C_GLOBAL[] = "Global Context"; + +// Special context that leads to all "more specific" contexts to be ignored. +// If you use Context(mycontextId, C_GLOBAL_CUTOFF) for a widget that has focus, +// mycontextId will be enabled but the contexts for all parent widgets, the manually added +// "additional" contexts, and the global context will be turned off. +constexpr char C_GLOBAL_CUTOFF[] = "Global Cutoff"; + +// Action Id +constexpr char A_REPORTBUG[] = "IDE.Action.ReportBug"; +constexpr char A_HELPDOC[] = "IDE.Action.HelpDocument"; +constexpr char A_TOOLBUTTON[] = "IDE.Action.ToolButton"; +constexpr char A_OPEN_FILE[] = "IDE.Action.OpenFile"; +constexpr char A_OPEN_PROJECT[] = "IDE.Action.OpenProject"; + +// Default groups +constexpr char G_DEFAULT_ONE[] = "IDE.Group.Default.One"; +constexpr char G_DEFAULT_TWO[] = "IDE.Group.Default.Two"; +constexpr char G_DEFAULT_THREE[] = "IDE.Group.Default.Three"; + +// Main title bar menu groups +constexpr char G_FILE[] = "IDE.Group.File"; +constexpr char G_EDIT[] = "IDE.Group.Edit"; +constexpr char G_BUILD[] = "IDE.Group.Build"; +constexpr char G_DEBUG[] = "IDE.Group.Debug"; +constexpr char G_TOOLS[] = "IDE.Group.Tools"; +constexpr char G_HELP[] = "IDE.Group.Help"; + +// File menu groups +constexpr char G_FILE_NEW[] = "IDE.Group.File.New"; +constexpr char G_FILE_OPEN[] = "IDE.Group.File.Open"; +constexpr char G_FILE_CLOSE[] = "IDE.Group.File.Close"; +constexpr char G_FILE_SAVE[] = "IDE.Group.File.Save"; + +// Edit menu groups +constexpr char G_EDIT_UNDOREDO[] = "IDE.Group.Edit.UndoRedo"; +constexpr char G_EDIT_COPYPASTE[] = "IDE.Group.Edit.CopyPaste"; +constexpr char G_EDIT_SELECTALL[] = "IDE.Group.Edit.SelectAll"; +constexpr char G_EDIT_FIND[] = "IDE.Group.Edit.Find"; +constexpr char G_EDIT_OTHER[] = "IDE.Group.Edit.Other"; + +inline QString stripAccelerator(const QString &text) +{ + QString res = text; + for (int index = res.indexOf('&'); index != -1; index = res.indexOf('&', index + 1)) + res.remove(index, 1); + return res; +} + +#endif // ACTION_DEFINE_H diff --git a/src/common/actionmanager/actioncontainer.cpp b/src/common/actionmanager/actioncontainer.cpp new file mode 100644 index 000000000..dba93fd49 --- /dev/null +++ b/src/common/actionmanager/actioncontainer.cpp @@ -0,0 +1,336 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "actioncontainer.h" +#include "actionmanager_p.h" +#include "command.h" +#include "action_define.h" +#include "util/qtcassert.h" + +#include +#include + +struct Group +{ + Group(const QString &id) + : id(id) {} + QString id; + QList items; // Command * or ActionContainer * +}; + +class ActionContainerPrivate : public QObject +{ +public: + explicit ActionContainerPrivate(ActionContainer *qq, const QString &id, ActionManagerPrivate *actMngPrivate); + ~ActionContainerPrivate(); + + void scheduleUpdate(); + void itemDestroyed(QObject *sender); + QList::const_iterator findGroup(const QString &groupId) const; + QAction *insertLocation(QList::const_iterator group) const; + +public: + ActionContainer *q; + + QMenu *menu { nullptr }; + QString actId; + ActionManagerPrivate *actMngPrivate { nullptr }; + QList groupList; + ActionContainer::OnAllDisabledBehavior onAllDisabledBehavior; +}; + +ActionContainerPrivate::ActionContainerPrivate(ActionContainer *qq, const QString &id, ActionManagerPrivate *actMngPrivate) + : q(qq), + menu(new QMenu), + actId(id), + actMngPrivate(actMngPrivate), + onAllDisabledBehavior(ActionContainer::Disable) +{ +} + +ActionContainerPrivate::~ActionContainerPrivate() +{ + delete menu; +} + +void ActionContainerPrivate::scheduleUpdate() +{ + actMngPrivate->scheduleContainerUpdate(q); +} + +void ActionContainerPrivate::itemDestroyed(QObject *sender) +{ + for (Group &group : groupList) { + if (group.items.removeAll(sender) > 0) + break; + } +} + +QList::const_iterator ActionContainerPrivate::findGroup(const QString &groupId) const +{ + auto it = groupList.cbegin(); + while (it != groupList.constEnd()) { + if (it->id == groupId) + break; + ++it; + } + return it; +} + +QAction *ActionContainerPrivate::insertLocation(QList::const_iterator group) const +{ + if (group == groupList.constEnd()) + return nullptr; + + ++group; + while (group != groupList.constEnd()) { + if (!group->items.isEmpty()) { + QObject *item = group->items.first(); + QAction *action = q->actionForItem(item); + if (action) + return action; + } + ++group; + } + + return nullptr; +} + +ActionContainer::ActionContainer(const QString &id, ActionManagerPrivate *actMngPrivate) + : d(new ActionContainerPrivate(this, id, actMngPrivate)) +{ + appendGroup(G_DEFAULT_ONE); + appendGroup(G_DEFAULT_TWO); + appendGroup(G_DEFAULT_THREE); + d->scheduleUpdate(); +} + +ActionContainer::~ActionContainer() +{ + delete d; +} + +void ActionContainer::setOnAllDisabledBehavior(OnAllDisabledBehavior behavior) +{ + d->onAllDisabledBehavior = behavior; +} + +ActionContainer::OnAllDisabledBehavior ActionContainer::onAllDisabledBehavior() const +{ + return d->onAllDisabledBehavior; +} + +QString ActionContainer::id() const +{ + return d->actId; +} + +QMenu *ActionContainer::menu() const +{ + return d->menu; +} + +QAction *ActionContainer::containerAction() const +{ + return d->menu->menuAction(); +} + +void ActionContainer::appendGroup(const QString &groupId) +{ + d->groupList.append(Group(groupId)); +} + +void ActionContainer::insertGroup(const QString &before, const QString &groupId) +{ + auto it = d->groupList.begin(); + while (it != d->groupList.end()) { + if (it->id == before) { + d->groupList.insert(it, Group(groupId)); + break; + } + ++it; + } +} + +void ActionContainer::addAction(Command *action, const QString &groupId) +{ + if (!action || !action->action()) + return; + + auto actualGroupId = !groupId.isEmpty() ? groupId : G_DEFAULT_TWO; + auto groupIt = d->findGroup(actualGroupId); + QTC_ASSERT(groupIt != d->groupList.constEnd(), qDebug() << "Can't find group" << groupId << "in container" << id(); return ); + d->groupList[groupIt - d->groupList.constBegin()].items.append(action); + connect(action, &Command::activeStateChanged, d, &ActionContainerPrivate::scheduleUpdate); + connect(action, &QObject::destroyed, d, &ActionContainerPrivate::itemDestroyed); + + QAction *beforeAction = d->insertLocation(groupIt); + insertAction(beforeAction, action); + + d->scheduleUpdate(); +} + +void ActionContainer::addMenu(ActionContainer *menu, const QString &groupId) +{ + auto actualGroupId = !groupId.isEmpty() ? groupId : G_DEFAULT_TWO; + auto groupIt = d->findGroup(actualGroupId); + QTC_ASSERT(groupIt != d->groupList.constEnd(), return ); + + d->groupList[groupIt - d->groupList.constBegin()].items.append(menu); + connect(menu, &QObject::destroyed, d, &ActionContainerPrivate::itemDestroyed); + + QAction *beforeAction = d->insertLocation(groupIt); + insertMenu(beforeAction, menu); + + d->scheduleUpdate(); +} + +void ActionContainer::addMenu(ActionContainer *before, ActionContainer *menu) +{ + for (Group &group : d->groupList) { + const int insertionPoint = group.items.indexOf(before); + if (insertionPoint >= 0) { + group.items.insert(insertionPoint, menu); + break; + } + } + connect(menu, &QObject::destroyed, d, &ActionContainerPrivate::itemDestroyed); + + QAction *beforeAction = before->containerAction(); + if (beforeAction) + insertMenu(beforeAction, menu); + + d->scheduleUpdate(); +} + +Command *ActionContainer::addSeparator(const QString &group) +{ + static const QStringList context { C_GLOBAL }; + return addSeparator(context, group); +} + +Command *ActionContainer::addSeparator(const QStringList &context, const QString &group, QAction **outSeparator) +{ + static int separatorIdCount = 0; + auto separator = new QAction(this); + separator->setSeparator(true); + auto sepId = id().append(".Separator.%1").arg(++separatorIdCount); + Command *cmd = ActionManager::instance()->registerAction(separator, sepId, context); + addAction(cmd, group); + if (outSeparator) + *outSeparator = separator; + + return cmd; +} + +void ActionContainer::clear() +{ + for (Group &group : d->groupList) { + for (QObject *item : std::as_const(group.items)) { + if (auto command = qobject_cast(item)) { + removeAction(command); + disconnect(command, &Command::activeStateChanged, + d, &ActionContainerPrivate::scheduleUpdate); + disconnect(command, &QObject::destroyed, d, &ActionContainerPrivate::itemDestroyed); + } else if (auto container = qobject_cast(item)) { + container->clear(); + disconnect(container, &QObject::destroyed, + d, &ActionContainerPrivate::itemDestroyed); + removeMenu(container); + } + } + group.items.clear(); + } + + d->scheduleUpdate(); +} + +QAction *ActionContainer::actionForItem(QObject *item) const +{ + if (auto cmd = qobject_cast(item)) { + return cmd->action(); + } else if (auto container = qobject_cast(item)) { + if (container->containerAction()) + return container->containerAction(); + } + QTC_ASSERT(false, return nullptr); +} + +void ActionContainer::insertAction(QAction *before, Command *command) +{ + d->menu->insertAction(before, command->action()); +} + +void ActionContainer::insertMenu(QAction *before, ActionContainer *container) +{ + QMenu *menu = container->menu(); + QTC_ASSERT(menu, return ); + menu->setParent(d->menu, menu->windowFlags()); + d->menu->insertMenu(before, menu); +} + +void ActionContainer::removeAction(Command *command) +{ + d->menu->removeAction(command->action()); +} + +void ActionContainer::removeMenu(ActionContainer *container) +{ + QMenu *menu = container->menu(); + QTC_ASSERT(menu, return ); + d->menu->removeAction(menu->menuAction()); +} + +bool ActionContainer::update() +{ + bool hasitems = false; + QList actions = d->menu->actions(); + + for (const Group &group : std::as_const(d->groupList)) { + for (QObject *item : std::as_const(group.items)) { + if (auto container = qobject_cast(item)) { + actions.removeAll(container->menu()->menuAction()); + if (container == this) { + QByteArray warning = Q_FUNC_INFO + QByteArray(" container '"); + if (this->menu()) + warning += this->menu()->title().toLocal8Bit(); + warning += "' contains itself as subcontainer"; + qWarning("%s", warning.constData()); + continue; + } + if (container->update()) { + hasitems = true; + break; + } + } else if (auto command = qobject_cast(item)) { + actions.removeAll(command->action()); + if (command->isActive() + && command->action()->menuRole() != QAction::ApplicationSpecificRole) { + hasitems = true; + break; + } + } else { + QTC_ASSERT(false, continue); + } + } + if (hasitems) + break; + } + if (!hasitems) { + // look if there were actions added that we don't control and check if they are enabled + for (const QAction *action : std::as_const(actions)) { + if (!action->isSeparator() && action->isEnabled()) { + hasitems = true; + break; + } + } + } + + if (onAllDisabledBehavior() == Hide) + d->menu->menuAction()->setVisible(hasitems); + else if (onAllDisabledBehavior() == Disable) + d->menu->menuAction()->setEnabled(hasitems); + + return hasitems; +} diff --git a/src/common/actionmanager/actioncontainer.h b/src/common/actionmanager/actioncontainer.h new file mode 100644 index 000000000..9df4eac72 --- /dev/null +++ b/src/common/actionmanager/actioncontainer.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef ACTIONCONTAINER_H +#define ACTIONCONTAINER_H + +#include + +class QMenu; +class QAction; +class Command; +class ActionManagerPrivate; +class ActionContainerPrivate; +class ActionContainer : public QObject +{ + Q_OBJECT +public: + enum OnAllDisabledBehavior { + Disable, + Hide, + Show + }; + + explicit ActionContainer(const QString &id, ActionManagerPrivate *actMngPrivate); + ~ActionContainer(); + + void setOnAllDisabledBehavior(OnAllDisabledBehavior behavior); + ActionContainer::OnAllDisabledBehavior onAllDisabledBehavior() const; + + QString id() const; + QMenu *menu() const; + QAction *containerAction() const; + + void appendGroup(const QString &groupId); + void insertGroup(const QString &before, const QString &groupId); + void addAction(Command *action, const QString &groupId = {}); + void addMenu(ActionContainer *menu, const QString &groupId = {}); + void addMenu(ActionContainer *before, ActionContainer *menu); + Command *addSeparator(const QString &group = {}); + Command *addSeparator(const QStringList &context, const QString &group = {}, QAction **outSeparator = nullptr); + void clear(); + + QAction *actionForItem(QObject *item) const; + void insertAction(QAction *before, Command *command); + void insertMenu(QAction *before, ActionContainer *container); + + void removeAction(Command *command); + void removeMenu(ActionContainer *container); + + bool update(); + +private: + ActionContainerPrivate *const d; +}; + +#endif // ACTIONCONTAINER_H diff --git a/src/common/actionmanager/actionmanager.cpp b/src/common/actionmanager/actionmanager.cpp index 117ea171b..080232892 100644 --- a/src/common/actionmanager/actionmanager.cpp +++ b/src/common/actionmanager/actionmanager.cpp @@ -1,219 +1,251 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #include "actionmanager.h" -#include "util/shortcututil.h" +#include "actionmanager_p.h" +#include "actioncontainer.h" +#include "command_p.h" #include "util/custompaths.h" -#include #include +#include +#include -class ActionManagerPrivate final -{ -public: - using IdCmdMap = QHash; - - explicit ActionManagerPrivate(ActionManager *qq); - ~ActionManagerPrivate(); - - Action *addOverrideAction(QString id, QAction *action); - Action *removeOverrideAction(QString id); - Command *command(QString id); - QList commands(); - - void addSetting(QString id, Action *action); - void removeSetting(QString id); - void saveAllSetting(); - void readUserSetting(); - -private: - ActionManager *q; - IdCmdMap idCmdMap; - QString configFilePath; -}; +constexpr char kKeyboardShortcuts[] = "KeyboardShortcuts"; +static ActionManager *m_instance = nullptr; -ActionManagerPrivate::ActionManagerPrivate(ActionManager *qq) - : q(qq), - configFilePath(CustomPaths::user(CustomPaths::Flags::Configures) + QDir::separator() + QString("shortcut.support")) +ActionManagerPrivate::ActionManagerPrivate() + : settings(CustomPaths::user(CustomPaths::Flags::Configures) + QDir::separator() + QString("shortcut.ini"), QSettings::IniFormat) { - } ActionManagerPrivate::~ActionManagerPrivate() { + for (auto container : std::as_const(idContainerMap)) + disconnect(container, &QObject::destroyed, this, &ActionManagerPrivate::containerDestroyed); + qDeleteAll(idContainerMap); + qDeleteAll(idCmdMap); } -Action *ActionManagerPrivate::addOverrideAction(QString id, QAction *action) +void ActionManagerPrivate::setContext(const QStringList &context) { - Action *a = idCmdMap.value(id, nullptr); - if (!a) { - a = new Action(id, action, q); - idCmdMap.insert(id, a); - } + cmdContext = context; + auto it = idCmdMap.cbegin(); + for (; it != idCmdMap.cend(); ++it) + it.value()->d->setCurrentContext(context); +} - return a; +bool ActionManagerPrivate::hasContext(const QStringList &context) const +{ + for (int i = 0; i < cmdContext.size(); ++i) { + if (context.contains(cmdContext.at(i))) + return true; + } + return false; } -Action *ActionManagerPrivate::removeOverrideAction(QString id) +Command *ActionManagerPrivate::overridableAction(const QString &id) { - Action *a = idCmdMap.value(id, nullptr); - if (a) { - idCmdMap.remove(id); + Command *cmd = idCmdMap.value(id, nullptr); + if (!cmd) { + cmd = new Command(id); + idCmdMap.insert(id, cmd); + readUserSettings(id, cmd); + QAction *action = cmd->action(); + mainWindow()->addAction(action); + action->setObjectName(id); + action->setShortcutContext(Qt::ApplicationShortcut); + cmd->d->setCurrentContext(cmdContext); } - return a; + return cmd; } -Command *ActionManagerPrivate::command(QString id) +void ActionManagerPrivate::scheduleContainerUpdate(ActionContainer *actionContainer) { - return idCmdMap.value(id, nullptr); + const bool needsSchedule = scheduledContainerUpdates.isEmpty(); + scheduledContainerUpdates.insert(actionContainer); + if (needsSchedule) + QMetaObject::invokeMethod(this, + &ActionManagerPrivate::updateContainer, + Qt::QueuedConnection); } -QList ActionManagerPrivate::commands() +void ActionManagerPrivate::updateContainer() { - QList result; - foreach (Command *cmd, idCmdMap) { - result << cmd; - } - - return result; + for (ActionContainer *c : std::as_const(scheduledContainerUpdates)) + c->update(); + scheduledContainerUpdates.clear(); } -void ActionManagerPrivate::addSetting(QString id, Action *action) +void ActionManagerPrivate::containerDestroyed(QObject *sender) { - QString shortcut = action->keySequence().toString(); - QString description = action->description(); - - QMap shortcutItemMap; - ShortcutUtil::readFromJson(configFilePath, shortcutItemMap); - QStringList valueList = {description, shortcut}; - shortcutItemMap[id] = valueList; - ShortcutUtil::writeToJson(configFilePath, shortcutItemMap); + auto container = static_cast(sender); + idContainerMap.remove(idContainerMap.key(container)); + scheduledContainerUpdates.remove(container); } -void ActionManagerPrivate::removeSetting(QString id) +QWidget *ActionManagerPrivate::mainWindow() const { - QMap shortcutItemMap; - ShortcutUtil::readFromJson(configFilePath, shortcutItemMap); - if (shortcutItemMap.contains(id)) { - shortcutItemMap.remove(id); + static QWidget *window { nullptr }; + if (window) + return window; + + for (auto w : qApp->allWidgets()) { + if (w->objectName() == "MainWindow") { + window = w; + break; + } } - ShortcutUtil::writeToJson(configFilePath, shortcutItemMap); + + return window; } -void ActionManagerPrivate::saveAllSetting() +void ActionManagerPrivate::saveSettings() { - QMap shortcutItemMap; - IdCmdMap::const_iterator iter = idCmdMap.begin(); - for (; iter != idCmdMap.end(); ++iter) - { - QStringList valueList = {iter.value()->description(), iter.value()->keySequence().toString()}; - shortcutItemMap.insert(iter.key(), valueList); + auto it = idCmdMap.cbegin(); + for (; it != idCmdMap.cend(); ++it) { + saveSettings(it.value()); } - - ShortcutUtil::writeToJson(configFilePath, shortcutItemMap); } -void ActionManagerPrivate::readUserSetting() -{ - QMap shortcutItemMap; - ShortcutUtil::readFromJson(configFilePath, shortcutItemMap); +void ActionManagerPrivate::saveSettings(Command *cmd) +{ + const auto &id = cmd->id(); + const auto settingsKey = QString(kKeyboardShortcuts) + '/' + id; + const QList keys = cmd->keySequences(); + const QList defaultKeys = cmd->defaultKeySequences(); + if (keys != defaultKeys) { + if (keys.isEmpty()) { + settings.setValue(settingsKey, QString()); + } else if (keys.size() == 1) { + settings.setValue(settingsKey, keys.first().toString()); + } else { + QStringList shortcutList; + std::transform(keys.begin(), keys.end(), shortcutList.begin(), + [](const QKeySequence &k) { + return k.toString(); + }); + settings.setValue(settingsKey, shortcutList); + } + } else { + settings.remove(settingsKey); + } +} - IdCmdMap::const_iterator iter = idCmdMap.begin(); - for (; iter != idCmdMap.end(); ++iter) - { - QString id = iter.key(); - if (shortcutItemMap.contains(id) && iter.value()->action()) { - QString shortcut = shortcutItemMap.value(id).last(); - iter.value()->action()->setShortcut(QKeySequence(shortcut)); +void ActionManagerPrivate::readUserSettings(const QString &id, Command *cmd) +{ + settings.beginGroup(kKeyboardShortcuts); + if (settings.contains(id)) { + const QVariant v = settings.value(id); + if (QMetaType::Type(v.type()) == QMetaType::QStringList) { + auto list = v.toStringList(); + QList keySequenceList; + std::transform(list.begin(), list.end(), keySequenceList.begin(), + [](const QString &s) { + return QKeySequence::fromString(s); + }); + cmd->setKeySequences(keySequenceList); + } else { + cmd->setKeySequences({ QKeySequence::fromString(v.toString()) }); } } + settings.endGroup(); } ActionManager::ActionManager(QObject *parent) - : QObject(parent) - , d(new ActionManagerPrivate(this)) + : QObject(parent), + d(new ActionManagerPrivate) { - + m_instance = this; } ActionManager::~ActionManager() { - if (d) { - delete d; - } + delete d; } -ActionManager *ActionManager::getInstance() +ActionManager *ActionManager::instance() { - static ActionManager ins; - return &ins; + return m_instance; } -/*! - \fn Command *ActionManager::registerAction(QAction *action, const QString id, - const QString description, - const QKeySequence defaultShortcut) +ActionContainer *ActionManager::createContainer(const QString &containerId) +{ + auto it = d->idContainerMap.constFind(containerId); + if (it != d->idContainerMap.constEnd()) + return it.value(); - Makes an action known to the system under the specified action, id, description, default shortcut. - New a command and insert to map, set the keysequence and description to action, and save info to config file. + auto mc = new ActionContainer(containerId, d); + d->idContainerMap.insert(containerId, mc); + connect(mc, &QObject::destroyed, d, &ActionManagerPrivate::containerDestroyed); - Returns a Command instance that represents the action in the application - and is owned by the ActionManager. + return mc; +} - Usage: ActionManager::getInstance->registerAction(...); -*/ -Command *ActionManager::registerAction(QAction *action, const QString &id, - const QString &description/* = nullptr*/, - const QKeySequence defaultShortcut/* = QKeySequence()*/) +ActionContainer *ActionManager::actionContainer(const QString &containerId) { - if(!action || id.isEmpty()) + auto it = d->idContainerMap.constFind(containerId); + if (it == d->idContainerMap.constEnd()) { + qWarning() << "failed to find :" << containerId; return nullptr; - - connect(action, &QAction::destroyed, this, [=] { - unregisterAction(id); - }); - - Action *a = d->addOverrideAction(id, action); - if (a) { - a->setKeySequence(defaultShortcut); - a->setDescription(description); } - - return a; + return it.value(); } -/*! - \fn void ActionManager::unregisterAction(QString id) - - Removes the knowledge about an action under the specified id. - Remove from map, set action shortcut to null, and save info to config file. - - Usage: ActionManager::getInstance->unregisterAction(...); -*/ -void ActionManager::unregisterAction(QString id) +Command *ActionManager::registerAction(QAction *action, const QString &id, const QStringList &context) { - d->removeOverrideAction(id); + Command *cmd = d->overridableAction(id); + if (cmd) { + cmd->d->addOverrideAction(action, context); + emit commandListChanged(); + emit commandAdded(id); + } + return cmd; } -Command *ActionManager::command(QString id) +void ActionManager::unregisterAction(QAction *action, const QString &id) { - return d->command(id); + Command *cmd = d->idCmdMap.value(id, nullptr); + if (!cmd) { + qWarning() << "unregisterAction: id" << id + << "is registered with a different command type."; + return; + } + + cmd->d->removeOverrideAction(action); + if (cmd->d->isEmpty()) { + // clean up + d->saveSettings(cmd); + delete cmd->action(); + d->idCmdMap.remove(id); + delete cmd; + } + emit commandListChanged(); } -QList ActionManager::commands() +Command *ActionManager::command(const QString &id) { - return d->commands(); + auto it = d->idCmdMap.constFind(id); + if (it == d->idCmdMap.constEnd()) { + qWarning() << " failed to find :" << id; + return nullptr; + } + return it.value(); } -void ActionManager::readUserSetting() +QList ActionManager::commandList() { - return d->readUserSetting(); + return d->idCmdMap.values(); } -void ActionManager::saveSetting() +void ActionManager::saveSettings() { - return d->saveAllSetting(); + d->saveSettings(); } +void ActionManager::setContext(const QStringList &context) +{ + d->setContext(context); +} diff --git a/src/common/actionmanager/actionmanager.h b/src/common/actionmanager/actionmanager.h index 6cdf4e228..982ff6550 100644 --- a/src/common/actionmanager/actionmanager.h +++ b/src/common/actionmanager/actionmanager.h @@ -1,41 +1,46 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef ACTIONMANAGER_H #define ACTIONMANAGER_H -#include "common/common_global.h" +#include "action_define.h" #include "command.h" +#include "actioncontainer.h" #include -#include +class QAction; class ActionManagerPrivate; -class COMMON_EXPORT ActionManager : public QObject +class ActionManager : public QObject { Q_OBJECT public: - static ActionManager *getInstance(); + static ActionManager *instance(); - Command *registerAction(QAction *action, const QString &id, - const QString &description = nullptr, - const QKeySequence defaultShortcut = QKeySequence()); - void unregisterAction(QString id); + ActionContainer *createContainer(const QString &containerId); + ActionContainer *actionContainer(const QString &containerId); - Command *command(QString id); - QList commands(); + Command *registerAction(QAction *action, const QString &id, + const QStringList &context = { C_GLOBAL }); + void unregisterAction(QAction *action, const QString &id); + Command *command(const QString &id); + QList commandList(); - void readUserSetting(); - void saveSetting(); + void saveSettings(); + void setContext(const QStringList &context); signals: + void commandListChanged(); + void commandAdded(const QString &id); private: - explicit ActionManager(QObject *parent = nullptr); - virtual ~ActionManager() override; + ActionManager(QObject *parent = nullptr); + ~ActionManager() override; ActionManagerPrivate *const d; + friend class Controller; }; -#endif // ACTIONMANAGER_H +#endif // ACTIONMANAGER_H diff --git a/src/common/actionmanager/actionmanager_p.h b/src/common/actionmanager/actionmanager_p.h new file mode 100644 index 000000000..e8e5abcdf --- /dev/null +++ b/src/common/actionmanager/actionmanager_p.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef ACTIONMANAGER_P_H +#define ACTIONMANAGER_P_H + +#include "actionmanager.h" + +#include +#include +#include + +class ActionManagerPrivate : public QObject +{ + Q_OBJECT +public: + ActionManagerPrivate(); + ~ActionManagerPrivate(); + + void setContext(const QStringList &context); + bool hasContext(const QStringList &context) const; + + Command *overridableAction(const QString &id); + void scheduleContainerUpdate(ActionContainer *actionContainer); + void updateContainer(); + void containerDestroyed(QObject *sender); + QWidget *mainWindow() const; + + void saveSettings(); + void saveSettings(Command *cmd); + void readUserSettings(const QString &id, Command *cmd); + +public: + using IdCmdMap = QHash; + using IdContainerMap = QHash; + + IdCmdMap idCmdMap; + IdContainerMap idContainerMap; + QSet scheduledContainerUpdates; + QStringList cmdContext; + QSettings settings; +}; + +#endif // ACTIONMANAGER_P_H diff --git a/src/common/actionmanager/command.cpp b/src/common/actionmanager/command.cpp index 1a2ea8b2e..04ee1262e 100644 --- a/src/common/actionmanager/command.cpp +++ b/src/common/actionmanager/command.cpp @@ -1,85 +1,226 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #include "command.h" +#include "command_p.h" +#include "commandaction.h" +#include "action_define.h" -#include +#include -class ActionPrivate +static QString msgActionWarning(QAction *newAction, const QString &id, QAction *oldAction) { -public: - ActionPrivate(); - virtual ~ActionPrivate(); + QString msg; + QTextStream str(&msg); + str << "addOverrideAction " << newAction->objectName() << '/' << newAction->text() + << ": Action "; + if (oldAction) + str << oldAction->objectName() << '/' << oldAction->text(); + str << " is already registered for context " << id << '.'; + return msg; +} + +CommandPrivate::CommandPrivate(const QString &id, Command *qq) + : q(qq), + cmdId(id), + action(new CommandAction(qq)) +{ + action->setShortcutVisibleInToolTip(true); + connect(action, &QAction::changed, this, &CommandPrivate::updateActiveState); +} + +void CommandPrivate::setCurrentContext(const QStringList &context) +{ + cmdContext = context; -private: - QString id; - QKeySequence shortcutKey; - QString description; - QAction *action; + QAction *currentAction = nullptr; + for (const auto &id : std::as_const(context)) { + if (id == C_GLOBAL_CUTOFF) + break; - friend class Action; -}; + if (QAction *a = contextActionMap.value(id, nullptr)) { + currentAction = a; + break; + } + } -ActionPrivate::ActionPrivate() - : action(nullptr) + action->setAction(currentAction); + updateActiveState(); +} + +void CommandPrivate::addOverrideAction(QAction *action, const QStringList &context) { + if (action->menuRole() == QAction::TextHeuristicRole) + action->setMenuRole(QAction::NoRole); + + if (isEmpty()) + this->action->initialize(action); + + if (context.isEmpty()) { + contextActionMap.insert(C_GLOBAL, action); + } else { + for (const auto &id : context) { + if (contextActionMap.contains(id)) + qWarning("%s", qPrintable(msgActionWarning(action, id, contextActionMap.value(id, nullptr)))); + contextActionMap.insert(id, action); + } + } + + setCurrentContext(cmdContext); +} +void CommandPrivate::removeOverrideAction(QAction *action) +{ + auto iter = contextActionMap.begin(); + for (; iter != contextActionMap.end();) { + if (!iter.value() || iter.value() == action) + iter = contextActionMap.erase(iter); + else + ++iter; + } } -ActionPrivate::~ActionPrivate() +bool CommandPrivate::isEmpty() const { + return contextActionMap.isEmpty(); } -Action::Action(QString id, QAction *action, QObject *parent) - : Command(parent), - d(new ActionPrivate()) +void CommandPrivate::updateActiveState() { - d->id = id; + setActive(action->isEnabled() && action->isVisible() && !action->isSeparator()); +} - if (action && !action->parent()) - action->setParent(this); - d->action = action; +void CommandPrivate::setActive(bool state) +{ + if (state == active) + return; + + active = state; + emit q->activeStateChanged(); +} + +Command::Command(const QString &id, QObject *parent) + : QObject(parent), + d(new CommandPrivate(id, this)) +{ } -Action::~Action() +Command::~Command() { delete d; } -QString Action::id() const +void Command::setDefaultKeySequence(const QKeySequence &key) { - return d->id; + if (!d->isKeyInitialized) + setKeySequences({ key }); + d->defaultKeys = { key }; } -QAction *Action::action() const +void Command::setDefaultKeySequences(const QList &keys) { - return d->action; + if (!d->isKeyInitialized) + setKeySequences(keys); + d->defaultKeys = keys; +} + +void Command::setKeySequences(const QList &keys) +{ + d->isKeyInitialized = true; + d->action->setShortcuts(keys); + emit keySequenceChanged(); +} + +QList Command::defaultKeySequences() const +{ + return d->defaultKeys; } -void Action::setKeySequence(const QKeySequence &key) +QList Command::keySequences() const { - d->shortcutKey = key; - if (d->action) - d->action->setShortcut(key); + return d->action->shortcuts(); } -QKeySequence Action::keySequence() const +QKeySequence Command::keySequence() const { - return d->shortcutKey; + return d->action->shortcut(); } -void Action::setDescription(const QString &text) +void Command::setDescription(const QString &text) { - d->description = text; - if (d->action) - d->action->setText(text); + d->defaultText = text; } -QString Action::description() const +QString Command::description() const { - return d->description; + if (!d->defaultText.isEmpty()) + return d->defaultText; + if (QAction *act = action()) { + const QString text = stripAccelerator(act->text()); + if (!text.isEmpty()) + return text; + } + return d->cmdId; } +QString Command::id() const +{ + return d->cmdId; +} +QAction *Command::action() const +{ + return d->action; +} +QStringList Command::context() const +{ + return d->cmdContext; +} + +void Command::setAttribute(CommandAttribute attr) +{ + d->attributes |= attr; + switch (attr) { + case Command::CA_Hide: + d->action->setAttribute(CommandAction::Hide); + break; + case Command::CA_UpdateText: + d->action->setAttribute(CommandAction::UpdateText); + break; + case Command::CA_UpdateIcon: + d->action->setAttribute(CommandAction::UpdateIcon); + break; + case Command::CA_NonConfigurable: + break; + } +} + +void Command::removeAttribute(CommandAttribute attr) +{ + d->attributes &= ~attr; + switch (attr) { + case Command::CA_Hide: + d->action->removeAttribute(CommandAction::Hide); + break; + case Command::CA_UpdateText: + d->action->removeAttribute(CommandAction::UpdateText); + break; + case Command::CA_UpdateIcon: + d->action->removeAttribute(CommandAction::UpdateIcon); + break; + case Command::CA_NonConfigurable: + break; + } +} + +bool Command::hasAttribute(CommandAttribute attr) const +{ + return d->attributes.testFlag(attr); +} + +bool Command::isActive() const +{ + return d->active; +} diff --git a/src/common/actionmanager/command.h b/src/common/actionmanager/command.h index 631b6782f..d8de5a4cb 100644 --- a/src/common/actionmanager/command.h +++ b/src/common/actionmanager/command.h @@ -1,56 +1,62 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef COMMAND_H #define COMMAND_H -#include "common/common_global.h" - #include -#include +QT_BEGIN_NAMESPACE class QAction; class QKeySequence; -class ActionPrivate; -class COMMON_EXPORT Command : public QObject +class QToolButton; +QT_END_NAMESPACE + +class CommandPrivate; +class Command : public QObject { Q_OBJECT public: - explicit Command(QObject *parent = nullptr) - : QObject(parent) {} - - virtual QString id() const = 0; - virtual QAction *action() const = 0; - - virtual void setKeySequence(const QKeySequence &key) = 0; - virtual QKeySequence keySequence() const = 0; - - virtual void setDescription(const QString &text) = 0; - virtual QString description() const = 0; + enum CommandAttribute { + CA_Hide = 1, + CA_UpdateText = 2, + CA_UpdateIcon = 4, + CA_NonConfigurable = 8 + }; + Q_DECLARE_FLAGS(CommandAttributes, CommandAttribute) + + Command(const QString &id, QObject *parent = nullptr); + ~Command(); + + void setDefaultKeySequence(const QKeySequence &key); + void setDefaultKeySequences(const QList &keys); + void setKeySequences(const QList &keys); + QList defaultKeySequences() const; + QList keySequences() const; + QKeySequence keySequence() const; + + void setDescription(const QString &text); + QString description() const; + QString id() const; + QAction *action() const; + QStringList context() const; + + void setAttribute(CommandAttribute attr); + void removeAttribute(CommandAttribute attr); + bool hasAttribute(CommandAttribute attr) const; + + bool isActive() const; signals: void keySequenceChanged(); -}; - -class Action : public Command -{ - Q_OBJECT -public: - Action(QString id, QAction *action, QObject *parent = nullptr); - virtual ~Action() override; - - QString id() const override; - QAction *action() const override; - - void setKeySequence(const QKeySequence &key) override; - QKeySequence keySequence() const override; - - void setDescription(const QString &text) override; - QString description() const override; + void activeStateChanged(); private: - ActionPrivate *const d; + friend class ActionManager; + friend class ActionManagerPrivate; + + CommandPrivate *const d; }; #endif // COMMAND_H diff --git a/src/common/actionmanager/command_p.h b/src/common/actionmanager/command_p.h new file mode 100644 index 000000000..3bb76a6f6 --- /dev/null +++ b/src/common/actionmanager/command_p.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef COMMAND_P_H +#define COMMAND_P_H + +#include "command.h" +#include "commandaction.h" + +#include +#include +#include +#include + +class CommandPrivate : public QObject +{ +public: + CommandPrivate(const QString &id, Command *qq); + + void setCurrentContext(const QStringList &context); + void addOverrideAction(QAction *action, const QStringList &context); + void removeOverrideAction(QAction *action); + + bool isEmpty() const; + void updateActiveState(); + void setActive(bool state); + +public: + Command *q; + + QString cmdId; + Command::CommandAttributes attributes; + QList defaultKeys; + QString defaultText; + bool isKeyInitialized { false }; + + QStringList cmdContext; + CommandAction *action { nullptr }; + QMap> contextActionMap; + QString toolTip; + bool active { false }; +}; + +#endif // COMMAND_P_H diff --git a/src/common/actionmanager/commandaction.cpp b/src/common/actionmanager/commandaction.cpp new file mode 100644 index 000000000..911f00cac --- /dev/null +++ b/src/common/actionmanager/commandaction.cpp @@ -0,0 +1,198 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "commandaction.h" +#include "action_define.h" + +class CommandActionPrivate : public QObject +{ +public: + CommandActionPrivate(CommandAction *qq); + + void actionChanged(); + void updateState(); + void updateToolTipWithKeySequence(); + void disconnectAction(); + void connectAction(); + void update(QAction *action, bool initialize); + +public: + CommandAction *q; + + QPointer action; + CommandAction::Attributes attributes; + bool showShortcut = false; + QString toolTip; + bool block = false; +}; + +CommandActionPrivate::CommandActionPrivate(CommandAction *qq) + : q(qq) +{ +} + +void CommandActionPrivate::actionChanged() +{ + update(action, false); +} + +void CommandActionPrivate::updateState() +{ + if (action) { + update(action, false); + } else { + if (q->hasAttribute(CommandAction::Hide)) + q->setVisible(false); + q->setEnabled(false); + } +} + +void CommandActionPrivate::updateToolTipWithKeySequence() +{ + if (block) + return; + + block = true; + if (!showShortcut || q->shortcut().isEmpty()) + q->setToolTip(toolTip); + else + q->setToolTip(q->stringWithAppendedShortcut(toolTip, q->shortcut())); + block = false; +} + +void CommandActionPrivate::disconnectAction() +{ + if (action) { + disconnect(action.data(), &QAction::changed, this, &CommandActionPrivate::actionChanged); + disconnect(q, &CommandAction::triggered, action.data(), &QAction::triggered); + disconnect(q, &CommandAction::toggled, action.data(), &QAction::setChecked); + } +} + +void CommandActionPrivate::connectAction() +{ + if (action) { + connect(action.data(), &QAction::changed, this, &CommandActionPrivate::actionChanged); + connect(q, &CommandAction::triggered, action.data(), &QAction::triggered); + connect(q, &CommandAction::toggled, action.data(), &QAction::setChecked); + } +} + +void CommandActionPrivate::update(QAction *action, bool initialize) +{ + if (!action) + return; + + disconnect(q, &CommandAction::changed, this, &CommandActionPrivate::updateToolTipWithKeySequence); + if (initialize) { + q->setSeparator(action->isSeparator()); + q->setMenuRole(action->menuRole()); + } + if (q->hasAttribute(CommandAction::UpdateIcon) || initialize) { + q->setIcon(action->icon()); + q->setIconText(action->iconText()); + q->setIconVisibleInMenu(action->isIconVisibleInMenu()); + } + if (q->hasAttribute(CommandAction::UpdateText) || initialize) { + q->setText(action->text()); + toolTip = action->toolTip(); + updateToolTipWithKeySequence(); + q->setStatusTip(action->statusTip()); + q->setWhatsThis(action->whatsThis()); + } + + q->setCheckable(action->isCheckable()); + if (!initialize) { + if (q->isChecked() != action->isChecked()) { + if (this->action) + disconnect(q, &CommandAction::toggled, this->action.data(), &QAction::setChecked); + q->setChecked(action->isChecked()); + if (this->action) + connect(q, &CommandAction::toggled, this->action.data(), &QAction::setChecked); + } + q->setEnabled(action->isEnabled()); + q->setVisible(action->isVisible()); + } + connect(q, &CommandAction::changed, this, &CommandActionPrivate::updateToolTipWithKeySequence); +} + +CommandAction::CommandAction(QObject *parent) + : QAction(parent), + d(new CommandActionPrivate(this)) +{ + connect(this, &QAction::changed, d, &CommandActionPrivate::updateToolTipWithKeySequence); + d->updateState(); +} + +CommandAction::~CommandAction() +{ + delete d; +} + +void CommandAction::initialize(QAction *action) +{ + d->update(action, true); +} + +void CommandAction::setAction(QAction *action) +{ + if (d->action == action) + return; + + d->disconnectAction(); + d->action = action; + d->connectAction(); + d->updateState(); + emit currentActionChanged(action); +} + +QAction *CommandAction::action() const +{ + return d->action; +} + +bool CommandAction::shortcutVisibleInToolTip() const +{ + return d->showShortcut; +} + +void CommandAction::setShortcutVisibleInToolTip(bool visible) +{ + d->showShortcut = visible; + d->updateToolTipWithKeySequence(); +} + +void CommandAction::setAttribute(Attribute attribute) +{ + d->attributes |= attribute; + d->updateState(); +} + +void CommandAction::removeAttribute(Attribute attribute) +{ + d->attributes &= ~attribute; + d->updateState(); +} + +bool CommandAction::hasAttribute(Attribute attribute) +{ + return d->attributes.testFlag(attribute); +} + +QString CommandAction::stringWithAppendedShortcut(const QString &str, const QKeySequence &shortcut) +{ + const QString s = stripAccelerator(str); + return QString::fromLatin1("
%1 " + "%2
") + .arg(s, shortcut.toString(QKeySequence::NativeText)); +} + +CommandAction *CommandAction::commandActionWithIcon(QAction *original, const QIcon &newIcon) +{ + auto proxyAction = new CommandAction(original); + proxyAction->setAction(original); + proxyAction->setIcon(newIcon); + proxyAction->setAttribute(UpdateText); + return proxyAction; +} diff --git a/src/common/actionmanager/commandaction.h b/src/common/actionmanager/commandaction.h new file mode 100644 index 000000000..efc1ff365 --- /dev/null +++ b/src/common/actionmanager/commandaction.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef COMMANDACTION_H +#define COMMANDACTION_H + +#include +#include + +class CommandActionPrivate; +class CommandAction : public QAction +{ + Q_OBJECT +public: + enum Attribute { + Hide = 0x01, + UpdateText = 0x02, + UpdateIcon = 0x04 + }; + Q_DECLARE_FLAGS(Attributes, Attribute) + + explicit CommandAction(QObject *parent = nullptr); + ~CommandAction(); + + void initialize(QAction *action); + + void setAction(QAction *action); + QAction *action() const; + + bool shortcutVisibleInToolTip() const; + void setShortcutVisibleInToolTip(bool visible); + + void setAttribute(Attribute attribute); + void removeAttribute(Attribute attribute); + bool hasAttribute(Attribute attribute); + + static QString stringWithAppendedShortcut(const QString &str, const QKeySequence &shortcut); + static CommandAction *commandActionWithIcon(QAction *original, const QIcon &newIcon); + +signals: + void currentActionChanged(QAction *action); + +private: + CommandActionPrivate *const d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(CommandAction::Attributes) + +#endif // COMMANDACTION_H diff --git a/src/common/util/utils.h b/src/common/util/utils.h index 6dc5b1d5b..1f36d3611 100644 --- a/src/common/util/utils.h +++ b/src/common/util/utils.h @@ -22,7 +22,6 @@ namespace utils { QString toolTipStr = action->text(); if (!action->shortcut().isEmpty()) { toolTipStr = toolTipStr + " " + action->shortcut().toString(); - iconBtn->setShortcut(action->shortcut()); } if (!toolTipStr.isEmpty()) @@ -32,8 +31,6 @@ namespace utils { QObject::connect(action, &QAction::changed, iconBtn, [=] { QString toolTipStr = action->text() + " " + action->shortcut().toString(); iconBtn->setToolTip(toolTipStr); - iconBtn->setShortcut(action->shortcut()); - iconBtn->setIcon(action->icon()); iconBtn->setEnabled(action->isEnabled()); }); diff --git a/src/plugins/binarytools/binarytools.cpp b/src/plugins/binarytools/binarytools.cpp index 4e08c644e..abc283d02 100644 --- a/src/plugins/binarytools/binarytools.cpp +++ b/src/plugins/binarytools/binarytools.cpp @@ -3,35 +3,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "binarytools.h" -#include "mainframe/binarytoolsdialog.h" #include "configure/binarytoolsmanager.h" -#include "common/common.h" -#include "base/abstractaction.h" -#include "services/window/windowservice.h" - void BinaryTools::initialize() { } bool BinaryTools::start() { - qInfo() << __FUNCTION__; - using namespace dpfservice; - auto &ctx = dpfInstance.serviceContext(); - WindowService *windowService = ctx.service(WindowService::name()); - - if (windowService) { - auto action = new QAction(MWMTA_BINARY_TOOLS); - auto inputAction = new AbstractAction(action, this); - inputAction->setShortCutInfo("Tools.Binary", action->text()); - windowService->addAction(MWM_TOOLS, inputAction); - - toolMenu = new QMenu(); - action->setMenu(toolMenu); - BinaryToolsManager::instance()->setToolMenu(toolMenu); - } - + BinaryToolsManager::instance()->setupToolMenu(); const auto &tools = BinaryToolsManager::instance()->tools(); BinaryToolsManager::instance()->checkAndAddToToolbar(tools); BinaryToolsManager::instance()->updateToolMenu(tools); @@ -41,8 +21,5 @@ bool BinaryTools::start() dpf::Plugin::ShutdownFlag BinaryTools::stop() { - if (toolMenu) - toolMenu->deleteLater(); - return Sync; } diff --git a/src/plugins/binarytools/binarytools.h b/src/plugins/binarytools/binarytools.h index 3adcd5a66..de9742c58 100644 --- a/src/plugins/binarytools/binarytools.h +++ b/src/plugins/binarytools/binarytools.h @@ -17,9 +17,6 @@ class BinaryTools : public dpf::Plugin virtual void initialize() override; virtual bool start() override; virtual dpf::Plugin::ShutdownFlag stop() override; - -private: - QMenu *toolMenu { nullptr }; }; #endif // BINARYTOOLS_H diff --git a/src/plugins/binarytools/configure/binarytoolsmanager.cpp b/src/plugins/binarytools/configure/binarytoolsmanager.cpp index 5a689c605..1a1898547 100644 --- a/src/plugins/binarytools/configure/binarytoolsmanager.cpp +++ b/src/plugins/binarytools/configure/binarytoolsmanager.cpp @@ -9,6 +9,7 @@ #include "common/util/custompaths.h" #include "common/util/eventdefinitions.h" #include "common/util/macroexpander.h" +#include "common/actionmanager/actionmanager.h" #include "services/window/windowservice.h" #include "services/terminal/terminalservice.h" #include "services/editor/editorservice.h" @@ -22,6 +23,10 @@ #include #include +constexpr char G_ACTIONS[] { "BinaryTools.Group.Actions" }; +constexpr char G_CONFIGURE[] { "BinaryTools.Group.Configure" }; +constexpr char A_CONFIGURE[] { "BinaryTools.Action.Configure" }; + constexpr char GroupObject[] { "groups" }; constexpr char ToolObject[] { "tools" }; constexpr char AdvanceObject[] { "advance" }; @@ -407,32 +412,44 @@ void BinaryToolsManager::checkAndAddToToolbar(const BinaryTools &tools) void BinaryToolsManager::updateToolMenu(const BinaryTools &tools) { - if (!toolMenu) - return; + auto mBinaryTools = ActionManager::instance()->actionContainer(M_TOOLS_BINARY); + mBinaryTools->clear(); - toolMenu->clear(); + int idCount = 0; auto iter = tools.begin(); for (; iter != tools.end(); ++iter) { - auto groupAct = toolMenu->addAction(iter.key()); - auto subMenu = new QMenu(toolMenu); - groupAct->setMenu(subMenu); + auto groupId = QString(M_TOOLS_BINARY).append(".Group.%1").arg(++idCount); + auto mGroup = ActionManager::instance()->createContainer(groupId); + mGroup->menu()->setTitle(iter.key()); + mBinaryTools->addMenu(mGroup, G_ACTIONS); + for (const auto &tool : iter.value()) { - auto act = subMenu->addAction(QIcon::fromTheme(tool.icon), tool.name); + auto act = new QAction(QIcon::fromTheme(tool.icon), tool.name, mGroup); + auto cmd = ActionManager::instance()->registerAction(act, tool.id); + mGroup->addAction(cmd); + connect(act, &QAction::triggered, this, std::bind(&BinaryToolsManager::executeTool, this, tool.id)); } } - toolMenu->addSeparator(); - auto configureAct = toolMenu->addAction(tr("Configure...")); + auto configureAct = new QAction(tr("Configure..."), mBinaryTools); + auto cmd = ActionManager::instance()->registerAction(configureAct, A_CONFIGURE); + mBinaryTools->addAction(cmd, G_CONFIGURE); connect(configureAct, &QAction::triggered, this, [=]() { BinaryToolsDialog dlg; dlg.exec(); }); } -void BinaryToolsManager::setToolMenu(QMenu *menu) +void BinaryToolsManager::setupToolMenu() { - toolMenu = menu; + auto mTools = ActionManager::instance()->actionContainer(M_TOOLS); + auto mBinaryTools = ActionManager::instance()->createContainer(M_TOOLS_BINARY); + mBinaryTools->menu()->setTitle(tr("Binary Tools")); + mBinaryTools->appendGroup(G_ACTIONS); + mBinaryTools->appendGroup(G_CONFIGURE); + mBinaryTools->addSeparator(G_CONFIGURE); + mTools->addMenu(mBinaryTools); } void BinaryToolsManager::installTool(const QString &id) @@ -561,31 +578,33 @@ void BinaryToolsManager::addToToolBar(const ToolInfo &tool) act->setIcon(QIcon::fromTheme(tool.icon)); connect(act, &QAction::triggered, this, std::bind(&BinaryToolsManager::executeTool, this, tool.id)); - auto actImpl = new AbstractAction(act, this); - return actImpl; + auto cmd = ActionManager::instance()->registerAction(act, tool.id); + return cmd; }; if (!windowSrv) windowSrv = dpfGetService(WindowService); - if (!tool.addToToolbar && actMap.contains(tool.id)) { - windowSrv->removeTopToolItem(actMap[tool.id]); - actMap.remove(tool.id); - } else if (tool.addToToolbar && !actMap.contains(tool.id)) { - auto act = createAction(tool); - actMap.insert(tool.id, act); - windowSrv->addTopToolItemToRight(act, false, Priority::high); - } else if (tool.addToToolbar && actMap.contains(tool.id)) { - auto act = actMap[tool.id]; - auto qAct = act->qAction(); - - if (tool.description != qAct->text()) { - qAct->setText(tool.description); + if (!tool.addToToolbar && cmdMap.contains(tool.id)) { + windowSrv->removeTopToolItem(cmdMap[tool.id]); + cmdMap.remove(tool.id); + } else if (tool.addToToolbar && !cmdMap.contains(tool.id)) { + auto cmd = createAction(tool); + cmdMap.insert(tool.id, cmd); + windowSrv->addTopToolItemToRight(cmd, false, Priority::high); + } else if (tool.addToToolbar && cmdMap.contains(tool.id)) { + auto cmd = cmdMap[tool.id]; + auto act = cmd->action(); + + if (tool.description != act->text()) { + act->setText(tool.description); + cmd->setAttribute(Command::CA_UpdateText); } - if (tool.icon != qAct->iconText()) { - qAct->setIconText(tool.icon); - qAct->setIcon(QIcon::fromTheme(tool.icon)); + if (tool.icon != act->iconText()) { + act->setIconText(tool.icon); + act->setIcon(QIcon::fromTheme(tool.icon)); + cmd->setAttribute(Command::CA_UpdateIcon); } } } diff --git a/src/plugins/binarytools/configure/binarytoolsmanager.h b/src/plugins/binarytools/configure/binarytoolsmanager.h index 4e5ab4792..01dd2bc62 100644 --- a/src/plugins/binarytools/configure/binarytoolsmanager.h +++ b/src/plugins/binarytools/configure/binarytoolsmanager.h @@ -18,7 +18,7 @@ class WindowService; class TerminalService; class EditorService; } -class AbstractAction; +class Command; class ToolProcess : public QObject { @@ -75,7 +75,7 @@ class BinaryToolsManager : public QObject void executeTool(const QString &id); void checkAndAddToToolbar(const BinaryTools &tools); void updateToolMenu(const BinaryTools &tools); - void setToolMenu(QMenu *menu); + void setupToolMenu(); void installTool(const QString &id); void eventTriggered(EventType event, const QVariantList &args); @@ -110,8 +110,7 @@ private Q_SLOTS: dpfservice::WindowService *windowSrv { nullptr }; dpfservice::TerminalService *terminalSrv { nullptr }; dpfservice::EditorService *editorSrv { nullptr }; - QMap actMap; - QMenu *toolMenu { nullptr }; + QMap cmdMap; QString cfgVersion; }; diff --git a/src/plugins/builder/mainframe/buildmanager.cpp b/src/plugins/builder/mainframe/buildmanager.cpp index 6c7871489..7c2e9c515 100644 --- a/src/plugins/builder/mainframe/buildmanager.cpp +++ b/src/plugins/builder/mainframe/buildmanager.cpp @@ -8,6 +8,7 @@ #include "common/util/commandparser.h" #include "common/project/projectinfo.h" #include "common/find/outputdocumentfind.h" +#include "common/actionmanager/actioncontainer.h" #include "problemoutputpane.h" #include "commonparser.h" #include "transceiver/buildersender.h" @@ -37,13 +38,12 @@ class BuildManagerPrivate { friend class BuildManager; - QAction* buildCancelAction; - QAction* buildActionNoIcon; - QAction* rebuildAction; - QAction* cleanAction; - QAction* cancelAction; - QAction* cancelActionNoIcon; + QAction *buildAction; + QAction *rebuildAction; + QAction *cleanAction; + QAction *cancelAction; + DToolButton *buildCancelBtn = nullptr; CompileOutputPane *compileOutputPane = nullptr; ProblemOutputPane *problemOutputPane = nullptr; DWidget *issuesWidget = nullptr; @@ -60,7 +60,6 @@ class BuildManagerPrivate QFuture buildThread; BuildState currentState = BuildState::kNoBuild; - }; BuildManager *BuildManager::instance() @@ -70,8 +69,7 @@ BuildManager *BuildManager::instance() } BuildManager::BuildManager(QObject *parent) - : QObject(parent) - , d(new BuildManagerPrivate()) + : QObject(parent), d(new BuildManagerPrivate()) { addMenu(); initCompileWidget(); @@ -104,58 +102,47 @@ void BuildManager::addMenu() if (!windowService) return; - auto actionInit = [&](QAction *action, QString actionID, QKeySequence key, QString iconFileName) - -> AbstractAction* { - action->setIcon(QIcon::fromTheme(iconFileName)); - auto inputAction = new AbstractAction(action, this); - inputAction->setShortCutInfo(actionID, action->text(), key); - return inputAction; + auto actionInit = [&](QAction *action, const QString &actionID, + const QKeySequence &key, + const QString &iconFileName = {}) + -> Command * { + if (!iconFileName.isEmpty()) + action->setIcon(QIcon::fromTheme(iconFileName)); + auto cmd = ActionManager::instance()->registerAction(action, actionID); + if (!key.isEmpty()) + cmd->setDefaultKeySequence(key); + return cmd; }; - d->buildCancelAction = new QAction(MWMBA_BUILD, this); - windowService->addTopToolItem(actionInit(d->buildCancelAction, "Build.Build", - QKeySequence(Qt::Modifier::CTRL | Qt::Key::Key_B), - "build"), true, Priority::low); - - d->cancelActionNoIcon = new QAction(MWMBA_CANCEL, this); - windowService->addAction(dpfservice::MWM_BUILD, actionInit(d->cancelActionNoIcon, "Build.Cancel", - QKeySequence(Qt::Modifier::ALT | Qt::Key::Key_Backspace), - "")); - - d->buildActionNoIcon = new QAction(MWMBA_BUILD, this); - windowService->addAction(dpfservice::MWM_BUILD, actionInit(d->buildActionNoIcon, "Build.Build", - QKeySequence(Qt::Modifier::CTRL | Qt::Key::Key_B), - "")); + auto mBuild = ActionManager::instance()->actionContainer(M_BUILD); + d->buildAction = new QAction(MWMBA_BUILD, this); + auto cmd = actionInit(d->buildAction, "Build.Build", + QKeySequence(Qt::Modifier::CTRL | Qt::Key::Key_B), + "build"); + mBuild->addAction(cmd); + d->buildCancelBtn = windowService->addTopToolItem(cmd, true, Priority::low); d->cancelAction = new QAction(MWMBA_CANCEL, this); d->cancelAction->setIcon(QIcon::fromTheme("cancel")); - ActionManager::getInstance()->registerAction(d->cancelAction, "Build.Cancel", MWMBA_CANCEL, - QKeySequence(Qt::Modifier::ALT | Qt::Key::Key_Backspace)); + cmd = actionInit(d->cancelAction, "Build.Cancel", QKeySequence(Qt::ALT | Qt::Key_Backspace)); + mBuild->addAction(cmd); d->rebuildAction = new QAction(MWMBA_REBUILD, this); d->rebuildAction->setIcon(QIcon::fromTheme("rebuild")); - ActionManager::getInstance()->registerAction(d->rebuildAction, "Build.Rebuild", MWMBA_REBUILD, - QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::SHIFT | Qt::Key::Key_B)); - + actionInit(d->rebuildAction, "Build.Rebuild", QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_B)); d->cleanAction = new QAction(MWMBA_CLEAN, this); d->cleanAction->setIcon(QIcon::fromTheme("clearall")); - ActionManager::getInstance()->registerAction(d->cleanAction, "Build.Clean", MWMBA_CLEAN, - QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::SHIFT | Qt::Key::Key_C)); - + actionInit(d->cleanAction, "Build.Clean", QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C)); - QObject::connect(d->buildCancelAction, &QAction::triggered, + QObject::connect(d->buildAction, &QAction::triggered, this, &BuildManager::buildCancelProject, Qt::DirectConnection); - QObject::connect(d->buildActionNoIcon, &QAction::triggered, - this, &BuildManager::buildProject, Qt::DirectConnection); QObject::connect(d->rebuildAction, &QAction::triggered, this, &BuildManager::rebuildProject, Qt::DirectConnection); QObject::connect(d->cleanAction, &QAction::triggered, this, &BuildManager::cleanProject, Qt::DirectConnection); QObject::connect(d->cancelAction, &QAction::triggered, this, &BuildManager::cancelBuild, Qt::DirectConnection); - QObject::connect(d->cancelActionNoIcon, &QAction::triggered, - this, &BuildManager::cancelBuild, Qt::DirectConnection); } void BuildManager::initCompileWidget() @@ -203,18 +190,18 @@ void BuildManager::initIssueList() hIssueTopLayout->setContentsMargins(0, 0, 5, 0); hIssueTopLayout->setAlignment(Qt::AlignVCenter); - DMenu* filterMenu = new DMenu(filterButton); + DMenu *filterMenu = new DMenu(filterButton); - QAction* showAllAction = new QAction(tr("All"), this); + QAction *showAllAction = new QAction(tr("All"), this); showAllAction->setCheckable(true); showAllAction->setChecked(true); filterMenu->addAction(showAllAction); - QAction* showErrorAction = new QAction(tr("Error"), this); + QAction *showErrorAction = new QAction(tr("Error"), this); showErrorAction->setCheckable(true); filterMenu->addAction(showErrorAction); - QAction* showWarningAction = new QAction(tr("Warning"), this); + QAction *showWarningAction = new QAction(tr("Warning"), this); showWarningAction->setCheckable(true); filterMenu->addAction(showWarningAction); @@ -265,7 +252,7 @@ void BuildManager::initCompileOutput() hOutputTopLayout->setContentsMargins(0, 0, 5, 0); hOutputTopLayout->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); - auto createVLine = [this]{ + auto createVLine = [this] { DVerticalLine *vLine = new DVerticalLine(d->compileWidget); vLine->setFixedHeight(20); return vLine; @@ -288,7 +275,7 @@ void BuildManager::initCompileOutput() DToolButton *clearLogBtn = new DToolButton(d->compileWidget); clearLogBtn->setIconSize({ 16, 16 }); - clearLogBtn->setFixedSize({ 26, 26}); + clearLogBtn->setFixedSize({ 26, 26 }); clearLogBtn->setIcon(QIcon::fromTheme("clear_log")); clearLogBtn->setToolTip(tr("Clear Output")); connect(clearLogBtn, &DToolButton::clicked, d->compileOutputPane, &CompileOutputPane::clearContents); @@ -331,17 +318,17 @@ void BuildManager::buildCancelProject() void BuildManager::buildProject() { - execBuildStep({Build}); + execBuildStep({ Build }); } void BuildManager::rebuildProject() { - execBuildStep({Clean, Build}); + execBuildStep({ Clean, Build }); } void BuildManager::cleanProject() { - execBuildStep({Clean}); + execBuildStep({ Clean }); } void BuildManager::cancelBuild() @@ -353,13 +340,12 @@ void BuildManager::cancelBuild() } } - void BuildManager::execBuildStep(QList menuTypelist) { // save all modified files before build. dpfGetService(EditorService)->saveAll(); - if(!canStartBuild()) { + if (!canStartBuild()) { QMetaObject::invokeMethod(this, "message", Q_ARG(QString, "The builder is running, please try again later!")); return; @@ -443,7 +429,7 @@ bool BuildManager::isActivatedProject(const ProjectInfo &info) bool BuildManager::handleCommand(const QList &commandInfo, bool isSynchronous) { - if(!canStartBuild()) { + if (!canStartBuild()) { QMetaObject::invokeMethod(this, "message", Q_ARG(QString, "The builder is running, please try again later!")); return false; @@ -479,7 +465,7 @@ bool BuildManager::execCommands(const QList &commandList, bool } } else { if (!commandList.isEmpty()) { - d->buildThread = QtConcurrent::run([=](){ + d->buildThread = QtConcurrent::run([=]() { QMutexLocker locker(&releaseMutex); for (auto command : commandList) { execCommand(command); @@ -500,24 +486,24 @@ bool BuildManager::execCommand(const BuildCommandInfo &info) d->cmdProcess.setWorkingDirectory(info.workingDir); QString startMsg = tr("Start execute command: \"%1\" \"%2\" in workspace \"%3\".\n") - .arg(info.program, info.arguments.join(" "), info.workingDir); + .arg(info.program, info.arguments.join(" "), info.workingDir); outputLog(startMsg, OutputPane::OutputFormat::NormalMessage); connect(&d->cmdProcess, static_cast(&QProcess::finished), [&](int exitcode, QProcess::ExitStatus exitStatus) { - if (0 == exitcode && exitStatus == QProcess::ExitStatus::NormalExit) { - ret = true; - executeResult = tr("The process \"%1\" exited normally.\n").arg(d->cmdProcess.program()); - } else if (exitStatus == QProcess::NormalExit) { - ret = false; - executeResult = tr("The process \"%1\" exited with code %2.\n") - .arg(d->cmdProcess.program(), QString::number(exitcode)); - } else { - ret = false; - executeResult = tr("The process \"%1\" crashed.\n") - .arg(d->cmdProcess.program()); - } - }); + if (0 == exitcode && exitStatus == QProcess::ExitStatus::NormalExit) { + ret = true; + executeResult = tr("The process \"%1\" exited normally.\n").arg(d->cmdProcess.program()); + } else if (exitStatus == QProcess::NormalExit) { + ret = false; + executeResult = tr("The process \"%1\" exited with code %2.\n") + .arg(d->cmdProcess.program(), QString::number(exitcode)); + } else { + ret = false; + executeResult = tr("The process \"%1\" crashed.\n") + .arg(d->cmdProcess.program()); + } + }); connect(&d->cmdProcess, &QProcess::readyReadStandardOutput, [&]() { d->cmdProcess.setReadChannel(QProcess::StandardOutput); @@ -591,8 +577,8 @@ void BuildManager::addOutput(const QString &content, const OutputPane::OutputFor { QString newContent = content; if (OutputPane::OutputFormat::NormalMessage == format - || OutputPane::OutputFormat::ErrorMessage == format - || OutputPane::OutputFormat::StdOut == format) { + || OutputPane::OutputFormat::ErrorMessage == format + || OutputPane::OutputFormat::StdOut == format) { QDateTime curDatetime = QDateTime::currentDateTime(); QString time = curDatetime.toString("hh:mm:ss"); @@ -612,24 +598,24 @@ void BuildManager::slotBuildState(const BuildState &buildState) switch (buildState) { case BuildState::kNoBuild: - case BuildState::kBuildFailed: - d->buildCancelAction->setIcon(QIcon::fromTheme("build")); - d->buildCancelAction->setText(MWMBA_BUILD); - d->buildCancelAction->setShortcut(ActionManager::getInstance()->command("Build.Build")->keySequence()); - d->buildActionNoIcon->setEnabled(true); + case BuildState::kBuildFailed: { + d->buildCancelBtn->setIcon(QIcon::fromTheme("build")); + auto cmd = ActionManager::instance()->command("Build.Build"); + auto toolTip = QString(MWMBA_CANCEL).append(" %1").arg(cmd->keySequence().toString()); + d->buildCancelBtn->setToolTip(toolTip); d->rebuildAction->setEnabled(true); d->cleanAction->setEnabled(true); d->cancelAction->setEnabled(false); - break; - case BuildState::kBuilding: - d->buildCancelAction->setIcon(QIcon::fromTheme("cancel")); - d->buildCancelAction->setText(MWMBA_CANCEL); - d->buildCancelAction->setShortcut(d->cancelAction->shortcut()); - d->buildActionNoIcon->setEnabled(true); + } break; + case BuildState::kBuilding: { + d->buildCancelBtn->setIcon(QIcon::fromTheme("cancel")); + auto cmd = ActionManager::instance()->command("Build.Cancel"); + auto toolTip = QString(MWMBA_CANCEL).append(" %1").arg(cmd->keySequence().toString()); + d->buildCancelBtn->setToolTip(toolTip); d->rebuildAction->setEnabled(false); d->cleanAction->setEnabled(false); d->cancelAction->setEnabled(true); - break; + } break; } } @@ -640,8 +626,7 @@ bool BuildManager::canStartBuild() void BuildManager::disconnectSignals() { - disconnect(&d->cmdProcess, static_cast(&QProcess::finished), nullptr, nullptr); + disconnect(&d->cmdProcess, static_cast(&QProcess::finished), nullptr, nullptr); disconnect(&d->cmdProcess, &QProcess::readyReadStandardOutput, nullptr, nullptr); disconnect(&d->cmdProcess, &QProcess::readyReadStandardError, nullptr, nullptr); } diff --git a/src/plugins/codeeditor/codeeditor.cpp b/src/plugins/codeeditor/codeeditor.cpp index d65169be9..dc49ab0a2 100644 --- a/src/plugins/codeeditor/codeeditor.cpp +++ b/src/plugins/codeeditor/codeeditor.cpp @@ -113,17 +113,22 @@ void CodeEditor::initButtonBox() void CodeEditor::initActions() { + auto mEdit = ActionManager::instance()->actionContainer(M_EDIT); + QAction *backAction = new QAction(tr("Backward"), this); connect(backAction, &QAction::triggered, EditorCallProxy::instance(), &EditorCallProxy::reqBack); - EditorUtils::registerShortcut(backAction, "Editor.back", QKeySequence(Qt::ALT | Qt::Key_Left)); + auto cmd = EditorUtils::registerShortcut(backAction, "Editor.back", QKeySequence(Qt::ALT | Qt::Key_Left)); + mEdit->addAction(cmd); QAction *forwardAction = new QAction(tr("Forward"), this); connect(forwardAction, &QAction::triggered, EditorCallProxy::instance(), &EditorCallProxy::reqForward); - EditorUtils::registerShortcut(forwardAction, "Editor.forward", QKeySequence(Qt::ALT | Qt::Key_Right)); + cmd = EditorUtils::registerShortcut(forwardAction, "Editor.forward", QKeySequence(Qt::ALT | Qt::Key_Right)); + mEdit->addAction(cmd); QAction *closeAction = new QAction(tr("Close Current Editor"), this); connect(closeAction, &QAction::triggered, EditorCallProxy::instance(), &EditorCallProxy::reqCloseCurrentEditor); - EditorUtils::registerShortcut(closeAction, "Editor.close", QKeySequence(Qt::CTRL | Qt::Key_W)); + cmd = EditorUtils::registerShortcut(closeAction, "Editor.close", QKeySequence(Qt::CTRL | Qt::Key_W)); + mEdit->addAction(cmd, G_EDIT_OTHER); QAction *switchHeaderSourceAction = new QAction(tr("Switch Header/Source"), this); connect(switchHeaderSourceAction, &QAction::triggered, EditorCallProxy::instance(), &EditorCallProxy::reqSwitchHeaderSource); @@ -194,11 +199,6 @@ void CodeEditor::initWindowService() windowService->registerWidgetToMode("editWindow", new AbstractWidget(workspaceWidget), CM_EDIT, Position::Central, true, true); windowService->registerWidgetToMode("editWindow", new AbstractWidget(workspaceWidget), CM_DEBUG, Position::Central, true, true); - - auto sep = new QAction(this); - sep->setSeparator(true); - windowService->addAction(MWM_FILE, new AbstractAction(sep)); - windowService->addContextWidget(QTabWidget::tr("Search &Results"), new AbstractWidget(CodeLens::instance()), true); StatusInfoManager::instance()->init(windowService); diff --git a/src/plugins/codeeditor/gui/tabwidget.cpp b/src/plugins/codeeditor/gui/tabwidget.cpp index f56d68bc6..9674e0e72 100644 --- a/src/plugins/codeeditor/gui/tabwidget.cpp +++ b/src/plugins/codeeditor/gui/tabwidget.cpp @@ -194,7 +194,7 @@ QWidget *TabWidgetPrivate::createSpaceWidget() QGridLayout *gridLayout = new QGridLayout; gridLayout->setSpacing(10); auto addCommandLine = [this, gridLayout](const QString &id) { - auto cmd = ActionManager::getInstance()->command(id); + auto cmd = ActionManager::instance()->command(id); if (!cmd || !cmd->action()) return; @@ -203,7 +203,7 @@ QWidget *TabWidgetPrivate::createSpaceWidget() gridLayout->addWidget(new KeyLabel(cmd->keySequence().toString(), q), row, 1, Qt::AlignLeft); }; - addCommandLine("File.Open.File"); + addCommandLine(A_OPEN_FILE); addCommandLine("Find.findInDocument"); addCommandLine("Editor.close"); addCommandLine("locator.EnterCommand"); diff --git a/src/plugins/codeeditor/gui/workspacewidget.cpp b/src/plugins/codeeditor/gui/workspacewidget.cpp index 904a3d883..05732ca91 100644 --- a/src/plugins/codeeditor/gui/workspacewidget.cpp +++ b/src/plugins/codeeditor/gui/workspacewidget.cpp @@ -67,20 +67,14 @@ void WorkspaceWidgetPrivate::initActions() // add/del comment QAction *commentAction = new QAction(tr("Add/Delete Comment"), q); - - auto abstractCommentAction = new AbstractAction(commentAction, q); - abstractCommentAction->setShortCutInfo("Editor.addAndRemoveComment", - tr("Add/Remove Comment"), QKeySequence(Qt::Modifier::CTRL | Qt::Key_Slash)); - windowService->addAction(tr("&Add/Remove Comment"), abstractCommentAction); + auto cmd = ActionManager::instance()->registerAction(commentAction, "Editor.AddAndRemoveComment"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key_Slash); connect(commentAction, &QAction::triggered, this, &WorkspaceWidgetPrivate::handleSetComment); // show opened files QAction *showOpenedAction = new QAction(tr("Show opened files"), q); - - auto abstractShowOpenedAction = new AbstractAction(showOpenedAction, q); - abstractShowOpenedAction->setShortCutInfo("Editor.showOpened", - tr("Show opened files"), QKeySequence(Qt::CTRL | Qt::Key_Tab)); - windowService->addAction(tr("&Show open files"), abstractShowOpenedAction); + cmd = ActionManager::instance()->registerAction(commentAction, "Editor.ShowOpenedFiles"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key_Tab); connect(showOpenedAction, &QAction::triggered, this, &WorkspaceWidgetPrivate::handleShowOpenedFiles); } @@ -461,7 +455,7 @@ void WorkspaceWidgetPrivate::handleCloseCurrentEditor() { if (stackWidget->currentIndex() == 0) { auto tabWidget = currentTabWidget(); - if (!tabWidget || !tabWidget->hasFocus()) + if (!tabWidget) return; tabWidget->closeFileEditor(); diff --git a/src/plugins/codeeditor/utils/editorutils.cpp b/src/plugins/codeeditor/utils/editorutils.cpp index 96a91b0f1..bc27699d3 100644 --- a/src/plugins/codeeditor/utils/editorutils.cpp +++ b/src/plugins/codeeditor/utils/editorutils.cpp @@ -4,8 +4,7 @@ #include "editorutils.h" -#include "base/abstractaction.h" -#include "services/window/windowservice.h" +#include "common/actionmanager/actionmanager.h" int EditorUtils::nbDigitsFromNbLines(long nbLines) { @@ -35,13 +34,9 @@ int EditorUtils::nbDigitsFromNbLines(long nbLines) return nbDigits; } -void EditorUtils::registerShortcut(QAction *act, const QString &id, const QKeySequence &shortCut) +Command *EditorUtils::registerShortcut(QAction *act, const QString &id, const QKeySequence &shortCut) { - auto winSrv = dpfGetService(dpfservice::WindowService); - if (!winSrv) - return; - - auto actImpl = new AbstractAction(act, qApp); - actImpl->setShortCutInfo(id, act->text(), shortCut); - winSrv->addAction(tr("&Edit"), actImpl); + auto cmd = ActionManager::instance()->registerAction(act, id); + cmd->setDefaultKeySequence(shortCut); + return cmd; } diff --git a/src/plugins/codeeditor/utils/editorutils.h b/src/plugins/codeeditor/utils/editorutils.h index b4eee4f13..009d3704e 100644 --- a/src/plugins/codeeditor/utils/editorutils.h +++ b/src/plugins/codeeditor/utils/editorutils.h @@ -7,12 +7,13 @@ #include +class Command; class EditorUtils : public QObject { Q_OBJECT public: static int nbDigitsFromNbLines(long nbLines); - static void registerShortcut(QAction *act, const QString &id, const QKeySequence &shortCut); + static Command *registerShortcut(QAction *act, const QString &id, const QKeySequence &shortCut); }; #endif // EDITORUTILS_H diff --git a/src/plugins/codeporting/codeportingplugin.cpp b/src/plugins/codeporting/codeportingplugin.cpp index 85cdc3c59..213983e8c 100644 --- a/src/plugins/codeporting/codeportingplugin.cpp +++ b/src/plugins/codeporting/codeportingplugin.cpp @@ -9,9 +9,12 @@ #include "base/abstractwidget.h" #include "services/window/windowservice.h" #include "common/actionmanager/actionmanager.h" +#include "common/actionmanager/actioncontainer.h" #include +constexpr char A_CODE_PORTING[] = "CodePorting.Base"; + using namespace dpfservice; void CodePortingPlugin::initialize() @@ -28,12 +31,12 @@ bool CodePortingPlugin::start() } // Add code porting item in tool menu. - QAction *action = new QAction(tr("Code Porting")); - auto inputAction = new AbstractAction(action, this); - inputAction->setShortCutInfo("Tool.CodePorting", action->text(),QKeySequence()); - connect(action, &QAction::triggered, CodePortingManager::instance(), &CodePortingManager::slotShowConfigWidget); + auto mTools = ActionManager::instance()->actionContainer(M_TOOLS); - windowService->addAction(MWM_TOOLS, inputAction); + QAction *action = new QAction(tr("Code Porting"), mTools); + auto cmd = ActionManager::instance()->registerAction(action, A_CODE_PORTING); + mTools->addAction(cmd); + connect(action, &QAction::triggered, CodePortingManager::instance(), &CodePortingManager::slotShowConfigWidget); return true; } diff --git a/src/plugins/collaborators/mainframe/svn/svnclientwidget.cpp b/src/plugins/collaborators/mainframe/svn/svnclientwidget.cpp index 65d84d108..906807fd8 100644 --- a/src/plugins/collaborators/mainframe/svn/svnclientwidget.cpp +++ b/src/plugins/collaborators/mainframe/svn/svnclientwidget.cpp @@ -38,13 +38,13 @@ SvnClientWidget::SvnClientWidget(QWidget *parent, Qt::WindowFlags flags) homeMenu->setObjectName("MainMenuBtn"); const auto clone = menu->addAction(QAction::tr("Checkout repository")); - ActionManager::getInstance()->registerAction(clone, "SVN.Checkout.Repository", - tr("Checkout repository"), QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::ALT | Qt::Key::Key_C)); + auto cmd = ActionManager::instance()->registerAction(clone, "SVN.Checkout.Repository"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C); connect(clone, &QAction::triggered, this, &SvnClientWidget::showCheckoutDialog); const auto open = menu->addAction(QAction::tr("Open repository")); - ActionManager::getInstance()->registerAction(open, "SVN.Open.Repository", - tr("Open repository"), QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::ALT | Qt::Key::Key_R)); + cmd = ActionManager::instance()->registerAction(open, "SVN.Open.Repository"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_R); connect(open, &QAction::triggered, this, &SvnClientWidget::showOpenLocalRepos); mRepos->setObjectName("GitQlientTab"); diff --git a/src/plugins/core/core.cpp b/src/plugins/core/core.cpp index 9547ed779..a80bc1a90 100644 --- a/src/plugins/core/core.cpp +++ b/src/plugins/core/core.cpp @@ -7,7 +7,6 @@ #include "services/window/windowservice.h" #include "locator/locatormanager.h" #include "locator/actionlocator.h" -#include "find/findtoolbar.h" #include #include "common/common.h" @@ -33,7 +32,6 @@ bool Core::start() LocatorManager::instance()->registerLocator(actionLocator); QObject::connect(&dpf::Listener::instance(), &dpf::Listener::pluginsStarted, [=] { - ActionManager::getInstance()->readUserSetting(); uiController.doSwitch(MWNA_RECENT); }); diff --git a/src/plugins/core/find/findtoolbar.cpp b/src/plugins/core/find/findtoolbar.cpp index 9cad3542a..ad5c7add5 100644 --- a/src/plugins/core/find/findtoolbar.cpp +++ b/src/plugins/core/find/findtoolbar.cpp @@ -5,6 +5,8 @@ #include "findtoolbar.h" #include "placeholdermanager.h" +#include "common/actionmanager/actionmanager.h" +#include "common/actionmanager/actioncontainer.h" #include "common/find/abstractdocumentfind.h" #include "base/abstractaction.h" #include "services/window/windowservice.h" @@ -20,6 +22,10 @@ using namespace dpfservice; DWIDGET_USE_NAMESPACE +constexpr char M_FIND[] = "Find.FindMenu"; +constexpr char G_FIND_CURRENTDOCUMENT[] = "Find.FindMenu.CurrentDocument"; +constexpr char G_FIND_ACTIONS[] = "Find.FindMenu.Actions"; + class FindToolBarPrivate { public: @@ -103,33 +109,33 @@ void FindToolBarPrivate::initConnection() void FindToolBarPrivate::initActions() { - auto &ctx = dpfInstance.serviceContext(); - WindowService *windowService = ctx.service(WindowService::name()); - if (!windowService) - return; + auto mEdit = ActionManager::instance()->actionContainer(M_EDIT); + auto mFind = ActionManager::instance()->createContainer(M_FIND); + mFind->menu()->setTitle("&Find/Replace"); + mFind->appendGroup(G_FIND_CURRENTDOCUMENT); + mFind->appendGroup(G_FIND_ACTIONS); + mFind->addSeparator(G_FIND_ACTIONS); + mEdit->addMenu(mFind, G_EDIT_FIND); QAction *findReplaceAction = new QAction(FindToolBar::tr("Find/Replace"), q); - auto inputFindReplaceAction = new AbstractAction(findReplaceAction, q); - inputFindReplaceAction->setShortCutInfo("Find.findInDocument", - FindToolBar::tr("Find/Replace"), QKeySequence(Qt::Modifier::CTRL | Qt::Key_F)); - windowService->addAction(FindToolBar::tr("&Find"), inputFindReplaceAction); + auto cmd = ActionManager::instance()->registerAction(findReplaceAction, "Find.findInDocument"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key_F); + mFind->addAction(cmd, G_FIND_CURRENTDOCUMENT); q->connect(findReplaceAction, &QAction::triggered, q, [this] { q->openFindToolBar(); }); - QAction *findNextAction = new QAction(FindToolBar::tr("Find/Replace"), q); - auto inputFindNextAction = new AbstractAction(findNextAction, q); - inputFindNextAction->setShortCutInfo("Find.findNext", - FindToolBar::tr("Find Next"), QKeySequence(Qt::Key_F3)); - windowService->addAction(FindToolBar::tr("&Find"), inputFindNextAction); + QAction *findNextAction = new QAction(FindToolBar::tr("Find Next"), q); + cmd = ActionManager::instance()->registerAction(findNextAction, "Find.findNext"); + cmd->setDefaultKeySequence(Qt::Key_F3); + mFind->addAction(cmd, G_FIND_ACTIONS); q->connect(findNextAction, &QAction::triggered, q, [this] { if (q->isVisible()) q->findNext(); }); - QAction *findPreviousAction = new QAction(FindToolBar::tr("Find/Replace"), q); - auto inputFindPreviousAction = new AbstractAction(findPreviousAction, q); - inputFindPreviousAction->setShortCutInfo("Find.findPrevious", - FindToolBar::tr("Find Previous"), QKeySequence(Qt::Modifier::SHIFT | Qt::Key_F3)); - windowService->addAction(FindToolBar::tr("&Find"), inputFindPreviousAction); + QAction *findPreviousAction = new QAction(FindToolBar::tr("Find Previous"), q); + cmd = ActionManager::instance()->registerAction(findPreviousAction, "Find.findPrevious"); + cmd->setDefaultKeySequence(Qt::SHIFT | Qt::Key_F3); + mFind->addAction(cmd, G_FIND_ACTIONS); q->connect(findPreviousAction, &QAction::triggered, q, [this] { if (q->isVisible()) q->findPrevious(); diff --git a/src/plugins/core/locator/actionlocator.cpp b/src/plugins/core/locator/actionlocator.cpp index f568d673b..e557523a0 100644 --- a/src/plugins/core/locator/actionlocator.cpp +++ b/src/plugins/core/locator/actionlocator.cpp @@ -20,14 +20,13 @@ void ActionLocator::prepareSearch(const QString &searchText) { Q_UNUSED(searchText) - commandList = ActionManager::getInstance()->commands(); + commandList = ActionManager::instance()->commandList(); foreach (auto command, commandList) { - auto action = dynamic_cast(command); baseLocatorItem item(this); - item.id = action->id(); - item.displayName = action->description(); - item.extraInfo = action->keySequence().toString(); + item.id = command->id(); + item.displayName = command->description(); + item.extraInfo = command->keySequence().toString(); locatorList.append(item); } diff --git a/src/plugins/core/locator/locatormanager.cpp b/src/plugins/core/locator/locatormanager.cpp index 1ff8fdb47..5e73a8dd0 100644 --- a/src/plugins/core/locator/locatormanager.cpp +++ b/src/plugins/core/locator/locatormanager.cpp @@ -180,7 +180,7 @@ void LocatorManager::registerLocator(abstractLocator *locator) { if (!locator || locatorList.contains(locator)) return; - if(!locator->getShortCut().isEmpty()) + if (!locator->getShortCut().isEmpty()) setShortCutForLocator(locator, locator->getShortCut()); locatorList.append(locator); @@ -282,46 +282,34 @@ void LocatorManager::showSpinner() void LocatorManager::initShortCut() { - shortCut = new QShortcut(inputEdit); - shortCut->setKey(Qt::Modifier::CTRL | Qt::Key::Key_K); - connect(shortCut, &QShortcut::activated, inputEdit, [=]() { + QAction *action = new QAction(tr("Enter Command"), this); + auto cmd = ActionManager::instance()->registerAction(action, "locator.EnterCommand"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key::Key_K); + connect(action, &QAction::triggered, inputEdit, [=]() { inputEdit->setFocus(); inputEdit->lineEdit()->selectAll(); }); - QAction *action = new QAction(this); - action->setShortcut(shortCut->key()); - ActionManager::getInstance()->registerAction(action, "locator.EnterCommand", tr("Enter command"), shortCut->key()); - - inputEdit->setPlaceHolder(tr("Enter command %1").arg(shortCut->key().toString())); - connect(action, &QAction::changed, shortCut, [=]() { - if (action->shortcut() != shortCut->key()) { - shortCut->setKey(action->shortcut()); - inputEdit->setPlaceHolder(tr("Enter command %1").arg(shortCut->key().toString())); - } + inputEdit->setPlaceHolder(tr("Enter command %1").arg(cmd->keySequence().toString())); + connect(cmd, &Command::keySequenceChanged, this, [=]() { + inputEdit->setPlaceHolder(tr("Enter command %1").arg(cmd->keySequence().toString())); }); } void LocatorManager::setShortCutForLocator(abstractLocator *locator, const QKeySequence &key) { - if(key.isEmpty()) + if (key.isEmpty()) return; - QShortcut *shortCut = new QShortcut(this->inputEdit); - shortCut->setKey(key); - connect(shortCut, &QShortcut::activated, inputEdit, [=]() { - inputEdit->setFocus(); - inputEdit->setText(locator->getDisplayName() + " "); - }); - QAction *action = new QAction(this); - action->setShortcut(shortCut->key()); QString id = QString("locator.EnterCommand.%1").arg(locator->getDisplayName()); QString description = locator->getDescription(); - ActionManager::getInstance()->registerAction(action, id, description, shortCut->key()); - connect(action, &QAction::changed, shortCut, [=]() { - if (action->shortcut() != shortCut->key()) - shortCut->setKey(action->shortcut()); + auto cmd = ActionManager::instance()->registerAction(action, id); + cmd->setDescription(description); + cmd->setDefaultKeySequence(key); + connect(action, &QAction::triggered, inputEdit, [=]() { + inputEdit->setFocus(); + inputEdit->setText(locator->getDisplayName() + " "); }); } diff --git a/src/plugins/core/locator/locatormanager.h b/src/plugins/core/locator/locatormanager.h index 0647d0ca7..33308a9c4 100644 --- a/src/plugins/core/locator/locatormanager.h +++ b/src/plugins/core/locator/locatormanager.h @@ -71,7 +71,6 @@ class LocatorManager : public QObject QFutureWatcher watcher; QList locatorList; - QShortcut *shortCut { nullptr }; QTimer timer; }; diff --git a/src/plugins/core/modules/pluginmanagermodule.cpp b/src/plugins/core/modules/pluginmanagermodule.cpp index 5f05d4168..277dfb88f 100644 --- a/src/plugins/core/modules/pluginmanagermodule.cpp +++ b/src/plugins/core/modules/pluginmanagermodule.cpp @@ -4,6 +4,7 @@ #include "pluginmanagermodule.h" #include "common/actionmanager/actionmanager.h" +#include "common/actionmanager/actioncontainer.h" #include "services/window/windowelement.h" #include "services/window/windowservice.h" #include "base/abstractaction.h" @@ -31,19 +32,19 @@ PluginManagerModule::~PluginManagerModule() void PluginManagerModule::initialize(Controller *_uiController) { AbstractModule::initialize(_uiController); + auto mHelp = ActionManager::instance()->actionContainer(M_HELP); + mHelp->appendGroup("Help.Group.Plugin"); + mHelp->addSeparator("Help.Group.Plugin"); - QAction *pluginManagerAction = new QAction(MWMTA_PLUGINS, this); - pluginManagerAction->setIcon(QIcon::fromTheme("plugins-navigation")); - ActionManager::getInstance()->registerAction( - pluginManagerAction, "Help.AboutPlugins", MWM_ABOUT_PLUGINS, QKeySequence()); + QAction *aboutPluginAction = new QAction(MWMTA_PLUGINS, this); + auto cmd = ActionManager::instance()->registerAction(aboutPluginAction, "Help.AboutPlugins"); + mHelp->addAction(cmd, "Help.Group.Plugin"); - auto actionOptionsImpl = new AbstractAction(pluginManagerAction, this); + QAction *navigationItemAction = new QAction(MWMTA_PLUGINS, this); + navigationItemAction->setIcon(QIcon::fromTheme("plugins-navigation")); + auto actionOptionsImpl = new AbstractAction(navigationItemAction, this); actionOptionsImpl->setShortCutInfo("Tools.Plugins", MWMTA_PLUGINS); - - auto menuAction = new QAction(MWMTA_PLUGINS, this); - menuAction->setIcon(QIcon::fromTheme("plugins-navigation")); - uiController->addAction(MWM_HELP, new AbstractAction(menuAction)); uiController->addNavigationItem(actionOptionsImpl, Priority::lowest); std::function detailWidgetCreator = [this]()->AbstractWidget*{ @@ -65,12 +66,12 @@ void PluginManagerModule::initialize(Controller *_uiController) uiController->bindWidgetToNavigation(MWMTA_PLUGINS, actionOptionsImpl); - QObject::connect(pluginManagerAction, &QAction::triggered, this, [this]() { + QObject::connect(navigationItemAction, &QAction::triggered, this, [this]() { uiController->showWidgetAtPosition("pluginDetail", Position::Central); uiController->showWidgetAtPosition(MWMTA_PLUGINS, Position::Left); auto windowService = dpfGetService(dpfservice::WindowService); if (windowService) windowService->setDockHeaderName(MWMTA_PLUGINS, tr("Extensions")); }); - QObject::connect(menuAction, &QAction::triggered, this, [this](){uiController->switchWidgetNavigation(MWM_ABOUT_PLUGINS);}); + QObject::connect(aboutPluginAction, &QAction::triggered, this, [this](){uiController->switchWidgetNavigation(MWM_ABOUT_PLUGINS);}); } diff --git a/src/plugins/core/uicontroller/controller.cpp b/src/plugins/core/uicontroller/controller.cpp index c49e780ec..6f825b256 100644 --- a/src/plugins/core/uicontroller/controller.cpp +++ b/src/plugins/core/uicontroller/controller.cpp @@ -19,7 +19,9 @@ #include "modules/dependencemodule.h" #include "locator/locatormanager.h" #include "find/placeholdermanager.h" + #include "common/util/utils.h" +#include "common/actionmanager/actioncontainer.h" #include #include @@ -142,8 +144,6 @@ class ControllerPrivate WindowStatusBar *statusBar { nullptr }; - DMenu *menu { nullptr }; - QStringList validModeList { CM_EDIT, CM_DEBUG, CM_RECENT }; QMap modePluginMap { { CM_EDIT, MWNA_EDIT }, { CM_RECENT, MWNA_RECENT }, { CM_DEBUG, MWNA_DEBUG } }; QString mode { "" }; // mode: CM_EDIT/CM_DEBUG/CM_RECENT @@ -277,18 +277,6 @@ void Controller::registerService() if (!windowService->switchContextWidget) { windowService->switchContextWidget = std::bind(&Controller::switchContextWidget, this, _1); } - if (!windowService->addChildMenu) { - windowService->addChildMenu = std::bind(&Controller::addChildMenu, this, _1); - } - if (!windowService->insertAction) { - windowService->insertAction = std::bind(&Controller::insertAction, this, _1, _2, _3); - } - if (!windowService->addAction) { - windowService->addAction = std::bind(&Controller::addAction, this, _1, _2); - } - if (!windowService->removeActions) { - windowService->removeActions = std::bind(&Controller::removeActions, this, _1); - } if (!windowService->addWidgetToTopTool) { windowService->addWidgetToTopTool = std::bind(&Controller::addWidgetToTopTool, this, _1, _2, _3, _4); } @@ -739,110 +727,6 @@ void Controller::switchContextWidget(const QString &title) } } -void Controller::addChildMenu(AbstractMenu *abstractMenu) -{ - DMenu *inputMenu = abstractMenu->qMenu(); - if (!d->mainWindow || !inputMenu) - return; - - foreach (AbstractAction *action, abstractMenu->actionList()) { - if (action && action->hasShortCut()) { - registerActionShortCut(action); - addMenuShortCut(action->qAction()); - } - } - - // make the `helper` menu at the last - for (QAction *action : d->menu->actions()) { - if (action->text() == MWM_TOOLS) { - d->menu->insertMenu(action, inputMenu); - return; - } - } - - // add menu to last - d->menu->addMenu(inputMenu); -} - -void Controller::insertAction(const QString &menuName, const QString &beforActionName, AbstractAction *action) -{ - if (!action) - return; - - QAction *inputAction = action->qAction(); - if (!inputAction) - return; - - if (action->hasShortCut()) - registerActionShortCut(action); - - for (QAction *qAction : d->mainWindow->menuBar()->actions()) { - if (qAction->text() == menuName) { - for (auto childAction : qAction->menu()->actions()) { - if (childAction->text() == beforActionName) { - qAction->menu()->insertAction(childAction, inputAction); - break; - } else if (qAction->text() == MWM_FILE - && childAction->text() == MWMFA_QUIT) { - qAction->menu()->insertAction(qAction, inputAction); - break; - } - } - } - } -} - -void Controller::addAction(const QString &menuName, AbstractAction *action) -{ - QAction *inputAction = action->qAction(); - if (!inputAction) - return; - - if (action->hasShortCut()) - registerActionShortCut(action); - - //防止与edit和debug界面的topToolBar快捷键冲突 - if (menuName != MWM_DEBUG && menuName != MWM_BUILD) - addMenuShortCut(inputAction); - - if (menuName == MWMFA_NEW_FILE_OR_PROJECT) { - for (QAction *qAction : d->menu->actions()) { - if (qAction->text() == MWM_BUILD) { - d->menu->insertAction(qAction, inputAction); - d->menu->insertSeparator(qAction); - return; - } - } - } - - for (QAction *qAction : d->menu->actions()) { - if (qAction->text() == menuName) { - if (qAction->text() == MWM_FILE) { - auto endAction = *(qAction->menu()->actions().rbegin()); - if (endAction->text() == MWMFA_QUIT) { - return qAction->menu()->insertAction(endAction, inputAction); - } - } - qAction->menu()->addAction(inputAction); - } - } - - if (!inputAction->parent()) - inputAction->setParent(this); -} - -void Controller::removeActions(const QString &menuName) -{ - for (QAction *qAction : d->mainWindow->menuBar()->actions()) { - if (qAction->text() == menuName) { - foreach (QAction *action, qAction->menu()->actions()) { - qAction->menu()->removeAction(action); - } - break; - } - } -} - void Controller::addWidgetToTopTool(AbstractWidget *abstractWidget, bool addSeparator, bool addToLeft, quint8 priority) { if (!abstractWidget) @@ -887,27 +771,22 @@ void Controller::addWidgetToTopTool(AbstractWidget *abstractWidget, bool addSepa hlayout->insertWidget(index, widget); } -void Controller::addTopToolItem(AbstractAction *action, bool addSeparator, quint8 priority) +DToolButton *Controller::addTopToolItem(Command *action, bool addSeparator, quint8 priority) { - if (!action || !action->qAction()) - return; - - if (action->hasShortCut()) - registerActionShortCut(action); + if (!action || !action->action()) + return nullptr; - auto iconBtn = createIconButton(action->qAction()); + auto iconBtn = createIconButton(action->action()); addWidgetToTopTool(new AbstractWidget(iconBtn), addSeparator, true, priority); + return iconBtn; } -void Controller::addTopToolItemToRight(AbstractAction *action, bool addSeparator, quint8 priority) +void Controller::addTopToolItemToRight(Command *action, bool addSeparator, quint8 priority) { - if (!action || !action->qAction()) + if (!action || !action->action()) return; - if (action->hasShortCut()) - registerActionShortCut(action); - - auto iconBtn = createIconButton(action->qAction()); + auto iconBtn = createIconButton(action->action()); addWidgetToTopTool(new AbstractWidget(iconBtn), addSeparator, false, priority); } @@ -945,8 +824,11 @@ void Controller::initMainWindow() qInfo() << __FUNCTION__; if (!d->mainWindow) { d->mainWindow = new MainWindow; + d->mainWindow->setObjectName("MainWindow"); d->mainWindow->setMinimumSize(MW_MIN_WIDTH, MW_MIN_HEIGHT); - initMenu(); + new ActionManager(this); + registerDefaultContainers(); + registerDefaultActions(); QString initFile = CustomPaths::user(CustomPaths::Configures) + "/mainwindow.ini"; QFile file(initFile); @@ -1003,89 +885,6 @@ void Controller::initNavigationBar() vLayout->setContentsMargins(0, 0, 2, 0); } -void Controller::initMenu() -{ - qInfo() << __FUNCTION__; - if (!d->mainWindow) - return; - if (!d->menu) - d->menu = new DMenu(d->mainWindow->titlebar()); - - createFileActions(); - createBuildActions(); - createDebugActions(); - - d->menu->addSeparator(); - - createHelpActions(); - createToolsActions(); - - d->mainWindow->titlebar()->setMenu(d->menu); -} - -void Controller::createHelpActions() -{ - auto helpMenu = new DMenu(MWM_HELP, d->menu); - d->menu->addMenu(helpMenu); - - QAction *actionReportBug = new QAction(MWM_REPORT_BUG, helpMenu); - ActionManager::getInstance()->registerAction(actionReportBug, "Help.Report.Bug", - MWM_REPORT_BUG, QKeySequence()); - addMenuShortCut(actionReportBug); - helpMenu->addAction(actionReportBug); - - QAction *actionHelpDoc = new QAction(MWM_HELP_DOCUMENTS, helpMenu); - ActionManager::getInstance()->registerAction(actionHelpDoc, "Help.Help.Documents", - MWM_HELP_DOCUMENTS, QKeySequence()); - helpMenu->addAction(actionHelpDoc); - addMenuShortCut(actionHelpDoc); - - helpMenu->addSeparator(); - - QAction::connect(actionReportBug, &QAction::triggered, this, [=]() { - QDesktopServices::openUrl(QUrl("https://github.com/linuxdeepin/deepin-unioncode/issues")); - }); - QAction::connect(actionHelpDoc, &QAction::triggered, this, [=]() { - QDesktopServices::openUrl(QUrl("https://uosdn.uniontech.com/#document2?dirid=656d40a9bd766615b0b02e5e")); - }); -} - -void Controller::createToolsActions() -{ - auto toolsMenu = new DMenu(MWM_TOOLS); - d->menu->addMenu(toolsMenu); -} - -void Controller::createDebugActions() -{ - auto *debugMenu = new DMenu(MWM_DEBUG); - d->menu->addMenu(debugMenu); -} - -void Controller::createBuildActions() -{ - auto *buildMenu = new DMenu(MWM_BUILD); - d->menu->addMenu(buildMenu); -} - -void Controller::createFileActions() -{ - QAction *actionOpenFile = new QAction(MWMFA_OPEN_FILE); - ActionManager::getInstance()->registerAction(actionOpenFile, "File.Open.File", - MWMFA_OPEN_FILE, QKeySequence(Qt::Modifier::CTRL | Qt::Key::Key_O)); - - QAction::connect(actionOpenFile, &QAction::triggered, this, &Controller::openFileDialog); - d->menu->addAction(actionOpenFile); - addMenuShortCut(actionOpenFile); - - QAction *actionOpenProject = new QAction(MWMFA_OPEN_PROJECT); - d->menu->addAction(actionOpenProject); - QAction::connect(actionOpenProject, &QAction::triggered, this, [=]() { - auto prjService = dpfGetService(ProjectService); - prjService->openProject(); - }); -} - void Controller::initContextWidget() { if (!d->stackContextWidget) @@ -1217,19 +1016,103 @@ void Controller::initDocksManager() }); } -void Controller::addMenuShortCut(QAction *action, QKeySequence keySequence) -{ - QKeySequence key = keySequence; - if (keySequence.isEmpty()) - key = action->shortcut(); - - QShortcut *shortCut = new QShortcut(key, d->mainWindow); - connect(action, &QAction::changed, this, [=]() { - if (action->shortcut() != shortCut->key()) - shortCut->setKey(action->shortcut()); +void Controller::registerDefaultContainers() +{ + ActionManager::instance()->setContext({ C_GLOBAL }); + auto titleContainer = ActionManager::instance()->createContainer(M_TITLEBAR); + titleContainer->appendGroup(G_FILE); + titleContainer->appendGroup(G_EDIT); + titleContainer->appendGroup(G_BUILD); + titleContainer->appendGroup(G_DEBUG); + titleContainer->appendGroup(G_TOOLS); + titleContainer->appendGroup(G_HELP); + + titleContainer->addSeparator(G_BUILD); + titleContainer->addSeparator(G_TOOLS); + d->mainWindow->titlebar()->setMenu(titleContainer->menu()); + + // file menu + auto fileContainer = ActionManager::instance()->createContainer(M_FILE); + fileContainer->menu()->setTitle(tr("&File")); + fileContainer->appendGroup(G_FILE_NEW); + fileContainer->appendGroup(G_FILE_OPEN); + fileContainer->appendGroup(G_FILE_CLOSE); + fileContainer->appendGroup(G_FILE_SAVE); + + fileContainer->addSeparator(G_FILE_NEW); + fileContainer->addSeparator(G_FILE_OPEN); + fileContainer->addSeparator(G_FILE_CLOSE); + fileContainer->addSeparator(G_FILE_SAVE); + titleContainer->addMenu(fileContainer, G_FILE); + + // edit menu + auto editContainer = ActionManager::instance()->createContainer(M_EDIT); + editContainer->menu()->setTitle(tr("&Edit")); + editContainer->appendGroup(G_EDIT_UNDOREDO); + editContainer->appendGroup(G_EDIT_COPYPASTE); + editContainer->appendGroup(G_EDIT_SELECTALL); + editContainer->appendGroup(G_EDIT_FIND); + editContainer->appendGroup(G_EDIT_OTHER); + + editContainer->addSeparator(G_EDIT_COPYPASTE); + editContainer->addSeparator(G_EDIT_SELECTALL); + editContainer->addSeparator(G_EDIT_FIND); + titleContainer->addMenu(editContainer, G_EDIT); + + // build menu + auto buildContainer = ActionManager::instance()->createContainer(M_BUILD); + buildContainer->menu()->setTitle(tr("&Build")); + titleContainer->addMenu(buildContainer, G_BUILD); + + // debug menu + auto debugContainer = ActionManager::instance()->createContainer(M_DEBUG); + debugContainer->menu()->setTitle(tr("&Debug")); + titleContainer->addMenu(debugContainer, G_DEBUG); + + // tools menu + auto toolsContainer = ActionManager::instance()->createContainer(M_TOOLS); + toolsContainer->menu()->setTitle(tr("&Tools")); + titleContainer->addMenu(toolsContainer, G_TOOLS); + + // help menu + auto helpContainer = ActionManager::instance()->createContainer(M_HELP); + helpContainer->menu()->setTitle(tr("&Help")); + titleContainer->addMenu(helpContainer, G_HELP); +} + +void Controller::registerDefaultActions() +{ + auto mFile = ActionManager::instance()->actionContainer(M_FILE); + auto mHelp = ActionManager::instance()->actionContainer(M_HELP); + + // file actions + QAction *act = new QAction(tr("Open File"), mFile); + auto cmd = ActionManager::instance()->registerAction(act, A_OPEN_FILE); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::Key_O); + mFile->addAction(cmd, G_FILE_OPEN); + connect(act, &QAction::triggered, this, &Controller::openFileDialog); + + act = new QAction(tr("Open Project"), mFile); + cmd = ActionManager::instance()->registerAction(act, A_OPEN_PROJECT); + mFile->addAction(cmd, G_FILE_OPEN); + connect(act, &QAction::triggered, this, [=]() { + auto prjService = dpfGetService(ProjectService); + prjService->openProject(); + }); + + // help actions + act = new QAction(tr("Report Bug"), mHelp); + cmd = ActionManager::instance()->registerAction(act, A_REPORTBUG); + mHelp->addAction(cmd); + connect(act, &QAction::triggered, this, [=]() { + QDesktopServices::openUrl(QUrl("https://github.com/linuxdeepin/deepin-unioncode/issues")); }); - connect(shortCut, &QShortcut::activated, action, [=] { - action->trigger(); + + act = new QAction(tr("Help Documents"), mHelp); + cmd = ActionManager::instance()->registerAction(act, A_HELPDOC); + mHelp->addAction(cmd); + connect(act, &QAction::triggered, this, [=]() { + QDesktopServices::openUrl(QUrl("https://uosdn.uniontech.com/#document2?dirid=656d40a9bd766615b0b02e5e")); }); } @@ -1260,14 +1143,6 @@ void Controller::switchWorkspace(const QString &titleName) d->workspace->switchWidgetWorkspace(titleName); } -void Controller::registerActionShortCut(AbstractAction *action) -{ - auto qAction = action->qAction(); - if (!qAction) - return; - ActionManager::getInstance()->registerAction(qAction, action->id(), action->description(), action->keySequence()); -} - void Controller::showWorkspace() { auto &workSpaceInfo = d->allWidgets[WN_WORKSPACE]; @@ -1328,15 +1203,15 @@ DToolButton *Controller::createIconButton(QAction *action) return iconBtn; } -void Controller::removeTopToolItem(AbstractAction *action) +void Controller::removeTopToolItem(Command *action) { - if (!action || !action->qAction()) + if (!action || !action->action()) return; - auto iconBtn = d->topToolBtn.value(action->qAction()); + auto iconBtn = d->topToolBtn.value(action->action()); delete iconBtn; - d->topToolBtn.remove(action->qAction()); + d->topToolBtn.remove(action->action()); } bool Controller::checkDocksManager() @@ -1398,11 +1273,11 @@ DToolButton *Controller::createDockButton(const WidgetInfo &info) return btn; } -void Controller::setTopToolItemVisible(AbstractAction *action, bool visible) +void Controller::setTopToolItemVisible(Command *action, bool visible) { - if (!action || !action->qAction()) + if (!action || !action->action()) return; - auto iconBtn = d->topToolBtn.value(action->qAction()); + auto iconBtn = d->topToolBtn.value(action->action()); iconBtn->setVisible(visible); } diff --git a/src/plugins/core/uicontroller/controller.h b/src/plugins/core/uicontroller/controller.h index e3e3d2684..1751f0ac7 100644 --- a/src/plugins/core/uicontroller/controller.h +++ b/src/plugins/core/uicontroller/controller.h @@ -6,8 +6,10 @@ #define CONTROLLER_H #include "mainwindow.h" + #include "base/abstractmenu.h" #include "base/abstractwidget.h" +#include "common/actionmanager/command.h" #include @@ -60,20 +62,13 @@ public slots: void hideContextWidget(); void switchContextWidget(const QString &title); - //menu - void addChildMenu(AbstractMenu *menu); - void insertAction(const QString &menuName, const QString &beforActionName, - AbstractAction *action); - void addAction(const QString &menuName, AbstractAction *action); - void removeActions(const QString &menuName); - //topToolBar void addWidgetToTopTool(AbstractWidget *abstractWidget, bool addSeparator, bool addToLeft, quint8 priority); - void addTopToolItem(AbstractAction *action, bool addSeparator, quint8 priority); - void addTopToolItemToRight(AbstractAction *action, bool addSeparator, quint8 priority); + DToolButton *addTopToolItem(Command *action, bool addSeparator, quint8 priority); + void addTopToolItemToRight(Command *action, bool addSeparator, quint8 priority); void showTopToolBar(); - void removeTopToolItem(AbstractAction *action); - void setTopToolItemVisible(AbstractAction *action, bool visible); + void removeTopToolItem(Command *action); + void setTopToolItemVisible(Command *action, bool visible); void openFileDialog(); @@ -100,7 +95,6 @@ public slots: void initMainWindow(); void initNavigationBar(); - void initMenu(); void initContextWidget(); void initStatusBar(); void initWorkspaceWidget(); @@ -108,16 +102,9 @@ public slots: void initModules(); void initDocksManager(); - //menu - void createHelpActions(); - void createToolsActions(); - void createDebugActions(); - void createBuildActions(); - void createFileActions(); - - void addMenuShortCut(QAction *action, QKeySequence keySequence = QKeySequence()); - - void registerActionShortCut(AbstractAction *action); + //menu and action + void registerDefaultContainers(); + void registerDefaultActions(); void showWorkspace(); diff --git a/src/plugins/core/uicontroller/mainwindow.cpp b/src/plugins/core/uicontroller/mainwindow.cpp index 1152af9d0..f30c0336b 100644 --- a/src/plugins/core/uicontroller/mainwindow.cpp +++ b/src/plugins/core/uicontroller/mainwindow.cpp @@ -60,6 +60,7 @@ MainWindow::MainWindow(QWidget *parent) { titlebar()->setTitle("Deepin Union Code"); titlebar()->setIcon(QIcon::fromTheme("ide")); + titlebar()->setFocusPolicy(Qt::NoFocus); setWindowIcon(QIcon::fromTheme("ide")); setAttribute(Qt::WA_DeleteOnClose); diff --git a/src/plugins/cxx/cmake/project/cmakeprojectgenerator.cpp b/src/plugins/cxx/cmake/project/cmakeprojectgenerator.cpp index a65870f19..9b832fbb4 100644 --- a/src/plugins/cxx/cmake/project/cmakeprojectgenerator.cpp +++ b/src/plugins/cxx/cmake/project/cmakeprojectgenerator.cpp @@ -101,11 +101,11 @@ CmakeProjectGenerator::CmakeProjectGenerator() abort(); } + auto mBuild = ActionManager::instance()->actionContainer(M_BUILD); // add run cmake menu item. - QAction *runCMake = new QAction(tr("Run CMake")); - auto inputAction = new AbstractAction(runCMake, this); - inputAction->setShortCutInfo("Build.RunCMake", runCMake->text()); - dpfGetService(WindowService)->addAction(dpfservice::MWM_BUILD, inputAction); + QAction *runCMake = new QAction(tr("Run CMake"), this); + auto cmd = ActionManager::instance()->registerAction(runCMake, "Build.RunCMake"); + mBuild->addAction(cmd); QObject::connect(runCMake, &QAction::triggered, this, [this](){ auto prjService = dpfGetService(ProjectService); @@ -125,9 +125,8 @@ CmakeProjectGenerator::CmakeProjectGenerator() // add clear cmake menu item QAction *clearCMake = new QAction(tr("Clear CMake")); - auto abstractClearCMake = new AbstractAction(clearCMake, this); - abstractClearCMake->setShortCutInfo("Build.ClearCMake", clearCMake->text()); - dpfGetService(WindowService)->addAction(dpfservice::MWM_BUILD, abstractClearCMake); + cmd = ActionManager::instance()->registerAction(clearCMake, "Build.ClearCMake"); + mBuild->addAction(cmd); QObject::connect(clearCMake, &QAction::triggered, this, [this](){ auto prjService = dpfGetService(ProjectService); @@ -646,7 +645,7 @@ void CmakeProjectGenerator::createBuildMenu(QMenu *menu) menu->addSeparator(); auto addBuildMenu = [&](const QString &actionID){ - auto command = ActionManager::getInstance()->command(actionID); + auto command = ActionManager::instance()->command(actionID); if (command && command->action()) { menu->addAction(command->action()); } diff --git a/src/plugins/debugger/interface/menumanager.cpp b/src/plugins/debugger/interface/menumanager.cpp index 8e0479a81..96d2700ff 100644 --- a/src/plugins/debugger/interface/menumanager.cpp +++ b/src/plugins/debugger/interface/menumanager.cpp @@ -8,6 +8,7 @@ #include "debuggerglobals.h" #include "base/abstractmenu.h" #include "common/common.h" +#include "common/actionmanager/actioncontainer.h" #include "common/widget/appoutputpane.h" #include "services/window/windowservice.h" #include "remotedebug/remotedebugdlg.h" @@ -26,19 +27,22 @@ void MenuManager::initialize(WindowService *windowService) return; auto initAction = [&](QAction *action, const QString &id, const QString &description, - QKeySequence key, const QString &iconName) -> AbstractAction * { + QKeySequence key, const QString &iconName = {}) -> Command * { action->setIcon(QIcon::fromTheme(iconName)); - auto actionImpl = new AbstractAction(action, this); - actionImpl->setShortCutInfo(id, description, key); - return actionImpl; + auto cmd = ActionManager::instance()->registerAction(action, id); + cmd->setDefaultKeySequence(key); + cmd->setDescription(description); + return cmd; }; + auto mDebug = ActionManager::instance()->actionContainer(M_DEBUG); + startDebugging.reset(new QAction(MWMDA_START_DEBUG)); connect(startDebugging.get(), &QAction::triggered, debugManager, &DebugManager::run); auto actionImpl = initAction(startDebugging.get(), "Debug.Start.Debugging", MWMDA_START_DEBUG, QKeySequence(Qt::Key::Key_F5), "debugger_start"); - windowService->addAction(MWM_DEBUG, actionImpl); + mDebug->addAction(actionImpl); windowService->addTopToolItem(actionImpl, false, Priority::medium); #if 0 // not used yet. detachDebugger.reset(new QAction("Detach Debugger")); @@ -56,8 +60,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(interrupt.get(), "Debug.Interrupt", MWMDA_INTERRUPT, QKeySequence(Qt::Key::Key_F5), "debugger_interrupt"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), true); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), true); continueDebugging.reset(new QAction(MWMDA_CONTINUE)); continueDebugging->setEnabled(false); @@ -65,8 +69,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(continueDebugging.get(), "Debug.Continue", MWMDA_CONTINUE, QKeySequence(Qt::Key::Key_F5), "debugger_continue"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), false); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), false); abortDebugging.reset(new QAction(MWMDA_ABORT_DEBUGGING)); abortDebugging->setEnabled(false); @@ -74,8 +78,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(abortDebugging.get(), "Debug.Abort.Debugging", MWMDA_ABORT_DEBUGGING, QKeySequence(Qt::Modifier::SHIFT | Qt::Key::Key_F5), "debugger_stop"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), false); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), false); restartDebugging.reset(new QAction(MWMDA_RESTART_DEBUGGING)); restartDebugging->setEnabled(false); @@ -83,8 +87,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(restartDebugging.get(), "Debug.Restart.Debugging", MWMDA_RESTART_DEBUGGING, QKeySequence(Qt::Modifier::SHIFT | Qt::Key::Key_B), "restart_debug"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), false); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), false); stepOver.reset(new QAction(MWMDA_STEP_OVER)); stepOver->setEnabled(false); @@ -92,8 +96,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(stepOver.get(), "Debug.Step.Over", MWMDA_STEP_OVER, QKeySequence(Qt::Key::Key_F10), "debugger_stepover"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), true); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), true); stepIn.reset(new QAction(MWMDA_STEP_IN)); stepIn->setEnabled(false); @@ -101,8 +105,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(stepIn.get(), "Debug.Step.In", MWMDA_STEP_IN, QKeySequence(Qt::Key::Key_F11), "debugger_stepinto"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), false); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), false); stepOut.reset(new QAction(MWMDA_STEP_OUT)); stepOut->setEnabled(false); @@ -110,8 +114,8 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(stepOut.get(), "Debug.Step.Out", MWMDA_STEP_OUT, QKeySequence(Qt::Modifier::SHIFT | Qt::Key::Key_F11), "debugger_stepout"); - windowService->addAction(MWM_DEBUG, actionImpl); - appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->qAction(), false); + mDebug->addAction(actionImpl); + appOutPutPane->registerItemToToolBar(debugToolBarName, actionImpl->action(), false); remoteDebug.reset(new QAction(MWMDA_REMOTE_DEBUG)); connect(remoteDebug.get(), &QAction::triggered, debugManager, [=]() { @@ -122,14 +126,14 @@ void MenuManager::initialize(WindowService *windowService) actionImpl = initAction(remoteDebug.get(), "Debug.Remote.Debug", MWMDA_REMOTE_DEBUG, QKeySequence(), "debugger_remotedebug"); - windowService->addAction(MWM_DEBUG, actionImpl); + mDebug->addAction(actionImpl); attachDebugging.reset(new QAction(MWMDA_ATTACH_DEBUG)); connect(attachDebugging.get(), &QAction::triggered, debugManager, &DebugManager::attachDebug); actionImpl = initAction(attachDebugging.get(), "Debug.Attach.Debugging", MWMDA_ATTACH_DEBUG, QKeySequence(), "debugger_start"); - windowService->addAction(MWM_DEBUG, actionImpl); + mDebug->addAction(actionImpl); } void MenuManager::handleRunStateChanged(AbstractDebugger::RunState state) diff --git a/src/plugins/debugger/runner/runner.cpp b/src/plugins/debugger/runner/runner.cpp index 0541b63be..1bad27e7c 100644 --- a/src/plugins/debugger/runner/runner.cpp +++ b/src/plugins/debugger/runner/runner.cpp @@ -47,11 +47,10 @@ Runner::Runner(QObject *parent) d->runAction.get()->setIcon(QIcon::fromTheme("run")); connect(d->runAction.get(), &QAction::triggered, this, &Runner::run); - auto actionImpl = new AbstractAction(d->runAction.get(), this); - actionImpl->setShortCutInfo("Debug.Running", - MWMDA_RUNNING, QKeySequence(Qt::Modifier::CTRL | Qt::Key::Key_F5)); + auto cmd = ActionManager::instance()->registerAction(d->runAction.get(), "Debug.Running"); + cmd->setDefaultKeySequence(Qt::Modifier::CTRL | Qt::Key::Key_F5); WindowService *service = dpfGetService(WindowService); - service->addTopToolItem(actionImpl, false, Priority::high); + service->addTopToolItem(cmd, false, Priority::high); d->runProgram = new DComboBox; d->runProgram->setFixedSize(200, 36); diff --git a/src/plugins/find/findplugin.cpp b/src/plugins/find/findplugin.cpp index b44b8666b..ed47d1faf 100644 --- a/src/plugins/find/findplugin.cpp +++ b/src/plugins/find/findplugin.cpp @@ -9,12 +9,16 @@ #include "gui/advancedsearchwidget.h" #include "common/common.h" +#include "common/actionmanager/actioncontainer.h" #include "base/abstractmenu.h" #include "base/abstractwidget.h" #include #include +constexpr char M_FIND[] = "Find.FindMenu"; + + using namespace dpfservice; void FindPlugin::initialize() @@ -47,10 +51,13 @@ void FindPlugin::switchToSearch() void FindPlugin::registerShortcut() { - QAction *advancedFindAction = new QAction(this); - auto advancedFindActionImpl = new AbstractAction(advancedFindAction); - advancedFindActionImpl->setShortCutInfo("Edit.Advanced.Find", - tr("Advanced Find"), QKeySequence(Qt::Modifier::CTRL | Qt::Modifier::SHIFT | Qt::Key_F)); + auto mFind = ActionManager::instance()->actionContainer(M_FIND); + mFind->insertGroup("Find.FindMenu.Actions", "Find.FindMenu.Advanced"); + + QAction *advancedFindAction = new QAction(tr("Advanced Find"), mFind); + auto cmd = ActionManager::instance()->registerAction(advancedFindAction, "Find.AdvancedFind"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_F); + mFind->addAction(cmd, "Find.FindMenu.Advanced"); connect(advancedFindAction, &QAction::triggered, qApp, [=] { auto editSrv = dpfGetService(EditorService); const auto &selectedText = editSrv->getSelectedText(); @@ -58,7 +65,6 @@ void FindPlugin::registerShortcut() advSearchWidget->setSearchText(selectedText); windowService->switchWidgetNavigation(MWNA_ADVANCEDSEARCH); }); - windowService->addAction("&Edit", advancedFindActionImpl); } dpf::Plugin::ShutdownFlag FindPlugin::stop() diff --git a/src/plugins/git/git.cpp b/src/plugins/git/git.cpp index e1a565d6f..b04c71b15 100644 --- a/src/plugins/git/git.cpp +++ b/src/plugins/git/git.cpp @@ -46,6 +46,6 @@ void Git::initWindowService() if (!windowService) return; - GitMenuManager::instance()->initialize(windowService); + GitMenuManager::instance()->initialize(); windowService->addStatusBarItem(GitClient::instance()->instantBlameWidget()); } diff --git a/src/plugins/git/utils/gitmenumanager.cpp b/src/plugins/git/utils/gitmenumanager.cpp index f042ec002..9f1151f24 100644 --- a/src/plugins/git/utils/gitmenumanager.cpp +++ b/src/plugins/git/utils/gitmenumanager.cpp @@ -12,6 +12,15 @@ #include +constexpr char M_GIT[] { "Git.Menu" }; +constexpr char M_GIT_FILE[] { "Git.Menu.File" }; +constexpr char M_GIT_PROJECT[] { "Git.Menu.Project" }; +constexpr char A_GIT_LOG_FILE[] { "Git.Action.File.Log" }; +constexpr char A_GIT_BLAME_FILE[] { "Git.Action.File.Blame" }; +constexpr char A_GIT_DIFF_FILE[] { "Git.Action.File.Diff" }; +constexpr char A_GIT_LOG_PROJECT[] { "Git.Action.Project.Log" }; +constexpr char A_GIT_DIFF_PROJECT[] { "Git.Action.Project.Diff" }; + using namespace dpfservice; GitMenuManager::GitMenuManager(QObject *parent) @@ -19,10 +28,10 @@ GitMenuManager::GitMenuManager(QObject *parent) { } -void GitMenuManager::actionHandler(QAction *act, GitType type) +void GitMenuManager::actionHandler(Command *cmd, GitType type) { - const auto &filePath = act->property(GitFilePath).toString(); - bool isProject = act->property(GitIsProject).toBool(); + const auto &filePath = cmd->property(GitFilePath).toString(); + bool isProject = cmd->property(GitIsProject).toBool(); bool ret = false; switch (type) { case GitLog: @@ -51,36 +60,35 @@ GitMenuManager *GitMenuManager::instance() return &ins; } -void GitMenuManager::initialize(dpfservice::WindowService *service) +void GitMenuManager::initialize() { - if (!service) - return; - - winSrv = service; - gitAct = new QAction("&Git", this); - auto gitActImpl = new AbstractAction(gitAct, this); - service->addAction(MWM_TOOLS, gitActImpl); + auto mTools = ActionManager::instance()->actionContainer(M_TOOLS); + auto mGit = ActionManager::instance()->createContainer(M_GIT); + mGit->menu()->setTitle("&Git"); + mTools->addMenu(mGit); createGitSubMenu(); - gitAct->setMenu(&gitSubMenu); } void GitMenuManager::setupProjectMenu() { + auto mCurProject = ActionManager::instance()->actionContainer(M_GIT_PROJECT); auto activeProjInfo = dpfGetService(dpfservice::ProjectService)->getActiveProjectInfo(); if (!activeProjInfo.isVaild() || !GitClient::instance()->checkRepositoryExist(activeProjInfo.workspaceFolder())) { - curProjectAct->setEnabled(false); + mCurProject->containerAction()->setEnabled(false); return; } + mCurProject->containerAction()->setEnabled(true); QFileInfo info(activeProjInfo.workspaceFolder()); - curProjectAct->setEnabled(true); + auto projectLogAct = ActionManager::instance()->command(A_GIT_LOG_PROJECT); projectLogAct->setProperty(GitFilePath, activeProjInfo.workspaceFolder()); - projectLogAct->setText(tr("Log of \"%1\"").arg(info.fileName())); + projectLogAct->action()->setText(tr("Log of \"%1\"").arg(info.fileName())); + auto projectDiffAct = ActionManager::instance()->command(A_GIT_DIFF_PROJECT); projectDiffAct->setProperty(GitFilePath, activeProjInfo.workspaceFolder()); - projectDiffAct->setText(tr("Diff of \"%1\"").arg(info.fileName())); + projectDiffAct->action()->setText(tr("Diff of \"%1\"").arg(info.fileName())); } void GitMenuManager::setupFileMenu(const QString &filePath) @@ -93,78 +101,89 @@ void GitMenuManager::setupFileMenu(const QString &filePath) file = editSrv->currentFile(); } + auto mCurFile = ActionManager::instance()->actionContainer(M_GIT_FILE); if (file.isEmpty() || !GitClient::instance()->checkRepositoryExist(file)) { - curFileAct->setEnabled(false); + mCurFile->containerAction()->setEnabled(false); return; } - curFileAct->setEnabled(true); + mCurFile->containerAction()->setEnabled(true); QFileInfo info(file); + auto fileLogAct = ActionManager::instance()->command(A_GIT_LOG_FILE); fileLogAct->setProperty(GitFilePath, file); - fileLogAct->setText(tr("Log of \"%1\"").arg(info.fileName())); + fileLogAct->action()->setText(tr("Log of \"%1\"").arg(info.fileName())); + auto fileBlameAct = ActionManager::instance()->command(A_GIT_BLAME_FILE); fileBlameAct->setProperty(GitFilePath, file); - fileBlameAct->setText(tr("Blame of \"%1\"").arg(info.fileName())); + fileBlameAct->action()->setText(tr("Blame of \"%1\"").arg(info.fileName())); + auto fileDiffAct = ActionManager::instance()->command(A_GIT_DIFF_FILE); fileDiffAct->setProperty(GitFilePath, file); - fileDiffAct->setText(tr("Diff of \"%1\"").arg(info.fileName())); + fileDiffAct->action()->setText(tr("Diff of \"%1\"").arg(info.fileName())); } QAction *GitMenuManager::gitAction() const { - return gitAct; + auto mGit = ActionManager::instance()->actionContainer(M_GIT); + return mGit->containerAction(); } void GitMenuManager::createGitSubMenu() { - curFileAct = gitSubMenu.addAction(tr("Current File")); - curFileAct->setEnabled(false); - curFileAct->setMenu(&fileSubMenu); + auto mGit = ActionManager::instance()->actionContainer(M_GIT); + auto mCurFile = ActionManager::instance()->createContainer(M_GIT_FILE); + mCurFile->menu()->setTitle(tr("Current File")); + mCurFile->containerAction()->setEnabled(false); + mGit->addMenu(mCurFile); createFileSubMenu(); - curProjectAct = gitSubMenu.addAction(tr("Current Project")); - curProjectAct->setEnabled(false); - curProjectAct->setMenu(&projectSubMenu); + auto mCurProject = ActionManager::instance()->createContainer(M_GIT_PROJECT); + mCurProject->menu()->setTitle(tr("Current Project")); + mCurProject->containerAction()->setEnabled(false); + mGit->addMenu(mCurProject); createProjectSubMenu(); } void GitMenuManager::createFileSubMenu() { - fileLogAct = new QAction(this); - connect(fileLogAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, fileLogAct, GitLog)); - registerShortcut(fileLogAct, "Git.log", tr("Git Log"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_L)); - - fileBlameAct = new QAction(this); - connect(fileBlameAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, fileBlameAct, GitBlame)); - registerShortcut(fileBlameAct, "Git.blame", tr("Git Blame"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_B)); - - fileDiffAct = new QAction(this); - connect(fileDiffAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, fileDiffAct, GitDiff)); - registerShortcut(fileDiffAct, "Git.diff", tr("Git Diff"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_D)); - - fileSubMenu.addAction(fileLogAct); - fileSubMenu.addAction(fileBlameAct); - fileSubMenu.addAction(fileDiffAct); + auto mCurFile = ActionManager::instance()->actionContainer(M_GIT_FILE); + auto fileLogAct = new QAction(this); + auto cmd = registerShortcut(fileLogAct, A_GIT_LOG_FILE, tr("Git Log"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_L)); + mCurFile->addAction(cmd); + connect(fileLogAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, cmd, GitLog)); + + auto fileBlameAct = new QAction(this); + cmd = registerShortcut(fileBlameAct, A_GIT_BLAME_FILE, tr("Git Blame"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_B)); + mCurFile->addAction(cmd); + connect(fileBlameAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, cmd, GitBlame)); + + auto fileDiffAct = new QAction(this); + cmd = registerShortcut(fileDiffAct, A_GIT_DIFF_FILE, tr("Git Diff"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_D)); + mCurFile->addAction(cmd); + connect(fileDiffAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, cmd, GitDiff)); } void GitMenuManager::createProjectSubMenu() { - projectLogAct = new QAction(this); - projectLogAct->setProperty(GitIsProject, true); - connect(projectLogAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, projectLogAct, GitLog)); - - projectDiffAct = new QAction(this); - projectDiffAct->setProperty(GitIsProject, true); - connect(projectDiffAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, projectDiffAct, GitDiff)); - - projectSubMenu.addAction(projectLogAct); - projectSubMenu.addAction(projectDiffAct); + auto mCurProject = ActionManager::instance()->actionContainer(M_GIT_PROJECT); + auto projectLogAct = new QAction(this); + auto cmd = ActionManager::instance()->registerAction(projectLogAct, A_GIT_LOG_PROJECT); + cmd->setProperty(GitIsProject, true); + mCurProject->addAction(cmd); + connect(projectLogAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, cmd, GitLog)); + + auto projectDiffAct = new QAction(this); + cmd = ActionManager::instance()->registerAction(projectDiffAct, A_GIT_DIFF_PROJECT); + cmd->setProperty(GitIsProject, true); + mCurProject->addAction(cmd); + connect(projectDiffAct, &QAction::triggered, this, std::bind(&GitMenuManager::actionHandler, this, cmd, GitDiff)); } -void GitMenuManager::registerShortcut(QAction *act, const QString &id, const QString &description, const QKeySequence &shortCut) +Command *GitMenuManager::registerShortcut(QAction *act, const QString &id, const QString &description, const QKeySequence &shortCut) { - auto actImpl = new AbstractAction(act, qApp); - actImpl->setShortCutInfo(id, description, shortCut); - winSrv->addAction(tr("&Git"), actImpl); + auto cmd = ActionManager::instance()->registerAction(act, id); + cmd->setDefaultKeySequence(shortCut); + cmd->setDescription(description); + return cmd; } diff --git a/src/plugins/git/utils/gitmenumanager.h b/src/plugins/git/utils/gitmenumanager.h index 82f9c76b1..be75cfa6e 100644 --- a/src/plugins/git/utils/gitmenumanager.h +++ b/src/plugins/git/utils/gitmenumanager.h @@ -15,14 +15,14 @@ namespace dpfservice { class WindowService; class EditorService; } - +class Command; class GitMenuManager : public QObject { Q_OBJECT public: static GitMenuManager *instance(); - void initialize(dpfservice::WindowService *service); + void initialize(); void setupProjectMenu(); void setupFileMenu(const QString &filePath = QString()); QAction *gitAction() const; @@ -30,29 +30,14 @@ class GitMenuManager : public QObject private: explicit GitMenuManager(QObject *parent = nullptr); - void actionHandler(QAction *act, GitType type); + void actionHandler(Command *cmd, GitType type); void createGitSubMenu(); void createFileSubMenu(); void createProjectSubMenu(); - void registerShortcut(QAction *act, const QString &id, const QString &description, const QKeySequence &shortCut); + Command *registerShortcut(QAction *act, const QString &id, const QString &description, const QKeySequence &shortCut); private: dpfservice::EditorService *editSrv { nullptr }; - dpfservice::WindowService *winSrv { nullptr }; - - QMenu gitSubMenu; - QMenu fileSubMenu; - QMenu projectSubMenu; - - QAction *gitAct { nullptr }; - QAction *curFileAct { nullptr }; - QAction *fileLogAct { nullptr }; - QAction *fileBlameAct { nullptr }; - QAction *fileDiffAct { nullptr }; - - QAction *curProjectAct { nullptr }; - QAction *projectLogAct { nullptr }; - QAction *projectDiffAct { nullptr }; }; #endif // GITMENUMANAGER_H diff --git a/src/plugins/option/optioncore/mainframe/shortcutsettingwidget.cpp b/src/plugins/option/optioncore/mainframe/shortcutsettingwidget.cpp index b7c835b98..6c26b2faa 100644 --- a/src/plugins/option/optioncore/mainframe/shortcutsettingwidget.cpp +++ b/src/plugins/option/optioncore/mainframe/shortcutsettingwidget.cpp @@ -60,8 +60,8 @@ ShortCut::~ShortCut() void ShortCut::updateUi() { //更新配置时先删除旧项 - if(d->bgGplayout->count()){ - while(auto layout = d->bgGplayout->takeAt(0)) + if (d->bgGplayout->count()) { + while (auto layout = d->bgGplayout->takeAt(0)) delete layout->widget(); } @@ -110,7 +110,7 @@ void ShortCut::updateUi() if (isRepeat) { showWarning(tr("Shortcut Repeated"), tr("Shortcut Repeated, Please enter again!")); qWarning() << "isRepeat!!"; - if (oldSequence.isEmpty()){ + if (oldSequence.isEmpty()) { keyEdit->clear(); } else { keyEdit->setKeySequence(oldSequence); @@ -122,7 +122,8 @@ void ShortCut::updateUi() } } -inline void ShortCut::showWarning(const QString& title, const QString& message){ +inline void ShortCut::showWarning(const QString &title, const QString &message) +{ DDialog warningDialog; warningDialog.setWindowTitle(title); warningDialog.setMessage(message); @@ -180,34 +181,29 @@ void ShortCut::saveShortcut() { ShortcutUtil::writeToJson(d->configFilePath, d->shortcutItemMap); - QList commandsList = ActionManager::getInstance()->commands(); - QList::iterator iter = commandsList.begin(); - for (; iter != commandsList.end(); ++iter) { - Action *action = dynamic_cast(*iter); - QString id = action->id(); - + QList commandList = ActionManager::instance()->commandList(); + for (auto cmd : commandList) { + QString id = cmd->id(); if (d->shortcutItemMap.contains(id)) { QStringList valueList = d->shortcutItemMap[id]; - action->setKeySequence(QKeySequence(valueList.last())); + cmd->setKeySequences({ QKeySequence(valueList.last()) }); } } } void ShortCut::readShortcut() { - QList commandsList = ActionManager::getInstance()->commands(); - QList::iterator iter = commandsList.begin(); - for (; iter != commandsList.end(); ++iter) { - Action *action = dynamic_cast(*iter); - QString id = action->id(); - QStringList valueList = QStringList { action->description(), action->keySequence().toString() }; + QList commandList = ActionManager::instance()->commandList(); + for (auto cmd : commandList) { + QString id = cmd->id(); + QStringList valueList = QStringList { cmd->description(), cmd->keySequence().toString() }; d->shortcutItemMap[id] = valueList; } QMap shortcutItemMap; ShortcutUtil::readFromJson(d->configFilePath, shortcutItemMap); foreach (const QString key, shortcutItemMap.keys()) { - if(d->shortcutItemMap[key].isEmpty()) + if (d->shortcutItemMap[key].isEmpty()) d->shortcutItemMap[key] = shortcutItemMap.value(key); else d->shortcutItemMap[key].last() = shortcutItemMap.value(key).last(); @@ -218,20 +214,18 @@ void ShortCut::readShortcut() void ShortCut::updateDescriptions() { - QList commandsList = ActionManager::getInstance()->commands(); - QList::iterator iter = commandsList.begin(); + QList commandList = ActionManager::instance()->commandList(); bool update = false; - for (; iter != commandsList.end(); ++iter) { - Action *action = dynamic_cast(*iter); - QString id = action->id(); + for (auto cmd : commandList) { + QString id = cmd->id(); //已存在该Id的快捷键,但描述不同 -- 比如 配置中为中文 但应用为英文,显示会异常。 - if(!d->shortcutItemMap[id].isEmpty() && (d->shortcutItemMap[id].first() != action->description())) { - d->shortcutItemMap[id].first() = action->description(); + if (!d->shortcutItemMap[id].isEmpty() && (d->shortcutItemMap[id].first() != cmd->description())) { + d->shortcutItemMap[id].first() = cmd->description(); update = true; } } - if(update) { + if (update) { updateUi(); d->shortcutItemShadowMap = d->shortcutItemMap; } diff --git a/src/plugins/option/optioncore/optioncore.cpp b/src/plugins/option/optioncore/optioncore.cpp index 729b5c257..4515e5e4c 100644 --- a/src/plugins/option/optioncore/optioncore.cpp +++ b/src/plugins/option/optioncore/optioncore.cpp @@ -55,31 +55,30 @@ bool OptionCore::start() optionService->showOptionDialog = std::bind(&OptionsDialog::showAtItem, OptionDefaultKeeper::getOptionDialog(), _1); } - if (windowService && windowService->addAction) { + if (windowService) { + auto mTool = ActionManager::instance()->actionContainer(M_TOOLS); + auto actionOptions = new QAction(MWMTA_OPTIONS, this); actionOptions->setIcon(QIcon::fromTheme("options_setting")); - auto actionOptionsImpl = new AbstractAction(actionOptions, this); - actionOptionsImpl->setShortCutInfo("Tools.Options", - MWMTA_OPTIONS, - QKeySequence(Qt::Modifier::CTRL | - Qt::Modifier::SHIFT | - Qt::Key::Key_H)); + auto cmd = ActionManager::instance()->registerAction(actionOptions, "Tools.Options"); + cmd->setDefaultKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_H); + mTool->addAction(cmd); - windowService->addAction(MWM_TOOLS, actionOptionsImpl); + auto actionOptionsImpl = new AbstractAction(actionOptions, this); windowService->addNavigationItemToBottom(actionOptionsImpl, Priority::lowest); QObject::connect(actionOptions, &QAction::triggered, optionDialog, &QDialog::show); } DPF_USE_NAMESPACE - QObject::connect(&Listener::instance(), &Listener::pluginsStarted, [=](){ + QObject::connect(&Listener::instance(), &Listener::pluginsStarted, [=]() { if (optionDialog) { auto groups = optionService->generatorGroups(); if (groups.isEmpty()) return; //raise general and language group - auto raiseGroupPriority= [=](QStringList &groupList, const QString &groupName){ + auto raiseGroupPriority = [=](QStringList &groupList, const QString &groupName) { if (groupList.contains(groupName)) { groupList.removeOne(groupName); groupList.insert(0, groupName); @@ -95,7 +94,7 @@ bool OptionCore::start() for (auto name : generatorNames) { auto generator = optionService->createGenerator(name); if (generator) { - PageWidget *optionWidget = dynamic_cast(generator->optionWidget()); + PageWidget *optionWidget = dynamic_cast(generator->optionWidget()); if (optionWidget) { optionDialog->insertOptionPanel(name, optionWidget); optionWidget->readConfig(); diff --git a/src/plugins/project/mainframe/projecttree.cpp b/src/plugins/project/mainframe/projecttree.cpp index b35d5ecbc..8a49a08d6 100644 --- a/src/plugins/project/mainframe/projecttree.cpp +++ b/src/plugins/project/mainframe/projecttree.cpp @@ -217,7 +217,7 @@ void ProjectTree::doItemMenuRequest(QStandardItem *item, QContextMenuEvent *even if (rootItem == item) { menu = rootMenu(rootItem); // add action that running. - auto runCommand = ActionManager::getInstance()->command("Debug.Running"); + auto runCommand = ActionManager::instance()->command("Debug.Running"); if (runCommand && runCommand->action()) { menu->addSeparator(); menu->addAction(runCommand->action()); diff --git a/src/plugins/reversedebug/reversedebuggermgr.cpp b/src/plugins/reversedebug/reversedebuggermgr.cpp index 36ddc39ce..fb3e6fa81 100644 --- a/src/plugins/reversedebug/reversedebuggermgr.cpp +++ b/src/plugins/reversedebug/reversedebuggermgr.cpp @@ -221,7 +221,7 @@ void ReverseDebuggerMgr::outputMessage(const QString &msg) void ReverseDebuggerMgr::exist() { - auto command = ActionManager::getInstance()->command("Debug.Abort.Debugging"); + auto command = ActionManager::instance()->command("Debug.Abort.Debugging"); QAction *action = nullptr; if (command && (action = command->action()) && action->isEnabled()) { action->trigger(); diff --git a/src/plugins/reversedebug/reversedebugplugin.cpp b/src/plugins/reversedebug/reversedebugplugin.cpp index 52de3c8e4..97e2d3914 100644 --- a/src/plugins/reversedebug/reversedebugplugin.cpp +++ b/src/plugins/reversedebug/reversedebugplugin.cpp @@ -8,10 +8,14 @@ #include "services/window/windowservice.h" #include "common/util/eventdefinitions.h" #include "common/actionmanager/actionmanager.h" +#include "common/actionmanager/actioncontainer.h" #include "reversedebuggermgr.h" #include +constexpr char A_REVERSE_DEBUG_RECORD[] = "ReverseDebug.Action.Record"; +constexpr char A_REVERSE_DEBUG_REPLAY[] = "ReverseDebug.Action.Replay"; + DWIDGET_USE_NAMESPACE using namespace dpfservice; using namespace ReverseDebugger::Internal; @@ -29,24 +33,20 @@ bool ReverseDebugPlugin::start() abort(); } - auto actionInit = [&](QAction *action, QString actionID, QKeySequence key, QString iconFileName){ - action->setIcon(QIcon::fromTheme(iconFileName)); - AbstractAction *actionImpl = new AbstractAction(action, this); - actionImpl->setShortCutInfo(actionID, action->text(), key); + auto mTools = ActionManager::instance()->actionContainer(M_TOOLS); + auto mReverseDbg = ActionManager::instance()->createContainer(M_TOOLS_REVERSEDEBUG); + mReverseDbg->menu()->setTitle(tr("Reverse debug")); + mTools->addMenu(mReverseDbg); - windowService->addAction(dpfservice::MWM_TOOLS, actionImpl); + auto actionInit = [&](QAction *action, QString actionID) { + auto cmd = ActionManager::instance()->registerAction(action, actionID); + mReverseDbg->addAction(cmd); }; - auto reverseDbgAction = new QAction(tr("Reverse debug"), this); - DMenu *menu = new DMenu(); - reverseDbgAction->setMenu(menu); - actionInit(reverseDbgAction, "Tool.Reverse", {}, ""); - - auto recoredAction = new QAction(tr("Record"), this); - auto replayAction = new QAction(tr("Replay"), this); - - menu->addAction(recoredAction); - menu->addAction(replayAction); + auto recoredAction = new QAction(tr("Record"), mReverseDbg); + actionInit(recoredAction, A_REVERSE_DEBUG_RECORD); + auto replayAction = new QAction(tr("Replay"), mReverseDbg); + actionInit(replayAction, A_REVERSE_DEBUG_REPLAY); reverseDebug = new ReverseDebuggerMgr(this); connect(recoredAction, &QAction::triggered, reverseDebug, &ReverseDebuggerMgr::recored); diff --git a/src/plugins/template/templatemanager.cpp b/src/plugins/template/templatemanager.cpp index dad681c11..f357c3cce 100644 --- a/src/plugins/template/templatemanager.cpp +++ b/src/plugins/template/templatemanager.cpp @@ -50,12 +50,12 @@ void TemplateManager::addMenu() if (!windowService) return; + auto mFile = ActionManager::instance()->actionContainer(M_FILE); auto actionInit = [&](QAction *action, QString actionID, QKeySequence key, QString iconFileName){ action->setIcon(QIcon::fromTheme(iconFileName)); - AbstractAction *actionImpl = new AbstractAction(action, this); - actionImpl->setShortCutInfo(actionID, action->text(), key); - - windowService->addAction(dpfservice::MWMFA_NEW_FILE_OR_PROJECT, actionImpl); + auto cmd = ActionManager::instance()->registerAction(action, actionID); + cmd->setDefaultKeySequence(key); + mFile->addAction(cmd, G_FILE_NEW); }; d->newAction.reset(new QAction(MWMFA_NEW_FILE_OR_PROJECT, this)); diff --git a/src/plugins/valgrind/mainframe/valgrindrunner.cpp b/src/plugins/valgrind/mainframe/valgrindrunner.cpp index 7ee9f737b..c29b60074 100644 --- a/src/plugins/valgrind/mainframe/valgrindrunner.cpp +++ b/src/plugins/valgrind/mainframe/valgrindrunner.cpp @@ -43,23 +43,15 @@ ValgrindRunner::ValgrindRunner(QObject *parent) void ValgrindRunner::initialize() { - auto &ctx = dpfInstance.serviceContext(); - auto windowService = ctx.service(WindowService::name()); - if (!windowService) - return; + auto mTools = ActionManager::instance()->actionContainer(M_TOOLS); d->memcheckAction.reset(new QAction(MWMTA_VALGRIND_MEMCHECK, this)); - auto memcheckActionImpl = new AbstractAction(d->memcheckAction.get(), this); - memcheckActionImpl->setShortCutInfo("Analyze.ValgrindMemcheck", - d->memcheckAction->text()); - windowService->addAction(MWM_TOOLS, memcheckActionImpl); + auto cmd = ActionManager::instance()->registerAction(d->memcheckAction.get(), "Analyze.ValgrindMemcheck"); + mTools->addAction(cmd); d->helgrindAction.reset(new QAction(MWMTA_VALGRIND_HELGRIND, this)); - auto helgrindActionImpl = new AbstractAction(d->helgrindAction.get(), this); - helgrindActionImpl->setShortCutInfo("Analyze.ValgrindHelgrind", - d->helgrindAction->text()); - - windowService->addAction(MWM_TOOLS, helgrindActionImpl); + cmd = ActionManager::instance()->registerAction(d->helgrindAction.get(), "Analyze.ValgrindHelgrind"); + mTools->addAction(cmd); QObject::connect(d->memcheckAction.get(), &QAction::triggered, this, [=]() { QtConcurrent::run([=]() { diff --git a/src/services/window/windowservice.h b/src/services/window/windowservice.h index 9e13737c6..55da875c6 100644 --- a/src/services/window/windowservice.h +++ b/src/services/window/windowservice.h @@ -19,6 +19,7 @@ class Core; class AbstractAction; +class Command; class AbstractMenu; class AbstractWidget; class AbstractInstaller; @@ -146,20 +147,6 @@ class WindowService final : public dpf::PluginService, dpf::AutoServiceRegister< */ DPF_INTERFACE(void, switchContextWidget, const QString &title); - DPF_INTERFACE(void, addChildMenu, AbstractMenu *menu); - - /*! - * \brief insertAction 添加Action到其他由框架发布的可扩展menu - * \param menuName 框架扩展menu发布名称 - * \param beforActionName 之后的Action名称 - * \param action 实例对象 - */ - DPF_INTERFACE(void, insertAction, const QString &menuName, const QString &beforActionName, AbstractAction *action); - - DPF_INTERFACE(void, addAction, const QString &menuName, AbstractAction *action); - - DPF_INTERFACE(void, removeActions, const QString &menuName); - /*! * \brief addWidgetToTopTool Adding widget to a toptoolbar * widgets belongs to a group, you can show toptoolbar by group in swtichWidget event. @@ -171,10 +158,10 @@ class WindowService final : public dpf::PluginService, dpf::AutoServiceRegister< */ DPF_INTERFACE(void, addWidgetToTopTool, AbstractWidget *abstractWidget, bool addSeparator, bool addToLeft, quint8 priority); - DPF_INTERFACE(void, addTopToolItem, AbstractAction *action, bool addSeparator, quint8 priority); - DPF_INTERFACE(void, addTopToolItemToRight, AbstractAction *action, bool addSeparator, quint8 priority); - DPF_INTERFACE(void, removeTopToolItem, AbstractAction *action); - DPF_INTERFACE(void, setTopToolItemVisible, AbstractAction *action, bool visible); + DPF_INTERFACE(DTK_WIDGET_NAMESPACE::DToolButton *, addTopToolItem, Command *action, bool addSeparator, quint8 priority); + DPF_INTERFACE(void, addTopToolItemToRight, Command *action, bool addSeparator, quint8 priority); + DPF_INTERFACE(void, removeTopToolItem, Command *action); + DPF_INTERFACE(void, setTopToolItemVisible, Command *action, bool visible); DPF_INTERFACE(void, showTopToolBar); DPF_INTERFACE(void, hideTopToolBar);