diff options
Diffstat (limited to 'src/plugins/coreplugin/actionmanager/actionmanager.cpp')
-rw-r--r-- | src/plugins/coreplugin/actionmanager/actionmanager.cpp | 236 |
1 files changed, 128 insertions, 108 deletions
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp index 449a0040bc..391cc077f4 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp +++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp @@ -29,7 +29,8 @@ #include "command_p.h" #include <coreplugin/icore.h> -#include <coreplugin/id.h> + +#include <utils/algorithm.h> #include <utils/fadingindicator.h> #include <utils/qtcassert.h> @@ -46,98 +47,72 @@ namespace { } static const char kKeyboardSettingsKey[] = "KeyboardShortcuts"; +static const char kKeyboardSettingsKeyV2[] = "KeyboardShortcutsV2"; using namespace Core; using namespace Core::Internal; +using namespace Utils; /*! \class Core::ActionManager + \inheaderfile coreplugin/actionmanager/actionmanager.h \ingroup mainclasses \inmodule QtCreator \brief The ActionManager class is responsible for registration of menus and menu items and keyboard shortcuts. - The ActionManager is the central bookkeeper of actions and their shortcuts and layout. - It is a singleton containing mostly static functions. If you need access to the instance, - e.g. for connecting to signals, call its ActionManager::instance() function. - - The main reasons for the need of this class is to provide a central place where the users - can specify all their keyboard shortcuts, and to provide a solution for actions that should - behave differently in different contexts (like the copy/replace/undo/redo actions). - - \section1 Contexts - - All actions that are registered with the same Id (but different context lists) - are considered to be overloads of the same command, represented by an instance - of the Core::Command class. - Exactly only one of the registered actions with the same ID is active at any time. - Which action this is, is defined by the context list that the actions were registered - with: - - If the current focus widget was registered via \l{ICore::addContextObject()}, - all the contexts returned by its IContext object are active. In addition all - contexts set via \l{ICore::addAdditionalContext()} are active as well. If one - of the actions was registered for one of these active contexts, it is the one - active action, and receives \c triggered and \c toggled signals. Also the - appearance of the visible action for this ID might be adapted to this - active action (depending on the settings of the corresponding \l{Command} object). - - The action that is visible to the user is the one returned by Command::action(). - If you provide yourself a user visible representation of your action you need - to use Command::action() for this. - When this action is invoked by the user, - the signal is forwarded to the registered action that is valid for the current context. - - \section1 Registering Actions - - To register a globally active action "My Action" - put the following in your plugin's IPlugin::initialize function: + The action manager is the central bookkeeper of actions and their shortcuts + and layout. It is a singleton containing mostly static functions. If you + need access to the instance, for example for connecting to signals, call + its ActionManager::instance() function. + + The action manager makes it possible to provide a central place where the + users can specify all their keyboard shortcuts, and provides a solution for + actions that should behave differently in different contexts (like the + copy/replace/undo/redo actions). + + See \l{The Action Manager and Commands} for an overview of the interaction + between Core::ActionManager, Core::Command, and Core::Context. + + Register a globally active action "My Action" by putting the following in + your plugin's ExtensionSystem::IPlugin::initialize() function. + \code QAction *myAction = new QAction(tr("My Action"), this); - Command *cmd = ActionManager::registerAction(myAction, - "myplugin.myaction", - Context(C_GLOBAL)); + Command *cmd = ActionManager::registerAction(myAction, "myplugin.myaction", Context(C_GLOBAL)); cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+u"))); connect(myAction, &QAction::triggered, this, &MyPlugin::performMyAction); \endcode - So the \c connect is done to your own QAction instance. If you create e.g. - a tool button that should represent the action you add the action - from Command::action() to it: + The \c connect is done to your own QAction instance. If you create for + example a tool button that should represent the action, add the action from + Command::action() to it. + \code QToolButton *myButton = new QToolButton(someParentWidget); myButton->setDefaultAction(cmd->action()); \endcode - Also use the ActionManager to add items to registered - action containers like the applications menu bar or menus in that menu bar. - To do this, you register your action via the - registerAction functions, get the action container for a specific ID (like specified in - the Core::Constants namespace) with a call of - actionContainer(const Id&) and add your command to this container. + Also use the action manager to add items to registered action containers + like the application's menu bar or menus in that menu bar. Register your + action via the Core::ActionManager::registerAction() function, get the + action container for a specific ID (as specified for example in the + Core::Constants namespace) with Core::ActionManager::actionContainer(), and + add your command to this container. + + Building on the example, adding "My Action" to the "Tools" menu would be + done with - Following the example adding "My Action" to the "Tools" menu would be done by \code - ActionManager::actionContainer(M_TOOLS)->addAction(cmd); + ActionManager::actionContainer(Core::Constants::M_TOOLS)->addAction(cmd); \endcode - \section1 Important Guidelines: - \list - \li Always register your actions and shortcuts! - \li Register your actions and shortcuts during your plugin's \l{ExtensionSystem::IPlugin::initialize()} - or \l{ExtensionSystem::IPlugin::extensionsInitialized()} functions, otherwise the shortcuts won't appear - in the keyboard settings dialog from the beginning. - \li When registering an action with \c{cmd=registerAction(action, id, contexts)} be sure to connect - your own action \c{connect(action, SIGNAL...)} but make \c{cmd->action()} visible to the user, i.e. - \c{widget->addAction(cmd->action())}. - \li Use this class to add actions to the applications menus - \endlist - \sa Core::ICore \sa Core::Command \sa Core::ActionContainer \sa Core::IContext + \sa {The Action Manager and Commands} */ /*! @@ -147,7 +122,7 @@ using namespace Core::Internal; */ /*! - \fn void Core::ActionManager::commandAdded(Core::Id id) + \fn void Core::ActionManager::commandAdded(Utils::Id id) Emitted when a command (with the \a id) is added. */ @@ -176,7 +151,7 @@ ActionManager::~ActionManager() } /*! - Returns the pointer to the instance, which is only used for connecting to signals. + Returns the pointer to the instance. Only use for connecting to signals. */ ActionManager *ActionManager::instance() { @@ -184,13 +159,13 @@ ActionManager *ActionManager::instance() } /*! - Creates a new menu with the given \a id. + Creates a new menu action container or returns an existing container with + the specified \a id. The ActionManager owns the returned ActionContainer. + Add your menu to some other menu or a menu bar via the actionContainer() + and ActionContainer::addMenu() functions. - Returns a new ActionContainer that you can use to get the QMenu instance - or to add menu items to the menu. The ActionManager owns - the returned ActionContainer. - Add your menu to some other menu or a menu bar via the - ActionManager::actionContainer and ActionContainer::addMenu functions. + \sa actionContainer() + \sa ActionContainer::addMenu() */ ActionContainer *ActionManager::createMenu(Id id) { @@ -207,11 +182,12 @@ ActionContainer *ActionManager::createMenu(Id id) } /*! - Creates a new menu bar with the given \a id. + Creates a new menu bar action container or returns an existing container + with the specified \a id. The ActionManager owns the returned + ActionContainer. - Returns a new ActionContainer that you can use to get the QMenuBar instance - or to add menus to the menu bar. The ActionManager owns - the returned ActionContainer. + \sa createMenu() + \sa ActionContainer::addMenu() */ ActionContainer *ActionManager::createMenuBar(Id id) { @@ -232,13 +208,17 @@ ActionContainer *ActionManager::createMenuBar(Id id) } /*! - Creates a touch bar with the given \a id. + Creates a new (sub) touch bar action container or returns an existing + container with the specified \a id. The ActionManager owns the returned + ActionContainer. - Returns a new ActionContainer that you can use to add items to a (sub) touch bar. Note that it is only possible to create a single level of sub touch bars. - The sub touch bar will be represented as a button with \a icon and \a text (one can be left - empty), which opens the sub touch bar when touched. - The ActionManager owns the returned ActionContainer. + The sub touch bar will be represented as a button with \a icon and \a text + (either of which can be left empty), which opens the sub touch bar when + touched. + + \sa actionContainer() + \sa ActionContainer::addMenu() */ ActionContainer *ActionManager::createTouchBar(Id id, const QIcon &icon, const QString &text) { @@ -255,15 +235,13 @@ ActionContainer *ActionManager::createTouchBar(Id id, const QIcon &icon, const Q /*! Makes an \a action known to the system under the specified \a id. - Returns a command object that represents the action in the application and is - owned by the ActionManager. You can register several actions with the - same \a id as long as the \a context is different. In this case - a trigger of the actual action is forwarded to the registered QAction - for the currently active context. - If the optional \a context argument is not specified, the global context - will be assumed. - A \a scriptable action can be called from a script without the need for the user - to interact with it. + Returns a Command instance that represents the action in the application + and is owned by the ActionManager. You can register several actions with + the same \a id as long as the \a context is different. In this case + triggering the action is forwarded to the registered QAction for the + currently active context. If the optional \a context argument is not + specified, the global context will be assumed. A \a scriptable action can + be called from a script without the need for the user to interact with it. */ Command *ActionManager::registerAction(QAction *action, Id id, const Context &context, bool scriptable) { @@ -277,10 +255,10 @@ Command *ActionManager::registerAction(QAction *action, Id id, const Context &co } /*! - Returns the Command object that is known to the system - under the given \a id. + Returns the Command instance that has been created with registerAction() + for the specified \a id. - \sa ActionManager::registerAction() + \sa registerAction() */ Command *ActionManager::command(Id id) { @@ -295,8 +273,15 @@ Command *ActionManager::command(Id id) } /*! - Returns the IActionContainter object that is know to the system - under the given \a id. + Returns the ActionContainter instance that has been created with + createMenu(), createMenuBar(), createTouchBar() for the specified \a id. + + Use the ID \c{Core::Constants::MENU_BAR} to retrieve the main menu bar. + + Use the IDs \c{Core::Constants::M_FILE}, \c{Core::Constants::M_EDIT}, and + similar constants to retrieve the various default menus. + + Use the ID \c{Core::Constants::TOUCH_BAR} to retrieve the main touch bar. \sa ActionManager::createMenu() \sa ActionManager::createMenuBar() @@ -314,7 +299,7 @@ ActionContainer *ActionManager::actionContainer(Id id) } /*! - Returns all commands that have been registered. + Returns all registered commands. */ QList<Command *> ActionManager::commands() { @@ -355,9 +340,7 @@ void ActionManager::unregisterAction(QAction *action, Id id) } /*! - Handles the display of the used shortcuts in the presentation mode. The presentation mode is - \a enabled when starting \QC with the command line argument \c{-presentationMode}. In the - presentation mode, \QC displays any pressed shortcut in a grey box. + \internal */ void ActionManager::setPresentationModeEnabled(bool enabled) { @@ -380,7 +363,9 @@ void ActionManager::setPresentationModeEnabled(bool enabled) /*! Returns whether presentation mode is enabled. - \sa setPresentationModeEnabled + The presentation mode is enabled when starting \QC with the command line + argument \c{-presentationMode}. In presentation mode, \QC displays any + pressed shortcut in an overlay box. */ bool ActionManager::isPresentationModeEnabled() { @@ -388,7 +373,8 @@ bool ActionManager::isPresentationModeEnabled() } /*! - \internal + Decorates the specified \a text with a numbered accelerator key \a number, + in the style of the \uicontrol {Recent Files} menu. */ QString ActionManager::withNumberAccelerator(const QString &text, const int number) { @@ -397,11 +383,17 @@ QString ActionManager::withNumberAccelerator(const QString &text, const int numb return QString("&%1 | %2").arg(number).arg(text); } +/*! + \internal +*/ void ActionManager::saveSettings() { d->saveSettings(); } +/*! + \internal +*/ void ActionManager::setContext(const Context &context) { d->setContext(context); @@ -495,22 +487,50 @@ Action *ActionManagerPrivate::overridableAction(Id id) void ActionManagerPrivate::readUserSettings(Id id, Action *cmd) { + // TODO Settings V2 were introduced in Qt Creator 4.13, remove old settings at some point QSettings *settings = ICore::settings(); - settings->beginGroup(QLatin1String(kKeyboardSettingsKey)); - if (settings->contains(id.toString())) - cmd->setKeySequence(QKeySequence(settings->value(id.toString()).toString())); + // transfer from old settings if not done before + const QString group = settings->childGroups().contains(kKeyboardSettingsKeyV2) + ? QString(kKeyboardSettingsKeyV2) + : QString(kKeyboardSettingsKey); + settings->beginGroup(group); + if (settings->contains(id.toString())) { + const QVariant v = settings->value(id.toString()); + if (QMetaType::Type(v.type()) == QMetaType::QStringList) { + cmd->setKeySequences(Utils::transform<QList>(v.toStringList(), [](const QString &s) { + return QKeySequence::fromString(s); + })); + } else { + cmd->setKeySequences({QKeySequence::fromString(v.toString())}); + } + } settings->endGroup(); } void ActionManagerPrivate::saveSettings(Action *cmd) { - const QString settingsKey = QLatin1String(kKeyboardSettingsKey) + QLatin1Char('/') - + cmd->id().toString(); - QKeySequence key = cmd->keySequence(); - if (key != cmd->defaultKeySequence()) - ICore::settings()->setValue(settingsKey, key.toString()); - else + const QString id = cmd->id().toString(); + const QString settingsKey = QLatin1String(kKeyboardSettingsKeyV2) + '/' + id; + const QString compatSettingsKey = QLatin1String(kKeyboardSettingsKey) + '/' + id; + const QList<QKeySequence> keys = cmd->keySequences(); + const QList<QKeySequence> defaultKeys = cmd->defaultKeySequences(); + if (keys != defaultKeys) { + if (keys.isEmpty()) { + ICore::settings()->setValue(settingsKey, QString()); + ICore::settings()->setValue(compatSettingsKey, QString()); + } else if (keys.size() == 1) { + ICore::settings()->setValue(settingsKey, keys.first().toString()); + ICore::settings()->setValue(compatSettingsKey, keys.first().toString()); + } else { + ICore::settings()->setValue(settingsKey, + Utils::transform<QStringList>(keys, + [](const QKeySequence &k) { + return k.toString(); + })); + } + } else { ICore::settings()->remove(settingsKey); + } } void ActionManagerPrivate::saveSettings() |