File indexing completed on 2024-06-23 05:20:47

0001 /*
0002    Copyright (C) 2012, 2013 by Glad Deschrijver <glad.deschrijver@gmail.com>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public License as
0006    published by the Free Software Foundation; either version 2 of
0007    the License or (at your option) version 3 or any later version
0008    accepted by the membership of KDE e.V. (or its successor approved
0009    by the membership of KDE e.V.), which shall act as a proxy
0010    defined in Section 14 of version 3 of the license.
0011 
0012    This program is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015    GNU General Public License for more details.
0016 
0017    You should have received a copy of the GNU General Public License
0018    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "ShortcutHandler.h"
0022 
0023 #ifndef QT_NO_SHORTCUT
0024 
0025 #include <QAction>
0026 #include <QSettings>
0027 
0028 #include "ShortcutConfigDialog.h"
0029 #include "ShortcutConfigWidget.h"
0030 #include "Common/SettingsCategoryGuard.h"
0031 #include "UiUtils/IconLoader.h"
0032 
0033 namespace Gui
0034 {
0035 
0036 ShortcutHandler *ShortcutHandler::self = 0;
0037 
0038 ShortcutHandler::ShortcutHandler(QWidget *parent)
0039     : QObject(parent)
0040     , m_settings(0)
0041     , m_shortcutConfigAction(0)
0042     , m_shortcutConfigDialog(0)
0043     , m_shortcutConfigWidget(0)
0044 {
0045     Q_ASSERT_X(!self, "ShortcutHandler", "there should be only one shortcut handler object");
0046     ShortcutHandler::self = this;
0047     m_exclusivityGroups.append(QStringList() << tr("Main Window"));
0048 }
0049 
0050 ShortcutHandler::~ShortcutHandler()
0051 {
0052     if (m_shortcutConfigAction)
0053         delete m_shortcutConfigAction;
0054     if (m_shortcutConfigDialog)
0055         delete m_shortcutConfigDialog;
0056     if (m_shortcutConfigWidget)
0057         delete m_shortcutConfigWidget;
0058     m_actionDescriptions.clear();
0059 }
0060 
0061 void ShortcutHandler::setSettingsObject(QSettings *settings)
0062 {
0063     m_settings = settings;
0064 }
0065 
0066 void ShortcutHandler::defineAction(const QString &actionName, const QString &iconName, const QString &text, const QString &defaultShortcut, const QString &parentId)
0067 {
0068 //  m_actionDescriptions[actionName] = {iconName, text, defaultShortcut, parentId}; // C++11 only, constructor in ActionDescription is then not needed
0069     m_actionDescriptions[actionName] = ActionDescription(iconName, text, defaultShortcut, parentId);
0070 }
0071 
0072 void ShortcutHandler::defineAction(const QString &actionName, const QString &iconName, const QString &text, const QKeySequence::StandardKey &key, const QString &parentId)
0073 {
0074     m_actionDescriptions[actionName] = ActionDescription(iconName, text, QKeySequence(key).toString(QKeySequence::PortableText), parentId);
0075 }
0076 
0077 QAction *ShortcutHandler::createAction(const QString &actionName, QWidget *parent)
0078 {
0079     return createAction(actionName, 0, "", parent);
0080 }
0081 
0082 QAction *ShortcutHandler::createAction(const QString &actionName, QObject *receiver, const char *member, QWidget *parent)
0083 {
0084     if (!m_actionDescriptions.contains(actionName))
0085         return 0;
0086 
0087     ActionDescription actionDescription = m_actionDescriptions[actionName];
0088     QAction *action = new QAction(parent);
0089     action->setObjectName(actionName);
0090     if (!actionDescription.iconName.isEmpty()) {
0091         action->setIcon(UiUtils::loadIcon(actionDescription.iconName));
0092     }
0093     action->setText(actionDescription.text);
0094     action->setShortcut(actionDescription.shortcut);
0095     if (receiver)
0096         connect(action, SIGNAL(triggered()), receiver, member); // new-signal-slot: this is a candidate for an overload to support type-safety
0097     m_actionDescriptions[actionName].action = action;
0098     return action;
0099 }
0100 
0101 void ShortcutHandler::addExclusivityGroup(const QStringList &groups)
0102 {
0103     if (groups.contains(tr("Main Window"))) {
0104         m_exclusivityGroups.takeFirst();
0105         m_exclusivityGroups.prepend(groups);
0106     } else {
0107         m_exclusivityGroups.append(groups);
0108     }
0109 
0110     if (m_shortcutConfigDialog)
0111         m_shortcutConfigDialog->setExclusivityGroups(m_exclusivityGroups);
0112     if (m_shortcutConfigWidget)
0113         m_shortcutConfigWidget->setExclusivityGroups(m_exclusivityGroups);
0114 }
0115 
0116 QSettings *ShortcutHandler::settingsObject()
0117 {
0118     return m_settings;
0119 }
0120 
0121 QAction *ShortcutHandler::action(const QString &actionName)
0122 {
0123     if (!m_actionDescriptions.contains(actionName))
0124         return 0;
0125     return m_actionDescriptions[actionName].action;
0126 }
0127 
0128 /***************************************************************************/
0129 
0130 void ShortcutHandler::changeShortcuts(const QHash<QString, ActionDescription> &actionDescriptions)
0131 {
0132     for (QHash<QString, ActionDescription>::const_iterator it = actionDescriptions.constBegin(); it != actionDescriptions.constEnd(); ++it) {
0133         ActionDescription actionDescription = it.value();
0134         QAction *action = m_actionDescriptions[it.key()].action;
0135         if (action)
0136             action->setShortcut(QKeySequence(actionDescription.shortcut));
0137     }
0138 }
0139 
0140 QAction *ShortcutHandler::shortcutConfigAction()
0141 {
0142     Q_ASSERT_X(!m_shortcutConfigWidget, "ShortcutHandler", "a shortcut configuration dialog and a shortcut configuration widget cannot exist at the same time in one application");
0143     if (!m_shortcutConfigAction) {
0144         m_shortcutConfigAction = new QAction(UiUtils::loadIcon(QStringLiteral("configure-shortcuts")), tr("Configure S&hortcuts..."), qobject_cast<QWidget*>(parent()));
0145         connect(m_shortcutConfigAction.data(), &QAction::triggered, this, &ShortcutHandler::openShortcutConfigDialog);
0146     }
0147     return m_shortcutConfigAction;
0148 }
0149 
0150 void ShortcutHandler::openShortcutConfigDialog()
0151 {
0152     if (!m_shortcutConfigDialog) {
0153         m_shortcutConfigDialog = new ShortcutConfigDialog(qobject_cast<QWidget*>(parent()));
0154         m_shortcutConfigDialog->setActionDescriptions(m_actionDescriptions);
0155         m_shortcutConfigDialog->setExclusivityGroups(m_exclusivityGroups);
0156         connect(m_shortcutConfigDialog.data(), &ShortcutConfigDialog::shortcutsChanged, this, &ShortcutHandler::changeShortcuts);
0157     }
0158     m_shortcutConfigDialog->exec();
0159 }
0160 
0161 /***************************************************************************/
0162 
0163 ShortcutConfigWidget *ShortcutHandler::configWidget()
0164 {
0165     Q_ASSERT_X(!m_shortcutConfigAction, "ShortcutHandler", "a shortcut configuration dialog and a shortcut configuration widget cannot exist at the same time in one application");
0166     if (!m_shortcutConfigWidget) {
0167         m_shortcutConfigWidget = new ShortcutConfigWidget(qobject_cast<QWidget*>(parent()));
0168         m_shortcutConfigWidget->setActionDescriptions(m_actionDescriptions);
0169         m_shortcutConfigWidget->setExclusivityGroups(m_exclusivityGroups);
0170         connect(m_shortcutConfigWidget.data(), &ShortcutConfigWidget::shortcutsChanged, this, &ShortcutHandler::changeShortcuts);
0171     }
0172     return m_shortcutConfigWidget;
0173 }
0174 
0175 void ShortcutHandler::accept()
0176 {
0177     m_shortcutConfigWidget->accept();
0178 }
0179 
0180 void ShortcutHandler::reject()
0181 {
0182     m_shortcutConfigWidget->reject();
0183 }
0184 
0185 /***************************************************************************/
0186 
0187 void ShortcutHandler::readSettings()
0188 {
0189     Q_ASSERT_X(m_settings, "ShortcutHandler", "a settings object should be set using setSettingsObject() prior to using readSettings()");
0190     Common::SettingsCategoryGuard guard(m_settings, QStringLiteral("ShortcutHandler"));
0191     const int size = m_settings->beginReadArray(QStringLiteral("Shortcuts"));
0192     for (int i = 0; i < size; ++i) {
0193         m_settings->setArrayIndex(i);
0194         const QString actionName = m_settings->value(QStringLiteral("Action")).toString();
0195         m_actionDescriptions[actionName].shortcut = m_settings->value(QStringLiteral("Shortcut")).toString();
0196 
0197         QAction *action = m_actionDescriptions[actionName].action;
0198         if (action)
0199             action->setShortcut(QKeySequence(m_settings->value(QStringLiteral("Shortcut")).toString()));
0200     }
0201     m_settings->endArray();
0202 }
0203 
0204 } // namespace Gui
0205 
0206 #endif // QT_NO_SHORTCUT