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 void ActionCollection::clear()
42 _actionByName.clear();
48 QAction *ActionCollection::action(const QString &name) const
50 return _actionByName.value(name, 0);
54 QList<QAction *> ActionCollection::actions() const
60 Action *ActionCollection::addAction(const QString &name, Action *action)
62 QAction *act = addAction(name, static_cast<QAction *>(action));
64 Q_ASSERT(act == action);
69 Action *ActionCollection::addAction(const QString &name, const QObject *receiver, const char *member)
71 Action *a = new Action(this);
72 if (receiver && member)
73 connect(a, SIGNAL(triggered(bool)), receiver, member);
74 return addAction(name, a);
78 QAction *ActionCollection::addAction(const QString &name, QAction *action)
83 const QString origName = action->objectName();
84 QString indexName = name;
86 if (indexName.isEmpty())
87 indexName = action->objectName();
89 action->setObjectName(indexName);
90 if (indexName.isEmpty())
91 indexName = indexName.sprintf("unnamed-%p", (void *)action);
93 // do we already have this action?
94 if (_actionByName.value(indexName, 0) == action)
96 // or maybe another action under this name?
97 if (QAction *oldAction = _actionByName.value(indexName))
98 takeAction(oldAction);
100 // do we already have this action under a different name?
101 int oldIndex = _actions.indexOf(action);
102 if (oldIndex != -1) {
103 _actionByName.remove(origName);
104 _actions.removeAt(oldIndex);
108 _actionByName.insert(indexName, action);
109 _actions.append(action);
111 foreach(QWidget *widget, _associatedWidgets) {
112 widget->addAction(action);
115 connect(action, SIGNAL(destroyed(QObject *)), SLOT(actionDestroyed(QObject *)));
117 connect(action, SIGNAL(hovered()), SLOT(slotActionHovered()));
118 if (_connectTriggered)
119 connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()));
121 emit inserted(action);
126 void ActionCollection::removeAction(QAction *action)
128 delete takeAction(action);
132 QAction *ActionCollection::takeAction(QAction *action)
134 if (!unlistAction(action))
137 foreach(QWidget *widget, _associatedWidgets) {
138 widget->removeAction(action);
141 action->disconnect(this);
146 void ActionCollection::readSettings()
149 QStringList savedShortcuts = s.savedShortcuts();
151 foreach(const QString &name, _actionByName.keys()) {
152 if (!savedShortcuts.contains(name))
154 Action *action = qobject_cast<Action *>(_actionByName.value(name));
156 action->setShortcut(s.loadShortcut(name), Action::ActiveShortcut);
161 void ActionCollection::writeSettings() const
164 foreach(const QString &name, _actionByName.keys()) {
165 Action *action = qobject_cast<Action *>(_actionByName.value(name));
168 if (!action->isShortcutConfigurable())
170 if (action->shortcut(Action::ActiveShortcut) == action->shortcut(Action::DefaultShortcut))
172 s.saveShortcut(name, action->shortcut(Action::ActiveShortcut));
177 void ActionCollection::slotActionTriggered()
179 QAction *action = qobject_cast<QAction *>(sender());
181 emit actionTriggered(action);
185 void ActionCollection::slotActionHovered()
187 QAction *action = qobject_cast<QAction *>(sender());
189 emit actionHovered(action);
193 void ActionCollection::actionDestroyed(QObject *obj)
195 // remember that this is not an QAction anymore at this point
196 QAction *action = static_cast<QAction *>(obj);
198 unlistAction(action);
201 void ActionCollection::connectNotify(const QMetaMethod &signal)
203 if (_connectHovered && _connectTriggered)
206 if (QMetaMethod::fromSignal(&ActionCollection::actionHovered) == signal) {
207 if (!_connectHovered) {
208 _connectHovered = true;
209 foreach(QAction* action, actions())
210 connect(action, SIGNAL(hovered()), SLOT(slotActionHovered()));
213 else if (QMetaMethod::fromSignal(&ActionCollection::actionTriggered) == signal) {
214 if (!_connectTriggered) {
215 _connectTriggered = true;
216 foreach(QAction* action, actions())
217 connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()));
221 QObject::connectNotify(signal);
225 void ActionCollection::associateWidget(QWidget *widget) const
227 foreach(QAction *action, actions()) {
228 if (!widget->actions().contains(action))
229 widget->addAction(action);
234 void ActionCollection::addAssociatedWidget(QWidget *widget)
236 if (!_associatedWidgets.contains(widget)) {
237 widget->addActions(actions());
238 _associatedWidgets.append(widget);
239 connect(widget, SIGNAL(destroyed(QObject *)), SLOT(associatedWidgetDestroyed(QObject *)));
244 void ActionCollection::removeAssociatedWidget(QWidget *widget)
246 foreach(QAction *action, actions())
247 widget->removeAction(action);
248 _associatedWidgets.removeAll(widget);
249 disconnect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(associatedWidgetDestroyed(QObject *)));
253 QList<QWidget *> ActionCollection::associatedWidgets() const
255 return _associatedWidgets;
259 void ActionCollection::clearAssociatedWidgets()
261 foreach(QWidget *widget, _associatedWidgets)
262 foreach(QAction *action, actions())
263 widget->removeAction(action);
265 _associatedWidgets.clear();
269 void ActionCollection::associatedWidgetDestroyed(QObject *obj)
271 _associatedWidgets.removeAll(static_cast<QWidget *>(obj));
275 bool ActionCollection::unlistAction(QAction *action)
277 // This might be called with a partly destroyed QAction!
279 int index = _actions.indexOf(action);
280 if (index == -1) return false;
282 QString name = action->objectName();
283 _actionByName.remove(name);
284 _actions.removeAt(index);
286 // TODO: remove from ActionCategory if we ever get that
292 #endif /* HAVE_KDE */