File indexing completed on 2024-04-14 15:33:22

0001 /**
0002  * SPDX-FileCopyrightText: 1999-2001 Lubos Lunak <l.lunak@kde.org>
0003  * SPDX-FileCopyrightText: 2009 Michael Jansen <kde@michael-jansen.biz>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  **/
0007 
0008 #include "settings_reader_v2.h"
0009 
0010 #include "action_data/action_data_group.h"
0011 #include "action_data/generic_action_data.h"
0012 #include "action_data/menuentry_shortcut_action_data.h"
0013 #include "action_data/simple_action_data.h"
0014 
0015 #include "conditions/conditions_list.h"
0016 
0017 #include "windows_helper/window_selection_list.h"
0018 
0019 #include <KConfig>
0020 #include <KConfigBase>
0021 #include <KConfigGroup>
0022 #include <QDebug>
0023 
0024 SettingsReaderV2::SettingsReaderV2(KHotKeys::Settings *settings, bool loadAll, KHotKeys::ActionState stateStrategy, const QString &importId)
0025     : _settings(settings)
0026     , _loadAll(loadAll)
0027     , _stateStrategy(stateStrategy)
0028     , _importId(importId)
0029 {
0030 #ifdef KHOTKEYS_TRACE
0031     qDebug() << "Created SettingsReader with disableActions(" << _stateStrategy << ")";
0032 #endif
0033 }
0034 
0035 SettingsReaderV2::~SettingsReaderV2()
0036 {
0037 }
0038 
0039 void SettingsReaderV2::read(const KConfigBase &config, KHotKeys::ActionDataGroup *parent)
0040 {
0041     KConfigGroup data(&config, "Data");
0042 
0043     // We have to skip the top level group.
0044     QString configName = data.name();
0045     int cnt = data.readEntry("DataCount", 0);
0046     for (int i = 1; i <= cnt; ++i) {
0047         KConfigGroup childConfig(data.config(), configName + '_' + QString::number(i));
0048         if (_loadAll || KHotKeys::ActionDataBase::cfg_is_enabled(childConfig)) {
0049             KHotKeys::ActionDataBase *elem = readActionData(childConfig, parent);
0050             if (!_importId.isEmpty())
0051                 elem->setImportId(_importId);
0052         }
0053     }
0054 }
0055 
0056 KHotKeys::ActionDataGroup *SettingsReaderV2::readGroup(const KConfigGroup &config, KHotKeys::ActionDataGroup *parent)
0057 {
0058 #ifdef KHOTKEYS_TRACE
0059     qDebug() << "Reading group" << config.readEntry("Name");
0060 #endif
0061     KHotKeys::ActionDataGroup *group = nullptr;
0062 
0063     // Check if it is allowed to merge the group. If yes check for a group
0064     // with the desired name
0065     if (config.readEntry("AllowMerge", false)) {
0066         Q_FOREACH (KHotKeys::ActionDataBase *child, parent->children()) {
0067             if (KHotKeys::ActionDataGroup *existing = dynamic_cast<KHotKeys::ActionDataGroup *>(child)) {
0068                 if (config.readEntry("Name") == existing->name()) {
0069                     group = existing;
0070                     break;
0071                 }
0072             }
0073         }
0074     }
0075 
0076     // Do not allow loading a system group if there is already one.
0077     unsigned int system_group_tmp = config.readEntry("SystemGroup", 0);
0078     if ((system_group_tmp != 0) && (system_group_tmp < KHotKeys::ActionDataGroup::SYSTEM_MAX)) {
0079         // It's a valid value. Get the system group and load into it
0080         group = _settings->get_system_group(static_cast<KHotKeys::ActionDataGroup::system_group_t>(system_group_tmp));
0081     }
0082 
0083     // if no group was found or merging is disabled create a new group
0084     if (!group) {
0085         group = new KHotKeys::ActionDataGroup(parent);
0086         _config = &config;
0087         group->accept(this);
0088     }
0089 
0090     Q_ASSERT(group);
0091 
0092     // Now load the children
0093     QString configName = config.name();
0094     int cnt = config.readEntry("DataCount", 0);
0095     for (int i = 1; i <= cnt; ++i) {
0096         KConfigGroup childConfig(config.config(), configName + '_' + QString::number(i));
0097         if (_loadAll || KHotKeys::ActionDataBase::cfg_is_enabled(childConfig)) {
0098             readActionData(childConfig, group);
0099         }
0100     }
0101 
0102     // The object is complete. Activate it if needed
0103     switch (_stateStrategy) {
0104     case KHotKeys::Retain:
0105         config.readEntry("Enabled", false) ? group->enable() : group->disable();
0106         break;
0107 
0108     case KHotKeys::Disabled:
0109         // Its disabled by default
0110         break;
0111 
0112     case KHotKeys::Enabled:
0113         group->enable();
0114         break;
0115 
0116     default:
0117         qWarning() << "Unknown stateStrategy";
0118         Q_ASSERT(false);
0119         break;
0120     };
0121 
0122     return group;
0123 }
0124 
0125 KHotKeys::ActionDataBase *SettingsReaderV2::readActionData(const KConfigGroup &config, KHotKeys::ActionDataGroup *parent)
0126 {
0127     QString type = config.readEntry("Type");
0128 
0129     if (type == "ACTION_DATA_GROUP") {
0130         return readGroup(config, parent);
0131     }
0132 
0133     KHotKeys::ActionData *newObject = nullptr;
0134 
0135     if (type == "GENERIC_ACTION_DATA") {
0136         newObject = new KHotKeys::Generic_action_data(parent);
0137     } else if (type == "MENUENTRY_SHORTCUT_ACTION_DATA") {
0138         // We collect all of those in the system group
0139         newObject = new KHotKeys::MenuEntryShortcutActionData(_settings->get_system_group(KHotKeys::ActionDataGroup::SYSTEM_MENUENTRIES));
0140     } else if (type == "SIMPLE_ACTION_DATA" || type == "COMMAND_URL_SHORTCUT_ACTION_DATA" || type == "DCOP_SHORTCUT_ACTION_DATA"
0141                || type == "DBUS_SHORTCUT_ACTION_DATA" || type == "KEYBOARD_INPUT_GESTURE_ACTION_DATA" || type == "KEYBOARD_INPUT_SHORTCUT_ACTION_DATA"
0142                || type == "ACTIVATE_WINDOW_SHORTCUT_ACTION_DATA") {
0143         newObject = new KHotKeys::SimpleActionData(parent);
0144     } else {
0145         qWarning() << "Unknown ActionDataBase type read from cfg file\n";
0146         return nullptr;
0147     }
0148 
0149     _config = &config;
0150     newObject->accept(this);
0151 
0152     // And the actions
0153     readActionList(config, newObject);
0154 
0155     // Now load the triggers
0156     readTriggerList(config, newObject);
0157 
0158     // The object is complete. Activate it if needed
0159     switch (_stateStrategy) {
0160     case KHotKeys::Retain:
0161         config.readEntry("Enabled", false) ? newObject->enable() : newObject->disable();
0162         break;
0163 
0164     case KHotKeys::Disabled:
0165         // Its disabled by default
0166         break;
0167 
0168     case KHotKeys::Enabled:
0169         newObject->enable();
0170         break;
0171 
0172     default:
0173         qWarning() << "Unknown stateStrategy";
0174         Q_ASSERT(false);
0175         break;
0176     };
0177 
0178 #ifdef KHOTKEYS_TRACE
0179     qDebug() << newObject->name() << "loaded into" << newObject->isEnabled(KHotKeys::ActionDataBase::Ignore) << "state";
0180 #endif
0181 
0182     return newObject;
0183 }
0184 
0185 KHotKeys::ActionList *SettingsReaderV2::readActionList(const KConfigGroup &config, KHotKeys::ActionData *parent)
0186 {
0187     KConfigGroup actionsGroup(config.config(), config.name() + "Actions");
0188 
0189     int cnt = actionsGroup.readEntry("ActionsCount", 0);
0190     QString save_cfg_group = actionsGroup.name();
0191     for (int i = 0; i < cnt; ++i) {
0192         KConfigGroup group(actionsGroup.config(), save_cfg_group + QString::number(i));
0193         KHotKeys::Action *action;
0194 
0195         QString type = group.readEntry("Type");
0196 
0197         if (type == "COMMAND_URL")
0198             action = new KHotKeys::CommandUrlAction(parent);
0199         else if (type == "MENUENTRY")
0200             action = new KHotKeys::MenuEntryAction(parent);
0201         else if (type == "DCOP" || type == "DBUS")
0202             action = new KHotKeys::DBusAction(parent);
0203         else if (type == "KEYBOARD_INPUT")
0204             action = new KHotKeys::KeyboardInputAction(parent);
0205         else if (type == "ACTIVATE_WINDOW")
0206             action = new KHotKeys::ActivateWindowAction(parent);
0207         else {
0208             qWarning() << "Unknown Action type read from cfg file\n";
0209             return nullptr;
0210         }
0211 
0212         _config = &group;
0213         action->accept(*this);
0214 
0215         parent->add_action(action);
0216     }
0217 
0218     return nullptr;
0219 }
0220 
0221 KHotKeys::Trigger_list *SettingsReaderV2::readTriggerList(const KConfigGroup &config, KHotKeys::ActionData *parent)
0222 {
0223     KConfigGroup triggersGroup(config.config(), config.name() + "Triggers");
0224     KHotKeys::Trigger_list *list = parent->triggers();
0225 
0226     if (!triggersGroup.exists())
0227         return list;
0228     Q_ASSERT(list);
0229 
0230     list->set_comment(triggersGroup.readEntry("Comment"));
0231 
0232     KHotKeys::Trigger *trigger = nullptr;
0233 
0234     int cnt = triggersGroup.readEntry("TriggersCount", 0);
0235     for (int i = 0; i < cnt; ++i) {
0236         KConfigGroup triggerConfig(triggersGroup.config(), triggersGroup.name() + QString::number(i));
0237         QString type = triggerConfig.readEntry("Type");
0238         QUuid uuid = triggerConfig.readEntry("Uuid");
0239         if (uuid.isNull())
0240             uuid = QUuid::createUuid();
0241 
0242         if (type == "SHORTCUT" || type == "SINGLE_SHORTCUT")
0243             trigger = new KHotKeys::ShortcutTrigger(parent, QKeySequence(), uuid);
0244         else if (type == "WINDOW")
0245             trigger = new KHotKeys::WindowTrigger(parent);
0246         else if (type == "GESTURE")
0247             trigger = new KHotKeys::GestureTrigger(parent);
0248         else {
0249             qWarning() << "khotkeys: Unknown trigger type" << type;
0250             return nullptr;
0251         }
0252 
0253         _config = &triggerConfig;
0254         trigger->accept(*this);
0255 
0256         if (trigger)
0257             parent->add_trigger(trigger);
0258     }
0259 
0260     return list;
0261 }
0262 
0263 void SettingsReaderV2::visit(KHotKeys::ActivateWindowAction &action)
0264 {
0265     QString save_cfg_group = _config->name();
0266     KConfigGroup windowGroup(_config->config(), save_cfg_group + "Window");
0267     action.set_window_list(new KHotKeys::Windowdef_list(windowGroup));
0268 }
0269 
0270 void SettingsReaderV2::visit(KHotKeys::CommandUrlAction &action)
0271 {
0272     action.set_command_url(_config->readEntry("CommandURL"));
0273 }
0274 
0275 void SettingsReaderV2::visit(KHotKeys::DBusAction &action)
0276 {
0277     action.set_remote_application(_config->readEntry("RemoteApp"));
0278     action.set_remote_object(_config->readEntry("RemoteObj"));
0279     action.set_called_function(_config->readEntry("Call"));
0280     action.set_arguments(_config->readEntry("Arguments"));
0281 }
0282 
0283 void SettingsReaderV2::visit(KHotKeys::GestureTrigger &trigger)
0284 {
0285     if (_config->hasKey("Gesture"))
0286         trigger.setKDE3Gesture(_config->readEntry("Gesture"));
0287     else
0288         trigger.setPointData(_config->readEntry("GesturePointData", QStringList()));
0289 }
0290 
0291 void SettingsReaderV2::visit(KHotKeys::KeyboardInputAction &action)
0292 {
0293     action.setInput(_config->readEntry("Input"));
0294 
0295     KHotKeys::Windowdef_list *window_list = nullptr;
0296     KHotKeys::KeyboardInputAction::DestinationWindow destWindow;
0297 
0298     // Try the new format with DestinationWindow
0299     int destination = _config->readEntry("DestinationWindow", -1);
0300 
0301     switch (destination) {
0302     case KHotKeys::KeyboardInputAction::SpecificWindow: {
0303         KConfigGroup windowGroup(_config->config(), _config->name() + "DestinationWindow");
0304         window_list = new KHotKeys::Windowdef_list(windowGroup);
0305         destWindow = KHotKeys::KeyboardInputAction::SpecificWindow;
0306     } break;
0307 
0308     case KHotKeys::KeyboardInputAction::ActionWindow:
0309         destWindow = KHotKeys::KeyboardInputAction::ActionWindow;
0310         break;
0311 
0312     case KHotKeys::KeyboardInputAction::ActiveWindow:
0313         destWindow = KHotKeys::KeyboardInputAction::ActiveWindow;
0314         break;
0315 
0316     case -1: {
0317         // Old format
0318         if (_config->readEntry("IsDestinationWindow", false)) {
0319             KConfigGroup windowGroup(_config->config(), _config->name() + "DestinationWindow");
0320             window_list = new KHotKeys::Windowdef_list(windowGroup);
0321             destWindow = KHotKeys::KeyboardInputAction::SpecificWindow;
0322         } else {
0323             if (_config->readEntry("ActiveWindow", false))
0324                 destWindow = KHotKeys::KeyboardInputAction::ActiveWindow;
0325             else
0326                 destWindow = KHotKeys::KeyboardInputAction::ActionWindow;
0327         }
0328     } break;
0329 
0330     default:
0331         Q_ASSERT(false);
0332         destWindow = KHotKeys::KeyboardInputAction::ActionWindow;
0333     }
0334 
0335     if (!window_list)
0336         window_list = new KHotKeys::Windowdef_list;
0337 
0338     action.setDestination(destWindow);
0339     action.setDestinationWindowRules(window_list);
0340 }
0341 
0342 void SettingsReaderV2::visit(KHotKeys::MenuEntryAction &action)
0343 {
0344     visit(*static_cast<KHotKeys::CommandUrlAction *>(&action));
0345 }
0346 
0347 void SettingsReaderV2::visit(KHotKeys::ShortcutTrigger &trigger)
0348 {
0349     QString shortcutString = _config->readEntry("Key");
0350 
0351     // TODO: Check if this is still necessary
0352     shortcutString.replace("Win+", "Meta+"); // Qt4 doesn't parse Win+, avoid a shortcut without modifier
0353 
0354     trigger.set_key_sequence(shortcutString);
0355 }
0356 
0357 void SettingsReaderV2::visit(KHotKeys::WindowTrigger &trigger)
0358 {
0359     KConfigGroup windowsConfig(_config->config(), _config->name() + "Windows");
0360     trigger.set_window_rules(new KHotKeys::Windowdef_list(windowsConfig));
0361     trigger.setOnWindowEvents(KHotKeys::WindowTrigger::WindowEvents(_config->readEntry("WindowActions", 0)));
0362 }
0363 
0364 void SettingsReaderV2::visitActionDataBase(KHotKeys::ActionDataBase *object)
0365 {
0366     object->set_name(_config->readEntry("Name"));
0367     object->set_comment(_config->readEntry("Comment"));
0368     object->setImportId(_config->readEntry("ImportId"));
0369     object->setAllowMerging(_config->readEntry("AllowMerge", false));
0370 
0371     KConfigGroup conditionsConfig(_config->config(), _config->name() + "Conditions");
0372 
0373     // Load the conditions if they exist
0374     if (conditionsConfig.exists()) {
0375         object->set_conditions(new KHotKeys::Condition_list(conditionsConfig, object));
0376     } else {
0377         object->set_conditions(new KHotKeys::Condition_list(QString(), object));
0378     }
0379 }
0380 
0381 void SettingsReaderV2::visitActionData(KHotKeys::ActionData *object)
0382 {
0383     visitActionDataBase(object);
0384 }
0385 
0386 void SettingsReaderV2::visitActionDataGroup(KHotKeys::ActionDataGroup *object)
0387 {
0388     unsigned int system_group_tmp = _config->readEntry("SystemGroup", 0);
0389 
0390     // Correct wrong values
0391     if (system_group_tmp >= KHotKeys::ActionDataGroup::SYSTEM_MAX) {
0392         system_group_tmp = 0;
0393     }
0394 
0395     object->set_system_group(static_cast<KHotKeys::ActionDataGroup::system_group_t>(system_group_tmp));
0396 
0397     visitActionDataBase(object);
0398 }
0399 
0400 void SettingsReaderV2::visitGenericActionData(KHotKeys::Generic_action_data *object)
0401 {
0402     visitActionData(object);
0403 }
0404 
0405 void SettingsReaderV2::visitMenuentryShortcutActionData(KHotKeys::MenuEntryShortcutActionData *object)
0406 {
0407     visitSimpleActionData(object);
0408 }
0409 
0410 void SettingsReaderV2::visitSimpleActionData(KHotKeys::SimpleActionData *object)
0411 {
0412     visitActionData(object);
0413 }