diff --git a/libs/widgetutils/kis_action_registry.cpp b/libs/widgetutils/kis_action_registry.cpp index ce7340ec0e..c6c8a7356f 100644 --- a/libs/widgetutils/kis_action_registry.cpp +++ b/libs/widgetutils/kis_action_registry.cpp @@ -1,482 +1,431 @@ /* * Copyright (c) 2015 Michael Abrahams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "KoResourcePaths.h" #include "kis_icon_utils.h" #include "kactioncollection.h" #include "kactioncategory.h" - #include "kis_action_registry.h" #include "kshortcutschemeshelper_p.h" namespace { /** * We associate several pieces of information with each shortcut. The first * piece of information is a QDomElement, containing the raw data from the * .action XML file. The second and third are QKeySequences, the first of * which is the default shortcut, the last of which is any custom shortcut. * The last two are the KActionCollection and KActionCategory used to * organize the shortcut editor. */ struct ActionInfoItem { QDomElement xmlData; QList defaultShortcuts; QList customShortcuts; QString collectionName; QString categoryName; }; // Convenience macros to extract text of a child node. QString getChildContent(QDomElement xml, QString node) { return xml.firstChildElement(node).text(); }; ActionInfoItem emptyActionInfo; // Used as default return value // Use Krita debug logging categories instead of KDE's default qDebug() for // harmless empty strings and translations QString quietlyTranslate(const QString &s) { if (s.isEmpty()) { return s; } QString translatedString = i18nc("action", s.toUtf8()); if (translatedString == s) { translatedString = i18n(s.toUtf8()); } if (translatedString.isEmpty()) { dbgAction << "No translation found for" << s; return s; } return translatedString; }; QList preferredShortcuts(ActionInfoItem action) { if (action.customShortcuts.isEmpty()) { return action.defaultShortcuts; } else { return action.customShortcuts; } }; }; class Q_DECL_HIDDEN KisActionRegistry::Private { public: Private(KisActionRegistry *_q) : q(_q) {}; // This is the main place containing ActionInfoItems. QMap actionInfoList; void loadActionFiles(); void loadCustomShortcuts(QString filename = QStringLiteral("kritashortcutsrc")); ActionInfoItem &actionInfo(const QString &name) { if (!actionInfoList.contains(name)) { dbgAction << "Tried to look up info for unknown action" << name; } return actionInfoList[name]; }; KisActionRegistry *q; QMap actionCollections; }; Q_GLOBAL_STATIC(KisActionRegistry, s_instance); KisActionRegistry *KisActionRegistry::instance() { return s_instance; }; KisActionRegistry::KisActionRegistry() : d(new KisActionRegistry::Private(this)) { d->loadActionFiles(); KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes"); QString schemeName = cg.readEntry("Current Scheme", "Default"); loadShortcutScheme(schemeName); loadCustomShortcuts(); } -QList KisActionRegistry::getCustomShortcut(const QString &name) -{ - return d->actionInfo(name).customShortcuts; -}; - -QList KisActionRegistry::getPreferredShortcut(const QString &name) -{ - return preferredShortcuts(d->actionInfo(name)); -}; - -QString KisActionRegistry::getCategory(const QString &name) -{ - return d->actionInfo(name).categoryName; -}; - -QStringList KisActionRegistry::allActions() -{ - return d->actionInfoList.keys(); -}; - -KActionCollection * KisActionRegistry::getDefaultCollection() -{ - return d->actionCollections.value("Krita"); -}; - void KisActionRegistry::addAction(const QString &name, QAction *a) { auto info = d->actionInfo(name); KActionCollection *collection = d->actionCollections.value(info.collectionName); if (!collection) { dbgAction << "No collection found for action" << name; return; } if (collection->action(name)) { dbgAction << "duplicate action" << name << "in collection" << collection->componentName(); } else { } collection->addCategorizedAction(name, a, info.categoryName); }; void KisActionRegistry::notifySettingsUpdated() { d->loadCustomShortcuts(); }; void KisActionRegistry::loadCustomShortcuts(const QString &path) { if (path.isEmpty()) { d->loadCustomShortcuts(); } else { d->loadCustomShortcuts(path); } }; void KisActionRegistry::loadShortcutScheme(const QString &schemeName) { // Load scheme file if (schemeName != QStringLiteral("Default")) { QString schemeFileName = KShortcutSchemesHelper::schemeFileLocations().value(schemeName); if (schemeFileName.isEmpty()) { return; } KConfig schemeConfig(schemeFileName, KConfig::SimpleConfig); applyShortcutScheme(&schemeConfig); } else { // Apply default scheme, updating KisActionRegistry data applyShortcutScheme(); } } QAction * KisActionRegistry::makeQAction(const QString &name, QObject *parent) { QAction * a = new QAction(parent); if (!d->actionInfoList.contains(name)) { dbgAction << "Warning: requested data for unknown action" << name; return a; } propertizeAction(name, a); return a; }; void KisActionRegistry::setupDialog(KisShortcutsDialog *dlg) { for (auto i = d->actionCollections.constBegin(); i != d->actionCollections.constEnd(); i++ ) { dlg->addCollection(i.value(), i.key()); } } void KisActionRegistry::settingsPageSaved() { // For now, custom shortcuts are dealt with by writing to file and reloading. loadCustomShortcuts(); // Announce UI should reload current shortcuts. emit shortcutsUpdated(); } void KisActionRegistry::applyShortcutScheme(const KConfigBase *config) { // First, update the things in KisActionRegistry if (config == 0) { // Use default shortcut scheme. Simplest just to reload everything. d->actionInfoList.clear(); d->loadActionFiles(); loadCustomShortcuts(); } else { const auto schemeEntries = config->group(QStringLiteral("Shortcuts")).entryMap(); // Load info item for each shortcut, reset custom shortcuts auto it = schemeEntries.constBegin(); while (it != schemeEntries.end()) { ActionInfoItem &info = d->actionInfo(it.key()); if (!it.value().isEmpty()) info.defaultShortcuts = QKeySequence::listFromString(it.value()); it++; } } } void KisActionRegistry::updateShortcut(const QString &name, QAction *action) { const ActionInfoItem &info = d->actionInfo(name); action->setShortcuts(preferredShortcuts(info)); action->setProperty("defaultShortcuts", qVariantFromValue(info.defaultShortcuts)); } bool KisActionRegistry::propertizeAction(const QString &name, QAction * a) { const ActionInfoItem info = d->actionInfo(name); QDomElement actionXml = info.xmlData; if (actionXml.text().isEmpty()) { dbgAction << "No XML data found for action" << name; return false; } // i18n requires converting format from QString. auto getChildContent_i18n = [=](QString node){return quietlyTranslate(getChildContent(actionXml, node));}; // Note: the fields in the .action documents marked for translation are determined by extractrc. QString icon = getChildContent(actionXml, "icon"); QString text = getChildContent_i18n("text"); QString whatsthis = getChildContent_i18n("whatsThis"); QString toolTip = getChildContent_i18n("toolTip"); QString statusTip = getChildContent_i18n("statusTip"); QString iconText = getChildContent_i18n("iconText"); bool isCheckable = getChildContent(actionXml, "isCheckable") == QString("true"); a->setObjectName(name); // This is helpful, should be added more places in Krita a->setIcon(KisIconUtils::loadIcon(icon.toLatin1())); a->setText(text); a->setObjectName(name); a->setWhatsThis(whatsthis); a->setToolTip(toolTip); a->setStatusTip(statusTip); a->setIconText(iconText); a->setCheckable(isCheckable); updateShortcut(name, a); // TODO: check for colliding shortcuts in .action files either here or in loading code #if 0 QMap existingShortcuts; Q_FOREACH (QAction* action, actionCollection->actions()) { if(action->shortcut() == QKeySequence(0)) { continue; } if (existingShortcuts.contains(action->shortcut())) { dbgAction << QString("Actions %1 and %2 have the same shortcut: %3") \ .arg(action->text()) \ .arg(existingShortcuts[action->shortcut()]->text()) \ .arg(action->shortcut()); } else { existingShortcuts[action->shortcut()] = action; } } #endif return true; } QString KisActionRegistry::getActionProperty(const QString &name, const QString &property) { ActionInfoItem info = d->actionInfo(name); QDomElement actionXml = info.xmlData; if (actionXml.text().isEmpty()) { dbgAction << "No XML data found for action" << name; return QString(); } return getChildContent(actionXml, property); } -void KisActionRegistry::writeCustomShortcuts(KConfigBase *config) const -{ - - KConfigGroup cg; - if (config == 0) { - cg = KConfigGroup(KSharedConfig::openConfig("kritashortcutsrc"), - QStringLiteral("Shortcuts")); - } else { - cg = KConfigGroup(config, QStringLiteral("Shortcuts")); - } - - for (auto it = d->actionInfoList.constBegin(); - it != d->actionInfoList.constEnd(); ++it) { - - QString actionName = it.key(); - QString s = QKeySequence::listToString(it.value().customShortcuts); - if (s.isEmpty()) { - cg.deleteEntry(actionName, KConfigGroup::Persistent); - } else { - cg.writeEntry(actionName, s, KConfigGroup::Persistent); - } - } - cg.sync(); -} - void KisActionRegistry::Private::loadActionFiles() { QStringList actionDefinitions = KoResourcePaths::findAllResources("kis_actions", "*.action", KoResourcePaths::Recursive); // Extract actions all XML .action files. Q_FOREACH (const QString &actionDefinition, actionDefinitions) { QDomDocument doc; QFile f(actionDefinition); f.open(QFile::ReadOnly); doc.setContent(f.readAll()); QDomElement base = doc.documentElement(); // "ActionCollection" outer group QString collectionName = base.attribute("name"); QString version = base.attribute("version"); if (version != "2") { errAction << ".action XML file" << actionDefinition << "has incorrect version; skipping."; continue; } KActionCollection *actionCollection; if (!actionCollections.contains(collectionName)) { actionCollection = new KActionCollection(q, collectionName); actionCollections.insert(collectionName, actionCollection); dbgAction << "Adding a new action collection " << collectionName; } else { actionCollection = actionCollections.value(collectionName); } // Loop over nodes. Each of these corresponds to a // KActionCategory, producing a group of actions in the shortcut dialog. QDomElement actions = base.firstChild().toElement(); while (!actions.isNull()) { // field QDomElement categoryTextNode = actions.firstChild().toElement(); QString categoryName = quietlyTranslate(categoryTextNode.text()); // KActionCategory *category = actionCollection->getCategory(categoryName); // dbgAction << "Using category" << categoryName; // tags QDomElement actionXml = categoryTextNode.nextSiblingElement(); // Loop over individual actions while (!actionXml.isNull()) { if (actionXml.tagName() == "Action") { // Read name from format QString name = actionXml.attribute("name"); // Bad things if (name.isEmpty()) { errAction << "Unnamed action in definitions file " << actionDefinition; } else if (actionInfoList.contains(name)) { // errAction << "NOT COOL: Duplicated action name from xml data: " << name; } else { ActionInfoItem info; info.xmlData = actionXml; // Use empty list to signify no shortcut QString shortcutText = getChildContent(actionXml, "shortcut"); if (!shortcutText.isEmpty()) info.defaultShortcuts << QKeySequence(shortcutText); info.categoryName = categoryName; info.collectionName = collectionName; // dbgAction << "default shortcut for" << name << " - " << info.defaultShortcut; actionInfoList.insert(name,info); } } actionXml = actionXml.nextSiblingElement(); } actions = actions.nextSiblingElement(); } } }; void KisActionRegistry::Private::loadCustomShortcuts(QString filename) { const KConfigGroup localShortcuts(KSharedConfig::openConfig(filename), QStringLiteral("Shortcuts")); if (!localShortcuts.exists()) { return; } // Distinguish between two "null" states for custom shortcuts. for (auto i = actionInfoList.begin(); i != actionInfoList.end(); ++i) { if (localShortcuts.hasKey(i.key())) { QString entry = localShortcuts.readEntry(i.key(), QString()); if (entry == QStringLiteral("none")) { // A shortcut list with a single entry "" means the user has disabled the shortcut. // This occurs after stealing the shortcut without assigning a new one. i.value().customShortcuts = QList(); } else { i.value().customShortcuts = QKeySequence::listFromString(entry); } } else { // An empty shortcut list means no custom shortcut has been set. i.value().customShortcuts = QList(); } } }; diff --git a/libs/widgetutils/kis_action_registry.h b/libs/widgetutils/kis_action_registry.h index 7da8b0c391..f5303c9877 100644 --- a/libs/widgetutils/kis_action_registry.h +++ b/libs/widgetutils/kis_action_registry.h @@ -1,165 +1,137 @@ /* * Copyright (c) 2015 Michael Abrahams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "kritawidgetutils_export.h" class KActionCollection; class QDomElement; class KConfigBase; class KisShortcutsDialog; /** * KisActionRegistry is intended to manage the global action configuration data * for Krita. The data come from four sources: * - .action files, containing static action configuration data in XML format, * - .rc configuration files, originally from XMLGUI and now in WidgetUtils, * - kritashortcutsrc, containing temporary shortcut configuration, and * - .shortcuts scheme files providing sets of default shortcuts, also from XMLGUI * * This class can be used as a factory by calling makeQAction. It can be used to * add standard properties such as default shortcuts and default tooltip to an * existing action with propertizeAction. If you have a custom action class * which needs to add other properties, you can use propertizeAction to add any * sort of data you wish to the .action configuration file. * * This class is also in charge of displaying the shortcut configuration dialog. * The interplay between this class, KActionCollection, KisShortcutsEditor and * so on can be complex, and is sometimes synchronized by file I/O by reading * and writing the configuration files mentioned above. * * It is a global static. Grab an ::instance(). */ class KRITAWIDGETUTILS_EXPORT KisActionRegistry : public QObject { Q_OBJECT public: static KisActionRegistry *instance(); - - /** - * Get shortcut for an action - */ - QList getPreferredShortcut(const QString &name); - - /** - * Get shortcut for an action - */ - QList getDefaultShortcut(const QString &name); - - /** - * Get custom shortcut for an action - */ - QList getCustomShortcut(const QString &name); - - /** - * Get category name - */ - QString getCategory(const QString &name); - /** * @return value @p property for an action @p name. * * Allow flexible info structure for KisActions, etc. */ QString getActionProperty(const QString &name, const QString &property); /** * Saves action in a category. Note that this grabs ownership of the action. */ void addAction(const QString &name, QAction *a); /** * Produces a new QAction based on the .action data files. * * N.B. this action will not be saved in the registry. */ QAction * makeQAction(const QString &name, QObject *parent); /** * Fills the standard QAction properties of an action. * * @return true if the action was loaded successfully. */ bool propertizeAction(const QString &name, QAction *a); - /** - * @return list of actions with data available. - */ - QStringList allActions(); - /** * Setup the shortcut configuration widget. */ void setupDialog(KisShortcutsDialog *dlg); /** * Called when "OK" button is pressed in settings dialog. */ void settingsPageSaved(); /** * Reload custom shortcuts from kritashortcutsrc */ void loadCustomShortcuts(const QString &path = QString()); - - /** - * Write custom shortcuts to a specific file - */ - void writeCustomShortcuts(KConfigBase *config) const; - - /** * Call after settings are changed. */ void notifySettingsUpdated(); + // If config == 0, reload defaults + void applyShortcutScheme(const KConfigBase *config = 0); + /** * Constructor. Please don't touch! */ KisActionRegistry(); - // Undocumented - void updateShortcut(const QString &name, QAction *ac); - KActionCollection * getDefaultCollection(); - + /** + * @brief loadShortcutScheme + * @param schemeName + */ void loadShortcutScheme(const QString &schemeName); - // If config == 0, reload defaults - void applyShortcutScheme(const KConfigBase *config = 0); + + // Undocumented + void updateShortcut(const QString &name, QAction *ac); Q_SIGNALS: void shortcutsUpdated(); private: + class Private; Private * const d; }; diff --git a/libs/widgetutils/xmlgui/KisShortcutsEditor.cpp b/libs/widgetutils/xmlgui/KisShortcutsEditor.cpp index 55b6e82485..fe2e517b19 100644 --- a/libs/widgetutils/xmlgui/KisShortcutsEditor.cpp +++ b/libs/widgetutils/xmlgui/KisShortcutsEditor.cpp @@ -1,321 +1,322 @@ /* This file is part of the KDE libraries Copyright (C) 1998 Mark Donohoe Copyright (C) 1997 Nicolas Hadacek Copyright (C) 1998 Matthias Ettrich Copyright (C) 2001 Ellis Whitehead Copyright (C) 2006 Hamish Rodda Copyright (C) 2007 Roberto Raggi Copyright (C) 2007 Andreas Hartmetz Copyright (C) 2008 Michael Jansen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisShortcutsEditor.h" #include "KisShortcutsEditor_p.h" #include "kshortcutschemeshelper_p.h" #include "config-xmlgui.h" #include "kis_action_registry.h" // The following is needed for KisShortcutsEditorPrivate and QTreeWidgetHack // #include "KisShortcutsDialog_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kactioncollection.h" #include "kactioncategory.h" #include //--------------------------------------------------------------------- // KisShortcutsEditor //--------------------------------------------------------------------- Q_DECLARE_METATYPE(KisShortcutsEditorItem *) KisShortcutsEditor::KisShortcutsEditor(QWidget *parent, ActionTypes actionType, LetterShortcuts allowLetterShortcuts) : QWidget(parent) , d(new KisShortcutsEditorPrivate(this)) { d->initGUI(actionType, allowLetterShortcuts); } KisShortcutsEditor::~KisShortcutsEditor() { delete d; } bool KisShortcutsEditor::isModified() const { // Iterate over all items QTreeWidgetItemIterator it(d->ui.list, QTreeWidgetItemIterator::NoChildren); for (; (*it); ++it) { KisShortcutsEditorItem *item = dynamic_cast(*it); if (item && item->isModified()) { return true; } } return false; } void KisShortcutsEditor::clearCollections() { d->delegate->contractAll(); d->ui.list->clear(); d->actionCollections.clear(); QTimer::singleShot(0, this, SLOT(resizeColumns())); } void KisShortcutsEditor::clearSearch() { d->ui.searchFilter->searchLine()->clear(); } void KisShortcutsEditor::addCollection(KActionCollection *collection, const QString &title) { // KXmlGui add action collections unconditionally. If some plugin doesn't // provide actions we don't want to create empty subgroups. if (collection->isEmpty()) { return; } // Pause updating. setUpdatesEnabled(false); /** * Forward this actioncollection to the delegate which will do conflict checking. * This _replaces_ existing collections in the delegate. */ d->actionCollections.append(collection); d->delegate->setCheckActionCollections(d->actionCollections); // Determine how we should label this collection in the widget. QString collectionTitle; if (!title.isEmpty()) { collectionTitle = title; } else { // Use the programName (Translated). collectionTitle = collection->componentDisplayName(); } // Create the collection root node. QTreeWidgetItem *hierarchy[3]; hierarchy[KisShortcutsEditorPrivate::Root] = d->ui.list->invisibleRootItem(); hierarchy[KisShortcutsEditorPrivate::Program] = d->findOrMakeItem(hierarchy[KisShortcutsEditorPrivate::Root], collectionTitle); hierarchy[KisShortcutsEditorPrivate::Action] = 0; // Remember which actions we have seen. We will be adding categorized // actions first, so this will help us keep track of which actions haven't // been categorized yet, so we can add them as uncategorized at the end. QSet actionsSeen; // Add a subtree for each category? Perhaps easier to think that this // doesn't exist. Basically you add KActionCategory as a QObject child of // KActionCollection, and then tag objects as belonging to the category. foreach (KActionCategory *category, collection->categories()) { // Don't display empty categories. if (category->actions().isEmpty()) { continue; } hierarchy[KisShortcutsEditorPrivate::Action] = d->findOrMakeItem(hierarchy[KisShortcutsEditorPrivate::Program], category->text()); // Add every item from the category. foreach (QAction *action, category->actions()) { actionsSeen.insert(action); d->addAction(action, hierarchy, KisShortcutsEditorPrivate::Action); } // Fold in each KActionCategory by default. hierarchy[KisShortcutsEditorPrivate::Action]->setExpanded(false); } // Finally, tack on any uncategorized actions. foreach (QAction *action, collection->actions()) { if (!actionsSeen.contains(action)) { d->addAction(action, hierarchy, KisShortcutsEditorPrivate::Program); } } // sort the list d->ui.list->sortItems(Name, Qt::AscendingOrder); // Now turn on updating again. setUpdatesEnabled(true); QTimer::singleShot(0, this, SLOT(resizeColumns())); } void KisShortcutsEditor::clearConfiguration() { d->clearConfiguration(); } void KisShortcutsEditor::importConfiguration(KConfigBase *config, bool isScheme) { Q_ASSERT(config); if (!config) { return; } // If this is a shortcut scheme, apply it if (isScheme) { KisActionRegistry::instance()->applyShortcutScheme(config); } // Update the dialog entry items const KConfigGroup schemeShortcuts(config, QStringLiteral("Shortcuts")); for (QTreeWidgetItemIterator it(d->ui.list); (*it); ++it) { if (!(*it)->parent()) { continue; } KisShortcutsEditorItem *item = static_cast(*it); const QString actionId = item->data(Id).toString(); if (!schemeShortcuts.hasKey(actionId)) continue; QList sc = QKeySequence::listFromString(schemeShortcuts.readEntry(actionId, QString())); d->changeKeyShortcut(item, LocalPrimary, primarySequence(sc)); d->changeKeyShortcut(item, LocalAlternate, alternateSequence(sc)); } } void KisShortcutsEditor::exportConfiguration(KConfigBase *config) const { Q_ASSERT(config); if (!config) { return; } if (d->actionTypes) { KConfigGroup group(config,QStringLiteral("Shortcuts")); foreach (KActionCollection *collection, d->actionCollections) { collection->writeSettings(&group, true); } } KisActionRegistry::instance()->notifySettingsUpdated(); } void KisShortcutsEditor::saveShortcuts(KConfigGroup *config) const { + qDebug() << "Saving shortcuts"; // This is a horrible mess with pointers... KConfigGroup cg; if (config == 0) { cg = KConfigGroup(KSharedConfig::openConfig("kritashortcutsrc"), QStringLiteral("Shortcuts")); config = &cg; } // Clear and reset temporary shortcuts config->deleteGroup(); foreach (KActionCollection *collection, d->actionCollections) { collection->writeSettings(config, false); } KisActionRegistry::instance()->notifySettingsUpdated(); } //slot void KisShortcutsEditor::resizeColumns() { for (int i = 0; i < d->ui.list->columnCount(); i++) { d->ui.list->resizeColumnToContents(i); } } void KisShortcutsEditor::commit() { for (QTreeWidgetItemIterator it(d->ui.list); (*it); ++it) { if (KisShortcutsEditorItem *item = dynamic_cast(*it)) { item->commit(); } } } void KisShortcutsEditor::save() { saveShortcuts(); commit(); // Not doing this would be bad } void KisShortcutsEditor::undo() { // TODO: is this working? for (QTreeWidgetItemIterator it(d->ui.list); (*it); ++it) { if (KisShortcutsEditorItem *item = dynamic_cast(*it)) { item->undo(); } } } void KisShortcutsEditor::allDefault() { d->allDefault(); } void KisShortcutsEditor::printShortcuts() const { d->printShortcuts(); } void KisShortcutsEditor::searchUpdated(QString s) { if (s.isEmpty()) { // Reset the tree area d->ui.list->collapseAll(); d->ui.list->expandToDepth(0); } else { d->ui.list->expandAll(); } } KisShortcutsEditor::ActionTypes KisShortcutsEditor::actionTypes() const { return d->actionTypes; } void KisShortcutsEditor::setActionTypes(ActionTypes actionTypes) { d->setActionTypes(actionTypes); } #include "moc_KisShortcutsEditor.cpp"