File indexing completed on 2024-07-21 13:06:22

0001 /*
0002    SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "hotkeys_context_menu.h"
0008 #include "hotkeys_export_widget.h"
0009 #include "hotkeys_tree_view.h"
0010 
0011 #include "hotkeys_model.h"
0012 
0013 #include "action_data/action_data_group.h"
0014 #include "action_data/simple_action_data.h"
0015 
0016 #include <QDebug>
0017 
0018 #include <QContextMenuEvent>
0019 #include <QFileDialog>
0020 #include <QSignalMapper>
0021 
0022 #include <KConfig>
0023 
0024 HotkeysTreeViewContextMenu::HotkeysTreeViewContextMenu(const QModelIndex &index, HotkeysTreeView *parent)
0025     : QMenu(parent)
0026     , _index(index)
0027     , _view(parent)
0028 {
0029     setTitle(i18n("Test"));
0030 
0031     connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow()));
0032 }
0033 
0034 HotkeysTreeViewContextMenu::HotkeysTreeViewContextMenu(HotkeysTreeView *parent)
0035     : QMenu(parent)
0036     , _index()
0037     , _view(parent)
0038 {
0039     setTitle(i18n("Test"));
0040 
0041     connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShowForCurrent()));
0042 }
0043 
0044 HotkeysTreeViewContextMenu::~HotkeysTreeViewContextMenu()
0045 {
0046 }
0047 
0048 KHotKeys::Action *HotkeysTreeViewContextMenu::createActionFromType(int actionType, KHotKeys::SimpleActionData *data) const
0049 {
0050     KHotKeys::Action *action = nullptr;
0051     switch (actionType) {
0052     case KHotKeys::Action::CommandUrlActionType:
0053         action = new KHotKeys::CommandUrlAction(data);
0054         break;
0055 
0056     case KHotKeys::Action::DBusActionType:
0057         action = new KHotKeys::DBusAction(data);
0058         break;
0059 
0060     case KHotKeys::Action::KeyboardInputActionType:
0061         action = new KHotKeys::KeyboardInputAction(data);
0062         break;
0063 
0064     case KHotKeys::Action::MenuEntryActionType:
0065         action = new KHotKeys::MenuEntryAction(data);
0066         break;
0067 
0068     default:
0069         Q_ASSERT(false);
0070         return nullptr;
0071     }
0072 
0073     data->set_action(action);
0074     return action;
0075 }
0076 
0077 void HotkeysTreeViewContextMenu::slotAboutToShowForCurrent()
0078 {
0079     _index = _view->currentIndex();
0080 
0081     slotAboutToShow();
0082 }
0083 
0084 void HotkeysTreeViewContextMenu::slotAboutToShow()
0085 {
0086     clear();
0087 
0088     if (_index.isValid()) {
0089         KHotKeys::ActionDataBase *element = _view->model()->indexToActionDataBase(_index);
0090         KHotKeys::ActionDataGroup *group = _view->model()->indexToActionDataGroup(_index);
0091         bool isGroup = group; // Is the current element a group
0092         if (!isGroup) {
0093             group = element->parent();
0094         }
0095 
0096         // Create the create actions
0097         createTriggerMenus(group->allowedTriggerTypes(), group->allowedActionTypes());
0098 
0099         // It is not allowed to create a subgroup for a system group.
0100         if (!group->is_system_group()) {
0101             addAction(i18n("New Group"), this, SLOT(newGroupAction()));
0102         }
0103 
0104         // It is not allowed to delete a system group
0105         if (!(isGroup && group->is_system_group())) {
0106             // Item related actions
0107             addAction(i18n("Delete"), this, SLOT(deleteAction()));
0108         }
0109     } else {
0110         createTriggerMenus(KHotKeys::Trigger::AllTypes, KHotKeys::Action::AllTypes);
0111         addAction(i18n("New Group"), this, SLOT(newGroupAction()));
0112     }
0113 
0114     addSeparator();
0115     addAction(i18n("Export Group..."), this, SLOT(exportAction()));
0116     addAction(i18n("Import..."), this, SLOT(importAction()));
0117 }
0118 
0119 void HotkeysTreeViewContextMenu::createTriggerMenus(KHotKeys::Trigger::TriggerTypes triggerTypes, KHotKeys::Action::ActionTypes actionTypes)
0120 {
0121     QMenu *newMenu = new QMenu(i18nc("@title:menu create various trigger types", "New"));
0122 
0123     if (triggerTypes & KHotKeys::Trigger::ShortcutTriggerType) {
0124         QSignalMapper *mapper = new QSignalMapper(this);
0125 
0126         QMenu *menu = new QMenu(i18n("Global Shortcut"));
0127         populateTriggerMenu(menu, mapper, actionTypes);
0128         newMenu->addMenu(menu);
0129 
0130         connect(mapper, SIGNAL(mapped(int)), this, SLOT(newGlobalShortcutActionAction(int)));
0131     }
0132 
0133     if (triggerTypes & KHotKeys::Trigger::WindowTriggerType) {
0134         QSignalMapper *mapper = new QSignalMapper(this);
0135 
0136         QMenu *menu = new QMenu(i18n("Window Action"));
0137         populateTriggerMenu(menu, mapper, actionTypes);
0138         newMenu->addMenu(menu);
0139 
0140         connect(mapper, SIGNAL(mapped(int)), this, SLOT(newWindowTriggerActionAction(int)));
0141     }
0142 
0143     if (triggerTypes & KHotKeys::Trigger::GestureTriggerType) {
0144         QSignalMapper *mapper = new QSignalMapper(this);
0145 
0146         QMenu *menu = new QMenu(i18n("Mouse Gesture Action"));
0147         populateTriggerMenu(menu, mapper, actionTypes);
0148         newMenu->addMenu(menu);
0149 
0150         connect(mapper, SIGNAL(mapped(int)), this, SLOT(newMouseGestureTriggerActionAction(int)));
0151     }
0152 
0153     addMenu(newMenu);
0154 }
0155 
0156 void HotkeysTreeViewContextMenu::importAction()
0157 {
0158     QUrl url = QFileDialog::getOpenFileUrl(this, QString(), QUrl(), QStringLiteral("*.khotkeys"));
0159     if (!url.isEmpty()) {
0160         KConfig config(url.path(QUrl::FullyDecoded), KConfig::SimpleConfig);
0161         _view->model()->importInputActions(_index, config);
0162     }
0163 }
0164 
0165 void HotkeysTreeViewContextMenu::exportAction()
0166 {
0167     KHotkeysExportDialog *widget = new KHotkeysExportDialog(this);
0168 
0169     KHotKeys::ActionDataGroup *group = _view->model()->indexToActionDataGroup(_index);
0170     if (!group)
0171         group = _view->model()->indexToActionDataBase(_index)->parent();
0172 
0173     widget->setImportId(group->importId());
0174     widget->setAllowMerging(group->allowMerging());
0175 
0176     if (widget->exec() == QDialog::Accepted) {
0177         KHotKeys::ActionState state;
0178         switch (widget->state()) {
0179         case 0:
0180             state = KHotKeys::Retain;
0181             break;
0182 
0183         case 1:
0184             state = KHotKeys::Enabled;
0185             break;
0186 
0187         case 2:
0188             state = KHotKeys::Disabled;
0189             break;
0190 
0191         default:
0192             // Unknown value fallen to our ui file. Use disabled as a
0193             // default.
0194             Q_ASSERT(false);
0195             state = KHotKeys::Disabled;
0196             break;
0197         }
0198 
0199         QString id = widget->importId();
0200         QUrl url = widget->url();
0201         bool allowMerging = widget->allowMerging();
0202         if (!url.isEmpty()) {
0203             KConfig config(url.path(), KConfig::SimpleConfig);
0204             _view->model()->exportInputActions(_index, config, id, state, allowMerging);
0205         }
0206     }
0207     delete widget;
0208 }
0209 
0210 void HotkeysTreeViewContextMenu::populateTriggerMenu(QMenu *menu, QSignalMapper *mapper, KHotKeys::Action::ActionTypes types)
0211 {
0212     if (types & KHotKeys::Action::CommandUrlActionType) {
0213         mapper->setMapping(menu->addAction(i18n("Command/URL"), mapper, SLOT(map())), KHotKeys::Action::CommandUrlActionType);
0214     }
0215 
0216     if (types & KHotKeys::Action::DBusActionType) {
0217         mapper->setMapping(menu->addAction(i18n("D-Bus Command"), mapper, SLOT(map())), KHotKeys::Action::DBusActionType);
0218     }
0219 
0220     if (types & KHotKeys::Action::MenuEntryActionType) {
0221         mapper->setMapping(menu->addAction(i18n("K-Menu Entry"), mapper, SLOT(map())), KHotKeys::Action::MenuEntryActionType);
0222     }
0223 
0224     if (types & KHotKeys::Action::KeyboardInputActionType) {
0225         mapper->setMapping(menu->addAction(i18n("Send Keyboard Input"), mapper, SLOT(map())), KHotKeys::Action::KeyboardInputActionType);
0226     }
0227 }
0228 
0229 void HotkeysTreeViewContextMenu::newGlobalShortcutActionAction(int actionType)
0230 {
0231     QModelIndex parent; // == root element
0232     if (!_index.isValid() || _view->model()->data(_index.sibling(_index.row(), KHotkeysModel::IsGroupColumn)).toBool()) {
0233         // if the index is invalid (root index) or represents an group use it.
0234         parent = _index;
0235     } else {
0236         // It is an action. Take the parent.
0237         parent = _index.parent();
0238     }
0239 
0240     KHotKeys::SimpleActionData *data = new KHotKeys::SimpleActionData(nullptr, i18n("New Action"), i18n("Comment"));
0241     data->set_trigger(new KHotKeys::ShortcutTrigger(data, QKeySequence()));
0242     data->enable();
0243 
0244     createActionFromType(actionType, data);
0245 
0246     QModelIndex newAct = _view->model()->insertActionData(data, parent);
0247     _view->setCurrentIndex(newAct);
0248     _view->edit(newAct);
0249     _view->resizeColumnToContents(KHotkeysModel::NameColumn);
0250 }
0251 
0252 void HotkeysTreeViewContextMenu::newMouseGestureTriggerActionAction(int actionType)
0253 {
0254     QModelIndex parent; // == root element
0255     if (!_index.isValid() || _view->model()->data(_index.sibling(_index.row(), KHotkeysModel::IsGroupColumn)).toBool()) {
0256         // if the index is invalid (root index) or represents an group use it.
0257         parent = _index;
0258     } else {
0259         // It is an action. Take the parent.
0260         parent = _index.parent();
0261     }
0262 
0263     KHotKeys::SimpleActionData *data = new KHotKeys::SimpleActionData(nullptr, i18n("New Action"), i18n("Comment"));
0264     data->set_trigger(new KHotKeys::GestureTrigger(data));
0265     data->enable();
0266 
0267     createActionFromType(actionType, data);
0268 
0269     QModelIndex newAct = _view->model()->insertActionData(data, parent);
0270     _view->setCurrentIndex(newAct);
0271     _view->edit(newAct);
0272     _view->resizeColumnToContents(KHotkeysModel::NameColumn);
0273 }
0274 
0275 void HotkeysTreeViewContextMenu::newWindowTriggerActionAction(int actionType)
0276 {
0277     QModelIndex parent; // == root element
0278     if (!_index.isValid() || _view->model()->data(_index.sibling(_index.row(), KHotkeysModel::IsGroupColumn)).toBool()) {
0279         // if the index is invalid (root index) or represents an group use it.
0280         parent = _index;
0281     } else {
0282         // It is an action. Take the parent.
0283         parent = _index.parent();
0284     }
0285 
0286     KHotKeys::SimpleActionData *data = new KHotKeys::SimpleActionData(nullptr, i18n("New Action"), i18n("Comment"));
0287     data->set_trigger(new KHotKeys::WindowTrigger(data));
0288     data->enable();
0289 
0290     createActionFromType(actionType, data);
0291 
0292     QModelIndex newAct = _view->model()->insertActionData(data, parent);
0293     _view->setCurrentIndex(newAct);
0294     _view->edit(newAct);
0295     _view->resizeColumnToContents(KHotkeysModel::NameColumn);
0296 }
0297 
0298 void HotkeysTreeViewContextMenu::newGroupAction()
0299 {
0300     QModelIndex parent; // == root element
0301     if (!_index.isValid() || _view->model()->data(_index.sibling(_index.row(), KHotkeysModel::IsGroupColumn)).toBool()) {
0302         // if the index is invalid (root index) or represents an group use it.
0303         parent = _index;
0304     } else {
0305         // It is an action. Take the parent.
0306         parent = _index.parent();
0307     }
0308 
0309     QModelIndex newGroup = _view->model()->addGroup(parent);
0310     _view->setCurrentIndex(newGroup);
0311     _view->edit(newGroup);
0312     _view->resizeColumnToContents(KHotkeysModel::NameColumn);
0313 }
0314 
0315 void HotkeysTreeViewContextMenu::deleteAction()
0316 {
0317     if (!_index.isValid()) {
0318         Q_ASSERT(_index.isValid());
0319         return;
0320     }
0321 
0322     bool deletionSuccess;
0323     deletionSuccess = _view->model()->removeRow(_index.row(), _index.parent());
0324     Q_ASSERT(deletionSuccess == true);
0325 
0326     _view->setCurrentIndex(QModelIndex());
0327 }
0328 
0329 #include "moc_hotkeys_context_menu.cpp"