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