File indexing completed on 2024-05-12 16:39:41

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 Jarosław Staniek <staniek@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "kexisharedactionhost.h"
0021 #include "kexisharedactionhost_p.h"
0022 #include "kexiactionproxy.h"
0023 #include "KexiWindow.h"
0024 #include "KexiMainWindowIface.h"
0025 
0026 #include <kexiutils/utils.h>
0027 #include <kexi_global.h>
0028 
0029 #include <KGuiItem>
0030 #include <KToggleAction>
0031 #include <KActionMenu>
0032 #include <KActionCollection>
0033 
0034 #include <QApplication>
0035 #include <QIcon>
0036 #include <QDebug>
0037 
0038 KexiSharedActionHostPrivate::KexiSharedActionHostPrivate(KexiSharedActionHost *h)
0039         : QObject()
0040         , actionMapper(this)
0041         , host(h)
0042 {
0043     setObjectName("KexiSharedActionHostPrivate");
0044     connect(&actionMapper, SIGNAL(mapped(QString)), this, SLOT(slotAction(QString)));
0045 }
0046 
0047 KexiSharedActionHostPrivate::~KexiSharedActionHostPrivate()
0048 {
0049     qDeleteAll(volatileActions);
0050     volatileActions.clear();
0051 }
0052 
0053 void KexiSharedActionHostPrivate::slotAction(const QString& act_id)
0054 {
0055     QWidget *w = host->focusWindow();
0056     KexiActionProxy *proxy = w ? actionProxies.value(w) : 0;
0057 
0058     if (!proxy || !proxy->activateSharedAction(act_id.toLatin1())) {
0059         //also try to find previous enabler
0060         w = enablers.contains(act_id) ? enablers.value(act_id) : 0;
0061         if (!w)
0062             return;
0063         proxy = actionProxies.value(w);
0064         if (!proxy)
0065             return;
0066         proxy->activateSharedAction(act_id.toLatin1());
0067     }
0068 }
0069 
0070 //--------------------------------------------------
0071 
0072 //! dummy host to avoid crashes
0073 Q_GLOBAL_STATIC_WITH_ARGS(KexiSharedActionHost, KexiSharedActionHost_dummy, (0))
0074 
0075 //! default host
0076 KexiSharedActionHost* KexiSharedActionHost_defaultHost = 0;
0077 
0078 KexiSharedActionHost* KexiSharedActionHost::defaultHost()
0079 {
0080     if (!KexiSharedActionHost_defaultHost)
0081         return KexiSharedActionHost_dummy;
0082     return KexiSharedActionHost_defaultHost;
0083 }
0084 
0085 void KexiSharedActionHost::setAsDefaultHost()
0086 {
0087     KexiSharedActionHost_defaultHost = this;
0088 }
0089 
0090 //--------------------------------------------------
0091 
0092 KexiSharedActionHost::KexiSharedActionHost(KexiMainWindowIface* mainWin)
0093         : d(new KexiSharedActionHostPrivate(this))
0094 {
0095     d->mainWin = mainWin;
0096 }
0097 
0098 KexiSharedActionHost::~KexiSharedActionHost()
0099 {
0100     if (KexiSharedActionHost_defaultHost == this) {
0101         KexiSharedActionHost_defaultHost = 0;
0102     }
0103     delete d;
0104     d = 0; //! to let takeActionProxyFor() know that we are almost dead :)
0105 }
0106 
0107 void KexiSharedActionHost::setActionAvailable(const QString& action_name, bool avail)
0108 {
0109     QAction *act = d->mainWin->actionCollection()->action(action_name);
0110     if (act) {
0111         act->setEnabled(avail);
0112     }
0113 }
0114 
0115 void KexiSharedActionHost::updateActionAvailable(const QString& action_name, bool avail, QObject *obj)
0116 {
0117     if (!d)
0118         return; //sanity
0119     QWidget *fw = d->mainWin->focusWidget();
0120     while (fw && obj != fw)
0121         fw = fw->parentWidget();
0122     if (!fw)
0123         return;
0124 
0125     setActionAvailable(action_name, avail);
0126     if (avail) {
0127         d->enablers.insert(action_name, fw);
0128     } else {
0129         d->enablers.take(action_name);
0130     }
0131 }
0132 
0133 void KexiSharedActionHost::plugActionProxy(KexiActionProxy *proxy)
0134 {
0135     d->actionProxies.insert(proxy->receiver(), proxy);
0136 }
0137 
0138 KexiMainWindowIface* KexiSharedActionHost::mainWindow() const
0139 {
0140     return d->mainWin;
0141 }
0142 
0143 void KexiSharedActionHost::invalidateSharedActions(QObject *o)
0144 {
0145     if (!d)
0146         return;
0147 
0148     KexiActionProxy *p = o ? d->actionProxies.value(o) : 0;
0149     foreach(QAction * a, d->sharedActions) {
0150         const bool avail = p && p->isAvailable(a->objectName());
0151         KexiVolatileActionData *va = d->volatileActions.value(a);
0152         if (va != 0) {
0153             if (p && p->isSupported(a->objectName())) {
0154                 QList<QAction *> actions_list;
0155                 actions_list.append(a);
0156                 if (!va->plugged) {
0157                     va->plugged = true;
0158                 }
0159             } else {
0160                 if (va->plugged) {
0161                     va->plugged = false;
0162                 }
0163             }
0164         }
0165         a->setEnabled(avail);
0166   //qDebug() << "Action " << a->name() << (avail ? " enabled." : " disabled.");
0167     }
0168 }
0169 
0170 KexiActionProxy* KexiSharedActionHost::actionProxyFor(QObject *o) const
0171 {
0172     return d->actionProxies.value(o);
0173 }
0174 
0175 KexiActionProxy* KexiSharedActionHost::takeActionProxyFor(QObject *o)
0176 {
0177     if (d)
0178         return d->actionProxies.take(o);
0179     return 0;
0180 }
0181 
0182 QWidget* KexiSharedActionHost::findWindow(QWidget * /*w*/)
0183 {
0184     return 0;
0185 }
0186 
0187 QWidget* KexiSharedActionHost::focusWindow()
0188 {
0189     QWidget *aw = QApplication::activeWindow();
0190     if (!aw)
0191         aw = dynamic_cast<QWidget*>(d->mainWin);
0192     QWidget *fw = aw->focusWidget();
0193     return findWindow(fw);
0194 }
0195 
0196 QAction * KexiSharedActionHost::createSharedActionInternal(QAction *action)
0197 {
0198     QObject::connect(action, SIGNAL(triggered()), &d->actionMapper, SLOT(map()));
0199     d->actionMapper.setMapping(action, action->objectName());
0200     d->sharedActions.append(action);
0201     return action;
0202 }
0203 
0204 QList<QAction *> KexiSharedActionHost::sharedActions() const
0205 {
0206     return d->sharedActions;
0207 }
0208 
0209 QAction * KexiSharedActionHost::createSharedAction(const QString &text, const QString &iconName,
0210         const QKeySequence &cut, const char *name, KActionCollection* col, const char *subclassName)
0211 {
0212     if (!col)
0213         col = d->mainWin->actionCollection();
0214 
0215     if (subclassName == 0) {
0216         QAction *action = new QAction(QIcon::fromTheme(iconName), text, col);
0217         action->setObjectName(name);
0218         action->setShortcut(cut);
0219         col->addAction(name, action);
0220         return createSharedActionInternal(action);
0221     } else if (qstricmp(subclassName, "KToggleAction") == 0) {
0222         KToggleAction *action = new KToggleAction(QIcon::fromTheme(iconName), text, col);
0223         action->setObjectName(name);
0224         action->setShortcut(cut);
0225         col->addAction(name, action);
0226         return createSharedActionInternal(action);
0227     } else if (qstricmp(subclassName, "KActionMenu") == 0) {
0228         KActionMenu *action = new KActionMenu(QIcon::fromTheme(iconName), text, col);
0229         action->setObjectName(name);
0230         action->setShortcut(cut);
0231         col->addAction(name, action);
0232         return createSharedActionInternal(action);
0233     }
0234     //! @todo more QAction subclasses
0235     return 0;
0236 }
0237 
0238 QAction * KexiSharedActionHost::createSharedAction(KStandardAction::StandardAction id,
0239         const char *name, KActionCollection* col)
0240 {
0241     if (!col)
0242         col = d->mainWin->actionCollection();
0243 
0244     QAction * action = KStandardAction::create(id, 0/*receiver*/, 0/*slot*/, col);
0245     if (name) {
0246         action->setObjectName(name);
0247     }
0248     (void)createSharedActionInternal(action);
0249     return action;
0250 }
0251 
0252 QAction * KexiSharedActionHost::createSharedAction(const KGuiItem& guiItem, const QKeySequence &cut,
0253         const char *name, KActionCollection* col)
0254 {
0255     if (!col)
0256         col = d->mainWin->actionCollection();
0257     QAction * action = new QAction(guiItem.icon(), guiItem.text(), col);
0258     action->setObjectName(name);
0259     action->setShortcut(cut);
0260     action->setEnabled(guiItem.isEnabled());
0261     //! @todo how to update enable/disable? is it needed anyway?
0262     action->setToolTip(guiItem.toolTip());
0263     action->setWhatsThis(guiItem.whatsThis());
0264     return createSharedActionInternal(action);
0265 }
0266 
0267 void KexiSharedActionHost::setActionVolatile(QAction *a, bool set)
0268 {
0269     if (!set) {
0270         d->volatileActions.remove(a);
0271         delete a;
0272         return;
0273     }
0274     if (d->volatileActions.value(a))
0275         return;
0276     d->volatileActions.insert(a, new KexiVolatileActionData());
0277 }