diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /lib/kross/main | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/kross/main')
-rw-r--r-- | lib/kross/main/Makefile.am | 33 | ||||
-rw-r--r-- | lib/kross/main/krossconfig.cpp | 36 | ||||
-rw-r--r-- | lib/kross/main/krossconfig.h | 116 | ||||
-rw-r--r-- | lib/kross/main/mainmodule.cpp | 117 | ||||
-rw-r--r-- | lib/kross/main/mainmodule.h | 181 | ||||
-rw-r--r-- | lib/kross/main/manager.cpp | 248 | ||||
-rw-r--r-- | lib/kross/main/manager.h | 168 | ||||
-rw-r--r-- | lib/kross/main/scriptaction.cpp | 247 | ||||
-rw-r--r-- | lib/kross/main/scriptaction.h | 309 | ||||
-rw-r--r-- | lib/kross/main/scriptcontainer.cpp | 293 | ||||
-rw-r--r-- | lib/kross/main/scriptcontainer.h | 210 | ||||
-rw-r--r-- | lib/kross/main/scriptguiclient.cpp | 384 | ||||
-rw-r--r-- | lib/kross/main/scriptguiclient.h | 217 | ||||
-rw-r--r-- | lib/kross/main/wdgscriptsmanager.cpp | 354 | ||||
-rw-r--r-- | lib/kross/main/wdgscriptsmanager.h | 60 | ||||
-rw-r--r-- | lib/kross/main/wdgscriptsmanagerbase.ui | 247 |
16 files changed, 3220 insertions, 0 deletions
diff --git a/lib/kross/main/Makefile.am b/lib/kross/main/Makefile.am new file mode 100644 index 00000000..0ab90117 --- /dev/null +++ b/lib/kross/main/Makefile.am @@ -0,0 +1,33 @@ +include $(top_srcdir)/lib/kross/Makefile.global + +lib_LTLIBRARIES = libkrossmain.la + +libkrossmain_la_SOURCES = krossconfig.cpp mainmodule.cpp scriptcontainer.cpp manager.cpp \ + scriptaction.cpp scriptguiclient.cpp wdgscriptsmanagerbase.ui wdgscriptsmanager.cpp + +libkrossmain_la_LDFLAGS = $(all_libraries) $(VER_INFO) -Wnounresolved + +mainincludedir=$(includedir)/kross/main + +maininclude_HEADERS = \ + krossconfig.h \ + mainmodule.h \ + manager.h \ + scriptaction.h \ + scriptcontainer.h \ + scriptguiclient.h \ + wdgscriptsmanager.h \ + wdgscriptsmanagerbase.h + +libkrossmain_la_LIBADD = \ + $(LIB_QT) \ + $(LIB_KDECORE) \ + $(LIB_KFILE) \ + $(LIB_KDEUI) \ + $(LIB_KNEWSTUFF) \ + $(LIB_KROSS_API) + +METASOURCES = AUTO +SUBDIRS = . +INCLUDES = $(KROSS_INCLUDES) $(all_includes) +noinst_HEADERS = wdgscriptsmanager.h diff --git a/lib/kross/main/krossconfig.cpp b/lib/kross/main/krossconfig.cpp new file mode 100644 index 00000000..61984532 --- /dev/null +++ b/lib/kross/main/krossconfig.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + * krossconfig.h + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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 "krossconfig.h" + +#ifdef KROSS_DEBUG_ENABLED + +#include <kdebug.h> + +void Kross::krossdebug(const QString &s) +{ + kdDebug() << "Kross: " << s << endl; +} + +void Kross::krosswarning(const QString &s) +{ + kdWarning() << "Kross: " << s << endl; +} + +#endif diff --git a/lib/kross/main/krossconfig.h b/lib/kross/main/krossconfig.h new file mode 100644 index 00000000..6b8bb25d --- /dev/null +++ b/lib/kross/main/krossconfig.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * krossconfig.h + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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. + ***************************************************************************/ + +#ifndef KROSS_MAIN_KROSSCONFIG_H +#define KROSS_MAIN_KROSSCONFIG_H + +#include <qstring.h> + +/** + * The Kross scripting bridge to embed scripting functionality + * into an application. + * + * - abstract API to access the scripting functionality. + * - interpreter independend to be able to decide on runtime + * if we like to use the python, kjs (KDE JavaScript) or + * whatever scripting interpreter. + * - flexibility by beeing able to connect different + * scripting interpreters together into something like + * a "working chain" (e.g. python-script script1 spends + * some functionality the kjs-script script2 likes to + * use. + * - transparently bridge functionality wrappers like + * \a Kross::KexiDB together with interpreters like \a Kross::Python. + * - Introspection where needed to be able to manipulate + * behaviours and functionality on runtime. + * - Qt/KDE based, so use the extended techs both spends. + * - integrate nicly as powerfull scripting system into the + * Kexi application. + * + * \author Sebastian Sauer + * \sa http://www.koffice.org/kexi + * \sa http://www.dipe.org/kross + */ +namespace Kross { + + /// Debugging enabled. + #define KROSS_DEBUG_ENABLED + + #ifdef KROSS_DEBUG_ENABLED + + /** + * Debugging function. + */ + void krossdebug(const QString &s); + + /** + * Warning function. + */ + void krosswarning(const QString &s); + + #else + // Define these to an empty statement if debugging is disabled. + #define krossdebug(x) + #define krosswarning(x) + #endif + + /** + * The common Kross API used as common codebase. + * + * The API spends \a Kross::Api::Object and more specialized + * classes to bridge other Kross parts together. Interaction + * between objects got wrapped at runtime and introspection- + * functionality enables dynamic manipulations. + * The proxy functionality prevents cross-dependencies + * between Kross parts like the \a Kross::Python implementation + * and the \a Kross::KexiDB wrapper. + * + * \author Sebastian Sauer + */ + namespace Api { + + //#define KROSS_API_OBJECT_CTOR_DEBUG + //#define KROSS_API_OBJECT_DTOR_DEBUG + //#define KROSS_API_OBJECT_ADDCHILD_DEBUG + //#define KROSS_API_OBJECT_REMCHILD_DEBUG + //#define KROSS_API_OBJECT_CALL_DEBUG + + //#define KROSS_API_EVENT_CALL_DEBUG + + //#define KROSS_API_CALLABLE_CALL_DEBUG + //#define KROSS_API_CALLABLE_CHECKARG_DEBUG + + //#define KROSS_API_EVENTSLOT_CALL_DEBUG + //#define KROSS_API_EVENTSIGNAL_CALL_DEBUG + + // The name of the interpreter's library. Those library got loaded + // dynamicly during runtime. Comment out to disable compiling of + // the interpreter-plugin or to hardcode the location of the lib + // like I did at the following line. + + //#define KROSS_PYTHON_LIBRARY "/home/snoopy/cvs/kde/trunk/koffice/lib/kross/python/krosspython.la" + #define KROSS_PYTHON_LIBRARY "krosspython" + #define KROSS_RUBY_LIBRARY "krossruby" + + } + +} + +#endif + diff --git a/lib/kross/main/mainmodule.cpp b/lib/kross/main/mainmodule.cpp new file mode 100644 index 00000000..0630e81a --- /dev/null +++ b/lib/kross/main/mainmodule.cpp @@ -0,0 +1,117 @@ +/*************************************************************************** + * mainmodule.cpp + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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 "mainmodule.h" + +using namespace Kross::Api; + +namespace Kross { namespace Api { + + /// \internal + class MainModulePrivate + { + public: + /** + * The \a Exception this \a MainModule throwed or + * NULL if we don't had an exception. + */ + Exception::Ptr exception; + }; + +}} + +MainModule::MainModule(const QString& name) + : Module(name) + , d(new MainModulePrivate()) +{ + d->exception = 0; +} + +MainModule::~MainModule() +{ + delete d; +} + +const QString MainModule::getClassName() const +{ + return "Kross::Api::MainModule"; +} + +bool MainModule::hadException() +{ + return d->exception != 0; +} + +Exception::Ptr MainModule::getException() +{ + return d->exception; +} + +void MainModule::setException(Exception::Ptr exception) +{ + d->exception = exception; +} + +#if 0 +bool MainModule::hasChild(const QString& name) const +{ + return Callable::hasChild(name); +} +#endif + +EventSignal::Ptr MainModule::addSignal(const QString& name, QObject* sender, QCString signal) +{ + EventSignal* event = new EventSignal(name, sender, signal); + if(! addChild(name, event)) { + krosswarning( QString("Failed to add signal name='%1' signature='%2'").arg(name).arg(signal) ); + return 0; + } + return event; +} + +EventSlot::Ptr MainModule::addSlot(const QString& name, QObject* receiver, QCString slot) +{ + EventSlot* event = new EventSlot(name, receiver, slot); + if(! addChild(name, event)) { + krosswarning( QString("Failed to add slot name='%1' signature='%2'").arg(name).arg(slot) ); + return 0; + } + return event; +} + +QtObject::Ptr MainModule::addQObject(QObject* object, const QString& name) +{ + QtObject* qtobject = new QtObject(object, name); + if(! addChild(name, qtobject)) { + krosswarning( QString("Failed to add QObject name='%1'").arg(object->name()) ); + return 0; + } + return qtobject; +} + +EventAction::Ptr MainModule::addKAction(KAction* action, const QString& name) +{ + EventAction* event = new EventAction(name, action); + if(! addChild(name, event)) { + krosswarning( QString("Failed to add KAction name='%1'").arg(action->name()) ); + return 0; + } + return event; +} + diff --git a/lib/kross/main/mainmodule.h b/lib/kross/main/mainmodule.h new file mode 100644 index 00000000..116e098d --- /dev/null +++ b/lib/kross/main/mainmodule.h @@ -0,0 +1,181 @@ +/*************************************************************************** + * mainmodule.h + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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. + ***************************************************************************/ + +#ifndef KROSS_API_MAINMODULE_H +#define KROSS_API_MAINMODULE_H + +#include "../api/object.h" +#include "../api/variant.h" +#include "../api/module.h" +#include "../api/event.h" +#include "../api/eventsignal.h" +#include "../api/eventslot.h" +#include "../api/qtobject.h" +#include "../api/eventaction.h" + +#include <qstring.h> +#include <qvariant.h> +#include <qobject.h> + +#include <ksharedptr.h> +#include <kaction.h> + +namespace Kross { namespace Api { + + // Forward declarations. + class MainModulePrivate; + + /** + * This class implements \a Module for the global + * \a Manager singleton and local \a ScriptContainer + * instances. + * + * The MainModule class provides base functionality + * for a root node in a tree of \a Kross::Api::Object + * instances. + */ + class MainModule : public Module + { + public: + + /// Shared pointer to implement reference-counting. + typedef KSharedPtr<MainModule> Ptr; + + /** + * Constructor. + * + * \param name the name of the \a Module . While the + * global manager module has the name "Kross" + * the \a ScriptContainer instances are accessible + * by there \a ScriptContainer::getName() name. + */ + explicit MainModule(const QString& name); + + /** + * Destructor. + */ + virtual ~MainModule(); + + /// \see Kross::Api::Object::getClassName() + virtual const QString getClassName() const; + + /** + * \return true if the script throwed an exception + * else false. + */ + bool hadException(); + + /** + * \return the \a Exception this module throwed. + */ + Exception::Ptr getException(); + + /** + * Set the \a Exception this module throwed. + * + * \param exception The \a Exception this module throws or + * NULL if you like to clear exception and to let + * \a hadException() return false. + */ + void setException(Exception::Ptr exception); + +#if 0 + /** + * Returns if the defined child is avaible. + * + * \return true if child exists else false. + */ + bool hasChild(const QString& name) const; +#endif + + /** + * Add a Qt signal to the \a Module by creating + * an \a EventSignal for it. + * + * \param name the name the \a EventSignal is + * reachable as + * \param sender the QObject instance which + * is the sender of the \p signal + * \param signal the Qt signal macro the \p sender + * emits to call the \a EventSignal + * \return the newly added \a EventSignal instance + * which is now a child of this \a MainModule + */ + EventSignal::Ptr addSignal(const QString& name, QObject* sender, QCString signal); + + /** + * Add a Qt slot to the \a Module by creating + * an \a EventSlot for it. + * + * \param name the name the \a EventSlot is + * reachable as + * \param receiver the QObject instance which + * is the receiver of the \p signal + * \param slot the Qt slot macro of the \p receiver + * to invoke if the \a EventSlot got called. + * \return the newly added \a EventSlot instance + * which is now a child of this \a MainModule + */ + EventSlot::Ptr addSlot(const QString& name, QObject* receiver, QCString slot); + + /** + * Add a \a QObject to the eventcollection. All + * signals and slots the QObject has will be + * added to a new \a EventCollection instance + * which is child of this \a EventCollection + * instance. + * + * \param object the QObject instance that should + * be added to this \a MainModule + * \param name the name under which this QObject instance + * should be registered as + * \return the newly added \a QtObject instance + * which is now a child of this \a MainModule + */ + QtObject::Ptr addQObject(QObject* object, const QString& name = QString::null); + + /** + * Add a \a KAction to the eventcollection. The + * KAction will be wrapped by a \a EventAction + * and will be added to this collection. + * + * \param name name to identify the \a action by + * \param action the KAction instance that should + * be added to this \a MainModule + * \return the newly added \a EventAction instance + * which is now a child of this \a MainModule + * + * \todo check \a name dox. + */ + EventAction::Ptr addKAction(KAction* action, const QString& name = QString::null); + + //typedef QValueList<Callable::Ptr> EventList; + //EventList getEvents(); + //const QString& serializeToXML(); + //void unserializeFromXML(const QString& xml); + + private: + /// Private d-pointer class. + MainModulePrivate* d; + }; + +}} + +#endif + diff --git a/lib/kross/main/manager.cpp b/lib/kross/main/manager.cpp new file mode 100644 index 00000000..cdb4d363 --- /dev/null +++ b/lib/kross/main/manager.cpp @@ -0,0 +1,248 @@ +/*************************************************************************** + * manager.cpp + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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 "manager.h" + +#include "../api/interpreter.h" +//#include "../api/qtobject.h" +#include "../api/eventslot.h" +#include "../api/eventsignal.h" +//#include "../api/script.h" + +#include "krossconfig.h" +#include "scriptcontainer.h" + +#include <qobject.h> +#include <qfile.h> +#include <qregexp.h> + +#include <klibloader.h> +#include <klocale.h> +#include <kstaticdeleter.h> + +extern "C" +{ + typedef Kross::Api::Object* (*def_module_func)(Kross::Api::Manager*); +} + +using namespace Kross::Api; + +namespace Kross { namespace Api { + + /// @internal + class ManagerPrivate + { + public: + /// List of \a InterpreterInfo instances. + QMap<QString, InterpreterInfo*> interpreterinfos; + + /// Loaded modules. + QMap<QString, Module::Ptr> modules; + }; + + /** + * The Manager-singleton instance is NULL by default till the + * Manager::scriptManager() method got called first time. + */ + static KSharedPtr<Manager> m_manager = KSharedPtr<Manager>(0); + +}} + +Manager* Manager::scriptManager() +{ + if(! m_manager.data()) { + // Create the Manager-singleton on demand. + m_manager = KSharedPtr<Manager>( new Manager() ); + } + + // and finally return the singleton. + return m_manager.data(); +} + +Manager::Manager() + : MainModule("Kross") // the manager has the name "Kross" + , d( new ManagerPrivate() ) +{ +#ifdef KROSS_PYTHON_LIBRARY + QString pythonlib = QFile::encodeName( KLibLoader::self()->findLibrary(KROSS_PYTHON_LIBRARY) ); + if(! pythonlib.isEmpty()) { // If the Kross Python plugin exists we offer it as supported scripting language. + InterpreterInfo::Option::Map pythonoptions; + pythonoptions.replace("restricted", + new InterpreterInfo::Option("Restricted", "Restricted Python interpreter", QVariant(false,0)) + ); + d->interpreterinfos.replace("python", + new InterpreterInfo("python", + pythonlib, // library + "*.py", // file filter-wildcard + QStringList() << /* "text/x-python" << */ "application/x-python", // mimetypes + pythonoptions // options + ) + ); + } +#endif +#ifdef KROSS_RUBY_LIBRARY + QString rubylib = QFile::encodeName( KLibLoader::self()->findLibrary(KROSS_RUBY_LIBRARY) ); + if(! rubylib.isEmpty()) { // If the Kross Ruby plugin exists we offer it as supported scripting language. + InterpreterInfo::Option::Map rubyoptions; + rubyoptions.replace("safelevel", + new InterpreterInfo::Option("safelevel", "Level of safety of the Ruby interpreter", QVariant(0)) // 0 -> unsafe, 4 -> very safe + ); + d->interpreterinfos.replace("ruby", + new InterpreterInfo("ruby", + rubylib, // library + "*.rb", // file filter-wildcard + QStringList() << /* "text/x-ruby" << */ "application/x-ruby", // mimetypes + rubyoptions // options + ) + ); + } else { + krossdebug("Ruby interpreter for kross in unavailable"); + } +#endif +} + +Manager::~Manager() +{ + for(QMap<QString, InterpreterInfo*>::Iterator it = d->interpreterinfos.begin(); it != d->interpreterinfos.end(); ++it) + delete it.data(); + delete d; +} + +QMap<QString, InterpreterInfo*> Manager::getInterpreterInfos() +{ + return d->interpreterinfos; +} + +bool Manager::hasInterpreterInfo(const QString& interpretername) const +{ + return d->interpreterinfos.contains(interpretername); +} + +InterpreterInfo* Manager::getInterpreterInfo(const QString& interpretername) +{ + return d->interpreterinfos[interpretername]; +} + +const QString Manager::getInterpreternameForFile(const QString& file) +{ + QRegExp rx; + rx.setWildcard(true); + for(QMap<QString, InterpreterInfo*>::Iterator it = d->interpreterinfos.begin(); it != d->interpreterinfos.end(); ++it) { + rx.setPattern((*it)->getWildcard()); + if( file.find(rx) >= 0 ) + return (*it)->getInterpretername(); + } + return QString::null; +} + +ScriptContainer::Ptr Manager::getScriptContainer(const QString& scriptname) +{ + //TODO at the moment we don't share ScriptContainer instances. + + //if(d->m_scriptcontainers.contains(scriptname)) + // return d->m_scriptcontainers[scriptname]; + ScriptContainer* scriptcontainer = new ScriptContainer(scriptname); + //ScriptContainer script(this, scriptname); + //d->m_scriptcontainers.replace(scriptname, scriptcontainer); + + return scriptcontainer; +} + +Interpreter* Manager::getInterpreter(const QString& interpretername) +{ + setException(0); // clear previous exceptions + + if(! d->interpreterinfos.contains(interpretername)) { + setException( new Exception(i18n("No such interpreter '%1'").arg(interpretername)) ); + return 0; + } + + return d->interpreterinfos[interpretername]->getInterpreter(); +} + +const QStringList Manager::getInterpreters() +{ + QStringList list; + + QMap<QString, InterpreterInfo*>::Iterator it( d->interpreterinfos.begin() ); + for(; it != d->interpreterinfos.end(); ++it) + list << it.key(); + +//list << "TestCase"; + + return list; +} + +bool Manager::addModule(Module::Ptr module) +{ + QString name = module->getName(); + //if( d->modules.contains(name) ) return false; + d->modules.replace(name, module); + return true; +} + +Module::Ptr Manager::loadModule(const QString& modulename) +{ + Module::Ptr module = 0; + + if(d->modules.contains(modulename)) { + module = d->modules[modulename]; + if(module) + return module; + else + krossdebug( QString("Manager::loadModule(%1) =======> Modulename registered, but module is invalid!").arg(modulename) ); + } + + KLibLoader* loader = KLibLoader::self(); + KLibrary* lib = loader->globalLibrary( modulename.latin1() ); + if(! lib) { + krosswarning( QString("Failed to load module '%1': %2").arg(modulename).arg(loader->lastErrorMessage()) ); + return 0; + } + krossdebug( QString("Successfully loaded module '%1'").arg(modulename) ); + + def_module_func func; + func = (def_module_func) lib->symbol("init_module"); + + if(! func) { + krosswarning( QString("Failed to determinate init function in module '%1'").arg(modulename) ); + return 0; + } + + try { + module = (Kross::Api::Module*) (func)(this); + } + catch(Kross::Api::Exception::Ptr e) { + krosswarning( e->toString() ); + module = 0; + } + lib->unload(); + + if(! module) { + krosswarning( QString("Failed to load module '%1'").arg(modulename) ); + return 0; + } + + // Don't remember module cause we like to have freeing it handled by the caller. + //d->modules.replace(modulename, module); + + //krossdebug( QString("Kross::Api::Manager::loadModule modulename='%1' module='%2'").arg(modulename).arg(module->toString()) ); + return module; +} + diff --git a/lib/kross/main/manager.h b/lib/kross/main/manager.h new file mode 100644 index 00000000..0de5833f --- /dev/null +++ b/lib/kross/main/manager.h @@ -0,0 +1,168 @@ +/*************************************************************************** + * manager.h + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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. + ***************************************************************************/ + +#ifndef KROSS_API_MANAGER_H +#define KROSS_API_MANAGER_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qmap.h> +//#include <qvariant.h> +#include <ksharedptr.h> + +class QObject; + +#include "../api/object.h" +#include "mainmodule.h" + +namespace Kross { namespace Api { + + // Forward declarations. + class Interpreter; + class Object; + class EventSlot; + class EventSignal; + class ScriptContainer; + class ManagerPrivate; + class InterpreterInfo; + + /** + * The Manager class is the main entry point to work with + * Kross. It spends an abstraction layer between what is + * under the hood of Kross and the functionality you need + * to access. + * Use \a Interpreter to just work with some implementated + * interpreter like python. While \a Script spends a more + * flexible container. + */ + class KDE_EXPORT Manager : public MainModule + { + protected: + + /** + * Constructor. Use \a scriptManager() to access + * the Manager singleton instance. + */ + Manager(); + + public: + + /** + * Destructor. + */ + ~Manager(); + + /** + * Return the Manager instance. Always use this + * function to access the Manager singleton. + */ + static Manager* scriptManager(); + + /** + * \return a map with \a InterpreterInfo* instances + * used to describe interpreters. + */ + QMap<QString, InterpreterInfo*> getInterpreterInfos(); + + /** + * \return true if there exists an interpreter with the + * name \p interpretername else false. + */ + bool hasInterpreterInfo(const QString& interpretername) const; + + /** + * \return the \a InterpreterInfo* matching to the defined + * \p interpretername or NULL if there does not exists such + * a interpreter. + */ + InterpreterInfo* getInterpreterInfo(const QString& interpretername); + + /** + * \return the name of the \a Interpreter that feels responsible + * for the defined \p file . + * + * \param file The filename we should try to determinate the + * interpretername for. + * \return The name of the \a Interpreter which will be used + * to execute the file or QString::null if we failed + * to determinate a matching interpreter for the file. + */ + const QString getInterpreternameForFile(const QString& file); + + /** + * Return the existing \a ScriptContainer with scriptname + * or create a new \a ScriptContainer instance and associate + * the passed scriptname with it. + * + * \param scriptname The name of the script. This + * should be unique for each \a Script and + * could be something like the filename. + * \return The \a ScriptContainer instance matching to + * scriptname. + */ + KSharedPtr<ScriptContainer> getScriptContainer(const QString& scriptname); + + /** + * Return the \a Interpreter instance defined by + * the interpretername. + * + * \param interpretername The name of the interpreter. + * e.g. "python" or "kjs". + * \return The Interpreter instance or NULL if there + * does not exists an interpreter with such + * an interpretername. + */ + Interpreter* getInterpreter(const QString& interpretername); + + /** + * \return a list of names of the at the backend + * supported interpreters. + */ + const QStringList getInterpreters(); + + /** + * Add the an external module to the global shared list of + * loaded modules. + * + * @param module The @a Module instace to add. + * @return true if the module was added successfully else + * false. + */ + bool addModule(Module::Ptr module); + + /** + * Load an external module and return it. + * + * \param modulename The name of the library we should try to + * load. Those library needs to be a valid kross module. + * \return The loaded \a Object or NULL if loading + * failed. The loaded Module isn't added to the global + * shared list of modules. + */ + Module::Ptr loadModule(const QString& modulename); + + private: + /// Private d-pointer class. + ManagerPrivate* d; + }; + +}} + +#endif + diff --git a/lib/kross/main/scriptaction.cpp b/lib/kross/main/scriptaction.cpp new file mode 100644 index 00000000..06ee9dd7 --- /dev/null +++ b/lib/kross/main/scriptaction.cpp @@ -0,0 +1,247 @@ +/*************************************************************************** + * scriptaction.cpp + * This file is part of the KDE project + * copyright (C) 2005 by Sebastian Sauer ([email protected]) + * + * 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 "scriptaction.h" +#include "manager.h" + +#include <qstylesheet.h> +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <kurl.h> +#include <kstandarddirs.h> +#include <kmimetype.h> + +using namespace Kross::Api; + +namespace Kross { namespace Api { + + /// @internal + class ScriptActionPrivate + { + public: + /** + * The packagepath is the directory that belongs to this + * \a ScriptAction instance. If this \a ScriptAction points + * to a scriptfile the packagepath will be the directory + * the scriptfile is located in. + */ + QString packagepath; + + /** + * List of logs this \a ScriptAction has. Initialization, + * execution and finalization should be logged for + * example. So, the logs are usuabled to provide some + * more detailed visual information to the user what + * our \a ScriptAction did so far. + */ + QStringList logs; + + /** + * The versionnumber this \a ScriptAction has. We are using + * the version to handle \a ScriptAction instances which + * have the same unique \a ScriptAction::name() . If the name + * is the same, we are able to use the version to determinate + * which \a ScriptAction is newer / replaces the other. + */ + int version; + + /** + * The description used to provide a way to the user to describe + * the \a ScriptAction with a longer string. + */ + QString description; + + /** + * List of \a ScriptActionCollection instances this \a ScriptAction + * is attached to. + */ + QValueList<ScriptActionCollection*> collections; + + /** + * Constructor. + */ + explicit ScriptActionPrivate() : version(0) {} + }; + +}} + +ScriptAction::ScriptAction(const QString& file) + : KAction(0, file.latin1()) + , Kross::Api::ScriptContainer(file) + , d( new ScriptActionPrivate() ) // initialize d-pointer class +{ + KURL url(file); + if(url.isLocalFile()) { + setFile(file); + setText(url.fileName()); + setIcon(KMimeType::iconForURL(url)); + } + else { + setText(file); + } + + setDescription(file); + setEnabled(false); +} + +ScriptAction::ScriptAction(const QString& scriptconfigfile, const QDomElement& element) + : KAction() + , Kross::Api::ScriptContainer() + , d( new ScriptActionPrivate() ) // initialize d-pointer class +{ + QString name = element.attribute("name"); + QString text = element.attribute("text"); + QString description = element.attribute("description"); + QString file = element.attribute("file"); + QString icon = element.attribute("icon"); + + QString version = element.attribute("version"); + bool ok; + int v = version.toInt(&ok); + if(ok) d->version = v; + + if(file.isEmpty()) { + if(text.isEmpty()) + text = name; + } + else { + if(name.isEmpty()) + name = file; + if(text.isEmpty()) + text = file; + } + + //d->scriptcontainer = Manager::scriptManager()->getScriptContainer(name); + + QString interpreter = element.attribute("interpreter"); + if(interpreter.isNull()) + setEnabled(false); + else + setInterpreterName( interpreter ); + + if(file.isNull()) { + setCode( element.text().stripWhiteSpace() ); + if(description.isNull()) + description = text; + ScriptContainer::setName(name); + } + else { + QDir dir = QFileInfo(scriptconfigfile).dir(true); + d->packagepath = dir.absPath(); + QFileInfo fi(dir, file); + file = fi.absFilePath(); + setEnabled(fi.exists()); + setFile(file); + if(icon.isNull()) + icon = KMimeType::iconForURL( KURL(file) ); + if(description.isEmpty()) + description = QString("%1<br>%2").arg(text.isEmpty() ? name : text).arg(file); + else + description += QString("<br>%1").arg(file); + ScriptContainer::setName(file); + } + + KAction::setName(name.latin1()); + KAction::setText(text); + setDescription(description); + KAction::setIcon(icon); + + // connect signal + connect(this, SIGNAL(activated()), this, SLOT(activate())); +} + +ScriptAction::~ScriptAction() +{ + detachAll(); + delete d; +} + +int ScriptAction::version() const +{ + return d->version; +} + +const QString ScriptAction::getDescription() const +{ + return d->description; +} + +void ScriptAction::setDescription(const QString& description) +{ + d->description = description; + setToolTip( description ); + setWhatsThis( description ); +} + +void ScriptAction::setInterpreterName(const QString& name) +{ + setEnabled( Manager::scriptManager()->hasInterpreterInfo(name) ); + Kross::Api::ScriptContainer::setInterpreterName(name); +} + +const QString ScriptAction::getPackagePath() const +{ + return d->packagepath; +} + +const QStringList& ScriptAction::getLogs() const +{ + return d->logs; +} + +void ScriptAction::attach(ScriptActionCollection* collection) +{ + d->collections.append( collection ); +} + +void ScriptAction::detach(ScriptActionCollection* collection) +{ + d->collections.remove( collection ); +} + +void ScriptAction::detachAll() +{ + for(QValueList<ScriptActionCollection*>::Iterator it = d->collections.begin(); it != d->collections.end(); ++it) + (*it)->detach( this ); +} + +void ScriptAction::activate() +{ + emit activated(this); + Kross::Api::ScriptContainer::execute(); + if( Kross::Api::ScriptContainer::hadException() ) { + QString errormessage = Kross::Api::ScriptContainer::getException()->getError(); + QString tracedetails = Kross::Api::ScriptContainer::getException()->getTrace(); + d->logs << QString("<b>%1</b><br>%2") + .arg( QStyleSheet::escape(errormessage) ) + .arg( QStyleSheet::escape(tracedetails) ); + emit failed(errormessage, tracedetails); + } + else { + emit success(); + } +} + +void ScriptAction::finalize() +{ + Kross::Api::ScriptContainer::finalize(); +} + +#include "scriptaction.moc" diff --git a/lib/kross/main/scriptaction.h b/lib/kross/main/scriptaction.h new file mode 100644 index 00000000..22bb37ec --- /dev/null +++ b/lib/kross/main/scriptaction.h @@ -0,0 +1,309 @@ +/*************************************************************************** + * scriptaction.h + * This file is part of the KDE project + * copyright (C) 2005 by Sebastian Sauer ([email protected]) + * + * 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. + ***************************************************************************/ + +#ifndef KROSS_API_SCRIPTACTION_H +#define KROSS_API_SCRIPTACTION_H + +#include <qdom.h> +#include <kaction.h> + +#include "scriptcontainer.h" + +namespace Kross { namespace Api { + + // Forward declarations. + class ScriptContainer; + class ScriptActionCollection; + class ScriptActionPrivate; + + /** + * A ScriptAction extends a KAction by providing a wrapper around + * a \a ScriptContainer to execute scripting code on activation. + */ + class ScriptAction + : public KAction + , public Kross::Api::ScriptContainer + { + Q_OBJECT + + /// The name of the interpreter used to execute the scripting code. + //Q_PROPERTY(QString interpretername READ getInterpreterName WRITE setInterpreterName) + + /// The scripting code which should be executed. + //Q_PROPERTY(QString code READ getCode WRITE setCode) + + /// The scriptfile which should be executed. + //Q_PROPERTY(QString file READ getFile WRITE setFile) + + /// The description for this \a ScriptAction . + Q_PROPERTY(QString description READ getDescription WRITE setDescription) + + public: + + /// Shared pointer to implement reference-counting. + typedef KSharedPtr<ScriptAction> Ptr; + + /// A list of \a ScriptAction instances. + //typedef QValueList<ScriptAction::Ptr> List; + + /** + * Constructor. + * + * \param file The KURL scriptfile this \a ScriptAction + * points to. + */ + explicit ScriptAction(const QString& file); + + /** + * Constructor. + * + * \param scriptconfigfile The XML-configurationfile + * the DOM-element was readed from. + * \param element The QDomElement which will be used + * to setup the \a ScriptAction attributes. + */ + explicit ScriptAction(const QString& scriptconfigfile, const QDomElement& element); + + /** + * Destructor. + */ + virtual ~ScriptAction(); + + /** + * \return the version this script has. Versions are used + * to be able to manage different versions of the same + * script. The version is 0 by default if not defined to + * something else in the rc-file. + */ + int version() const; + + /** + * \return the description for this \a ScriptAction has. + */ + const QString getDescription() const; + + /** + * Set the description \p description for this \a ScriptAction . + */ + void setDescription(const QString& description); + + /** + * Set the name of the interpreter which will be used + * on activation to execute the scripting code. + * + * \param name The name of the \a Interpreter . This + * could be e.g. "python". + */ + void setInterpreterName(const QString& name); + + /** + * \return the path of the package this \a ScriptAction + * belongs to or QString::null if it doesn't belong to + * any package. + */ + const QString getPackagePath() const; + + /** + * \return a list of all kind of logs this \a ScriptAction + * does remember. + */ + const QStringList& getLogs() const; + + /** + * Attach this \a ScriptAction to the \a ScriptActionCollection + * \p collection . + */ + void attach(ScriptActionCollection* collection); + + /** + * Detach this \a ScriptAction from the \a ScriptActionCollection + * \p collection . + */ + void detach(ScriptActionCollection* collection); + + /** + * Detach this \a ScriptAction from all \a ScriptActionCollection + * instance his \a ScriptAction is attached to. + */ + void detachAll(); + + public slots: + + /** + * If the \a ScriptAction got activated the \a ScriptContainer + * got executed. Once this slot got executed it will emit a + * \a success() or \a failed() signal. + */ + virtual void activate(); + + /** + * This slot finalizes the \a ScriptContainer and tries to clean + * any still running script. + */ + void finalize(); + + signals: + + /** + * This signal got emitted when this action is emitted before execution. + */ + void activated(const Kross::Api::ScriptAction*); + + /** + * This signal got emitted after this \a ScriptAction got + * executed successfully. + */ + void success(); + + /** + * This signal got emitted after the try to execute this + * \a ScriptAction failed. The \p errormessage contains + * the error message. + */ + void failed(const QString& errormessage, const QString& tracedetails); + + private: + /// Internaly used private d-pointer. + ScriptActionPrivate* d; + }; + + /** + * A collection to store \a ScriptAction shared pointers. + * + * A \a ScriptAction instance could be stored within + * multiple \a ScriptActionCollection instances. + */ + class ScriptActionCollection + { + private: + + /** + * The list of \a ScriptAction shared pointers. + */ + QValueList<ScriptAction::Ptr> m_list; + + /** + * A map of \a ScriptAction shared pointers used to access + * the actions with there name. + */ + QMap<QCString, ScriptAction::Ptr> m_actions; + + /** + * A KActionMenu which could be used to display the + * content of this \a ScriptActionCollection instance. + */ + KActionMenu* m_actionmenu; + + /** + * Boolean value used to represent the modified-state. Will + * be true if this \a ScriptActionCollection is modified + * aka dirty and e.g. the \a m_actionmenu needs to be + * updated else its false. + */ + bool m_dirty; + + /** + * Copy-constructor. The cctor is private cause instances + * of this class shouldn't be copied. If that changes one + * day, don't forgot that it's needed to copy the private + * member variables as well or we may end in dirty + * crashes :) + */ + ScriptActionCollection(const ScriptActionCollection&) {} + + public: + + /** + * Constructor. + * + * \param text The text used to display some describing caption. + * \param ac The KActionCollection which should be used to as + * initial content for the KActionMenu \a m_actionmenu . + * \param name The internal name. + */ + ScriptActionCollection(const QString& text, KActionCollection* ac, const char* name) + : m_actionmenu( new KActionMenu(text, ac, name) ) + , m_dirty(true) {} + + + /** + * Destructor. + */ + ~ScriptActionCollection() { + for(QValueList<ScriptAction::Ptr>::Iterator it = m_list.begin(); it != m_list.end(); ++it) + (*it)->detach(this); + } + + /** + * \return the \a ScriptAction instance which has the name \p name + * or NULL if there exists no such action. + */ + ScriptAction::Ptr action(const QCString& name) { return m_actions[name]; } + + /** + * \return a list of actions. + */ + QValueList<ScriptAction::Ptr> actions() { return m_list; } + + /** + * \return the KActionMenu \a m_actionmenu . + */ + KActionMenu* actionMenu() { return m_actionmenu; } + + /** + * Attach a \a ScriptAction instance to this \a ScriptActionCollection . + */ + void attach(ScriptAction::Ptr action) { + m_dirty = true; + m_actions[ action->name() ] = action; + m_list.append(action); + m_actionmenu->insert(action); + action->attach(this); + } + + /** + * Detach a \a ScriptAction instance from this \a ScriptActionCollection . + */ + void detach(ScriptAction::Ptr action) { + m_dirty = true; + m_actions.remove(action->name()); + m_list.remove(action); + m_actionmenu->remove(action); + action->detach(this); + } + + /** + * Clear this \a ScriptActionCollection . The collection + * will be empty and there are no actions attach any longer. + */ + void clear() { + for(QValueList<ScriptAction::Ptr>::Iterator it = m_list.begin(); it != m_list.end(); ++it) { + m_actionmenu->remove(*it); + (*it)->detach(this); + } + m_list.clear(); + m_actions.clear(); + } + + }; + +}} + +#endif + diff --git a/lib/kross/main/scriptcontainer.cpp b/lib/kross/main/scriptcontainer.cpp new file mode 100644 index 00000000..56c9bb8e --- /dev/null +++ b/lib/kross/main/scriptcontainer.cpp @@ -0,0 +1,293 @@ +/*************************************************************************** + * scriptcontainer.cpp + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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 "scriptcontainer.h" +#include "../api/object.h" +#include "../api/list.h" +#include "../api/interpreter.h" +#include "../api/script.h" +#include "../main/manager.h" +#include "mainmodule.h" + +#include <qfile.h> + +#include <klocale.h> + +using namespace Kross::Api; + +namespace Kross { namespace Api { + + /// @internal + class ScriptContainerPrivate + { + public: + + /** + * The \a Script instance the \a ScriptContainer uses + * if initialized. It will be NULL as long as we + * didn't initialized it what will be done on + * demand. + */ + Script* script; + + /** + * The unique name the \a ScriptContainer is + * reachable as. + */ + QString name; + + /** + * The scripting code. + */ + QString code; + + /** + * The name of the interpreter. This could be + * something like "python" for the python + * binding. + */ + QString interpretername; + + /** + * The name of the scriptfile that should be + * executed. Those scriptfile will be readed + * and the content will be used to set the + * scripting code and, if not defined, the + * used interpreter. + */ + QString scriptfile; + + /** + * Map of options that overwritte the \a InterpreterInfo::Option::Map + * standard options. + */ + QMap<QString, QVariant> options; + + }; + +}} + +ScriptContainer::ScriptContainer(const QString& name) + : MainModule(name) + , d( new ScriptContainerPrivate() ) // initialize d-pointer class +{ + //krossdebug( QString("ScriptContainer::ScriptContainer() Ctor name='%1'").arg(name) ); + + d->script = 0; + d->name = name; +} + +ScriptContainer::~ScriptContainer() +{ + //krossdebug( QString("ScriptContainer::~ScriptContainer() Dtor name='%1'").arg(d->name) ); + + finalize(); + delete d; +} + +const QString ScriptContainer::getName() const +{ + return d->name; +} + +void ScriptContainer::setName(const QString& name) +{ + d->name = name; +} + +QString ScriptContainer::getCode() const +{ + return d->code; +} + +void ScriptContainer::setCode(const QString& code) +{ + finalize(); + d->code = code; +} + +QString ScriptContainer::getInterpreterName() const +{ + return d->interpretername; +} + +void ScriptContainer::setInterpreterName(const QString& interpretername) +{ + finalize(); + d->interpretername = interpretername; +} + +QString ScriptContainer::getFile() const +{ + return d->scriptfile; +} + +void ScriptContainer::setFile(const QString& scriptfile) +{ + finalize(); + d->scriptfile = scriptfile; +} + +QMap<QString, QVariant>& ScriptContainer::getOptions() +{ + return d->options; +} + +QVariant ScriptContainer::getOption(const QString name, QVariant defaultvalue, bool /*recursive*/) +{ + if(d->options.contains(name)) + return d->options[name]; + Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo( d->interpretername ); + return info ? info->getOptionValue(name, defaultvalue) : defaultvalue; +} + +bool ScriptContainer::setOption(const QString name, const QVariant& value) +{ + Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo( d->interpretername ); + if(info) { + if(info->hasOption(name)) { + d->options.replace(name, value); + return true; + } else krosswarning( QString("Kross::Api::ScriptContainer::setOption(%1, %2): No such option").arg(name).arg(value.toString()) ); + } else krosswarning( QString("Kross::Api::ScriptContainer::setOption(%1, %2): No such interpreterinfo").arg(name).arg(value.toString()) ); + return false; +} + +Object::Ptr ScriptContainer::execute() +{ + if(! d->script) + if(! initialize()) + return 0; + + if(hadException()) + return 0; + + Object::Ptr r = d->script->execute(); + if(d->script->hadException()) { + setException( d->script->getException() ); + finalize(); + return 0; + } + return r; +} + +const QStringList ScriptContainer::getFunctionNames() +{ + return d->script ? d->script->getFunctionNames() : QStringList(); //FIXME init before if needed? +} + +Object::Ptr ScriptContainer::callFunction(const QString& functionname, List::Ptr arguments) +{ + if(! d->script) + if(! initialize()) + return 0; + + if(hadException()) + return 0; + + if(functionname.isEmpty()) { + setException( new Exception(i18n("No functionname defined for ScriptContainer::callFunction().")) ); + finalize(); + return 0; + } + + Object::Ptr r = d->script->callFunction(functionname, arguments); + if(d->script->hadException()) { + setException( d->script->getException() ); + finalize(); + return 0; + } + return r; +} + +QStringList ScriptContainer::getClassNames() +{ + return d->script ? d->script->getClassNames() : QStringList(); //FIXME init before if needed? +} + +Object::Ptr ScriptContainer::classInstance(const QString& classname) +{ + if(! d->script) + if(! initialize()) + return 0; + + if(hadException()) + return 0; + + Object::Ptr r = d->script->classInstance(classname); + if(d->script->hadException()) { + setException( d->script->getException() ); + finalize(); + return 0; + } + return r; +} + +bool ScriptContainer::initialize() +{ + finalize(); + + if(! d->scriptfile.isNull()) { + krossdebug( QString("Kross::Api::ScriptContainer::initialize() file=%1").arg(d->scriptfile) ); + + if(d->interpretername.isNull()) { + d->interpretername = Manager::scriptManager()->getInterpreternameForFile( d->scriptfile ); + if(d->interpretername.isNull()) { + setException( new Exception(i18n("Failed to determinate interpreter for scriptfile '%1'").arg(d->scriptfile)) ); + return false; + } + } + + QFile f( d->scriptfile ); + if(! f.open(IO_ReadOnly)) { + setException( new Exception(i18n("Failed to open scriptfile '%1'").arg(d->scriptfile)) ); + return false; + } + d->code = QString( f.readAll() ); + f.close(); + } + + Interpreter* interpreter = Manager::scriptManager()->getInterpreter(d->interpretername); + if(! interpreter) { + setException( new Exception(i18n("Unknown interpreter '%1'").arg(d->interpretername)) ); + return false; + } + + d->script = interpreter->createScript(this); + if(! d->script) { + setException( new Exception(i18n("Failed to create script for interpreter '%1'").arg(d->interpretername)) ); + return false; + } + if(d->script->hadException()) { + setException( d->script->getException() ); + finalize(); + return false; + } + setException( 0 ); // clear old exception + + return true; +} + +void ScriptContainer::finalize() +{ + delete d->script; + d->script = 0; +} + + diff --git a/lib/kross/main/scriptcontainer.h b/lib/kross/main/scriptcontainer.h new file mode 100644 index 00000000..a66293a2 --- /dev/null +++ b/lib/kross/main/scriptcontainer.h @@ -0,0 +1,210 @@ +/*************************************************************************** + * scriptcontainer.h + * This file is part of the KDE project + * copyright (C)2004-2005 by Sebastian Sauer ([email protected]) + * + * 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. + ***************************************************************************/ + +#ifndef KROSS_API_SCRIPTCONTAINER_H +#define KROSS_API_SCRIPTCONTAINER_H + +#include "mainmodule.h" + +#include <qstring.h> +#include <qvariant.h> +#include <qobject.h> +#include <ksharedptr.h> + +namespace Kross { namespace Api { + + // Forward declarations. + class Object; + class List; + class ScriptContainerPrivate; + + /** + * The ScriptContainer class is something like a single + * standalone scriptfile. + * + * Once you've such a ScriptContainer instance you're + * able to perform actions with it like to execute + * scripting code. The \a Manager takes care of + * handling the ScriptContainer instances application + * width. + * + * The class \a ScriptAction provides a higher level class + * to work with a \a ScriptContainer instances. + */ + class ScriptContainer : public MainModule + { + // We protected the constructor cause ScriptContainer + // instances should be created only within the + // Manager::getScriptContainer() method. + friend class Manager; + + protected: + + /** + * Constructor. + * + * The constructor is protected cause only with the + * \a ScriptManager it's possible to access + * \a ScriptContainer instances. + * + * \param name The unique name this ScriptContainer + * has. It's used e.g. at the \a Manager to + * identify the ScriptContainer. + */ + explicit ScriptContainer(const QString& name = QString::null); + + public: + + /// Shared pointer to implement reference-counting. + typedef KSharedPtr<ScriptContainer> Ptr; + + /** + * Destructor. + */ + virtual ~ScriptContainer(); + + /** + * \return the unique name this ScriptContainer is + * reachable as. + */ + const QString getName() const; + + /** + * Set the name this ScriptContainer is reachable as. + */ + void setName(const QString& name); + + /** + * Return the scriptcode this ScriptContainer holds. + */ + QString getCode() const; + + /** + * Set the scriptcode this ScriptContainer holds. + */ + void setCode(const QString& code); + + /** + * \return the name of the interpreter used + * on \a execute. + */ + QString getInterpreterName() const; + + /** + * Set the name of the interpreter used + * on \a execute. + */ + void setInterpreterName(const QString& interpretername); + + /** + * \return the filename which will be executed + * on \a execute. + */ + QString getFile() const; + + /** + * Set the filename which will be executed + * on \a execute. The \p scriptfile needs to + * be a valid local file or QString::null if + * you don't like to use a file rather then + * the with \a setCode() defined scripting code. + */ + void setFile(const QString& scriptfile); + + /** + * \return a map of options this \a ScriptContainer defines. + * The options are returned call-by-ref, so you are able to + * manipulate them. + */ + QMap<QString, QVariant>& getOptions(); + + /** + * \return the value of the option defined with \p name . + * If there doesn't exists an option with such a name, + * the \p defaultvalue is returned. If \p recursive is + * true then first the \a ScriptContainer options are + * seeked for the matching \p name and if not found + * the \a Manager options are seeked for the \p name and + * if not found either the \p defaultvalue is returned. + */ + QVariant getOption(const QString name, QVariant defaultvalue = QVariant(), bool recursive = false); + + /** + * Set the \a Interpreter::Option value. + */ + bool setOption(const QString name, const QVariant& value); + + /** + * Execute the script container. + */ + Object::Ptr execute(); + + /** + * Return a list of functionnames the with + * \a setCode defined scriptcode spends. + */ + const QStringList getFunctionNames(); + + /** + * Call a function in the script container. + * + * \param functionname The name of the function + * to call. + * \param arguments Optional list of arguments + * passed to the function. + * \return \a Object instance representing + * the functioncall returnvalue. + */ + KSharedPtr<Object> callFunction(const QString& functionname, KSharedPtr<List> arguments = 0); + + /** + * Return a list of classes. + */ + QStringList getClassNames(); + + /** + * Create and return a new class instance. + */ + KSharedPtr<Object> classInstance(const QString& classname); + + /** + * Initialize the \a Script instance. + * + * Normaly it's not needed to call this function direct cause + * if will be internaly called if needed (e.g. on \a execute ). + */ + bool initialize(); + + /** + * Finalize the \a Script instance and free's any cached or still + * running executions. Normaly it's not needed to call this + * function direct cause the \a ScriptContainer will take care + * of calling it if needed. + */ + void finalize(); + + private: + /// Internaly used private d-pointer. + ScriptContainerPrivate* d; + }; + +}} + +#endif + diff --git a/lib/kross/main/scriptguiclient.cpp b/lib/kross/main/scriptguiclient.cpp new file mode 100644 index 00000000..28a89015 --- /dev/null +++ b/lib/kross/main/scriptguiclient.cpp @@ -0,0 +1,384 @@ +/*************************************************************************** + * scriptguiclient.cpp + * This file is part of the KDE project + * copyright (C) 2005 by Sebastian Sauer ([email protected]) + * + * 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 QWidget widget. + */ + QWidget* parent; + + /** + * Map of \a ScriptActionCollection instances the \a ScriptGUIClient + * is attached to. + */ + QMap<QString, ScriptActionCollection*> collections; + }; + +}} + +ScriptGUIClient::ScriptGUIClient(KXMLGUIClient* guiclient, QWidget* parent) + : QObject( parent ) + , KXMLGUIClient( guiclient ) + , d( new ScriptGUIClientPrivate() ) // initialize d-pointer class +{ + krossdebug( QString("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, SLOT(executeScriptFile()), actionCollection(), "executescriptfile"); + + // acion to show the ScriptManagerGUI dialog. + new KAction(i18n("Scripts Manager..."), 0, 0, this, 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( QString("ScriptGUIClient::~ScriptGUIClient() Dtor") ); + for(QMap<QString, ScriptActionCollection*>::Iterator it = d->collections.begin(); it != d->collections.end(); ++it) + delete it.data(); + delete d; +} + +bool ScriptGUIClient::hasActionCollection(const QString& name) +{ + return d->collections.contains(name); +} + +ScriptActionCollection* ScriptGUIClient::getActionCollection(const QString& name) +{ + return d->collections[name]; +} + +QMap<QString, ScriptActionCollection*> ScriptGUIClient::getActionCollections() +{ + return d->collections; +} + +void ScriptGUIClient::addActionCollection(const QString& name, ScriptActionCollection* collection) +{ + removeActionCollection(name); + d->collections.replace(name, collection); +} + +bool ScriptGUIClient::removeActionCollection(const QString& 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(); + + QCString partname = d->guiclient->instance()->instanceName(); + QStringList files = KGlobal::dirs()->findAllResources("data", partname + "/scripts/*/*.rc"); + //files.sort(); + for(QStringList::iterator it = files.begin(); it != files.end(); ++it) + loadScriptConfigFile(*it); +} + +bool ScriptGUIClient::installScriptPackage(const QString& scriptpackagefile) +{ + krossdebug( QString("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; + } + + QCString partname = d->guiclient->instance()->instanceName(); + QString destination = KGlobal::dirs()->saveLocation("data", partname + "/scripts/", true); + //QString 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; + } + + QString packagename = QFileInfo(scriptpackagefile).baseName(); + destination += packagename; // add the packagename to the name of the destination-directory. + + if( QDir(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( QString("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 QString& 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 QString& scriptconfigfile) +{ + krossdebug( QString("ScriptGUIClient::loadScriptConfig file=%1").arg(scriptconfigfile) ); + + QDomDocument domdoc; + QFile file(scriptconfigfile); + if(! file.open(IO_ReadOnly)) { + krosswarning( QString("ScriptGUIClient::loadScriptConfig(): Failed to read scriptconfigfile: %1").arg(scriptconfigfile) ); + return false; + } + bool ok = domdoc.setContent(&file); + file.close(); + if(! ok) { + krosswarning( QString("ScriptGUIClient::loadScriptConfig(): Failed to parse scriptconfigfile: %1").arg(scriptconfigfile) ); + return false; + } + + return loadScriptConfigDocument(scriptconfigfile, domdoc); +} + +bool ScriptGUIClient::loadScriptConfigDocument(const QString& scriptconfigfile, const QDomDocument &document) +{ + ScriptActionCollection* installedcollection = d->collections["installedscripts"]; + QDomNodeList 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( QString("Kross::Api::ScriptGUIClient::loadScriptConfigDocument: There exists already a scriptaction with name \"%1\". Added anyway...").arg(action->name()) ); + } + } + installedcollection->attach( action ); + } + + connect(action.data(), SIGNAL( failed(const QString&, const QString&) ), + this, SLOT( executionFailed(const QString&, const QString&) )); + connect(action.data(), SIGNAL( success() ), + this, SLOT( successfullyExecuted() )); + connect(action.data(), SIGNAL( activated(const Kross::Api::ScriptAction*) ), SIGNAL( executionStarted(const Kross::Api::ScriptAction*))); + } + emit collectionChanged(installedcollection); + return true; +} + +void ScriptGUIClient::setXMLFile(const QString& file, bool merge, bool setXMLDoc) +{ + KXMLGUIClient::setXMLFile(file, merge, setXMLDoc); +} + +void ScriptGUIClient::setDOMDocument(const QDomDocument &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* >( QObject::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 QString& errormessage, const QString& tracedetails) +{ + const ScriptAction* action = dynamic_cast< const ScriptAction* >( QObject::sender() ); + if(action) + emit executionFinished(action); + if(tracedetails.isEmpty()) + KMessageBox::error(0, errormessage); + else + KMessageBox::detailedError(0, errormessage, tracedetails); +} + +KURL ScriptGUIClient::openScriptFile(const QString& caption) +{ + QStringList mimetypes; + QMap<QString, InterpreterInfo*> infos = Manager::scriptManager()->getInterpreterInfos(); + for(QMap<QString, InterpreterInfo*>::Iterator it = infos.begin(); it != infos.end(); ++it) + mimetypes.append( it.data()->getMimeTypes().join(" ").stripWhiteSpace() ); + + KFileDialog* filedialog = new KFileDialog( + QString::null, // 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(), SIGNAL( failed(const QString&, const QString&) ), + this, SLOT( executionFailed(const QString&, const QString&) )); + connect(action.data(), SIGNAL( success() ), + this, SLOT( successfullyExecuted() )); + connect(action.data(), SIGNAL( activated(const Kross::Api::ScriptAction*) ), 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 QString& file) +{ + krossdebug( QString("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(), SIGNAL( failed(const QString&, const QString&) ), + this, SLOT( executionFailed(const QString&, const QString&) )); + connect(action.data(), SIGNAL( success() ), + this, SLOT( successfullyExecuted() )); + connect(action.data(), SIGNAL( activated(const Kross::Api::ScriptAction*) ), 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( QSize(360, 320).expandedTo(dialog->minimumSizeHint()) ); + dialog->show(); +} + +#include "scriptguiclient.moc" diff --git a/lib/kross/main/scriptguiclient.h b/lib/kross/main/scriptguiclient.h new file mode 100644 index 00000000..955b55d9 --- /dev/null +++ b/lib/kross/main/scriptguiclient.h @@ -0,0 +1,217 @@ +/*************************************************************************** + * scriptguiclient.h + * This file is part of the KDE project + * copyright (C) 2005 by Sebastian Sauer ([email protected]) + * + * 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. + ***************************************************************************/ + +#ifndef KROSS_API_SCRIPTGUICLIENT_H +#define KROSS_API_SCRIPTGUICLIENT_H + +#include "scriptcontainer.h" +#include "scriptaction.h" + +#include <qobject.h> +#include <qdom.h> +#include <kurl.h> +#include <kxmlguiclient.h> + +class QWdiget; + +namespace Kross { namespace Api { + + // Forward declarations. + class ScriptAction; + class ScriptGUIClientPrivate; + + /** + * The ScriptGUIClient class provides abstract access to + * scripting code used to extend an applications functionality. + */ + class KDE_EXPORT ScriptGUIClient + : public QObject + , public KXMLGUIClient + { + Q_OBJECT + //Q_PROPERTY(QString configfile READ getConfigFile WRITE setConfigFile) + + public: + + /// List of KAction instances. + typedef QPtrList<KAction> List; + + /** + * Constructor. + * + * \param guiclient The KXMLGUIClient this \a ScriptGUIClient + * is a child of. + * \param parent The parent QWidget. If defined Qt will handle + * freeing this \a ScriptGUIClient instance else the + * caller has to take care of freeing this instance + * if not needed any longer. + */ + explicit ScriptGUIClient(KXMLGUIClient* guiclient, QWidget* parent = 0); + + /** + * Destructor. + */ + virtual ~ScriptGUIClient(); + + /** + * \return true if this \a ScriptGUIClient has a \a ScriptActionCollection + * with the name \p name else false is returned. + */ + bool hasActionCollection(const QString& name); + + /** + * \return the \a ScriptActionCollection which has the name \p name + * or NULL if there exists no such \a ScriptActionCollection . + */ + ScriptActionCollection* getActionCollection(const QString& name); + + /** + * \return a map of all avaiable \a ScriptActionCollection instances + * this \a ScriptGUIClient knows about. + * Per default there are 2 collections avaiable; + * 1. "installedscripts" The installed collection of scripts. + * 2. "loadedscripts" The loaded scripts. + */ + QMap<QString, ScriptActionCollection*> getActionCollections(); + + /** + * Add a new \a ScriptActionCollection with the name \p name to + * our map of actioncollections. + */ + void addActionCollection(const QString& name, ScriptActionCollection* collection); + + /** + * Remove the \a ScriptActionCollection defined with name \p name. + */ + bool removeActionCollection(const QString& name); + + /** + * Reload the list of installed scripts. + */ + void reloadInstalledScripts(); + + /** + * Install the packagefile \p scriptpackagefile . Those + * packagefile should be a tar.gz-archive which will be + * extracted and to the users script-directory. + */ + bool installScriptPackage(const QString& scriptpackagefile); + + /** + * Uninstall the scriptpackage located in the path + * \p scriptpackagepath . This just deletes the whole + * directory. + */ + bool uninstallScriptPackage(const QString& scriptpackagepath); + + /** + * Load the scriptpackage's configurationfile + * \p scriptconfigfile and add the defined \a ScriptAction + * instances to the list of installed scripts. + */ + bool loadScriptConfigFile(const QString& scriptconfigfile); + + /** + * Load the \p document DOM-document from the scriptpackage's + * XML-configfile \p scriptconfigfile and add the defined + * \a ScriptAction instances to the list of installed scripts. + */ + bool loadScriptConfigDocument(const QString& scriptconfigfile, const QDomDocument &document); + + /// KXMLGUIClient overloaded method to set the XML file. + virtual void setXMLFile(const QString& file, bool merge = false, bool setXMLDoc = true); + /// KXMLGUIClient overloaded method to set the XML DOM-document. + virtual void setDOMDocument(const QDomDocument &document, bool merge = false); + + public slots: + + /** + * A KFileDialog will be displayed to let the user choose + * a scriptfile. The choosen file will be returned as KURL. + */ + KURL openScriptFile(const QString& caption = QString::null); + + /** + * A KFileDialog will be displayed to let the user choose + * a scriptfile that should be loaded. + * Those loaded \a ScriptAction will be added to the + * \a ScriptActionCollection of loaded scripts. + */ + bool loadScriptFile(); + + /** + * A KFileDialog will be displayed to let the user choose + * the scriptfile that should be executed. + * The executed \a ScriptAction will be added to the + * \a ScriptActionCollection of executed scripts. + */ + bool executeScriptFile(); + + /** + * Execute the scriptfile \p file . Internaly we try to use + * the defined filename to auto-detect the \a Interpreter which + * should be used for the execution. + */ + bool executeScriptFile(const QString& file); + + /** + * This method executes the \a ScriptAction \p action . + * Internaly we just call \a ScriptAction::activate and + * redirect the success/failed signals to our internal slots. + */ + bool executeScriptAction(ScriptAction::Ptr action); + + /** + * The \a ScriptManagerGUI dialog will be displayed to + * let the user manage the scriptfiles. + */ + void showScriptManager(); + + private slots: + + /** + * Called if execution of this \a ScriptAction failed and + * displays an errormessage-dialog. + */ + void executionFailed(const QString& errormessage, const QString& tracedetails); + + /** + * Called if execution of this \a ScriptAction was + * successfully. The \a ScriptAction will be added + * to the history-collection of successfully executed + * \a ScriptAction instances. + */ + void successfullyExecuted(); + + signals: + /// Emitted if a \a ScriptActionCollection instances changed. + void collectionChanged(ScriptActionCollection*); + /// This signal is emited when the execution of a script is started + void executionStarted(const Kross::Api::ScriptAction* ); + /// This signal is emited when the execution of a script is finished + void executionFinished(const Kross::Api::ScriptAction* ); + private: + /// Internaly used private d-pointer. + ScriptGUIClientPrivate* d; + }; + +}} + +#endif + diff --git a/lib/kross/main/wdgscriptsmanager.cpp b/lib/kross/main/wdgscriptsmanager.cpp new file mode 100644 index 00000000..10924519 --- /dev/null +++ b/lib/kross/main/wdgscriptsmanager.cpp @@ -0,0 +1,354 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger <[email protected]> + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "wdgscriptsmanager.h" + +#include <qfile.h> +#include <qfileinfo.h> +#include <qheader.h> +#include <qobjectlist.h> +#include <qtooltip.h> + +#include <kapplication.h> +#include <kdeversion.h> +#include <kfiledialog.h> +#include <kiconloader.h> +#include <klistview.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpushbutton.h> +#include <kstandarddirs.h> +#include <ktoolbar.h> + +#if KDE_IS_VERSION(3, 4, 0) + // The KNewStuffSecure we use internaly for the GetHotNewStuff-functionality + // was introduced with KDE 3.4. + #define KROSS_SUPPORT_NEWSTUFF +#endif + +#ifdef KROSS_SUPPORT_NEWSTUFF + #include <knewstuff/provider.h> + #include <knewstuff/engine.h> + #include <knewstuff/downloaddialog.h> + #include <knewstuff/knewstuffsecure.h> +#endif + +#include "scriptguiclient.h" +#include "scriptaction.h" + +namespace Kross { namespace Api { + +#ifdef KROSS_SUPPORT_NEWSTUFF +class ScriptNewStuff : public KNewStuffSecure +{ + public: + ScriptNewStuff(ScriptGUIClient* scripguiclient, const QString& type, QWidget *parentWidget = 0) + : KNewStuffSecure(type, parentWidget) + , m_scripguiclient(scripguiclient) {} + virtual ~ScriptNewStuff() {} + private: + ScriptGUIClient* m_scripguiclient; + virtual void installResource() { m_scripguiclient->installScriptPackage( m_tarName ); } +}; +#endif + +class ListItem : public QListViewItem +{ + private: + ScriptActionCollection* m_collection; + ScriptAction::Ptr m_action; + public: + ListItem(QListView* parentview, ScriptActionCollection* collection) + : QListViewItem(parentview), m_collection(collection), m_action(0) {} + + ListItem(ListItem* parentitem, QListViewItem* afteritem, ScriptAction::Ptr action) + : QListViewItem(parentitem, afteritem), m_collection( parentitem->collection() ), m_action(action) {} + + ScriptAction::Ptr action() const { return m_action; } + ScriptActionCollection* collection() const { return m_collection; } + //ScriptActionMenu* actionMenu() const { return m_menu; } +}; + +class ToolTip : public QToolTip +{ + public: + ToolTip(KListView* parent) : QToolTip(parent->viewport()), m_parent(parent) {} + virtual ~ToolTip () { remove(m_parent->viewport()); } + protected: + virtual void maybeTip(const QPoint& p) { + ListItem* item = dynamic_cast<ListItem*>( m_parent->itemAt(p) ); + if(item) { + QRect r( m_parent->itemRect(item) ); + if(r.isValid() && item->action()) { + tip(r, QString("<qt>%1</qt>").arg(item->action()->toolTip())); + } + } + } + private: + KListView* m_parent; +}; + +class WdgScriptsManagerPrivate +{ + friend class WdgScriptsManager; + ScriptGUIClient* m_scripguiclient; + ToolTip* m_tooltip; +#ifdef KROSS_SUPPORT_NEWSTUFF + ScriptNewStuff* newstuff; +#endif + //enum { LoadBtn = 0, UnloadBtn, InstallBtn, UninstallBtn, ExecBtn, NewStuffBtn }; +}; + +WdgScriptsManager::WdgScriptsManager(ScriptGUIClient* scr, QWidget* parent, const char* name, WFlags fl ) + : WdgScriptsManagerBase(parent, name, fl) + , d(new WdgScriptsManagerPrivate) +{ + d->m_scripguiclient = scr; + d->m_tooltip = new ToolTip(scriptsList); +#ifdef KROSS_SUPPORT_NEWSTUFF + d->newstuff = 0; +#endif + + scriptsList->header()->hide(); + //scriptsList->header()->setClickEnabled(false); + scriptsList->setAllColumnsShowFocus(true); + //scriptsList->setRootIsDecorated(true); + scriptsList->setSorting(-1); + scriptsList->addColumn("text"); + //scriptsList->setColumnWidthMode(1, QListView::Manual); + + slotFillScriptsList(); + + slotSelectionChanged(0); + connect(scriptsList, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotSelectionChanged(QListViewItem*))); + + btnExec->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "exec", KIcon::MainToolbar, 16 )); + connect(btnExec, SIGNAL(clicked()), this, SLOT(slotExecuteScript())); + btnLoad->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "fileopen", KIcon::MainToolbar, 16 )); + connect(btnLoad, SIGNAL(clicked()), this, SLOT(slotLoadScript())); + btnUnload->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "fileclose", KIcon::MainToolbar, 16 )); + connect(btnUnload, SIGNAL(clicked()), this, SLOT(slotUnloadScript())); + btnInstall->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "fileimport", KIcon::MainToolbar, 16 )); + connect(btnInstall, SIGNAL(clicked()), this, SLOT(slotInstallScript())); + btnUninstall->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "fileclose", KIcon::MainToolbar, 16 )); + connect(btnUninstall, SIGNAL(clicked()), this, SLOT(slotUninstallScript())); +#ifdef KROSS_SUPPORT_NEWSTUFF + btnNewStuff->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "knewstuff", KIcon::MainToolbar, 16 )); + connect(btnNewStuff, SIGNAL(clicked()), this, SLOT(slotGetNewScript())); +#endif +/* + toolBar->setIconText( KToolBar::IconTextRight ); + + toolBar->insertButton("exec", WdgScriptsManagerPrivate::ExecBtn, false, i18n("Execute")); + toolBar->addConnection(WdgScriptsManagerPrivate::ExecBtn, SIGNAL(clicked()), this, SLOT(slotExecuteScript())); + toolBar->insertLineSeparator(); + toolBar->insertButton("fileopen", WdgScriptsManagerPrivate::LoadBtn, true, i18n("Load")); + toolBar->addConnection(WdgScriptsManagerPrivate::LoadBtn, SIGNAL(clicked()), this, SLOT(slotLoadScript())); + toolBar->insertButton("fileclose", WdgScriptsManagerPrivate::UnloadBtn, false, i18n("Unload")); + toolBar->addConnection(WdgScriptsManagerPrivate::UnloadBtn, SIGNAL(clicked()), this, SLOT(slotUnloadScript())); + toolBar->insertLineSeparator(); + toolBar->insertButton("fileimport", WdgScriptsManagerPrivate::InstallBtn, true, i18n("Install")); + toolBar->addConnection(WdgScriptsManagerPrivate::InstallBtn, SIGNAL(clicked()), this, SLOT(slotInstallScript())); + toolBar->insertButton("fileclose", WdgScriptsManagerPrivate::UninstallBtn, false, i18n("Uninstall")); + toolBar->addConnection(WdgScriptsManagerPrivate::UninstallBtn, SIGNAL(clicked()), this, SLOT(slotUninstallScript())); +#ifdef KROSS_SUPPORT_NEWSTUFF + toolBar->insertLineSeparator(); + toolBar->insertButton("knewstuff", WdgScriptsManagerPrivate::NewStuffBtn, true, i18n("Get More Scripts")); + toolBar->addConnection(WdgScriptsManagerPrivate::NewStuffBtn, SIGNAL(clicked()), this, SLOT(slotGetNewScript())); +#endif +*/ + connect(scr, SIGNAL( collectionChanged(ScriptActionCollection*) ), + this, SLOT( slotFillScriptsList() )); +} + +WdgScriptsManager::~WdgScriptsManager() +{ + delete d->m_tooltip; + delete d; +} + +void WdgScriptsManager::slotFillScriptsList() +{ + scriptsList->clear(); + + addItem( d->m_scripguiclient->getActionCollection("executedscripts") ); + addItem( d->m_scripguiclient->getActionCollection("loadedscripts") ); + addItem( d->m_scripguiclient->getActionCollection("installedscripts") ); +} + +void WdgScriptsManager::addItem(ScriptActionCollection* collection) +{ + if(! collection) + return; + + ListItem* i = new ListItem(scriptsList, collection); + i->setText(0, collection->actionMenu()->text()); + i->setOpen(true); + + QValueList<ScriptAction::Ptr> list = collection->actions(); + QListViewItem* lastitem = 0; + for(QValueList<ScriptAction::Ptr>::Iterator it = list.begin(); it != list.end(); ++it) + lastitem = addItem(*it, i, lastitem); +} + +QListViewItem* WdgScriptsManager::addItem(ScriptAction::Ptr action, QListViewItem* parentitem, QListViewItem* afteritem) +{ + if(! action) + return 0; + + ListItem* i = new ListItem(dynamic_cast<ListItem*>(parentitem), afteritem, action); + i->setText(0, action->text()); // FIXME: i18nise it for ko2.0 + //i->setText(1, action->getDescription()); // FIXME: i18nise it for ko2.0 + //i->setText(2, action->name()); + + QPixmap pm; + if(action->hasIcon()) { + KIconLoader* icons = KGlobal::iconLoader(); + pm = icons->loadIconSet(action->icon(), KIcon::Small).pixmap(QIconSet::Small, QIconSet::Active); + } + else { + pm = action->iconSet(KIcon::Small, 16).pixmap(QIconSet::Small, QIconSet::Active); + } + if(! pm.isNull()) + i->setPixmap(0, pm); // display the icon + + return i; +} + +void WdgScriptsManager::slotSelectionChanged(QListViewItem* item) +{ + ListItem* i = dynamic_cast<ListItem*>(item); + Kross::Api::ScriptActionCollection* installedcollection = d->m_scripguiclient->getActionCollection("installedscripts"); + + //toolBar->setItemEnabled(WdgScriptsManagerPrivate::ExecBtn, i && i->action()); + //toolBar->setItemEnabled(WdgScriptsManagerPrivate::UninstallBtn, i && i->action() && i->collection() == installedcollection); + //toolBar->setItemEnabled(WdgScriptsManagerPrivate::UnloadBtn, i && i->action() && i->collection() != installedcollection); + btnExec->setEnabled(i && i->action()); + btnUnload->setEnabled(i && i->action() && i->collection() != installedcollection); + btnUninstall->setEnabled(i && i->action() && i->collection() == installedcollection); +} + +void WdgScriptsManager::slotLoadScript() +{ + if(d->m_scripguiclient->loadScriptFile()) + slotFillScriptsList(); +} + +void WdgScriptsManager::slotInstallScript() +{ + KFileDialog* filedialog = new KFileDialog( + QString::null, // startdir + "*.tar.gz *.tgz *.bz2", // filter + this, // parent widget + "WdgScriptsManagerInstallFileDialog", // name + true // modal + ); + filedialog->setCaption( i18n("Install Script Package") ); + + if(! filedialog->exec()) + return; + + if(! d->m_scripguiclient->installScriptPackage( filedialog->selectedURL().path() )) { + krosswarning("Failed to install scriptpackage"); + return; + } + + slotFillScriptsList(); +} + +void WdgScriptsManager::slotUninstallScript() +{ + ListItem* item = dynamic_cast<ListItem*>( scriptsList->currentItem() ); + if( !item || !item->action() ) + return; + + Kross::Api::ScriptActionCollection* installedcollection = d->m_scripguiclient->getActionCollection("installedscripts"); + if( !item->collection() || item->collection() != installedcollection) + return; + + const QString packagepath = item->action()->getPackagePath(); + if( !packagepath) + return; + + if( KMessageBox::warningContinueCancel(0, + i18n("Uninstall the script package \"%1\" and delete the package's folder \"%2\"?") + .arg(item->action()->text()).arg(packagepath), + i18n("Uninstall")) != KMessageBox::Continue ) + { + return; + } + + if(! d->m_scripguiclient->uninstallScriptPackage(packagepath)) { + krosswarning("Failed to uninstall scriptpackage"); + return; + } + + slotFillScriptsList(); +} + +void WdgScriptsManager::slotExecuteScript() +{ + ListItem* item = dynamic_cast<ListItem*>( scriptsList->currentItem() ); + if(item && item->action()) + item->action()->activate(); +} + +void WdgScriptsManager::slotUnloadScript() +{ + ListItem* item = dynamic_cast<ListItem*>( scriptsList->currentItem() ); + if(item && item->action()) { + item->collection()->detach( item->action() ); + slotFillScriptsList(); + } +} + +void WdgScriptsManager::slotGetNewScript() +{ +#ifdef KROSS_SUPPORT_NEWSTUFF + const QString appname = KApplication::kApplication()->name(); + const QString type = QString("%1/script").arg(appname); + + if(! d->newstuff) { + d->newstuff = new ScriptNewStuff(d->m_scripguiclient, type); + connect(d->newstuff, SIGNAL(installFinished()), this, SLOT(slotResourceInstalled())); + } + + KNS::Engine *engine = new KNS::Engine(d->newstuff, type, this); + KNS::DownloadDialog *d = new KNS::DownloadDialog( engine, this ); + d->setType(type); + + KNS::ProviderLoader *p = new KNS::ProviderLoader(this); + QObject::connect(p, SIGNAL(providersLoaded(Provider::List*)), + d, SLOT(slotProviders(Provider::List*))); + + p->load(type, QString("http://download.kde.org/khotnewstuff/%1scripts-providers.xml").arg(appname)); + d->exec(); +#endif +} + +void WdgScriptsManager::slotResourceInstalled() +{ + // Delete KNewStuff's configuration entries. These entries reflect what has + // already been installed. As we cannot yet keep them in sync after uninstalling + // scripts, we deactivate the check marks entirely. + KGlobal::config()->deleteGroup("KNewStuffStatus"); +} + +}} + +#include "wdgscriptsmanager.moc" diff --git a/lib/kross/main/wdgscriptsmanager.h b/lib/kross/main/wdgscriptsmanager.h new file mode 100644 index 00000000..031d5b3c --- /dev/null +++ b/lib/kross/main/wdgscriptsmanager.h @@ -0,0 +1,60 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005-2006 Cyrille Berger <[email protected]> + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef WDGSCRIPTSMANAGER_H +#define WDGSCRIPTSMANAGER_H + +#include "main/scriptaction.h" +#include "main/wdgscriptsmanagerbase.h" + +class Scripting; + +namespace Kross { namespace Api { + +class ScriptGUIClient; +class WdgScriptsManagerPrivate; + +/** +@author Cyrille Berger +*/ +class WdgScriptsManager : public WdgScriptsManagerBase +{ + Q_OBJECT + public: + WdgScriptsManager(ScriptGUIClient* scr, QWidget* parent = 0, const char* name = 0, WFlags fl = 0); + ~WdgScriptsManager(); + public slots: + void slotLoadScript(); + void slotInstallScript(); + void slotUninstallScript(); + void slotExecuteScript(); + void slotUnloadScript(); + void slotGetNewScript(); + void slotSelectionChanged(QListViewItem*); + private slots: + void slotFillScriptsList(); + void slotResourceInstalled(); + private: + WdgScriptsManagerPrivate* d; + void addItem(ScriptActionCollection* collection); + QListViewItem* addItem(ScriptAction::Ptr, QListViewItem* parentitem, QListViewItem* afteritem); +}; + +}} + +#endif diff --git a/lib/kross/main/wdgscriptsmanagerbase.ui b/lib/kross/main/wdgscriptsmanagerbase.ui new file mode 100644 index 00000000..18ab2b23 --- /dev/null +++ b/lib/kross/main/wdgscriptsmanagerbase.ui @@ -0,0 +1,247 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>WdgScriptsManagerBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>WdgScriptsManagerBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>181</width> + <height>467</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="caption"> + <string>Scripts Manager</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KListView"> + <property name="name"> + <cstring>scriptsList</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>2</hsizetype> + <vsizetype>2</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KToolBar"> + <property name="name"> + <cstring>toolBar</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>btnExec</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Execute</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line2</cstring> + </property> + <property name="frameShape"> + <enum>VLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>btnLoad</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Load</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>btnUnload</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Unload</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line3</cstring> + </property> + <property name="frameShape"> + <enum>VLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>btnInstall</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Install</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>btnUninstall</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Uninstall</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line4</cstring> + </property> + <property name="frameShape"> + <enum>VLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>btnNewStuff</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Get More Scripts</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>KToolBar</class> + <header location="local">ktoolbar.h</header> + <sizehint> + <width>20</width> + <height>100</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> + <includehint>ktoolbar.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> |