lib

scriptguiclient.cpp

00001 /***************************************************************************
00002  * scriptguiclient.cpp
00003  * This file is part of the KDE project
00004  * copyright (C) 2005 by Sebastian Sauer (mail@dipe.org)
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  * You should have received a copy of the GNU Library General Public License
00015  * along with this program; see the file COPYING.  If not, write to
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  ***************************************************************************/
00019 
00020 #include "scriptguiclient.h"
00021 #include "manager.h"
00022 #include "../api/interpreter.h"
00023 #include "wdgscriptsmanager.h"
00024 
00025 #include <kapplication.h>
00026 #include <kpopupmenu.h>
00027 #include <kstandarddirs.h>
00028 #include <kmimetype.h>
00029 #include <kmessagebox.h>
00030 #include <kfiledialog.h>
00031 #include <klocale.h>
00032 #include <kurl.h>
00033 #include <ktar.h>
00034 #include <kstandarddirs.h>
00035 #include <kdebug.h>
00036 
00037 #include <kio/netaccess.h>
00038 
00039 using namespace Kross::Api;
00040 
00041 namespace Kross { namespace Api {
00042 
00044     class ScriptGUIClientPrivate
00045     {
00046         public:
00051             KXMLGUIClient* guiclient;
00052 
00056             QWidget* parent;
00057 
00062             QMap<QString, ScriptActionCollection*> collections;
00063     };
00064 
00065 }}
00066 
00067 ScriptGUIClient::ScriptGUIClient(KXMLGUIClient* guiclient, QWidget* parent)
00068     : QObject( parent )
00069     , KXMLGUIClient( guiclient )
00070     , d( new ScriptGUIClientPrivate() ) // initialize d-pointer class
00071 {
00072     kdDebug() << QString("ScriptGUIClient::ScriptGUIClient() Ctor") << endl;
00073 
00074     d->guiclient = guiclient;
00075     d->parent = parent;
00076 
00077     setInstance( ScriptGUIClient::instance() );
00078 
00079     // action to execute a scriptfile.
00080     new KAction(i18n("Execute Script File..."), 0, 0, this, SLOT(executeScriptFile()), actionCollection(), "executescriptfile");
00081 
00082     // acion to show the ScriptManagerGUI dialog.
00083     new KAction(i18n("Scripts Manager..."), 0, 0, this, SLOT(showScriptManager()), actionCollection(), "configurescripts");
00084 
00085     // The predefined ScriptActionCollection's this ScriptGUIClient provides.
00086     d->collections.replace("installedscripts",
00087         new ScriptActionCollection(i18n("Scripts"), actionCollection(), "installedscripts") );
00088     d->collections.replace("loadedscripts",
00089         new ScriptActionCollection(i18n("Loaded"), actionCollection(), "loadedscripts") );
00090     d->collections.replace("executedscripts",
00091         new ScriptActionCollection(i18n("History"), actionCollection(), "executedscripts") );
00092 
00093     reloadInstalledScripts();
00094 }
00095 
00096 ScriptGUIClient::~ScriptGUIClient()
00097 {
00098     kdDebug() << QString("ScriptGUIClient::~ScriptGUIClient() Dtor") << endl;
00099     for(QMap<QString, ScriptActionCollection*>::Iterator it = d->collections.begin(); it != d->collections.end(); ++it)
00100         delete it.data();
00101     delete d;
00102 }
00103 
00104 bool ScriptGUIClient::hasActionCollection(const QString& name)
00105 {
00106     return d->collections.contains(name);
00107 }
00108 
00109 ScriptActionCollection* ScriptGUIClient::getActionCollection(const QString& name)
00110 {
00111     return d->collections[name];
00112 }
00113 
00114 QMap<QString, ScriptActionCollection*> ScriptGUIClient::getActionCollections()
00115 {
00116     return d->collections;
00117 }
00118 
00119 void ScriptGUIClient::addActionCollection(const QString& name, ScriptActionCollection* collection)
00120 {
00121     removeActionCollection(name);
00122     d->collections.replace(name, collection);
00123 }
00124 
00125 bool ScriptGUIClient::removeActionCollection(const QString& name)
00126 {
00127     if(d->collections.contains(name)) {
00128         ScriptActionCollection* c = d->collections[name];
00129         d->collections.remove(name);
00130         delete c;
00131         return true;
00132     }
00133     return false;
00134 }
00135 
00136 void ScriptGUIClient::reloadInstalledScripts()
00137 {
00138     ScriptActionCollection* installedcollection = d->collections["installedscripts"];
00139     if(installedcollection)
00140         installedcollection->clear();
00141 
00142     QCString partname = d->guiclient->instance()->instanceName();
00143     QStringList files = KGlobal::dirs()->findAllResources("data", partname + "/scripts/*/*.rc");
00144     //files.sort();
00145     for(QStringList::iterator it = files.begin(); it != files.end(); ++it)
00146         loadScriptConfigFile(*it);
00147 }
00148 
00149 bool ScriptGUIClient::installScriptPackage(const QString& scriptpackagefile)
00150 {
00151     kdDebug() << QString("Install script package: %1").arg(scriptpackagefile) << endl;
00152     KTar archive( scriptpackagefile );
00153     if(! archive.open(IO_ReadOnly)) {
00154         KMessageBox::sorry(0, i18n("Could not read the package \"%1\".").arg(scriptpackagefile));
00155         return false;
00156     }
00157 
00158     QCString partname = d->guiclient->instance()->instanceName();
00159     QString destination = KGlobal::dirs()->saveLocation("data", partname + "/scripts/", true);
00160     //QString destination = KGlobal::dirs()->saveLocation("appdata", "scripts", true);
00161     if(destination.isNull()) {
00162         kdWarning() << "ScriptGUIClient::installScriptPackage() Failed to determinate location where the scriptpackage should be installed to!" << endl;
00163         return false;
00164     }
00165 
00166     QString packagename = QFileInfo(scriptpackagefile).baseName();
00167     destination += packagename; // add the packagename to the name of the destination-directory.
00168 
00169     if( QDir(destination).exists() ) {
00170         if( KMessageBox::warningContinueCancel(0,
00171             i18n("A script package with the name \"%1\" already exists. Replace this package?" ).arg(packagename),
00172             i18n("Replace")) != KMessageBox::Continue )
00173                 return false;
00174 
00175         if(! KIO::NetAccess::del(destination, 0) ) {
00176             KMessageBox::sorry(0, i18n("Could not uninstall this script package. You may not have sufficient permissions to delete the folder \"%1\".").arg(destination));
00177             return false;
00178         }
00179     }
00180 
00181     kdDebug() << QString("Copy script-package to destination directory: %1").arg(destination) << endl;
00182     const KArchiveDirectory* archivedir = archive.directory();
00183     archivedir->copyTo(destination, true);
00184 
00185     reloadInstalledScripts();
00186     return true;
00187 }
00188 
00189 bool ScriptGUIClient::uninstallScriptPackage(const QString& scriptpackagepath)
00190 {
00191     if(! KIO::NetAccess::del(scriptpackagepath, 0) ) {
00192         KMessageBox::sorry(0, i18n("Could not uninstall this script package. You may not have sufficient permissions to delete the folder \"%1\".").arg(scriptpackagepath));
00193         return false;
00194     }
00195     reloadInstalledScripts();
00196     return true;
00197 }
00198 
00199 bool ScriptGUIClient::loadScriptConfigFile(const QString& scriptconfigfile)
00200 {
00201     kdDebug() << "ScriptGUIClient::loadScriptConfig file=" << scriptconfigfile << endl;
00202 
00203     QDomDocument domdoc;
00204     QFile file(scriptconfigfile);
00205     if(! file.open(IO_ReadOnly)) {
00206         kdWarning() << "ScriptGUIClient::loadScriptConfig(): Failed to read scriptconfigfile: " << scriptconfigfile << endl;
00207         return false;
00208     }
00209     bool ok = domdoc.setContent(&file);
00210     file.close();
00211     if(! ok) {
00212         kdWarning() << "ScriptGUIClient::loadScriptConfig(): Failed to parse scriptconfigfile: " << scriptconfigfile << endl;
00213         return false;
00214     }
00215 
00216     return loadScriptConfigDocument(scriptconfigfile, domdoc);
00217 }
00218 
00219 bool ScriptGUIClient::loadScriptConfigDocument(const QString& scriptconfigfile, const QDomDocument &document)
00220 {
00221     ScriptActionCollection* installedcollection = d->collections["installedscripts"];
00222     QDomNodeList nodelist = document.elementsByTagName("ScriptAction");
00223     uint nodelistcount = nodelist.count();
00224     for(uint i = 0; i < nodelistcount; i++) {
00225         ScriptAction::Ptr action = new ScriptAction(scriptconfigfile, nodelist.item(i).toElement());
00226 
00227         if(installedcollection) {
00228             ScriptAction::Ptr otheraction = installedcollection->action( action->name() );
00229             if(otheraction) {
00230                 // There exists already an action with the same name. Use the versionnumber
00231                 // to see if one of them is newer and if that's the case display only
00232                 // the newer aka those with the highest version.
00233                 if(action->version() < otheraction->version() && action->version() >= 0) {
00234                     // Just don't do anything with the above created action. The
00235                     // shared pointer will take care of freeing the instance.
00236                     continue;
00237                 }
00238                 else if(action->version() > otheraction->version() && otheraction->version() >= 0) {
00239                     // The previously added scriptaction isn't up-to-date any
00240                     // longer. Remove it from the list of installed scripts.
00241                     otheraction->finalize();
00242                     installedcollection->detach(otheraction);
00243                     //otheraction->detachAll() //FIXME: why it crashes with detachAll() ?
00244                 }
00245                 else {
00246                     // else just print a warning and fall through (so, install the action
00247                     // and don't care any longer of the duplicated name)...
00248                     kdWarning() << QString("Kross::Api::ScriptGUIClient::loadScriptConfigDocument: There exists already a scriptaction with name \"%1\". Added anyway...").arg(action->name()) << endl;
00249                 }
00250             }
00251             installedcollection->attach( action );
00252         }
00253 
00254         connect(action.data(), SIGNAL( failed(const QString&, const QString&) ),
00255                 this, SLOT( executionFailed(const QString&, const QString&) ));
00256         connect(action.data(), SIGNAL( success() ),
00257                 this, SLOT( successfullyExecuted() ));
00258         connect(action.data(), SIGNAL( activated(const Kross::Api::ScriptAction*) ), SIGNAL( executionStarted(const Kross::Api::ScriptAction*)));
00259     }
00260     emit collectionChanged(installedcollection);
00261     return true;
00262 }
00263 
00264 void ScriptGUIClient::setXMLFile(const QString& file, bool merge, bool setXMLDoc)
00265 {
00266     KXMLGUIClient::setXMLFile(file, merge, setXMLDoc);
00267 }
00268 
00269 void ScriptGUIClient::setDOMDocument(const QDomDocument &document, bool merge)
00270 {
00271     ScriptActionCollection* installedcollection = d->collections["installedscripts"];
00272     if(! merge && installedcollection)
00273         installedcollection->clear();
00274 
00275     KXMLGUIClient::setDOMDocument(document, merge);
00276     loadScriptConfigDocument(xmlFile(), document);
00277 }
00278 
00279 void ScriptGUIClient::successfullyExecuted()
00280 {
00281     const ScriptAction* action = dynamic_cast< const ScriptAction* >( QObject::sender() );
00282     if(action) {
00283         emit executionFinished(action);
00284         ScriptActionCollection* executedcollection = d->collections["executedscripts"];
00285         if(executedcollection) {
00286             ScriptAction* actionptr = const_cast< ScriptAction* >( action );
00287             executedcollection->detach(actionptr);
00288             executedcollection->attach(actionptr);
00289             emit collectionChanged(executedcollection);
00290         }
00291     }
00292 }
00293 
00294 void ScriptGUIClient::executionFailed(const QString& errormessage, const QString& tracedetails)
00295 {
00296     const ScriptAction* action = dynamic_cast< const ScriptAction* >( QObject::sender() );
00297     if(action)
00298         emit executionFinished(action);
00299     if(tracedetails.isEmpty())
00300         KMessageBox::error(0, errormessage);
00301     else
00302         KMessageBox::detailedError(0, errormessage, tracedetails);
00303 }
00304 
00305 KURL ScriptGUIClient::openScriptFile(const QString& caption)
00306 {
00307     QStringList mimetypes;
00308     QMap<QString, InterpreterInfo*> infos = Manager::scriptManager()->getInterpreterInfos();
00309     for(QMap<QString, InterpreterInfo*>::Iterator it = infos.begin(); it != infos.end(); ++it)
00310         mimetypes.append( it.data()->getMimeTypes().join(" ").stripWhiteSpace() );
00311 
00312     KFileDialog* filedialog = new KFileDialog(
00313         QString::null, // startdir
00314         mimetypes.join(" "), // filter
00315         0, // parent widget
00316         "ScriptGUIClientFileDialog", // name
00317         true // modal
00318     );
00319     if(! caption.isNull())
00320         filedialog->setCaption(caption);
00321     if( filedialog->exec() )
00322         return filedialog->selectedURL();
00323     return KURL();
00324 }
00325 
00326 bool ScriptGUIClient::loadScriptFile()
00327 {
00328     KURL url = openScriptFile( i18n("Load Script File") );
00329     if(url.isValid()) {
00330         ScriptActionCollection* loadedcollection = d->collections["loadedscripts"];
00331         if(loadedcollection) {
00332             ScriptAction::Ptr action = new ScriptAction( url.path() );
00333             connect(action.data(), SIGNAL( failed(const QString&, const QString&) ),
00334                     this, SLOT( executionFailed(const QString&, const QString&) ));
00335             connect(action.data(), SIGNAL( success() ),
00336                     this, SLOT( successfullyExecuted() ));
00337             connect(action.data(), SIGNAL( activated(const Kross::Api::ScriptAction*) ), SIGNAL( executionStarted(const Kross::Api::ScriptAction*)));
00338 
00339             loadedcollection->detach(action);
00340             loadedcollection->attach(action);
00341             return true;
00342         }
00343     }
00344     return false;
00345 }
00346 
00347 bool ScriptGUIClient::executeScriptFile()
00348 {
00349     KURL url = openScriptFile( i18n("Execute Script File") );
00350     if(url.isValid())
00351         return executeScriptFile( url.path() );
00352     return false;
00353 }
00354 
00355 bool ScriptGUIClient::executeScriptFile(const QString& file)
00356 {
00357     kdDebug() << QString("Kross::Api::ScriptGUIClient::executeScriptFile() file='%1'").arg(file) << endl;
00358 
00359     ScriptAction::Ptr action = new ScriptAction(file);
00360     return executeScriptAction(action);
00361 }
00362 
00363 bool ScriptGUIClient::executeScriptAction(ScriptAction::Ptr action)
00364 {
00365     connect(action.data(), SIGNAL( failed(const QString&, const QString&) ),
00366             this, SLOT( executionFailed(const QString&, const QString&) ));
00367     connect(action.data(), SIGNAL( success() ),
00368             this, SLOT( successfullyExecuted() ));
00369     connect(action.data(), SIGNAL( activated(const Kross::Api::ScriptAction*) ), SIGNAL( executionStarted(const Kross::Api::ScriptAction*)));
00370     action->activate();
00371     bool ok = action->hadException();
00372     action->finalize(); // execution is done.
00373     return ok;
00374 }
00375 
00376 void ScriptGUIClient::showScriptManager()
00377 {
00378     KDialogBase* dialog = new KDialogBase(d->parent, "", true, i18n("Scripts Manager"), KDialogBase::Close);
00379     WdgScriptsManager* wsm = new WdgScriptsManager(this, dialog);
00380     dialog->setMainWidget(wsm);
00381     dialog->resize( QSize(360, 320).expandedTo(dialog->minimumSizeHint()) );
00382     dialog->show();
00383 }
00384 
00385 #include "scriptguiclient.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys