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 ***************************************************************************/
27 #include <QMetaMethod>
29 #include "actioncollection.h"
32 #include "uisettings.h"
34 ActionCollection::ActionCollection(QObject *parent) : QObject(parent)
36 _connectTriggered = _connectHovered = false;
40 ActionCollection::~ActionCollection()
45 void ActionCollection::clear()
47 _actionByName.clear();
53 QAction *ActionCollection::action(const QString &name) const
55 return _actionByName.value(name, 0);
59 QList<QAction *> ActionCollection::actions() const
65 Action *ActionCollection::addAction(const QString &name, Action *action)
67 QAction *act = addAction(name, static_cast<QAction *>(action));
69 Q_ASSERT(act == action);
74 Action *ActionCollection::addAction(const QString &name, const QObject *receiver, const char *member)
76 Action *a = new Action(this);
77 if (receiver && member)
78 connect(a, SIGNAL(triggered(bool)), receiver, member);
79 return addAction(name, a);
83 QAction *ActionCollection::addAction(const QString &name, QAction *action)
88 const QString origName = action->objectName();
89 QString indexName = name;
91 if (indexName.isEmpty())
92 indexName = action->objectName();
94 action->setObjectName(indexName);
95 if (indexName.isEmpty())
96 indexName = indexName.sprintf("unnamed-%p", (void *)action);
98 // do we already have this action?
99 if (_actionByName.value(indexName, 0) == action)
101 // or maybe another action under this name?
102 if (QAction *oldAction = _actionByName.value(indexName))
103 takeAction(oldAction);
105 // do we already have this action under a different name?
106 int oldIndex = _actions.indexOf(action);
107 if (oldIndex != -1) {
108 _actionByName.remove(origName);
109 _actions.removeAt(oldIndex);
113 _actionByName.insert(indexName, action);
114 _actions.append(action);
116 foreach(QWidget *widget, _associatedWidgets) {
117 widget->addAction(action);
120 connect(action, SIGNAL(destroyed(QObject *)), SLOT(actionDestroyed(QObject *)));
122 connect(action, SIGNAL(hovered()), SLOT(slotActionHovered()));
123 if (_connectTriggered)
124 connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()));
126 emit inserted(action);
131 void ActionCollection::removeAction(QAction *action)
133 delete takeAction(action);
137 QAction *ActionCollection::takeAction(QAction *action)
139 if (!unlistAction(action))
142 foreach(QWidget *widget, _associatedWidgets) {
143 widget->removeAction(action);
146 action->disconnect(this);
151 void ActionCollection::readSettings()
154 QStringList savedShortcuts = s.savedShortcuts();
156 foreach(const QString &name, _actionByName.keys()) {
157 if (!savedShortcuts.contains(name))
159 Action *action = qobject_cast<Action *>(_actionByName.value(name));
161 action->setShortcut(s.loadShortcut(name), Action::ActiveShortcut);
166 void ActionCollection::writeSettings() const
169 foreach(const QString &name, _actionByName.keys()) {
170 Action *action = qobject_cast<Action *>(_actionByName.value(name));
173 if (!action->isShortcutConfigurable())
175 if (action->shortcut(Action::ActiveShortcut) == action->shortcut(Action::DefaultShortcut))
177 s.saveShortcut(name, action->shortcut(Action::ActiveShortcut));
182 void ActionCollection::slotActionTriggered()
184 QAction *action = qobject_cast<QAction *>(sender());
186 emit actionTriggered(action);
190 void ActionCollection::slotActionHovered()
192 QAction *action = qobject_cast<QAction *>(sender());
194 emit actionHovered(action);
198 void ActionCollection::actionDestroyed(QObject *obj)
200 // remember that this is not an QAction anymore at this point
201 QAction *action = static_cast<QAction *>(obj);
203 unlistAction(action);
206 #if QT_VERSION >= 0x050000
207 void ActionCollection::connectNotify(const QMetaMethod &signal)
209 void ActionCollection::connectNotify(const char *signal)
212 if (_connectHovered && _connectTriggered)
215 #if QT_VERSION >= 0x050000
216 if (QMetaMethod::fromSignal(&ActionCollection::actionHovered) == signal) {
218 if (QMetaObject::normalizedSignature(SIGNAL(actionHovered(QAction *))) == signal) {
220 if (!_connectHovered) {
221 _connectHovered = true;
222 foreach(QAction* action, actions())
223 connect(action, SIGNAL(hovered()), SLOT(slotActionHovered()));
226 #if QT_VERSION >= 0x050000
227 else if (QMetaMethod::fromSignal(&ActionCollection::actionTriggered) == signal) {
229 else if (QMetaObject::normalizedSignature(SIGNAL(actionTriggered(QAction *))) == signal) {
231 if (!_connectTriggered) {
232 _connectTriggered = true;
233 foreach(QAction* action, actions())
234 connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()));
238 QObject::connectNotify(signal);
242 void ActionCollection::associateWidget(QWidget *widget) const
244 foreach(QAction *action, actions()) {
245 if (!widget->actions().contains(action))
246 widget->addAction(action);
251 void ActionCollection::addAssociatedWidget(QWidget *widget)
253 if (!_associatedWidgets.contains(widget)) {
254 widget->addActions(actions());
255 _associatedWidgets.append(widget);
256 connect(widget, SIGNAL(destroyed(QObject *)), SLOT(associatedWidgetDestroyed(QObject *)));
261 void ActionCollection::removeAssociatedWidget(QWidget *widget)
263 foreach(QAction *action, actions())
264 widget->removeAction(action);
265 _associatedWidgets.removeAll(widget);
266 disconnect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(associatedWidgetDestroyed(QObject *)));
270 QList<QWidget *> ActionCollection::associatedWidgets() const
272 return _associatedWidgets;
276 void ActionCollection::clearAssociatedWidgets()
278 foreach(QWidget *widget, _associatedWidgets)
279 foreach(QAction *action, actions())
280 widget->removeAction(action);
282 _associatedWidgets.clear();
286 void ActionCollection::associatedWidgetDestroyed(QObject *obj)
288 _associatedWidgets.removeAll(static_cast<QWidget *>(obj));
292 bool ActionCollection::unlistAction(QAction *action)
294 // This might be called with a partly destroyed QAction!
296 int index = _actions.indexOf(action);
297 if (index == -1) return false;
299 QString name = action->objectName();
300 _actionByName.remove(name);
301 _actions.removeAt(index);
303 // TODO: remove from ActionCategory if we ever get that
309 #endif /* HAVE_KDE */