Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
actioncollection.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 by the Quassel Project *
3  * devel@quassel-irc.org *
4  * *
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. *
9  * *
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. *
14  * *
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  ***************************************************************************/
22 
23 #ifndef HAVE_KDE
24 
25 #include <QAction>
26 #include <QDebug>
27 
28 #include "actioncollection.h"
29 
30 #include "action.h"
31 #include "uisettings.h"
32 
33 ActionCollection::ActionCollection(QObject *parent) : QObject(parent)
34 {
36 }
37 
38 
40 {
41 }
42 
43 
45 {
46  _actionByName.clear();
47  qDeleteAll(_actions);
48  _actions.clear();
49 }
50 
51 
52 QAction *ActionCollection::action(const QString &name) const
53 {
54  return _actionByName.value(name, 0);
55 }
56 
57 
58 QList<QAction *> ActionCollection::actions() const
59 {
60  return _actions;
61 }
62 
63 
64 Action *ActionCollection::addAction(const QString &name, Action *action)
65 {
66  QAction *act = addAction(name, static_cast<QAction *>(action));
67  Q_UNUSED(act);
68  Q_ASSERT(act == action);
69  return action;
70 }
71 
72 
73 Action *ActionCollection::addAction(const QString &name, const QObject *receiver, const char *member)
74 {
75  Action *a = new Action(this);
76  if (receiver && member)
77  connect(a, SIGNAL(triggered(bool)), receiver, member);
78  return addAction(name, a);
79 }
80 
81 
82 QAction *ActionCollection::addAction(const QString &name, QAction *action)
83 {
84  if (!action)
85  return action;
86 
87  const QString origName = action->objectName();
88  QString indexName = name;
89 
90  if (indexName.isEmpty())
91  indexName = action->objectName();
92  else
93  action->setObjectName(indexName);
94  if (indexName.isEmpty())
95  indexName = indexName.sprintf("unnamed-%p", (void *)action);
96 
97  // do we already have this action?
98  if (_actionByName.value(indexName, 0) == action)
99  return action;
100  // or maybe another action under this name?
101  if (QAction *oldAction = _actionByName.value(indexName))
102  takeAction(oldAction);
103 
104  // do we already have this action under a different name?
105  int oldIndex = _actions.indexOf(action);
106  if (oldIndex != -1) {
107  _actionByName.remove(origName);
108  _actions.removeAt(oldIndex);
109  }
110 
111  // add action
112  _actionByName.insert(indexName, action);
113  _actions.append(action);
114 
115  foreach(QWidget *widget, _associatedWidgets) {
116  widget->addAction(action);
117  }
118 
119  connect(action, SIGNAL(destroyed(QObject *)), SLOT(actionDestroyed(QObject *)));
120  if (_connectHovered)
121  connect(action, SIGNAL(hovered()), SLOT(slotActionHovered()));
122  if (_connectTriggered)
123  connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()));
124 
125  emit inserted(action);
126  return action;
127 }
128 
129 
130 void ActionCollection::removeAction(QAction *action)
131 {
132  delete takeAction(action);
133 }
134 
135 
136 QAction *ActionCollection::takeAction(QAction *action)
137 {
138  if (!unlistAction(action))
139  return 0;
140 
141  foreach(QWidget *widget, _associatedWidgets) {
142  widget->removeAction(action);
143  }
144 
145  action->disconnect(this);
146  return action;
147 }
148 
149 
151 {
153  QStringList savedShortcuts = s.savedShortcuts();
154 
155  foreach(const QString &name, _actionByName.keys()) {
156  if (!savedShortcuts.contains(name))
157  continue;
158  Action *action = qobject_cast<Action *>(_actionByName.value(name));
159  if (action)
160  action->setShortcut(s.loadShortcut(name), Action::ActiveShortcut);
161  }
162 }
163 
164 
166 {
168  foreach(const QString &name, _actionByName.keys()) {
169  Action *action = qobject_cast<Action *>(_actionByName.value(name));
170  if (!action)
171  continue;
172  if (!action->isShortcutConfigurable())
173  continue;
174  if (action->shortcut(Action::ActiveShortcut) == action->shortcut(Action::DefaultShortcut))
175  continue;
176  s.saveShortcut(name, action->shortcut(Action::ActiveShortcut));
177  }
178 }
179 
180 
182 {
183  QAction *action = qobject_cast<QAction *>(sender());
184  if (action)
185  emit actionTriggered(action);
186 }
187 
188 
190 {
191  QAction *action = qobject_cast<QAction *>(sender());
192  if (action)
193  emit actionHovered(action);
194 }
195 
196 
198 {
199  // remember that this is not an QAction anymore at this point
200  QAction *action = static_cast<QAction *>(obj);
201 
202  unlistAction(action);
203 }
204 
205 #if QT_VERSION >= 0x050000
206 void ActionCollection::connectNotify(const QMetaMethod &signal)
207 #else
208 void ActionCollection::connectNotify(const char *signal)
209 #endif
210 {
211  if (_connectHovered && _connectTriggered)
212  return;
213 
214 #if QT_VERSION >= 0x050000
215  if (QMetaMethod::fromSignal(&ActionCollection::actionHovered) == signal) {
216 #else
217  if (QMetaObject::normalizedSignature(SIGNAL(actionHovered(QAction *))) == signal) {
218 #endif
219  if (!_connectHovered) {
220  _connectHovered = true;
221  foreach(QAction* action, actions())
222  connect(action, SIGNAL(hovered()), SLOT(slotActionHovered()));
223  }
224  }
225 #if QT_VERSION >= 0x050000
226  else if (QMetaMethod::fromSignal(&ActionCollection::actionTriggered) == signal) {
227 #else
228  else if (QMetaObject::normalizedSignature(SIGNAL(actionTriggered(QAction *))) == signal) {
229 #endif
230  if (!_connectTriggered) {
231  _connectTriggered = true;
232  foreach(QAction* action, actions())
233  connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()));
234  }
235  }
236 
237  QObject::connectNotify(signal);
238 }
239 
240 
241 void ActionCollection::associateWidget(QWidget *widget) const
242 {
243  foreach(QAction *action, actions()) {
244  if (!widget->actions().contains(action))
245  widget->addAction(action);
246  }
247 }
248 
249 
251 {
252  if (!_associatedWidgets.contains(widget)) {
253  widget->addActions(actions());
254  _associatedWidgets.append(widget);
255  connect(widget, SIGNAL(destroyed(QObject *)), SLOT(associatedWidgetDestroyed(QObject *)));
256  }
257 }
258 
259 
261 {
262  foreach(QAction *action, actions())
263  widget->removeAction(action);
264  _associatedWidgets.removeAll(widget);
265  disconnect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(associatedWidgetDestroyed(QObject *)));
266 }
267 
268 
269 QList<QWidget *> ActionCollection::associatedWidgets() const
270 {
271  return _associatedWidgets;
272 }
273 
274 
276 {
277  foreach(QWidget *widget, _associatedWidgets)
278  foreach(QAction *action, actions())
279  widget->removeAction(action);
280 
281  _associatedWidgets.clear();
282 }
283 
284 
286 {
287  _associatedWidgets.removeAll(static_cast<QWidget *>(obj));
288 }
289 
290 
291 bool ActionCollection::unlistAction(QAction *action)
292 {
293  // This might be called with a partly destroyed QAction!
294 
295  int index = _actions.indexOf(action);
296  if (index == -1) return false;
297 
298  QString name = action->objectName();
299  _actionByName.remove(name);
300  _actions.removeAt(index);
301 
302  // TODO: remove from ActionCategory if we ever get that
303 
304  return true;
305 }
306 
307 
308 #endif /* HAVE_KDE */