1 /* This file is part of the KDE project
2 Copyright (C) 2004 Jarosław Staniek <staniek@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "kexisharedactionhost.h"
21 #include "kexisharedactionhost_p.h"
22 #include "kexiactionproxy.h"
23 #include "KexiWindow.h"
24 #include "KexiMainWindowIface.h"
25
26 #include <kexiutils/utils.h>
27 #include <kexi_global.h>
28
29 #include <KGuiItem>
30 #include <KToggleAction>
31 #include <KActionMenu>
32 #include <KActionCollection>
33
34 #include <QApplication>
35 #include <QIcon>
36 #include <QDebug>
37
KexiSharedActionHostPrivate(KexiSharedActionHost * h)38 KexiSharedActionHostPrivate::KexiSharedActionHostPrivate(KexiSharedActionHost *h)
39 : QObject()
40 , actionMapper(this)
41 , host(h)
42 {
43 setObjectName("KexiSharedActionHostPrivate");
44 connect(&actionMapper, SIGNAL(mapped(QString)), this, SLOT(slotAction(QString)));
45 }
46
~KexiSharedActionHostPrivate()47 KexiSharedActionHostPrivate::~KexiSharedActionHostPrivate()
48 {
49 qDeleteAll(volatileActions);
50 volatileActions.clear();
51 }
52
slotAction(const QString & act_id)53 void KexiSharedActionHostPrivate::slotAction(const QString& act_id)
54 {
55 QWidget *w = host->focusWindow();
56 KexiActionProxy *proxy = w ? actionProxies.value(w) : 0;
57
58 if (!proxy || !proxy->activateSharedAction(act_id.toLatin1())) {
59 //also try to find previous enabler
60 w = enablers.contains(act_id) ? enablers.value(act_id) : 0;
61 if (!w)
62 return;
63 proxy = actionProxies.value(w);
64 if (!proxy)
65 return;
66 proxy->activateSharedAction(act_id.toLatin1());
67 }
68 }
69
70 //--------------------------------------------------
71
72 //! dummy host to avoid crashes
73 Q_GLOBAL_STATIC_WITH_ARGS(KexiSharedActionHost, KexiSharedActionHost_dummy, (0))
74
75 //! default host
76 KexiSharedActionHost* KexiSharedActionHost_defaultHost = 0;
77
defaultHost()78 KexiSharedActionHost* KexiSharedActionHost::defaultHost()
79 {
80 if (!KexiSharedActionHost_defaultHost)
81 return KexiSharedActionHost_dummy;
82 return KexiSharedActionHost_defaultHost;
83 }
84
setAsDefaultHost()85 void KexiSharedActionHost::setAsDefaultHost()
86 {
87 KexiSharedActionHost_defaultHost = this;
88 }
89
90 //--------------------------------------------------
91
KexiSharedActionHost(KexiMainWindowIface * mainWin)92 KexiSharedActionHost::KexiSharedActionHost(KexiMainWindowIface* mainWin)
93 : d(new KexiSharedActionHostPrivate(this))
94 {
95 d->mainWin = mainWin;
96 }
97
~KexiSharedActionHost()98 KexiSharedActionHost::~KexiSharedActionHost()
99 {
100 if (KexiSharedActionHost_defaultHost == this) {
101 KexiSharedActionHost_defaultHost = 0;
102 }
103 delete d;
104 d = 0; //! to let takeActionProxyFor() know that we are almost dead :)
105 }
106
setActionAvailable(const QString & action_name,bool avail)107 void KexiSharedActionHost::setActionAvailable(const QString& action_name, bool avail)
108 {
109 QAction *act = d->mainWin->actionCollection()->action(action_name);
110 if (act) {
111 act->setEnabled(avail);
112 }
113 }
114
updateActionAvailable(const QString & action_name,bool avail,QObject * obj)115 void KexiSharedActionHost::updateActionAvailable(const QString& action_name, bool avail, QObject *obj)
116 {
117 if (!d)
118 return; //sanity
119 QWidget *fw = d->mainWin->focusWidget();
120 while (fw && obj != fw)
121 fw = fw->parentWidget();
122 if (!fw)
123 return;
124
125 setActionAvailable(action_name, avail);
126 if (avail) {
127 d->enablers.insert(action_name, fw);
128 } else {
129 d->enablers.take(action_name);
130 }
131 }
132
plugActionProxy(KexiActionProxy * proxy)133 void KexiSharedActionHost::plugActionProxy(KexiActionProxy *proxy)
134 {
135 d->actionProxies.insert(proxy->receiver(), proxy);
136 }
137
mainWindow() const138 KexiMainWindowIface* KexiSharedActionHost::mainWindow() const
139 {
140 return d->mainWin;
141 }
142
invalidateSharedActions(QObject * o)143 void KexiSharedActionHost::invalidateSharedActions(QObject *o)
144 {
145 if (!d)
146 return;
147
148 KexiActionProxy *p = o ? d->actionProxies.value(o) : 0;
149 foreach(QAction * a, d->sharedActions) {
150 const bool avail = p && p->isAvailable(a->objectName());
151 KexiVolatileActionData *va = d->volatileActions.value(a);
152 if (va != 0) {
153 if (p && p->isSupported(a->objectName())) {
154 QList<QAction *> actions_list;
155 actions_list.append(a);
156 if (!va->plugged) {
157 va->plugged = true;
158 }
159 } else {
160 if (va->plugged) {
161 va->plugged = false;
162 }
163 }
164 }
165 a->setEnabled(avail);
166 //qDebug() << "Action " << a->name() << (avail ? " enabled." : " disabled.");
167 }
168 }
169
actionProxyFor(QObject * o) const170 KexiActionProxy* KexiSharedActionHost::actionProxyFor(QObject *o) const
171 {
172 return d->actionProxies.value(o);
173 }
174
takeActionProxyFor(QObject * o)175 KexiActionProxy* KexiSharedActionHost::takeActionProxyFor(QObject *o)
176 {
177 if (d)
178 return d->actionProxies.take(o);
179 return 0;
180 }
181
findWindow(QWidget *)182 QWidget* KexiSharedActionHost::findWindow(QWidget * /*w*/)
183 {
184 return 0;
185 }
186
focusWindow()187 QWidget* KexiSharedActionHost::focusWindow()
188 {
189 QWidget *aw = QApplication::activeWindow();
190 if (!aw)
191 aw = dynamic_cast<QWidget*>(d->mainWin);
192 QWidget *fw = aw->focusWidget();
193 return findWindow(fw);
194 }
195
createSharedActionInternal(QAction * action)196 QAction * KexiSharedActionHost::createSharedActionInternal(QAction *action)
197 {
198 QObject::connect(action, SIGNAL(triggered()), &d->actionMapper, SLOT(map()));
199 d->actionMapper.setMapping(action, action->objectName());
200 d->sharedActions.append(action);
201 return action;
202 }
203
sharedActions() const204 QList<QAction *> KexiSharedActionHost::sharedActions() const
205 {
206 return d->sharedActions;
207 }
208
createSharedAction(const QString & text,const QString & iconName,const QKeySequence & cut,const char * name,KActionCollection * col,const char * subclassName)209 QAction * KexiSharedActionHost::createSharedAction(const QString &text, const QString &iconName,
210 const QKeySequence &cut, const char *name, KActionCollection* col, const char *subclassName)
211 {
212 if (!col)
213 col = d->mainWin->actionCollection();
214
215 if (subclassName == 0) {
216 QAction *action = new QAction(QIcon::fromTheme(iconName), text, col);
217 action->setObjectName(name);
218 action->setShortcut(cut);
219 col->addAction(name, action);
220 return createSharedActionInternal(action);
221 } else if (qstricmp(subclassName, "KToggleAction") == 0) {
222 KToggleAction *action = new KToggleAction(QIcon::fromTheme(iconName), text, col);
223 action->setObjectName(name);
224 action->setShortcut(cut);
225 col->addAction(name, action);
226 return createSharedActionInternal(action);
227 } else if (qstricmp(subclassName, "KActionMenu") == 0) {
228 KActionMenu *action = new KActionMenu(QIcon::fromTheme(iconName), text, col);
229 action->setObjectName(name);
230 action->setShortcut(cut);
231 col->addAction(name, action);
232 return createSharedActionInternal(action);
233 }
234 //! @todo more QAction subclasses
235 return 0;
236 }
237
createSharedAction(KStandardAction::StandardAction id,const char * name,KActionCollection * col)238 QAction * KexiSharedActionHost::createSharedAction(KStandardAction::StandardAction id,
239 const char *name, KActionCollection* col)
240 {
241 if (!col)
242 col = d->mainWin->actionCollection();
243
244 QAction * action = KStandardAction::create(id, 0/*receiver*/, 0/*slot*/, col);
245 if (name) {
246 action->setObjectName(name);
247 }
248 (void)createSharedActionInternal(action);
249 return action;
250 }
251
createSharedAction(const KGuiItem & guiItem,const QKeySequence & cut,const char * name,KActionCollection * col)252 QAction * KexiSharedActionHost::createSharedAction(const KGuiItem& guiItem, const QKeySequence &cut,
253 const char *name, KActionCollection* col)
254 {
255 if (!col)
256 col = d->mainWin->actionCollection();
257 QAction * action = new QAction(guiItem.icon(), guiItem.text(), col);
258 action->setObjectName(name);
259 action->setShortcut(cut);
260 action->setEnabled(guiItem.isEnabled());
261 //! @todo how to update enable/disable? is it needed anyway?
262 action->setToolTip(guiItem.toolTip());
263 action->setWhatsThis(guiItem.whatsThis());
264 return createSharedActionInternal(action);
265 }
266
setActionVolatile(QAction * a,bool set)267 void KexiSharedActionHost::setActionVolatile(QAction *a, bool set)
268 {
269 if (!set) {
270 d->volatileActions.remove(a);
271 delete a;
272 return;
273 }
274 if (d->volatileActions.value(a))
275 return;
276 d->volatileActions.insert(a, new KexiVolatileActionData());
277 }
278