File indexing completed on 2024-04-28 16:44:53

0001 /*
0002    SPDX-FileCopyrightText: 1999-2001 Lubos Lunak <l.lunak@kde.org>
0003    SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz>
0004 
0005    SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "action_data/action_data.h"
0009 #include "triggers/triggers.h"
0010 #include "windows_handler.h"
0011 
0012 #include <KConfigGroup>
0013 #include <KGlobalAccel>
0014 #include <QDebug>
0015 
0016 #include <QAction>
0017 
0018 #include "shortcuts_handler.h"
0019 
0020 namespace KHotKeys
0021 {
0022 ShortcutTriggerVisitor::~ShortcutTriggerVisitor()
0023 {
0024 }
0025 
0026 ShortcutTrigger::ShortcutTrigger(ActionData *data_P, const QKeySequence &shortcut, const QUuid &uuid)
0027     : Trigger(data_P)
0028     , _uuid(uuid)
0029     , _active(false)
0030     , _shortcut(shortcut)
0031 {
0032 }
0033 
0034 ShortcutTrigger::~ShortcutTrigger()
0035 {
0036     keyboard_handler->removeAction(_uuid.toString());
0037 }
0038 
0039 void ShortcutTrigger::accept(TriggerVisitor &visitor)
0040 {
0041     if (ShortcutTriggerVisitor *v = dynamic_cast<ShortcutTriggerVisitor *>(&visitor)) {
0042         v->visit(*this);
0043     } else {
0044         qDebug() << "Visitor error";
0045     }
0046 }
0047 
0048 void ShortcutTrigger::aboutToBeErased()
0049 {
0050     disable();
0051 }
0052 
0053 void ShortcutTrigger::activate(bool newState)
0054 {
0055 #ifdef KHOTKEYS_TRACE
0056     qDebug() << "new:" << newState << "old:" << _active;
0057 #endif
0058     // If there is no change in state just return.
0059     if (newState == _active)
0060         return;
0061 
0062     _active = newState;
0063 
0064     if (_active) {
0065         QString name = data ? data->name() : "TODO";
0066 
0067         // FIXME: The following workaround tries to prevent having two actions with
0068         // the same uuid. That happens wile exporting/importing actions. The uuid
0069         // is exported too.
0070         QAction *act = keyboard_handler->addAction(_uuid.toString(), name, _shortcut);
0071         // addAction can change the uuid. That's why we store the uuid from the
0072         // action
0073         _uuid = act->objectName();
0074 
0075         connect(act, SIGNAL(triggered(bool)), this, SLOT(trigger()));
0076     } else {
0077         // Disable the trigger. Delete the action.
0078         QAction *action = keyboard_handler->getAction(_uuid.toString());
0079         if (action) {
0080             // In case the shortcut was changed from the kcm.
0081             auto shortcuts = KGlobalAccel::self()->shortcut(action);
0082             if (!shortcuts.isEmpty()) {
0083                 _shortcut = QKeySequence(shortcuts.first());
0084             } else {
0085                 _shortcut = QKeySequence();
0086             }
0087             keyboard_handler->removeAction(_uuid.toString());
0088         }
0089     }
0090 }
0091 
0092 QString ShortcutTrigger::shortcuts() const
0093 {
0094     const auto shortcuts = shortcut();
0095     QString shortcutString;
0096     for (auto it = shortcuts.constBegin(); it != shortcuts.constEnd(); ++it) {
0097         if (it != shortcuts.constBegin()) {
0098             shortcutString.append(QStringLiteral(";"));
0099         }
0100         shortcutString.append((*it).toString());
0101     }
0102     return shortcutString;
0103 }
0104 
0105 void ShortcutTrigger::cfg_write(KConfigGroup &cfg_P) const
0106 {
0107     base::cfg_write(cfg_P);
0108     cfg_P.writeEntry("Key", shortcuts());
0109     cfg_P.writeEntry("Type", "SHORTCUT"); // overwrites value set in base::cfg_write()
0110     cfg_P.writeEntry("Uuid", _uuid.toString());
0111 }
0112 
0113 ShortcutTrigger *ShortcutTrigger::copy(ActionData *data_P) const
0114 {
0115     return new ShortcutTrigger(data_P ? data_P : data, shortcut().first(), QUuid::createUuid());
0116 }
0117 
0118 const QString ShortcutTrigger::description() const
0119 {
0120     return i18n("Shortcut trigger: ") + shortcuts();
0121 }
0122 
0123 void ShortcutTrigger::disable()
0124 {
0125     activate(false);
0126 
0127     // Unregister the shortcut with kglobalaccel
0128     QAction *action = keyboard_handler->getAction(_uuid.toString());
0129     if (action) {
0130         // In case the shortcut was changed from the kcm.
0131         auto shortcuts = KGlobalAccel::self()->shortcut(action);
0132         if (!shortcuts.isEmpty()) {
0133             _shortcut = QKeySequence(shortcuts.first());
0134         } else {
0135             _shortcut = QKeySequence();
0136         }
0137 
0138         // Unregister the global shortcut.
0139         KGlobalAccel::self()->removeAllShortcuts(action);
0140         keyboard_handler->removeAction(_uuid.toString());
0141     }
0142 }
0143 
0144 void ShortcutTrigger::enable()
0145 {
0146     // To enable the shortcut we have to just register it once with
0147     // kglobalaccel and deactivate it immediately
0148     activate(true);
0149     activate(false);
0150 }
0151 
0152 void ShortcutTrigger::set_key_sequence(const QKeySequence &seq)
0153 {
0154     // Get the action from the keyboard handler
0155     QAction *action = keyboard_handler->getAction(_uuid.toString());
0156     if (!action) {
0157         _shortcut = seq;
0158     } else {
0159         KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>() << seq, KGlobalAccel::KGlobalAccel::NoAutoloading);
0160     }
0161 }
0162 
0163 QList<QKeySequence> ShortcutTrigger::shortcut() const
0164 {
0165     // Get the action from the keyboard handler
0166     QAction *action = keyboard_handler->getAction(_uuid.toString());
0167     if (!action) {
0168         // Not active!
0169         return {_shortcut};
0170     }
0171 
0172     return KGlobalAccel::self()->shortcut(action);
0173 }
0174 
0175 QString ShortcutTrigger::primaryShortcut() const
0176 {
0177     const auto shortcuts = shortcut();
0178     if (!shortcuts.isEmpty()) {
0179         return shortcuts.first().toString();
0180     } else {
0181         return QString();
0182     }
0183 }
0184 
0185 void ShortcutTrigger::trigger()
0186 {
0187     if (khotkeys_active()) {
0188         windows_handler->set_action_window(0); // use active window
0189         data->execute();
0190     }
0191 }
0192 
0193 } // namespace KHotKeys