/***************************************************************************
* 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 " ) . arg ( scriptpackagefile ) ) ;
KTar archive ( scriptpackagefile ) ;
if ( ! archive . open ( IO_ReadOnly ) ) {
KMessageBox : : sorry ( 0 , i18n ( " Could not read the package \" %1 \" . " ) . arg ( 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? " ) . arg ( 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 \" . " ) . arg ( destination ) ) ;
return false ;
}
}
krossdebug ( TQString ( " Copy script-package to destination directory: %1 " ) . arg ( 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 \" . " ) . arg ( scriptpackagepath ) ) ;
return false ;
}
reloadInstalledScripts ( ) ;
return true ;
}
bool ScriptGUIClient : : loadScriptConfigFile ( const TQString & scriptconfigfile )
{
krossdebug ( TQString ( " ScriptGUIClient::loadScriptConfig file=%1 " ) . arg ( scriptconfigfile ) ) ;
TQDomDocument domdoc ;
TQFile file ( scriptconfigfile ) ;
if ( ! file . open ( IO_ReadOnly ) ) {
krosswarning ( TQString ( " ScriptGUIClient::loadScriptConfig(): Failed to read scriptconfigfile: %1 " ) . arg ( scriptconfigfile ) ) ;
return false ;
}
bool ok = domdoc . setContent ( & file ) ;
file . close ( ) ;
if ( ! ok ) {
krosswarning ( TQString ( " ScriptGUIClient::loadScriptConfig(): Failed to parse scriptconfigfile: %1 " ) . arg ( 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... " ) . arg ( 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' " ) . arg ( 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 - > minimumSizeHint ( ) ) ) ;
dialog - > show ( ) ;
}
# include "scriptguiclient.moc"