Warning, file /office/calligra/libs/kross/KoScriptingPart.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /***************************************************************************
0002  * KoScriptingPart.cpp
0003  * This file is part of the KDE project
0004  * copyright (C) 2006-2007 Sebastian Sauer <mail@dipe.org>
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this program; see the file COPYING.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  ***************************************************************************/
0021 
0022 #include "KoScriptingPart.h"
0023 
0024 #include "KoScriptingModule.h"
0025 #include "KoScriptManager.h"
0026 #include "KoScriptingDocker.h"
0027 #include "KoKrossDebug.h"
0028 // calligra
0029 #include <KoView.h>
0030 #include <KoMainWindow.h>
0031 // KF5
0032 #include <kactioncollection.h>
0033 #include <klocalizedstring.h>
0034 #include <kactionmenu.h>
0035 #include <kmessagebox.h>
0036 #include <kross/core/manager.h>
0037 #include <kross/core/interpreter.h>
0038 #include <kross/core/actioncollection.h>
0039 // Qt
0040 #include <QApplication>
0041 #include <QStandardPaths>
0042 #include <QDirIterator>
0043 #include <QMenu>
0044 #include <QFileDialog>
0045 
0046 
0047 /// \internal d-pointer class.
0048 class Q_DECL_HIDDEN KoScriptingPart::Private
0049 {
0050 public:
0051     /**
0052     * The \a KoScriptingModule instance that provides the base class for
0053     * Kross module functionality for Calligra applications.
0054     */
0055     QPointer<KoScriptingModule> module;
0056 
0057     /**
0058     * The \a KActionMenu instance that provides a menu of all enabled
0059     * collections and there actions as tree.
0060     */
0061     KActionMenu *scriptsmenu;
0062 
0063     /**
0064     * The list of \a Kross::Action instances this \a KoScriptingPart instance
0065     * owns. Each action is executed within a specific part instance where
0066     * each part has exactly one \a KoView instance. That way we are able to bind
0067     * a script explicit to a specific view.
0068     */
0069     QList<Kross::Action*> actions;
0070 };
0071 
0072 KoScriptingPart::KoScriptingPart(KoScriptingModule *const module)
0073     : d(new Private())
0074 {
0075     d->module = module;
0076     Q_ASSERT(d->module);
0077 
0078     QAction *execAction  = new QAction(i18n("Execute Script File..."), this);
0079     actionCollection()->addAction("executescriptfile", execAction);
0080     connect(execAction, SIGNAL(triggered(bool)), this, SLOT(slotShowExecuteScriptFile()));
0081 
0082     d->scriptsmenu = new KActionMenu(i18n("Scripts"), this);
0083     actionCollection()->addAction("scripts", d->scriptsmenu);
0084     connect(d->scriptsmenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotMenuAboutToShow()));
0085 
0086     QAction *manageraction  = new QAction(i18n("Script Manager..."), this);
0087     actionCollection()->addAction("scriptmanager", manageraction);
0088     connect(manageraction, SIGNAL(triggered(bool)), this, SLOT(slotShowScriptManager()));
0089 
0090     connect(&Kross::Manager::self(), SIGNAL(started(Kross::Action*)), this, SLOT(slotStarted(Kross::Action*)));
0091     //connect(&Kross::Manager::self(), SIGNAL(finished(Kross::Action*)), this, SLOT(slotFinished(Kross::Action*)));
0092 
0093     if (Kross::Manager::self().property("configfile") == QVariant::Invalid) {
0094         QString file = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QStringLiteral("/scripts/scripts.rc");
0095         QStringList files;
0096         const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::DataLocation, "scripts", QStandardPaths::LocateDirectory);
0097         foreach(const QString& dir, dirs) {
0098             QDirIterator it(dir, QStringList() << QStringLiteral("*.rc"));
0099             while (it.hasNext()) {
0100                 files.append(it.next());
0101             }
0102         }
0103 
0104         Kross::Manager::self().setProperty("configfile", file);
0105         Kross::Manager::self().setProperty("configfiles", files);
0106 
0107         if (QFileInfo(file).exists())
0108             Kross::Manager::self().actionCollection()->readXmlFile(file);
0109         else
0110             foreach(const QString &f, files)
0111                 Kross::Manager::self().actionCollection()->readXmlFile(f);
0112     }
0113 
0114     KoView *view = d->module->view();
0115     KoMainWindow *mainwindow = view ? view->mainWindow() : 0;
0116     if (mainwindow) {
0117         KoScriptingDockerFactory factory(mainwindow);
0118         mainwindow->createDockWidget(&factory);
0119     }
0120 
0121     if (view) {
0122         if (Kross::ActionCollection *c = Kross::Manager::self().actionCollection()->collection("docker")) {
0123             foreach (Kross::Action *a, c->actions()) {
0124                 if (! a->isEnabled())
0125                     continue;
0126                 a->addObject(d->module);
0127                 KoScriptingDockerFactory f(view, d->module, a);
0128                 if (mainwindow) mainwindow->createDockWidget(&f);
0129                 debugKoKross << "Adding scripting docker with id=" << f.id();
0130             }
0131         }
0132     }
0133 }
0134 
0135 KoScriptingPart::~KoScriptingPart()
0136 {
0137     foreach(Kross::Action *action, d->actions) {
0138         if (action)
0139             action->finalize();
0140     }
0141     delete d;
0142 }
0143 
0144 KoScriptingModule *KoScriptingPart::module() const
0145 {
0146     return d->module;
0147 }
0148 
0149 bool KoScriptingPart::showExecuteScriptFile()
0150 {
0151     QStringList mimetypes;
0152     foreach (const QString &interpretername, Kross::Manager::self().interpreters()) {
0153         Kross::InterpreterInfo *info = Kross::Manager::self().interpreterInfo(interpretername);
0154         Q_ASSERT(info);
0155         mimetypes.append(info->mimeTypes());
0156     }
0157     QFileDialog filedialog;
0158     //QT5TODO: QUrl("kfiledialog:///KrossExecuteScript"), // startdir
0159     filedialog.setMimeTypeFilters(mimetypes);
0160     filedialog.setWindowTitle(i18n("Execute Script File"));
0161     filedialog.setFileMode(QFileDialog::ExistingFile);
0162     if (filedialog.exec()) {
0163         Kross::Action action(this, "Execute Script File");
0164         action.addObject(d->module);
0165 
0166         action.setFile(filedialog.selectedUrls().at(0).path());
0167         action.trigger();
0168 
0169         return true;
0170     }
0171 
0172     return false;
0173 }
0174 
0175 void addMenu(QMenu *menu, Kross::ActionCollection *collection)
0176 {
0177     foreach (Kross::Action *a, collection->actions()) {
0178             if(a->isEnabled()) {
0179                 menu->addAction(a);
0180             }
0181         }
0182     foreach (const QString &collectionname, collection->collections()) {
0183         Kross::ActionCollection *c = collection->collection(collectionname);
0184         if (c->isEnabled())
0185             addMenu(menu->addMenu(c->text()), c);
0186     }
0187 }
0188 
0189 void KoScriptingPart::slotMenuAboutToShow()
0190 {
0191     d->scriptsmenu->menu()->clear();
0192     addMenu(d->scriptsmenu->menu(), Kross::Manager::self().actionCollection());
0193 }
0194 
0195 void KoScriptingPart::slotShowExecuteScriptFile()
0196 {
0197     showExecuteScriptFile();
0198 }
0199 
0200 void KoScriptingPart::slotShowScriptManager()
0201 {
0202     KoScriptManagerDialog *dialog = new KoScriptManagerDialog();
0203     dialog->exec();
0204     dialog->delayedDestruct();
0205 }
0206 
0207 void KoScriptingPart::slotStarted(Kross::Action *action)
0208 {
0209     debugKoKross << "action=" << action->objectName();
0210     KoMainWindow *mainwin = dynamic_cast<KoMainWindow*>(qApp->activeWindow());
0211     KoView *view = d->module ? d->module->view() : 0;
0212     if (view && mainwin && view->mainWindow() == mainwin && view == mainwin->rootView()) {
0213         action->addObject(d->module);
0214         d->actions.append(action);
0215         connect(action, SIGNAL(finished(Kross::Action*)), this, SLOT(slotFinished(Kross::Action*)));
0216         connect(action, SIGNAL(finalized(Kross::Action*)), this, SLOT(slotFinalized(Kross::Action*)));
0217         myStarted(action);
0218     }
0219 }
0220 
0221 void KoScriptingPart::slotFinished(Kross::Action *action)
0222 {
0223     debugKoKross <<"KoScriptingPart::slotFinished action=" << action->objectName();
0224     disconnect(action, SIGNAL(finished(Kross::Action*)), this, SLOT(slotFinished(Kross::Action*)));
0225     if (d->module && d->module == action->object(d->module->objectName())) {
0226         //d->view->document()->setModified(true);
0227         //QApplication::restoreOverrideCursor();
0228         KoView *view = d->module ? d->module->view() : 0;
0229         if (view && view->mainWindow() /* && view == view->mainWindow()->rootView() */) {
0230             if (action->hadError()) {
0231                 if (action->errorTrace().isNull())
0232                     KMessageBox::error(view, action->errorMessage());
0233                 else
0234                     KMessageBox::detailedError(view, action->errorMessage(), action->errorTrace());
0235             }
0236         }
0237         myFinished(action);
0238     }
0239 }
0240 
0241 void KoScriptingPart::slotFinalized(Kross::Action *action)
0242 {
0243     debugKoKross << "action=" << action->objectName();
0244     disconnect(action, SIGNAL(finalized(Kross::Action*)), this, SLOT(slotFinalized(Kross::Action*)));
0245     d->actions.removeAll(action);
0246     if (d->module && d->module == action->object(d->module->objectName())) {
0247         myFinalized(action);
0248     }
0249 }