X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Factioncollection.cpp;h=765d7f89ee0bed4e20ce1776ed3f3c27b8fbaf27;hp=c98c321b785cb60fe6bdd505c8c0d9d6a59f364a;hb=56491f1d5772764aa82a5bda85c83ab336af4346;hpb=bde6f40f73d85cff300b133a722e4f59bff77f84 diff --git a/src/uisupport/actioncollection.cpp b/src/uisupport/actioncollection.cpp index c98c321b..765d7f89 100644 --- a/src/uisupport/actioncollection.cpp +++ b/src/uisupport/actioncollection.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,5 +15,254 @@ * 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., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + *************************************************************************** + * Parts of this implementation are based on KDE's KActionCollection. * ***************************************************************************/ + +#include "actioncollection.h" + +#include +#include +#include + +#include "action.h" +#include "uisettings.h" + +void ActionCollection::addActions(const std::vector>& actions) +{ + for (auto&& p : actions) { + addAction(p.first, p.second); + } +} + +#ifndef HAVE_KDE + +int ActionCollection::count() const +{ + return actions().count(); +} + +bool ActionCollection::isEmpty() const +{ + return actions().count(); +} + +void ActionCollection::clear() +{ + _actionByName.clear(); + qDeleteAll(_actions); + _actions.clear(); +} + +QAction* ActionCollection::action(const QString& name) const +{ + return _actionByName.value(name, 0); +} + +QList ActionCollection::actions() const +{ + return _actions; +} + +QAction* ActionCollection::addAction(const QString& name, QAction* action) +{ + if (!action) + return action; + + const QString origName = action->objectName(); + QString indexName = name; + + if (indexName.isEmpty()) + indexName = action->objectName(); + else + action->setObjectName(indexName); + if (indexName.isEmpty()) + indexName = indexName.asprintf("unnamed-%p", (void*)action); + + // do we already have this action? + if (_actionByName.value(indexName, 0) == action) + return action; + // or maybe another action under this name? + if (QAction* oldAction = _actionByName.value(indexName)) + takeAction(oldAction); + + // do we already have this action under a different name? + int oldIndex = _actions.indexOf(action); + if (oldIndex != -1) { + _actionByName.remove(origName); + _actions.removeAt(oldIndex); + } + + // add action + _actionByName.insert(indexName, action); + _actions.append(action); + + foreach (QWidget* widget, _associatedWidgets) { + widget->addAction(action); + } + + connect(action, &QObject::destroyed, this, &ActionCollection::actionDestroyed); + if (_connectHovered) + connect(action, &QAction::hovered, this, &ActionCollection::slotActionHovered); + if (_connectTriggered) + connect(action, &QAction::triggered, this, &ActionCollection::slotActionTriggered); + + emit inserted(action); + return action; +} + +void ActionCollection::removeAction(QAction* action) +{ + delete takeAction(action); +} + +QAction* ActionCollection::takeAction(QAction* action) +{ + if (!unlistAction(action)) + return nullptr; + + foreach (QWidget* widget, _associatedWidgets) { + widget->removeAction(action); + } + + action->disconnect(this); + return action; +} + +void ActionCollection::readSettings() +{ + ShortcutSettings s; + QStringList savedShortcuts = s.savedShortcuts(); + + foreach (const QString& name, _actionByName.keys()) { + if (!savedShortcuts.contains(name)) + continue; + auto* action = qobject_cast(_actionByName.value(name)); + if (action) + action->setShortcut(s.loadShortcut(name), Action::ActiveShortcut); + } +} + +void ActionCollection::writeSettings() const +{ + ShortcutSettings s; + foreach (const QString& name, _actionByName.keys()) { + auto* action = qobject_cast(_actionByName.value(name)); + if (!action) + continue; + if (!action->isShortcutConfigurable()) + continue; + if (action->shortcut(Action::ActiveShortcut) == action->shortcut(Action::DefaultShortcut)) + continue; + s.saveShortcut(name, action->shortcut(Action::ActiveShortcut)); + } +} + +void ActionCollection::slotActionTriggered() +{ + auto* action = qobject_cast(sender()); + if (action) + emit actionTriggered(action); +} + +void ActionCollection::slotActionHovered() +{ + auto* action = qobject_cast(sender()); + if (action) + emit actionHovered(action); +} + +void ActionCollection::actionDestroyed(QObject* obj) +{ + // remember that this is not an QAction anymore at this point + auto* action = static_cast(obj); + + unlistAction(action); +} + +void ActionCollection::connectNotify(const QMetaMethod& signal) +{ + if (_connectHovered && _connectTriggered) + return; + + if (QMetaMethod::fromSignal(&ActionCollection::actionHovered) == signal) { + if (!_connectHovered) { + _connectHovered = true; + foreach (QAction* action, actions()) + connect(action, &QAction::hovered, this, &ActionCollection::slotActionHovered); + } + } + else if (QMetaMethod::fromSignal(&ActionCollection::actionTriggered) == signal) { + if (!_connectTriggered) { + _connectTriggered = true; + foreach (QAction* action, actions()) + connect(action, &QAction::triggered, this, &ActionCollection::slotActionTriggered); + } + } + + QObject::connectNotify(signal); +} + +void ActionCollection::associateWidget(QWidget* widget) const +{ + foreach (QAction* action, actions()) { + if (!widget->actions().contains(action)) + widget->addAction(action); + } +} + +void ActionCollection::addAssociatedWidget(QWidget* widget) +{ + if (!_associatedWidgets.contains(widget)) { + widget->addActions(actions()); + _associatedWidgets.append(widget); + connect(widget, &QObject::destroyed, this, &ActionCollection::associatedWidgetDestroyed); + } +} + +void ActionCollection::removeAssociatedWidget(QWidget* widget) +{ + foreach (QAction* action, actions()) + widget->removeAction(action); + _associatedWidgets.removeAll(widget); + disconnect(widget, &QObject::destroyed, this, &ActionCollection::associatedWidgetDestroyed); +} + +QList ActionCollection::associatedWidgets() const +{ + return _associatedWidgets; +} + +void ActionCollection::clearAssociatedWidgets() +{ + foreach (QWidget* widget, _associatedWidgets) + foreach (QAction* action, actions()) + widget->removeAction(action); + + _associatedWidgets.clear(); +} + +void ActionCollection::associatedWidgetDestroyed(QObject* obj) +{ + _associatedWidgets.removeAll(static_cast(obj)); +} + +bool ActionCollection::unlistAction(QAction* action) +{ + // This might be called with a partly destroyed QAction! + + int index = _actions.indexOf(action); + if (index == -1) + return false; + + QString name = action->objectName(); + _actionByName.remove(name); + _actions.removeAt(index); + + // TODO: remove from ActionCategory if we ever get that + + return true; +} + +#endif /* HAVE_KDE */