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