You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kross/main/scriptguiclient.cpp

385 lines
15 KiB

/***************************************************************************
* scriptguiclient.cpp
* This file is part of the KDE project
* copyright (C) 2005 by Sebastian Sauer (mail@dipe.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
***************************************************************************/
#include "scriptguiclient.h"
#include "manager.h"
#include "../api/interpreter.h"
#include "wdgscriptsmanager.h"
#include <kapplication.h>
#include <kpopupmenu.h>
#include <kstandarddirs.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kurl.h>
#include <ktar.h>
#include <kstandarddirs.h>
#include <kio/netaccess.h>
using namespace Kross::Api;
namespace Kross { namespace Api {
/// @internal
class ScriptGUIClientPrivate
{
public:
/**
* The \a KXMLGUIClient that is parent of the \a ScriptGUIClient
* instance.
*/
KXMLGUIClient* guiclient;
/**
* The optional parent TQWidget widget.
*/
TQWidget* parent;
/**
* Map of \a ScriptActionCollection instances the \a ScriptGUIClient
* is attached to.
*/
TQMap<TQString, ScriptActionCollection*> collections;
};
}}
ScriptGUIClient::ScriptGUIClient(KXMLGUIClient* guiclient, TQWidget* parent)
: TQObject( parent )
, KXMLGUIClient( guiclient )
, d( new ScriptGUIClientPrivate() ) // initialize d-pointer class
{
krossdebug( TQString("ScriptGUIClient::ScriptGUIClient() Ctor") );
d->guiclient = guiclient;
d->parent = parent;
setInstance( ScriptGUIClient::instance() );
// action to execute a scriptfile.
new KAction(i18n("Execute Script File..."), 0, 0, this, TQT_SLOT(executeScriptFile()), actionCollection(), "executescriptfile");
// acion to show the ScriptManagerGUI dialog.
new KAction(i18n("Scripts Manager..."), 0, 0, this, TQT_SLOT(showScriptManager()), actionCollection(), "configurescripts");
// The predefined ScriptActionCollection's this ScriptGUIClient provides.
d->collections.replace("installedscripts",
new ScriptActionCollection(i18n("Scripts"), actionCollection(), "installedscripts") );
d->collections.replace("loadedscripts",
new ScriptActionCollection(i18n("Loaded"), actionCollection(), "loadedscripts") );
d->collections.replace("executedscripts",
new ScriptActionCollection(i18n("History"), actionCollection(), "executedscripts") );
reloadInstalledScripts();
}
ScriptGUIClient::~ScriptGUIClient()
{
krossdebug( TQString("ScriptGUIClient::~ScriptGUIClient() Dtor") );
for(TQMap<TQString, ScriptActionCollection*>::Iterator it = d->collections.begin(); it != d->collections.end(); ++it)
delete it.data();
delete d;
}
bool ScriptGUIClient::hasActionCollection(const TQString& name)
{
return d->collections.contains(name);
}
ScriptActionCollection* ScriptGUIClient::getActionCollection(const TQString& name)
{
return d->collections[name];
}
TQMap<TQString, ScriptActionCollection*> ScriptGUIClient::getActionCollections()
{
return d->collections;
}
void ScriptGUIClient::addActionCollection(const TQString& name, ScriptActionCollection* collection)
{
removeActionCollection(name);
d->collections.replace(name, collection);
}
bool ScriptGUIClient::removeActionCollection(const TQString& name)
{
if(d->collections.contains(name)) {
ScriptActionCollection* c = d->collections[name];
d->collections.remove(name);
delete c;
return true;
}
return false;
}
void ScriptGUIClient::reloadInstalledScripts()
{
ScriptActionCollection* installedcollection = d->collections["installedscripts"];
if(installedcollection)
installedcollection->clear();
TQCString partname = d->guiclient->instance()->instanceName();
TQStringList files = KGlobal::dirs()->findAllResources("data", partname + "/scripts/*/*.rc");
//files.sort();
for(TQStringList::iterator it = files.begin(); it != files.end(); ++it)
loadScriptConfigFile(*it);
}
bool ScriptGUIClient::installScriptPackage(const TQString& scriptpackagefile)
{
krossdebug( TQString("Install script package: %1").tqarg(scriptpackagefile) );
KTar archive( scriptpackagefile );
if(! archive.open(IO_ReadOnly)) {
KMessageBox::sorry(0, i18n("Could not read the package \"%1\".").tqarg(scriptpackagefile));
return false;
}
TQCString partname = d->guiclient->instance()->instanceName();
TQString destination = KGlobal::dirs()->saveLocation("data", partname + "/scripts/", true);
//TQString destination = KGlobal::dirs()->saveLocation("appdata", "scripts", true);
if(destination.isNull()) {
krosswarning("ScriptGUIClient::installScriptPackage() Failed to determinate location where the scriptpackage should be installed to!");
return false;
}
TQString packagename = TQFileInfo(scriptpackagefile).baseName();
destination += packagename; // add the packagename to the name of the destination-directory.
if( TQDir(destination).exists() ) {
if( KMessageBox::warningContinueCancel(0,
i18n("A script package with the name \"%1\" already exists. Replace this package?" ).tqarg(packagename),
i18n("Replace")) != KMessageBox::Continue )
return false;
if(! KIO::NetAccess::del(destination, 0) ) {
KMessageBox::sorry(0, i18n("Could not uninstall this script package. You may not have sufficient permissions to delete the folder \"%1\".").tqarg(destination));
return false;
}
}
krossdebug( TQString("Copy script-package to destination directory: %1").tqarg(destination) );
const KArchiveDirectory* archivedir = archive.directory();
archivedir->copyTo(destination, true);
reloadInstalledScripts();
return true;
}
bool ScriptGUIClient::uninstallScriptPackage(const TQString& scriptpackagepath)
{
if(! KIO::NetAccess::del(scriptpackagepath, 0) ) {
KMessageBox::sorry(0, i18n("Could not uninstall this script package. You may not have sufficient permissions to delete the folder \"%1\".").tqarg(scriptpackagepath));
return false;
}
reloadInstalledScripts();
return true;
}
bool ScriptGUIClient::loadScriptConfigFile(const TQString& scriptconfigfile)
{
krossdebug( TQString("ScriptGUIClient::loadScriptConfig file=%1").tqarg(scriptconfigfile) );
TQDomDocument domdoc;
TQFile file(scriptconfigfile);
if(! file.open(IO_ReadOnly)) {
krosswarning( TQString("ScriptGUIClient::loadScriptConfig(): Failed to read scriptconfigfile: %1").tqarg(scriptconfigfile) );
return false;
}
bool ok = domdoc.setContent(&file);
file.close();
if(! ok) {
krosswarning( TQString("ScriptGUIClient::loadScriptConfig(): Failed to parse scriptconfigfile: %1").tqarg(scriptconfigfile) );
return false;
}
return loadScriptConfigDocument(scriptconfigfile, domdoc);
}
bool ScriptGUIClient::loadScriptConfigDocument(const TQString& scriptconfigfile, const TQDomDocument &document)
{
ScriptActionCollection* installedcollection = d->collections["installedscripts"];
TQDomNodeList nodelist = document.elementsByTagName("ScriptAction");
uint nodelistcount = nodelist.count();
for(uint i = 0; i < nodelistcount; i++) {
ScriptAction::Ptr action = new ScriptAction(scriptconfigfile, nodelist.item(i).toElement());
if(installedcollection) {
ScriptAction::Ptr otheraction = installedcollection->action( action->name() );
if(otheraction) {
// There exists already an action with the same name. Use the versionnumber
// to see if one of them is newer and if that's the case display only
// the newer aka those with the highest version.
if(action->version() < otheraction->version() && action->version() >= 0) {
// Just don't do anything with the above created action. The
// shared pointer will take care of freeing the instance.
continue;
}
else if(action->version() > otheraction->version() && otheraction->version() >= 0) {
// The previously added scriptaction isn't up-to-date any
// longer. Remove it from the list of installed scripts.
otheraction->finalize();
installedcollection->detach(otheraction);
//otheraction->detachAll() //FIXME: why it crashes with detachAll() ?
}
else {
// else just print a warning and fall through (so, install the action
// and don't care any longer of the duplicated name)...
krosswarning( TQString("Kross::Api::ScriptGUIClient::loadScriptConfigDocument: There exists already a scriptaction with name \"%1\". Added anyway...").tqarg(action->name()) );
}
}
installedcollection->attach( action );
}
connect(action.data(), TQT_SIGNAL( failed(const TQString&, const TQString&) ),
this, TQT_SLOT( executionFailed(const TQString&, const TQString&) ));
connect(action.data(), TQT_SIGNAL( success() ),
this, TQT_SLOT( successfullyExecuted() ));
connect(action.data(), TQT_SIGNAL( activated(const Kross::Api::ScriptAction*) ), TQT_SIGNAL( executionStarted(const Kross::Api::ScriptAction*)));
}
emit collectionChanged(installedcollection);
return true;
}
void ScriptGUIClient::setXMLFile(const TQString& file, bool merge, bool setXMLDoc)
{
KXMLGUIClient::setXMLFile(file, merge, setXMLDoc);
}
void ScriptGUIClient::setDOMDocument(const TQDomDocument &document, bool merge)
{
ScriptActionCollection* installedcollection = d->collections["installedscripts"];
if(! merge && installedcollection)
installedcollection->clear();
KXMLGUIClient::setDOMDocument(document, merge);
loadScriptConfigDocument(xmlFile(), document);
}
void ScriptGUIClient::successfullyExecuted()
{
const ScriptAction* action = dynamic_cast< const ScriptAction* >( TQObject::sender() );
if(action) {
emit executionFinished(action);
ScriptActionCollection* executedcollection = d->collections["executedscripts"];
if(executedcollection) {
ScriptAction* actionptr = const_cast< ScriptAction* >( action );
executedcollection->detach(actionptr);
executedcollection->attach(actionptr);
emit collectionChanged(executedcollection);
}
}
}
void ScriptGUIClient::executionFailed(const TQString& errormessage, const TQString& tracedetails)
{
const ScriptAction* action = dynamic_cast< const ScriptAction* >( TQObject::sender() );
if(action)
emit executionFinished(action);
if(tracedetails.isEmpty())
KMessageBox::error(0, errormessage);
else
KMessageBox::detailedError(0, errormessage, tracedetails);
}
KURL ScriptGUIClient::openScriptFile(const TQString& caption)
{
TQStringList mimetypes;
TQMap<TQString, InterpreterInfo*> infos = Manager::scriptManager()->getInterpreterInfos();
for(TQMap<TQString, InterpreterInfo*>::Iterator it = infos.begin(); it != infos.end(); ++it)
mimetypes.append( it.data()->getMimeTypes().join(" ").stripWhiteSpace() );
KFileDialog* filedialog = new KFileDialog(
TQString(), // startdir
mimetypes.join(" "), // filter
0, // parent widget
"ScriptGUIClientFileDialog", // name
true // modal
);
if(! caption.isNull())
filedialog->setCaption(caption);
if( filedialog->exec() )
return filedialog->selectedURL();
return KURL();
}
bool ScriptGUIClient::loadScriptFile()
{
KURL url = openScriptFile( i18n("Load Script File") );
if(url.isValid()) {
ScriptActionCollection* loadedcollection = d->collections["loadedscripts"];
if(loadedcollection) {
ScriptAction::Ptr action = new ScriptAction( url.path() );
connect(action.data(), TQT_SIGNAL( failed(const TQString&, const TQString&) ),
this, TQT_SLOT( executionFailed(const TQString&, const TQString&) ));
connect(action.data(), TQT_SIGNAL( success() ),
this, TQT_SLOT( successfullyExecuted() ));
connect(action.data(), TQT_SIGNAL( activated(const Kross::Api::ScriptAction*) ), TQT_SIGNAL( executionStarted(const Kross::Api::ScriptAction*)));
loadedcollection->detach(action);
loadedcollection->attach(action);
return true;
}
}
return false;
}
bool ScriptGUIClient::executeScriptFile()
{
KURL url = openScriptFile( i18n("Execute Script File") );
if(url.isValid())
return executeScriptFile( url.path() );
return false;
}
bool ScriptGUIClient::executeScriptFile(const TQString& file)
{
krossdebug( TQString("Kross::Api::ScriptGUIClient::executeScriptFile() file='%1'").tqarg(file) );
ScriptAction::Ptr action = new ScriptAction(file);
return executeScriptAction(action);
}
bool ScriptGUIClient::executeScriptAction(ScriptAction::Ptr action)
{
connect(action.data(), TQT_SIGNAL( failed(const TQString&, const TQString&) ),
this, TQT_SLOT( executionFailed(const TQString&, const TQString&) ));
connect(action.data(), TQT_SIGNAL( success() ),
this, TQT_SLOT( successfullyExecuted() ));
connect(action.data(), TQT_SIGNAL( activated(const Kross::Api::ScriptAction*) ), TQT_SIGNAL( executionStarted(const Kross::Api::ScriptAction*)));
action->activate();
bool ok = action->hadException();
action->finalize(); // execution is done.
return ok;
}
void ScriptGUIClient::showScriptManager()
{
KDialogBase* dialog = new KDialogBase(d->parent, "", true, i18n("Scripts Manager"), KDialogBase::Close);
WdgScriptsManager* wsm = new WdgScriptsManager(this, dialog);
dialog->setMainWidget(wsm);
dialog->resize( TQSize(360, 320).expandedTo(dialog->tqminimumSizeHint()) );
dialog->show();
}
#include "scriptguiclient.moc"