1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************
20 * Parts of this implementation are based on KDE's KActionCollection. *
21 ***************************************************************************/
25 #include <QMetaMethod>
27 #include "actioncollection.h"
30 #include "uisettings.h"
32 void ActionCollection::addActions(const std::vector<std::pair<QString, Action *>> &actions)
34 for (auto &&p : actions) {
35 addAction(p.first, p.second);
42 int ActionCollection::count() const
44 return actions().count();
48 bool ActionCollection::isEmpty() const
50 return actions().count();
53 void ActionCollection::clear()
55 _actionByName.clear();
61 QAction *ActionCollection::action(const QString &name) const
63 return _actionByName.value(name, 0);
67 QList<QAction *> ActionCollection::actions() const
72 QAction *ActionCollection::addAction(const QString &name, QAction *action)
77 const QString origName = action->objectName();
78 QString indexName = name;
80 if (indexName.isEmpty())
81 indexName = action->objectName();
83 action->setObjectName(indexName);
84 if (indexName.isEmpty())
85 indexName = indexName.sprintf("unnamed-%p", (void *)action);
87 // do we already have this action?
88 if (_actionByName.value(indexName, 0) == action)
90 // or maybe another action under this name?
91 if (QAction *oldAction = _actionByName.value(indexName))
92 takeAction(oldAction);
94 // do we already have this action under a different name?
95 int oldIndex = _actions.indexOf(action);
97 _actionByName.remove(origName);
98 _actions.removeAt(oldIndex);
102 _actionByName.insert(indexName, action);
103 _actions.append(action);
105 foreach(QWidget *widget, _associatedWidgets) {
106 widget->addAction(action);
109 connect(action, &QObject::destroyed, this, &ActionCollection::actionDestroyed);
111 connect(action, &QAction::hovered, this, &ActionCollection::slotActionHovered);
112 if (_connectTriggered)
113 connect(action, &QAction::triggered, this, &ActionCollection::slotActionTriggered);
115 emit inserted(action);
120 void ActionCollection::removeAction(QAction *action)
122 delete takeAction(action);
126 QAction *ActionCollection::takeAction(QAction *action)
128 if (!unlistAction(action))
131 foreach(QWidget *widget, _associatedWidgets) {
132 widget->removeAction(action);
135 action->disconnect(this);
140 void ActionCollection::readSettings()
143 QStringList savedShortcuts = s.savedShortcuts();
145 foreach(const QString &name, _actionByName.keys()) {
146 if (!savedShortcuts.contains(name))
148 auto *action = qobject_cast<Action *>(_actionByName.value(name));
150 action->setShortcut(s.loadShortcut(name), Action::ActiveShortcut);
155 void ActionCollection::writeSettings() const
158 foreach(const QString &name, _actionByName.keys()) {
159 auto *action = qobject_cast<Action *>(_actionByName.value(name));
162 if (!action->isShortcutConfigurable())
164 if (action->shortcut(Action::ActiveShortcut) == action->shortcut(Action::DefaultShortcut))
166 s.saveShortcut(name, action->shortcut(Action::ActiveShortcut));
171 void ActionCollection::slotActionTriggered()
173 auto *action = qobject_cast<QAction *>(sender());
175 emit actionTriggered(action);
179 void ActionCollection::slotActionHovered()
181 auto *action = qobject_cast<QAction *>(sender());
183 emit actionHovered(action);
187 void ActionCollection::actionDestroyed(QObject *obj)
189 // remember that this is not an QAction anymore at this point
190 auto *action = static_cast<QAction *>(obj);
192 unlistAction(action);
195 void ActionCollection::connectNotify(const QMetaMethod &signal)
197 if (_connectHovered && _connectTriggered)
200 if (QMetaMethod::fromSignal(&ActionCollection::actionHovered) == signal) {
201 if (!_connectHovered) {
202 _connectHovered = true;
203 foreach(QAction* action, actions())
204 connect(action, &QAction::hovered, this, &ActionCollection::slotActionHovered);
207 else if (QMetaMethod::fromSignal(&ActionCollection::actionTriggered) == signal) {
208 if (!_connectTriggered) {
209 _connectTriggered = true;
210 foreach(QAction* action, actions())
211 connect(action, &QAction::triggered, this, &ActionCollection::slotActionTriggered);
215 QObject::connectNotify(signal);
219 void ActionCollection::associateWidget(QWidget *widget) const
221 foreach(QAction *action, actions()) {
222 if (!widget->actions().contains(action))
223 widget->addAction(action);
228 void ActionCollection::addAssociatedWidget(QWidget *widget)
230 if (!_associatedWidgets.contains(widget)) {
231 widget->addActions(actions());
232 _associatedWidgets.append(widget);
233 connect(widget, &QObject::destroyed, this, &ActionCollection::associatedWidgetDestroyed);
238 void ActionCollection::removeAssociatedWidget(QWidget *widget)
240 foreach(QAction *action, actions())
241 widget->removeAction(action);
242 _associatedWidgets.removeAll(widget);
243 disconnect(widget, &QObject::destroyed, this, &ActionCollection::associatedWidgetDestroyed);
247 QList<QWidget *> ActionCollection::associatedWidgets() const
249 return _associatedWidgets;
253 void ActionCollection::clearAssociatedWidgets()
255 foreach(QWidget *widget, _associatedWidgets)
256 foreach(QAction *action, actions())
257 widget->removeAction(action);
259 _associatedWidgets.clear();
263 void ActionCollection::associatedWidgetDestroyed(QObject *obj)
265 _associatedWidgets.removeAll(static_cast<QWidget *>(obj));
269 bool ActionCollection::unlistAction(QAction *action)
271 // This might be called with a partly destroyed QAction!
273 int index = _actions.indexOf(action);
274 if (index == -1) return false;
276 QString name = action->objectName();
277 _actionByName.remove(name);
278 _actions.removeAt(index);
280 // TODO: remove from ActionCategory if we ever get that
285 #endif /* HAVE_KDE */