summaryrefslogtreecommitdiffstats
path: root/lib/kross
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kross')
-rw-r--r--lib/kross/CHANGES20
-rw-r--r--lib/kross/Makefile.am22
-rw-r--r--lib/kross/Makefile.global2
-rw-r--r--lib/kross/api/Makefile.am47
-rw-r--r--lib/kross/api/callable.cpp139
-rw-r--r--lib/kross/api/callable.h147
-rw-r--r--lib/kross/api/class.h89
-rw-r--r--lib/kross/api/dict.cpp47
-rw-r--r--lib/kross/api/dict.h69
-rw-r--r--lib/kross/api/event.h229
-rw-r--r--lib/kross/api/eventaction.cpp77
-rw-r--r--lib/kross/api/eventaction.h86
-rw-r--r--lib/kross/api/eventscript.cpp47
-rw-r--r--lib/kross/api/eventscript.h65
-rw-r--r--lib/kross/api/eventsignal.cpp66
-rw-r--r--lib/kross/api/eventsignal.h79
-rw-r--r--lib/kross/api/eventslot.cpp222
-rw-r--r--lib/kross/api/eventslot.h123
-rw-r--r--lib/kross/api/exception.cpp71
-rw-r--r--lib/kross/api/exception.h102
-rw-r--r--lib/kross/api/function.h132
-rw-r--r--lib/kross/api/interpreter.cpp151
-rw-r--r--lib/kross/api/interpreter.h197
-rw-r--r--lib/kross/api/list.cpp69
-rw-r--r--lib/kross/api/list.h167
-rw-r--r--lib/kross/api/module.h80
-rw-r--r--lib/kross/api/object.cpp63
-rw-r--r--lib/kross/api/object.h152
-rw-r--r--lib/kross/api/proxy.h342
-rw-r--r--lib/kross/api/qtobject.cpp235
-rw-r--r--lib/kross/api/qtobject.h135
-rw-r--r--lib/kross/api/script.cpp59
-rw-r--r--lib/kross/api/script.h140
-rw-r--r--lib/kross/api/value.h91
-rw-r--r--lib/kross/api/variant.cpp168
-rw-r--r--lib/kross/api/variant.h207
-rw-r--r--lib/kross/configure.in.bot16
-rw-r--r--lib/kross/configure.in.in108
-rw-r--r--lib/kross/main/Makefile.am33
-rw-r--r--lib/kross/main/krossconfig.cpp36
-rw-r--r--lib/kross/main/krossconfig.h116
-rw-r--r--lib/kross/main/mainmodule.cpp117
-rw-r--r--lib/kross/main/mainmodule.h181
-rw-r--r--lib/kross/main/manager.cpp248
-rw-r--r--lib/kross/main/manager.h168
-rw-r--r--lib/kross/main/scriptaction.cpp247
-rw-r--r--lib/kross/main/scriptaction.h309
-rw-r--r--lib/kross/main/scriptcontainer.cpp293
-rw-r--r--lib/kross/main/scriptcontainer.h210
-rw-r--r--lib/kross/main/scriptguiclient.cpp384
-rw-r--r--lib/kross/main/scriptguiclient.h217
-rw-r--r--lib/kross/main/wdgscriptsmanager.cpp354
-rw-r--r--lib/kross/main/wdgscriptsmanager.h60
-rw-r--r--lib/kross/main/wdgscriptsmanagerbase.ui247
-rw-r--r--lib/kross/python/Makefile.am33
-rw-r--r--lib/kross/python/cxx/Config.hxx74
-rw-r--r--lib/kross/python/cxx/Exception.hxx212
-rw-r--r--lib/kross/python/cxx/Extensions.hxx756
-rw-r--r--lib/kross/python/cxx/IndirectPythonInterface.cxx550
-rw-r--r--lib/kross/python/cxx/IndirectPythonInterface.hxx156
-rwxr-xr-xlib/kross/python/cxx/Legal.html40
-rw-r--r--lib/kross/python/cxx/Makefile.am19
-rw-r--r--lib/kross/python/cxx/Objects.hxx2804
-rw-r--r--lib/kross/python/cxx/PyCXX.html2131
-rw-r--r--lib/kross/python/cxx/README.html436
-rw-r--r--lib/kross/python/cxx/Readme.Kross.txt16
-rw-r--r--lib/kross/python/cxx/Version.txt1
-rw-r--r--lib/kross/python/cxx/cxx_extensions.cxx1287
-rw-r--r--lib/kross/python/cxx/cxxextensions.c19
-rw-r--r--lib/kross/python/cxx/cxxsupport.cxx142
-rw-r--r--lib/kross/python/pythonconfig.h105
-rw-r--r--lib/kross/python/pythonextension.cpp445
-rw-r--r--lib/kross/python/pythonextension.h221
-rw-r--r--lib/kross/python/pythoninterpreter.cpp255
-rw-r--r--lib/kross/python/pythoninterpreter.h90
-rw-r--r--lib/kross/python/pythonmodule.cpp100
-rw-r--r--lib/kross/python/pythonmodule.h76
-rw-r--r--lib/kross/python/pythonobject.cpp94
-rw-r--r--lib/kross/python/pythonobject.h95
-rw-r--r--lib/kross/python/pythonscript.cpp460
-rw-r--r--lib/kross/python/pythonscript.h98
-rw-r--r--lib/kross/python/pythonsecurity.cpp181
-rw-r--r--lib/kross/python/pythonsecurity.h109
-rw-r--r--lib/kross/python/scripts/Makefile.am4
-rw-r--r--lib/kross/python/scripts/RestrictedPython/Eval.py118
-rw-r--r--lib/kross/python/scripts/RestrictedPython/Guards.py136
-rw-r--r--lib/kross/python/scripts/RestrictedPython/Limits.py46
-rw-r--r--lib/kross/python/scripts/RestrictedPython/Makefile.am4
-rw-r--r--lib/kross/python/scripts/RestrictedPython/MutatingWalker.py74
-rw-r--r--lib/kross/python/scripts/RestrictedPython/PrintCollector.py23
-rw-r--r--lib/kross/python/scripts/RestrictedPython/RCompile.py235
-rw-r--r--lib/kross/python/scripts/RestrictedPython/RestrictionMutator.py372
-rw-r--r--lib/kross/python/scripts/RestrictedPython/SelectCompiler.py28
-rw-r--r--lib/kross/python/scripts/RestrictedPython/Utilities.py77
-rw-r--r--lib/kross/python/scripts/RestrictedPython/__init__.py19
-rwxr-xr-xlib/kross/python/scripts/gui.py396
-rw-r--r--lib/kross/readme.dox28
-rw-r--r--lib/kross/ruby/Makefile.am16
-rw-r--r--lib/kross/ruby/rubyconfig.h42
-rw-r--r--lib/kross/ruby/rubyextension.cpp378
-rw-r--r--lib/kross/ruby/rubyextension.h162
-rw-r--r--lib/kross/ruby/rubyinterpreter.cpp149
-rw-r--r--lib/kross/ruby/rubyinterpreter.h73
-rw-r--r--lib/kross/ruby/rubymodule.cpp68
-rw-r--r--lib/kross/ruby/rubymodule.h73
-rw-r--r--lib/kross/ruby/rubyscript.cpp193
-rw-r--r--lib/kross/ruby/rubyscript.h98
-rw-r--r--lib/kross/runner/Makefile.am11
-rw-r--r--lib/kross/runner/main.cpp144
-rw-r--r--lib/kross/test/Makefile.am17
-rw-r--r--lib/kross/test/main.cpp190
-rw-r--r--lib/kross/test/testaction.cpp49
-rw-r--r--lib/kross/test/testaction.h50
-rw-r--r--lib/kross/test/testcase.py144
-rw-r--r--lib/kross/test/testcase.rb15
-rw-r--r--lib/kross/test/testgui.py149
-rw-r--r--lib/kross/test/testkexidb.py214
-rw-r--r--lib/kross/test/testobject.cpp96
-rw-r--r--lib/kross/test/testobject.h64
-rwxr-xr-xlib/kross/test/testperformance.py75
-rw-r--r--lib/kross/test/testplugin.cpp126
-rw-r--r--lib/kross/test/testplugin.h75
-rw-r--r--lib/kross/test/testscripting.rc33
-rw-r--r--lib/kross/test/testwindow.cpp110
-rw-r--r--lib/kross/test/testwindow.h55
125 files changed, 22915 insertions, 0 deletions
diff --git a/lib/kross/CHANGES b/lib/kross/CHANGES
new file mode 100644
index 00000000..096aff0e
--- /dev/null
+++ b/lib/kross/CHANGES
@@ -0,0 +1,20 @@
+== Kross CHANGES ==
+
+1.6
+* Added krossdebug and krosswarning.
+* Integrated ProxyFunction's.
+* Python: Added unittest.
+* Removed Argument class.
+* Refactor of the tree-handling to improve the performance.
+* Tweaks on Object and Value to improve the performance.
+* Python: Fixed crasher in PyEval_EvalCode
+
+1.5.2
+* API: Fix possible crash in Manager::getInterpreternameForFile()
+
+1.5.1
+* Python: Fix compile with gcc 3.3.6
+
+1.5
+* Ruby: Fix 124649: libruby-devel lost when build.
+* Ruby: Fix crash cause of invalid rNode.
diff --git a/lib/kross/Makefile.am b/lib/kross/Makefile.am
new file mode 100644
index 00000000..6e0fa847
--- /dev/null
+++ b/lib/kross/Makefile.am
@@ -0,0 +1,22 @@
+# Compile python plugin only if python is installed. Kross itself doesn't
+# care of it cause it doesn't depend directly on the python plugin. Kross
+# determinates at runtime if it's avaiable and if that's the case it just
+# uses the plugin. So, we are able to don't compile the python plugin now
+# and at a later stage once we like to use it, just compile+install the
+# python plugin and let Kross use it without the need to recompiling whole
+# Kross. So, for packagers it's recommed to move the python plugin into
+# an own package that could be optional installed.
+if compile_kross_python
+ PYTHONSUBDIR = python
+endif
+
+# Also only compile the ruby plugin if ruby is installed.
+if compile_kross_ruby
+ RUBYSUBDIR = ruby
+endif
+
+SUBDIRS = api main $(PYTHONSUBDIR) $(RUBYSUBDIR) runner
+
+# Don't compile test by default. To use test, just cd into the directory
+# and do a "make && ./krosstest" manualy.
+#SUBDIRS += test
diff --git a/lib/kross/Makefile.global b/lib/kross/Makefile.global
new file mode 100644
index 00000000..db6d32df
--- /dev/null
+++ b/lib/kross/Makefile.global
@@ -0,0 +1,2 @@
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+VER_INFO = -version-info 1:0:0
diff --git a/lib/kross/api/Makefile.am b/lib/kross/api/Makefile.am
new file mode 100644
index 00000000..166e1bfa
--- /dev/null
+++ b/lib/kross/api/Makefile.am
@@ -0,0 +1,47 @@
+include $(top_srcdir)/lib/kross/Makefile.global
+apiincludedir=$(includedir)/kross/api
+
+apiinclude_HEADERS = \
+ callable.h \
+ class.h \
+ dict.h \
+ eventaction.h \
+ event.h \
+ eventscript.h \
+ eventsignal.h \
+ eventslot.h \
+ exception.h \
+ function.h \
+ interpreter.h \
+ list.h \
+ module.h \
+ object.h \
+ proxy.h \
+ qtobject.h \
+ script.h \
+ value.h \
+ variant.h
+
+lib_LTLIBRARIES = libkrossapi.la
+
+libkrossapi_la_SOURCES = \
+ object.cpp \
+ variant.cpp \
+ list.cpp \
+ dict.cpp \
+ exception.cpp \
+ callable.cpp \
+ eventaction.cpp \
+ eventsignal.cpp \
+ eventslot.cpp \
+ eventscript.cpp \
+ qtobject.cpp \
+ script.cpp \
+ interpreter.cpp
+
+libkrossapi_la_LDFLAGS = $(all_libraries) $(VER_INFO) -Wnounresolved
+libkrossapi_la_LIBADD = $(LIB_QT) $(LIB_KDECORE)
+
+METASOURCES = AUTO
+SUBDIRS = .
+INCLUDES = $(KROSS_INCLUDES) $(all_includes)
diff --git a/lib/kross/api/callable.cpp b/lib/kross/api/callable.cpp
new file mode 100644
index 00000000..261a1bf0
--- /dev/null
+++ b/lib/kross/api/callable.cpp
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * callable.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "callable.h"
+#include "variant.h"
+#include "dict.h"
+
+#include "../main/krossconfig.h"
+
+using namespace Kross::Api;
+
+Callable::Callable(const QString& name)
+ : Object()
+ , m_name(name)
+{
+}
+
+Callable::~Callable()
+{
+}
+
+const QString Callable::getName() const
+{
+ return m_name;
+}
+
+const QString Callable::getClassName() const
+{
+ return "Kross::Api::Callable";
+}
+
+bool Callable::hasChild(const QString& name) const
+{
+ return m_children.contains(name);
+}
+
+Object::Ptr Callable::getChild(const QString& name) const
+{
+ return m_children[name];
+}
+
+QMap<QString, Object::Ptr> Callable::getChildren() const
+{
+ return m_children;
+}
+
+bool Callable::addChild(const QString& name, Object* object)
+{
+#ifdef KROSS_API_OBJECT_ADDCHILD_DEBUG
+ krossdebug( QString("Kross::Api::Callable::addChild() object.name='%1' object.classname='%2'")
+ .arg(name).arg(object->getClassName()) );
+#endif
+ m_children.replace(name, Object::Ptr(object));
+ return true;
+}
+
+bool Callable::addChild(Callable* object)
+{
+ return addChild(object->getName(), object);
+}
+
+void Callable::removeChild(const QString& name)
+{
+#ifdef KROSS_API_OBJECT_REMCHILD_DEBUG
+ krossdebug( QString("Kross::Api::Callable::removeChild() name='%1'").arg(name) );
+#endif
+ m_children.remove(name);
+}
+
+void Callable::removeAllChildren()
+{
+#ifdef KROSS_API_OBJECT_REMCHILD_DEBUG
+ krossdebug( "Kross::Api::Callable::removeAllChildren()" );
+#endif
+ m_children.clear();
+}
+
+Object::Ptr Callable::call(const QString& name, List::Ptr args)
+{
+#ifdef KROSS_API_CALLABLE_CALL_DEBUG
+ krossdebug( QString("Kross::Api::Callable::call() name=%1 getName()=%2 arguments=%3").arg(name).arg(getName()).arg(args ? args->toString() : QString("")) );
+#endif
+
+ if(name.isEmpty()) // return a self-reference if no functionname is defined.
+ return this;
+
+ // if name is defined try to get the matching child and pass the call to it.
+ Object::Ptr object = getChild(name);
+ if(object) {
+ //TODO handle namespace, e.g. "mychild1.mychild2.myfunction"
+ return object->call(name, args);
+ }
+
+ if(name == "get") {
+ QString s = Variant::toString(args->item(0));
+ Object::Ptr obj = getChild(s);
+ if(! obj)
+ throw Exception::Ptr( new Exception(QString("The object '%1' has no child object '%2'").arg(getName()).arg(s)) );
+ return obj;
+ }
+ else if(name == "has") {
+ return new Variant( hasChild( Variant::toString(args->item(0)) ) );
+ }
+ else if(name == "call") {
+ //TODO should we remove first args-item?
+ return Object::call(Variant::toString(args->item(0)), args);
+ }
+ else if(name == "list") {
+ QStringList list;
+ QMap<QString, Object::Ptr> children = getChildren();
+ QMap<QString, Object::Ptr>::Iterator it( children.begin() );
+ for(; it != children.end(); ++it)
+ list.append( it.key() );
+ return new Variant(list);
+ }
+ else if(name == "dict") {
+ return new Dict( getChildren() );
+ }
+
+ // If there exists no such object return NULL.
+ krossdebug( QString("Object '%1' has no callable object named '%2'.").arg(getName()).arg(name) );
+ return 0;
+}
diff --git a/lib/kross/api/callable.h b/lib/kross/api/callable.h
new file mode 100644
index 00000000..4d25bd91
--- /dev/null
+++ b/lib/kross/api/callable.h
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * callable.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_CALLABLE_H
+#define KROSS_API_CALLABLE_H
+
+#include "object.h"
+#include "list.h"
+//#include "exception.h"
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <ksharedptr.h>
+
+namespace Kross { namespace Api {
+
+ /**
+ * Base class for callable objects. Classes like
+ * \a Event or \a Class are inherited from this class
+ * and implement the \a Object::call() method to handle
+ * the call.
+ */
+ class Callable : public Object
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<Callable> Ptr;
+
+ /**
+ * Constructor.
+ *
+ * \param name The name this callable object has and
+ * it is reachable as via \a getChild() .
+ */
+ Callable(const QString& name);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Callable();
+
+ /**
+ * \return the name this object has. Each callable object
+ * has a name which is used e.g. on \a addChild to be able
+ * to identify the object itself.
+ */
+ const QString getName() const;
+
+ /**
+ * Return the class name. This could be something
+ * like "Kross::Api::Callable" for this object. The
+ * value is mainly used for display purposes.
+ *
+ * \return The name of this class.
+ */
+ virtual const QString getClassName() const;
+
+ /**
+ * Returns if the defined child is avaible.
+ *
+ * \return true if child exists else false.
+ */
+ bool hasChild(const QString& name) const;
+
+ /**
+ * Return the defined child or NULL if there is
+ * no such object with that name avaible.
+ *
+ * \param name The name of the Object to return.
+ * \return The Object matching to the defined
+ * name or NULL if there is no such Object.
+ */
+ Object::Ptr getChild(const QString& name) const;
+
+ /**
+ * Return all children.
+ *
+ * \return A \a ObjectMap of children this Object has.
+ */
+ QMap<QString, Object::Ptr> getChildren() const;
+
+ /**
+ * Add a new child. Replaces a possible already existing
+ * child with such a name.
+ *
+ * \param name the name of the child
+ * \param object The Object to add.
+ * \return true if the Object was added successfully
+ * else false.
+ */
+ bool addChild(const QString& name, Object* object);
+
+ /**
+ * Same as the \a addChild method above but for callable
+ * objects which define there own name.
+ */
+ bool addChild(Callable* object);
+
+ /**
+ * Remove an existing child.
+ *
+ * \param name The name of the Object to remove.
+ * If there doesn't exists an Object with
+ * such name just nothing will be done.
+ */
+ void removeChild(const QString& name);
+
+ /**
+ * Remove all children.
+ */
+ void removeAllChildren();
+
+ /**
+ * Call the object.
+ */
+ virtual Object::Ptr call(const QString& name, List::Ptr arguments);
+
+ private:
+ /// Name this callable object has.
+ QString m_name;
+ /// A list of childobjects.
+ QMap<QString, Object::Ptr> m_children;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/class.h b/lib/kross/api/class.h
new file mode 100644
index 00000000..afcfe425
--- /dev/null
+++ b/lib/kross/api/class.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * class.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_CLASS_H
+#define KROSS_API_CLASS_H
+
+#include <qstring.h>
+//#include <qvaluelist.h>
+//#include <qmap.h>
+#include <qobject.h>
+
+//#include "../main/krossconfig.h"
+#include "object.h"
+#include "event.h"
+#include "list.h"
+#include "exception.h"
+#include "variant.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * From \a Event inherited template-class to represent
+ * class-structures. Classes implemetating this template
+ * are able to dynamicly define \a Event methodfunctions
+ * accessible from within scripts.
+ */
+ template<class T>
+ class Class : public Event<T>
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<T> Ptr;
+
+ /**
+ * Constructor.
+ *
+ * \param name The name this class has.
+ */
+ Class(const QString& name)
+ : Event<T>(name)
+ {
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~Class()
+ {
+ }
+
+ template<typename TYPE>
+ static Object::Ptr toObject(TYPE t) { return t; }
+
+ operator T* () { return (T*)this; }
+ //operator Ptr () { return (T*)this; }
+
+ /*
+ virtual Object::Ptr call(const QString& name, List::Ptr arguments)
+ {
+ krossdebug( QString("Class::call(%1)").arg(name) );
+ return Event<T>::call(name, arguments);
+ }
+ */
+
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/dict.cpp b/lib/kross/api/dict.cpp
new file mode 100644
index 00000000..b9fa5ddc
--- /dev/null
+++ b/lib/kross/api/dict.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * dict.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "dict.h"
+//#include "exception.h"
+
+using namespace Kross::Api;
+
+Dict::Dict(const QMap<QString, Object::Ptr> value)
+ : Value< List, QMap<QString, Object::Ptr> >(value)
+{
+}
+
+Dict::~Dict()
+{
+}
+
+const QString Dict::getClassName() const
+{
+ return "Kross::Api::Dict";
+}
+
+const QString Dict::toString()
+{
+ QString s = "[";
+ QMap<QString, Object::Ptr> list = getValue();
+ for(QMap<QString, Object::Ptr>::Iterator it = list.begin(); it != list.end(); ++it)
+ s += "'" + it.key() + "' = '" + it.data()->toString() + "', ";
+ return (s.endsWith(", ") ? s.left(s.length() - 2) : s) + "]";
+}
+
diff --git a/lib/kross/api/dict.h b/lib/kross/api/dict.h
new file mode 100644
index 00000000..773f36ac
--- /dev/null
+++ b/lib/kross/api/dict.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * dict.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_DICT_H
+#define KROSS_API_DICT_H
+
+#include <qstring.h>
+#include <qmap.h>
+
+#include "object.h"
+#include "value.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * The Dict class implementates \a Value to handle
+ * key=value base dictonaries/maps.
+ */
+ class Dict : public Value< List, QMap<QString, Object::Ptr> >
+ {
+ friend class Value< List, QMap<QString, Object::Ptr> >;
+ public:
+
+ /**
+ * Constructor.
+ *
+ * @param value The map of \a Object instances accessible
+ * via there string-identifier that is in this
+ * \a Dict intialy.
+ */
+ explicit Dict(const QMap<QString, Object::Ptr> value);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Dict();
+
+ /// \see Kross::Api::Object::getClassName()
+ virtual const QString getClassName() const;
+
+ /**
+ * \return a string representation of the whole dictonary.
+ *
+ * \see Kross::Api::Object::toString()
+ */
+ virtual const QString toString();
+
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/event.h b/lib/kross/api/event.h
new file mode 100644
index 00000000..2df5a331
--- /dev/null
+++ b/lib/kross/api/event.h
@@ -0,0 +1,229 @@
+/***************************************************************************
+ * event.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_EVENT_H
+#define KROSS_API_EVENT_H
+
+#include "../main/krossconfig.h"
+#include "object.h"
+#include "callable.h"
+#include "list.h"
+#include "exception.h"
+#include "function.h"
+#include "proxy.h"
+#include "variant.h"
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+
+namespace Kross { namespace Api {
+
+ /**
+ * Template class for all kinds of callable events. An
+ * event is the abstract base for callable objects like
+ * methodfunctions in \a Class instances or \a EventSlot
+ * and \a EventSignal to access Qt signals and slots.
+ */
+ template<class T>
+ class Event : public Callable
+ {
+ private:
+
+ /**
+ * Definition of function-pointers.
+ */
+ typedef Object::Ptr(T::*FunctionPtr)(List::Ptr);
+
+ /**
+ * List of memberfunctions. Each function is accessible
+ * by the functionname.
+ */
+ QMap<QString, Function* > m_functions;
+
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param name The name this \a Event has.
+ */
+ Event(const QString& name)
+ : Callable(name)
+ {
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~Event()
+ {
+ QMapConstIterator<QString, Function* > endit = m_functions.constEnd();
+ for(QMapConstIterator<QString, Function* > it = m_functions.constBegin(); it != endit; ++it)
+ delete it.data();
+ }
+
+ /**
+ * Add a \a Callable methodfunction to the list of functions
+ * this Object supports.
+ *
+ * The FunctionPtr points to the concret
+ * Object::Ptr myfuncname(List::Ptr)
+ * method in the class defined with template T.
+ *
+ * \param name The functionname. Each function this object
+ * holds should have an unique name to be
+ * still accessable.
+ * \param function A pointer to the methodfunction that
+ * should handle calls.
+ *
+ * \todo Remove this method as soon as there is no code using it
+ */
+ inline void addFunction(const QString& name, FunctionPtr function)
+ {
+ m_functions.replace(name, new Function0<T>(static_cast<T*>(this), function));
+ }
+
+ /**
+ * Add a methodfunction to the list of functions this Object
+ * supports.
+ *
+ * \param name The functionname. Each function this object
+ * holds should have an unique name to be
+ * still accessable.
+ * \param function A \a Function instance which defines
+ * the methodfunction. This \a Event will be the
+ * owner of the \a Function instance and will take
+ * care of deleting it if this \a Event got deleted.
+ */
+ inline void addFunction(const QString& name, Function* function)
+ {
+ m_functions.replace(name, function);
+ }
+
+ /**
+ * Template function to add a \a ProxyFunction as builtin-function
+ * to this \a Event instance.
+ */
+ template<class RETURNOBJ, class ARG1OBJ, class ARG2OBJ, class ARG3OBJ, class ARG4OBJ, class INSTANCE, typename METHOD>
+ inline void addFunction4(const QString& name, INSTANCE* instance, METHOD method, ARG1OBJ* arg1 = 0, ARG2OBJ* arg2 = 0, ARG3OBJ* arg3 = 0, ARG4OBJ* arg4 = 0)
+ {
+ m_functions.replace(name,
+ new Kross::Api::ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ, ARG2OBJ, ARG3OBJ, ARG4OBJ>
+ (instance, method, arg1, arg2, arg3, arg4)
+ );
+ }
+
+ /// Same as above with three arguments.
+ template<class RETURNOBJ, class ARG1OBJ, class ARG2OBJ, class ARG3OBJ, class INSTANCE, typename METHOD>
+ inline void addFunction3(const QString& name, INSTANCE* instance, METHOD method, ARG1OBJ* arg1 = 0, ARG2OBJ* arg2 = 0, ARG3OBJ* arg3 = 0)
+ {
+ m_functions.replace(name,
+ new Kross::Api::ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ, ARG2OBJ, ARG3OBJ>
+ (instance, method, arg1, arg2, arg3)
+ );
+ }
+
+ /// Same as above with two arguments.
+ template<class RETURNOBJ, class ARG1OBJ, class ARG2OBJ, class INSTANCE, typename METHOD>
+ inline void addFunction2(const QString& name, INSTANCE* instance, METHOD method, ARG1OBJ* arg1 = 0, ARG2OBJ* arg2 = 0)
+ {
+ m_functions.replace(name,
+ new Kross::Api::ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ, ARG2OBJ>
+ (instance, method, arg1, arg2)
+ );
+ }
+
+ /// Same as above, but with one argument.
+ template<class RETURNOBJ, class ARG1OBJ, class INSTANCE, typename METHOD>
+ inline void addFunction1(const QString& name, INSTANCE* instance, METHOD method, ARG1OBJ* arg1 = 0)
+ {
+ m_functions.replace(name,
+ new Kross::Api::ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ>
+ (instance, method, arg1)
+ );
+ }
+
+ /// Same as above with no arguments.
+ template<class RETURNOBJ, class INSTANCE, typename METHOD>
+ inline void addFunction0(const QString& name, INSTANCE* instance, METHOD method)
+ {
+ m_functions.replace(name,
+ new Kross::Api::ProxyFunction<INSTANCE, METHOD, RETURNOBJ>
+ (instance, method)
+ );
+ }
+
+ /**
+ * Check if a function is a member of this \a Callable
+ * \param name the function name
+ * \return true if the function is available in this \a Callable
+ */
+ bool isAFunction(const QString & name) const
+ {
+ return m_functions.contains(name);
+ }
+
+ /**
+ * Overloaded method to handle function-calls.
+ *
+ * \throw AttributeException if argumentparameters
+ * arn't valid.
+ * \throw RuntimeException if the functionname isn't
+ * valid.
+ * \param name The functionname. Each function this
+ * Object holds should have a different
+ * name cause they are access by they name.
+ * If name is QString::null or empty, a
+ * self-reference to this instance is
+ * returned.
+ * \param arguments The list of arguments.
+ * \return An Object representing the call result
+ * or NULL if there doesn't exists such a
+ * function with defined name.
+ */
+ virtual Object::Ptr call(const QString& name, List::Ptr arguments)
+ {
+#ifdef KROSS_API_EVENT_CALL_DEBUG
+ krossdebug( QString("Event::call() name='%1' getName()='%2'").arg(name).arg(getName()) );
+#endif
+
+ Function* function = m_functions[name];
+ if(function) {
+#ifdef KROSS_API_EVENT_CALL_DEBUG
+ krossdebug( QString("Event::call() name='%1' is a builtin function.").arg(name) );
+#endif
+ return function->call(arguments);
+ }
+
+ if(name.isNull()) {
+ // If no name is defined, we return a reference to our instance.
+ return this;
+ }
+
+ // Redirect the call to the Kross::Api::Callable we are inherited from.
+ return Callable::call(name, arguments);
+ }
+
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/eventaction.cpp b/lib/kross/api/eventaction.cpp
new file mode 100644
index 00000000..fffaec5c
--- /dev/null
+++ b/lib/kross/api/eventaction.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * eventaction.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "eventaction.h"
+#include "variant.h"
+
+//#include <qobject.h>
+//#include <kaction.h>
+
+using namespace Kross::Api;
+
+EventAction::EventAction(const QString& name, KAction* action)
+ : Event<EventAction>(name.isEmpty() ? action->name() : name)
+ , m_action(action)
+{
+ addFunction("getText", &EventAction::getText);
+ addFunction("setText", &EventAction::setText);
+
+ addFunction("isEnabled", &EventAction::isEnabled);
+ addFunction("setEnabled", &EventAction::setEnabled);
+
+ addFunction("activate", &EventAction::activate);
+}
+
+EventAction::~EventAction()
+{
+}
+
+const QString EventAction::getClassName() const
+{
+ return "Kross::Api::EventAction";
+}
+
+Object::Ptr EventAction::getText(List::Ptr)
+{
+ return new Variant(m_action->text());
+}
+
+Object::Ptr EventAction::setText(List::Ptr args)
+{
+ m_action->setText( Variant::toString(args->item(0)) );
+ return 0;
+}
+
+Object::Ptr EventAction::isEnabled(List::Ptr)
+{
+ return new Variant(m_action->isEnabled());
+}
+
+Object::Ptr EventAction::setEnabled(List::Ptr args)
+{
+ m_action->setEnabled( Variant::toBool(args->item(0)) );
+ return 0;
+}
+
+Object::Ptr EventAction::activate(List::Ptr)
+{
+ m_action->activate();
+ return 0;
+}
+
diff --git a/lib/kross/api/eventaction.h b/lib/kross/api/eventaction.h
new file mode 100644
index 00000000..8f09c116
--- /dev/null
+++ b/lib/kross/api/eventaction.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * eventaction.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_EVENTACTION_H
+#define KROSS_API_EVENTACTION_H
+
+#include <qstring.h>
+//#include <qobject.h>
+#include <kaction.h>
+#include <ksharedptr.h>
+
+#include "event.h"
+
+namespace Kross { namespace Api {
+
+ // Forward declarations.
+ class ScriptContainer;
+
+ /**
+ * The EventAction class is used to wrap KAction instances
+ * into the Kross object hierachy and provide access to
+ * them.
+ */
+ class EventAction : public Event<EventAction>
+ {
+
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<EventAction> Ptr;
+
+ /**
+ * Constructor.
+ */
+ EventAction(const QString& name, KAction* action);
+
+ /**
+ * Destructor.
+ */
+ virtual ~EventAction();
+
+ /// \see Kross::Api::Object::getClassName()
+ virtual const QString getClassName() const;
+
+ /// \see Kross::Api::Event::call()
+ //virtual Object::Ptr call(const QString& name, KSharedPtr<List> arguments);
+
+ private:
+ KAction* m_action;
+
+ /// \return the text associated with this action.
+ Kross::Api::Object::Ptr getText(Kross::Api::List::Ptr);
+ /// Sets the text associated with this action.
+ Kross::Api::Object::Ptr setText(Kross::Api::List::Ptr);
+
+ /// \return true if this action is enabled else false.
+ Kross::Api::Object::Ptr isEnabled(Kross::Api::List::Ptr);
+ /// Enables or disables this action.
+ Kross::Api::Object::Ptr setEnabled(Kross::Api::List::Ptr);
+
+ /// Activates the action.
+ Kross::Api::Object::Ptr activate(Kross::Api::List::Ptr);
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/eventscript.cpp b/lib/kross/api/eventscript.cpp
new file mode 100644
index 00000000..39ceb59d
--- /dev/null
+++ b/lib/kross/api/eventscript.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * eventscript.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "eventscript.h"
+//#include "object.h"
+//#include "variant.h"
+//#include "../main/scriptcontainer.h"
+
+using namespace Kross::Api;
+
+EventScript::EventScript(const QString& name)
+ : Event<EventScript>(name)
+{
+}
+
+EventScript::~EventScript()
+{
+}
+
+const QString EventScript::getClassName() const
+{
+ return "Kross::Api::EventScript";
+}
+
+Object::Ptr EventScript::call(const QString& name, KSharedPtr<List> arguments)
+{
+ krossdebug( QString("EventScript::call() name=%1 arguments=%2").arg(name).arg(arguments->toString()) );
+ //TODO
+ return 0;
+}
+
diff --git a/lib/kross/api/eventscript.h b/lib/kross/api/eventscript.h
new file mode 100644
index 00000000..8ef9b7eb
--- /dev/null
+++ b/lib/kross/api/eventscript.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * eventscript.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_EVENTSCRIPT_H
+#define KROSS_API_EVENTSCRIPT_H
+
+#include <qstring.h>
+#include <qobject.h>
+
+#include "event.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * \todo implement EventScript ?!
+ */
+ class EventScript : public Event<EventScript>
+ {
+
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<EventScript> Ptr;
+
+ /**
+ * Constructor.
+ */
+ EventScript(const QString& name);
+
+ /**
+ * Destructor.
+ */
+ virtual ~EventScript();
+
+ virtual const QString getClassName() const;
+
+ virtual Object::Ptr call(const QString& name, KSharedPtr<List> arguments);
+
+ private:
+ //ScriptContainer* m_scriptcontainer;
+ //Callable* m_callable;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/eventsignal.cpp b/lib/kross/api/eventsignal.cpp
new file mode 100644
index 00000000..455ca61f
--- /dev/null
+++ b/lib/kross/api/eventsignal.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * eventsignal.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "eventsignal.h"
+
+#include "variant.h"
+#include "qtobject.h"
+
+#include <qmetaobject.h>
+#include <private/qucom_p.h> // for the Qt QUObject API.
+
+using namespace Kross::Api;
+
+EventSignal::EventSignal(const QString& name, QObject* sender, QCString signal)
+ : Event<EventSignal>(name)
+ , m_sender(sender)
+ , m_signal(signal) //QObject::normalizeSignalSlot(signal)
+{
+}
+
+EventSignal::~EventSignal()
+{
+}
+
+const QString EventSignal::getClassName() const
+{
+ return "Kross::Api::EventSignal";
+}
+
+Object::Ptr EventSignal::call(const QString& /*name*/, KSharedPtr<List> arguments)
+{
+#ifdef KROSS_API_EVENTSIGNAL_CALL_DEBUG
+ krossdebug( QString("EventSignal::call() m_signal=%1 arguments=%2").arg(m_signal).arg(arguments->toString()) );
+#endif
+
+ QString n = m_signal;
+
+ if(n.startsWith("2")) // Remove prefix of SIGNAL-macros
+ n.remove(0,1);
+
+ int signalid = m_sender->metaObject()->findSignal(n.latin1(), false);
+ if(signalid < 0)
+ throw new Exception(QString("No such signal '%1'.").arg(n));
+
+ QUObject* uo = QtObject::toQUObject(n, arguments);
+ m_sender->qt_emit(signalid, uo); // emit the signal
+ delete [] uo;
+
+ return new Variant( QVariant(true,0) );
+}
diff --git a/lib/kross/api/eventsignal.h b/lib/kross/api/eventsignal.h
new file mode 100644
index 00000000..aea58b12
--- /dev/null
+++ b/lib/kross/api/eventsignal.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * eventsignal.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_EVENTSIGNAL_H
+#define KROSS_API_EVENTSIGNAL_H
+
+//#include <qstring.h>
+//#include <qvaluelist.h>
+//#include <qmap.h>
+//#include <qvariant.h>
+//#include <qsignalmapper.h>
+//#include <qguardedptr.h>
+#include <qobject.h>
+#include <ksharedptr.h>
+
+#include "event.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * Each Qt signal and slot connection between a QObject
+ * instance and a functionname is represented with
+ * a EventSignal and handled by \a EventManager.
+ */
+ class EventSignal : public Event<EventSignal>
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<EventSignal> Ptr;
+
+ /**
+ * Constructor.
+ */
+ EventSignal(const QString& name, QObject* sender, QCString signal);
+
+ /**
+ * Destructor.
+ */
+ virtual ~EventSignal();
+
+ virtual const QString getClassName() const;
+
+ virtual Object::Ptr call(const QString& name, KSharedPtr<List> arguments);
+
+/*
+ signals:
+ void callback();
+ void callback(const QString&);
+ void callback(int);
+ void callback(bool);
+*/
+ private:
+ QObject* m_sender;
+ QCString m_signal;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/eventslot.cpp b/lib/kross/api/eventslot.cpp
new file mode 100644
index 00000000..df70c9c8
--- /dev/null
+++ b/lib/kross/api/eventslot.cpp
@@ -0,0 +1,222 @@
+/***************************************************************************
+ * eventslot.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "eventslot.h"
+
+#include "variant.h"
+#include "qtobject.h"
+
+#include <qmetaobject.h>
+#include <private/qucom_p.h> // for the Qt QUObject API.
+
+using namespace Kross::Api;
+
+EventSlot::EventSlot(const QString& name, QObject* receiver, QCString slot)
+ : Event<EventSlot>(name)
+ , m_receiver(receiver)
+ , m_slot(slot) //QObject::normalizeSignalSlot(slot)
+{
+}
+
+EventSlot::~EventSlot()
+{
+}
+
+const QString EventSlot::getClassName() const
+{
+ return "Kross::Api::EventSlot";
+}
+
+Object::Ptr EventSlot::call(const QString& /*name*/, List::Ptr arguments)
+{
+#ifdef KROSS_API_EVENTSLOT_CALL_DEBUG
+ krossdebug( QString("EventSlot::call() m_slot=%1 arguments=%2").arg(m_slot).arg(arguments->toString()) );
+#endif
+
+ QString n = m_slot; //TODO name; //Variant::toString(args->item(0));
+
+ if(n.startsWith("1")) // Remove prefix of SLOT-macros
+ n.remove(0,1);
+
+ int slotid = m_receiver->metaObject()->findSlot(n.latin1(), false);
+ if(slotid < 0)
+ throw Exception::Ptr( new Exception(QString("No such slot '%1'.").arg(n)) );
+
+ QUObject* uo = QtObject::toQUObject(n, arguments);
+ m_receiver->qt_invoke(slotid, uo); // invoke the slot
+ delete [] uo;
+
+ return new Variant( QVariant(true,0) );
+}
+
+/*
+QCString EventSlot::getSlot(const QCString& signal)
+{
+ QString signature = QString(signal).mid(1);
+ int startpos = signature.find("(");
+ int endpos = signature.findRev(")");
+ if(startpos < 0 || startpos > endpos) {
+ krosswarning( QString("EventSlot::getSlot(%1) Invalid signal.").arg(signal) );
+ return QCString();
+ }
+ QString signalname = signature.left(startpos);
+ QString params = signature.mid(startpos + 1, endpos - startpos - 1);
+ //QStringList paramlist = QStringList::split(",", params);
+ QCString slot = QString("callback(" + params + ")").latin1(); //normalizeSignalSlot();
+
+ QMetaObject* mo = metaObject();
+ int slotid = mo->findSlot(slot, false);
+ if(slotid < 0) {
+ krossdebug( QString("EventSlot::getSlot(%1) No such slot '%2' avaiable.").arg(signal).arg(slot) );
+ return QCString();
+ }
+
+ const QMetaData* md = mo->slot(slotid, false);
+ if(md->access != QMetaData::Public) {
+ krossdebug( QString("EventSlot::getSlot(%1) The slot '%2' is not public.").arg(signal).arg(slot) );
+ return QCString();
+ }
+
+//QMember* member = md->member;
+//const QUMethod *method = md->method;
+
+ krossdebug( QString("signal=%1 slot=%2 slotid=%3 params=%4 mdname=%5")
+ .arg(signal).arg(slot).arg(slotid).arg(params).arg(md->name) );
+ return QCString("1" + slot); // Emulate the SLOT(...) macro by adding as first char a "1".
+}
+
+bool EventSlot::connect(EventManager* eventmanager, QObject* senderobj, const QCString& signal, QString function, const QCString& slot)
+{
+ if(m_sender && ! disconnect())
+ return false;
+
+ const QCString& myslot = slot.isEmpty() ? getSlot(signal) : slot;
+ if(! myslot)
+ return false;
+
+ if(! m_eventmanager) {
+ EventSlot* eventslot = create(eventmanager);
+ eventslot->connect(eventmanager, senderobj, signal, function, slot);
+ m_slots.append(eventslot);
+ krossdebug( QString("EventSlot::connect(%1, %2, %3) added child EventSlot !!!").arg(senderobj->name()).arg(signal).arg(function) );
+ }
+ else {
+ m_sender = senderobj;
+ m_signal = signal;
+ m_function = function;
+ m_slot = myslot;
+ if(! QObject::connect((QObject*)senderobj, signal, this, myslot)) {
+ krossdebug( QString("EventSlot::connect(%1, %2, %3) failed.").arg(senderobj->name()).arg(signal).arg(function) );
+ return false;
+ }
+ krossdebug( QString("EventSlot::connect(%1, %2, %3) successfully connected.").arg(senderobj->name()).arg(signal).arg(function) );
+ }
+ return true;
+}
+
+bool EventSlot::disconnect()
+{
+ if(! m_sender) return false;
+ QObject::disconnect((QObject*)m_sender, m_signal, this, m_slot);
+ m_sender = 0;
+ m_signal = 0;
+ m_slot = 0;
+ m_function = QString::null;
+ return true;
+}
+
+void EventSlot::call(const QVariant& variant)
+{
+ krossdebug( QString("EventSlot::call() sender='%1' signal='%2' function='%3'")
+ .arg(m_sender->name()).arg(m_signal).arg(m_function) );
+
+ Kross::Api::List* arglist = 0;
+
+ QValueList<Kross::Api::Object*> args;
+ if(variant.isValid()) {
+ args.append(Kross::Api::Variant::create(variant));
+ arglist = Kross::Api::List::create(args);
+ }
+
+ try {
+ m_eventmanager->m_scriptcontainer->callFunction(m_function, arglist);
+ }
+ catch(Exception& e) {
+ //TODO add hadError(), getError() and setError()
+ krossdebug( QString("EXCEPTION in EventSlot::call('%1') type='%2' description='%3'").arg(variant.toString()).arg(e.type()).arg(e.description()) );
+ }
+}
+
+void EventSlot::callback() {
+ call(QVariant()); }
+void EventSlot::callback(short s) {
+ call(QVariant(s)); }
+void EventSlot::callback(int i) {
+ call(QVariant(i)); }
+void EventSlot::callback(int i1, int i2) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 )); }
+void EventSlot::callback(int i1, int i2, int i3) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 << i3 )); }
+void EventSlot::callback(int i1, int i2, int i3, int i4) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 << i3 << i4 )); }
+void EventSlot::callback(int i1, int i2, int i3, int i4, int i5) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 << i3 << i4 << i5 )); }
+void EventSlot::callback(int i1, int i2, int i3, int i4, bool b) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 << i3 << i4 << b )); }
+void EventSlot::callback(int i1, bool b) {
+ call(QVariant( QValueList<QVariant>() << i1 << b )); }
+void EventSlot::callback(int i1, int i2, bool b) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 << b )); }
+void EventSlot::callback(int i1, int i2, const QString& s) {
+ call(QVariant( QValueList<QVariant>() << i1 << i2 << s )); }
+void EventSlot::callback(uint i) {
+ call(QVariant(i)); }
+void EventSlot::callback(long l) {
+ call(QVariant((Q_LLONG)l)); }
+void EventSlot::callback(ulong l) {
+ call(QVariant((Q_ULLONG)l)); }
+void EventSlot::callback(double d) {
+ call(QVariant(d)); }
+void EventSlot::callback(const char* c) {
+ call(QVariant(c)); }
+void EventSlot::callback(bool b) {
+ call(QVariant(b)); }
+void EventSlot::callback(const QString& s) {
+ call(QVariant(s)); }
+void EventSlot::callback(const QString& s, int i) {
+ call(QVariant( QValueList<QVariant>() << s << i )); }
+void EventSlot::callback(const QString& s, int i1, int i2) {
+ call(QVariant( QValueList<QVariant>() << s << i1 << i2 )); }
+void EventSlot::callback(const QString& s, uint i) {
+ call(QVariant( QValueList<QVariant>() << s << i )); }
+void EventSlot::callback(const QString& s, bool b) {
+ call(QVariant( QValueList<QVariant>() << s << b )); }
+void EventSlot::callback(const QString& s, bool b1, bool b2) {
+ call(QVariant( QValueList<QVariant>() << s << b1 << b2 )); }
+void EventSlot::callback(const QString& s, bool b, int i) {
+ call(QVariant( QValueList<QVariant>() << s << b << i )); }
+void EventSlot::callback(const QString& s1, const QString& s2) {
+ call(QVariant( QValueList<QVariant>() << s1 << s2 )); }
+void EventSlot::callback(const QString& s1, const QString& s2, const QString& s3) {
+ call(QVariant( QValueList<QVariant>() << s1 << s2 << s3 )); }
+void EventSlot::callback(const QStringList& sl) {
+ call(QVariant(sl)); }
+void EventSlot::callback(const QVariant& variant) {
+ call(variant); }
+*/
diff --git a/lib/kross/api/eventslot.h b/lib/kross/api/eventslot.h
new file mode 100644
index 00000000..8f564103
--- /dev/null
+++ b/lib/kross/api/eventslot.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ * eventslot.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_EVENTSLOT_H
+#define KROSS_API_EVENTSLOT_H
+
+#include <qstring.h>
+#include <qobject.h>
+#include <ksharedptr.h>
+
+#include "event.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * Each Qt signal and slot connection between a QObject
+ * instance and a functionname is represented with
+ * a EventSlot and handled by the \a EventManager.
+ */
+ class EventSlot : public Event<EventSlot>
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<EventSlot> Ptr;
+
+ /**
+ * Constructor.
+ *
+ * \param name The name of the EventSlot. The EventSlot
+ * will be accessible by that unique name via
+ * it's parent.
+ * \param receiver The receiver of the event.
+ * \param slot The slot of the receiver which this
+ * EventSlot points to.
+ */
+ EventSlot(const QString& name, QObject* receiver, QCString slot);
+
+ /**
+ * Destructor.
+ */
+ virtual ~EventSlot();
+
+ /// \see Kross::Api::Object::getClassName()
+ virtual const QString getClassName() const;
+
+ /// \see Kross::Api::Event::call()
+ virtual Object::Ptr call(const QString& name, KSharedPtr<List> arguments);
+
+/*
+ private:
+ EventManager* m_eventmanager;
+ QGuardedPtr<QObject> m_sender;
+ QCString m_signal;
+ QCString m_slot;
+ QString m_function;
+ QValueList<EventSlot*> m_slots;
+ protected:
+ void call(const QVariant&);
+ public slots:
+ // Stupid signals and slots. To get the passed
+ // arguments we need to have all cases of slots
+ // avaiable for EventManager::connect() signals.
+ void callback();
+ void callback(short);
+ void callback(int);
+ void callback(int, int);
+ void callback(int, int, int);
+ void callback(int, int, int, int);
+ void callback(int, int, int, int, int);
+ void callback(int, int, int, int, bool);
+ void callback(int, bool);
+ void callback(int, int, bool);
+ void callback(int, int, const QString&);
+ void callback(uint);
+ void callback(long);
+ void callback(ulong);
+ void callback(double);
+ void callback(const char*);
+ void callback(bool);
+ void callback(const QString&);
+ void callback(const QString&, int);
+ void callback(const QString&, int, int);
+ void callback(const QString&, uint);
+ void callback(const QString&, bool);
+ void callback(const QString&, bool, bool);
+ void callback(const QString&, bool, int);
+ void callback(const QString&, const QString&);
+ void callback(const QString&, const QString&, const QString&);
+ void callback(const QStringList&);
+ void callback(const QVariant&);
+ // The following both slots are more generic to
+ // handle Kross::Api::Object instances.
+ //void callback(Kross::Api::Object*);
+ //void callback(Kross::Api::List*);
+*/
+ private:
+ QObject* m_receiver;
+ QCString m_slot;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/exception.cpp b/lib/kross/api/exception.cpp
new file mode 100644
index 00000000..a54bae88
--- /dev/null
+++ b/lib/kross/api/exception.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * exception.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "object.h"
+#include "exception.h"
+
+//#include <qstring.h>
+//#include <ksharedptr.h>
+
+using namespace Kross::Api;
+
+Exception::Exception(const QString& error, long lineno)
+ : Object()
+ , m_error(error)
+ , m_lineno(lineno)
+{
+ krosswarning( QString("Kross::Api::Exception error='%1' lineno='%3'").arg(m_error).arg(m_lineno) );
+}
+
+Exception::~Exception()
+{
+}
+
+const QString Exception::getClassName() const
+{
+ return "Kross::Api::Exception";
+}
+
+const QString Exception::toString()
+{
+ return (m_lineno != -1)
+ ? QString("Exception at line %1: %2").arg(m_lineno).arg(m_error)
+ : QString("Exception: %1").arg(m_error);
+}
+
+const QString Exception::getError() const
+{
+ return m_error;
+}
+
+const QString Exception::getTrace() const
+{
+ return m_trace;
+}
+
+void Exception::setTrace(const QString& tracemessage)
+{
+ m_trace = tracemessage;
+}
+
+long Exception::getLineNo() const
+{
+ return m_lineno;
+}
+
diff --git a/lib/kross/api/exception.h b/lib/kross/api/exception.h
new file mode 100644
index 00000000..6ee9597b
--- /dev/null
+++ b/lib/kross/api/exception.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ * exception.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_EXCEPTION_H
+#define KROSS_API_EXCEPTION_H
+
+#include "object.h"
+
+#include <qstring.h>
+#include <ksharedptr.h>
+
+namespace Kross { namespace Api {
+
+ /**
+ * Common exception class used for representing exceptions
+ * in Kross.
+ *
+ * Internal we use \a Exception instances to throw and handle
+ * exceptions. Those exceptions are inherited from \a Object
+ * and therefore they are first class citizens in Kross.
+ */
+ class Exception : public Object
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<Exception> Ptr;
+
+ /**
+ * Constructor.
+ *
+ * \param error The error message.
+ * \param lineno The liner number in the scripting
+ * code where this exception got thrown.
+ */
+ Exception(const QString& error, long lineno = -1);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Exception();
+
+ /// \see Kross::Api::Object::getClassName()
+ virtual const QString getClassName() const;
+
+ /// \see Kross::Api::Object::toString()
+ virtual const QString toString();
+
+ /**
+ * \return the error message.
+ */
+ const QString getError() const;
+
+ /**
+ * \return a more detailed tracemessage or QString::null if
+ * there is no trace avaiable.
+ */
+ const QString getTrace() const;
+
+ /**
+ * Set a more detailed tracemessage.
+ */
+ void setTrace(const QString& tracemessage);
+
+ /**
+ * \return the line number in the scripting code
+ * where the exception got thrown or -1 if there
+ * was no line number defined.
+ */
+ long getLineNo() const;
+
+ private:
+ /// The error message.
+ QString m_error;
+ /// The trace message.
+ QString m_trace;
+ /// The line number where the exception got thrown
+ long m_lineno;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/function.h b/lib/kross/api/function.h
new file mode 100644
index 00000000..6b75752a
--- /dev/null
+++ b/lib/kross/api/function.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * function.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_FUNCTION_H
+#define KROSS_API_FUNCTION_H
+
+#include "../main/krossconfig.h"
+#include "object.h"
+#include "list.h"
+
+#include <qstring.h>
+
+namespace Kross { namespace Api {
+
+ /**
+ * The base class for functions. Classes like \a Function0 and
+ * \a ProxyFunction inheritate this class.
+ */
+ class Function
+ {
+ public:
+
+ /**
+ * Each function needs to implement the call-method which will
+ * be executed if the function itself should be executed.
+ */
+ virtual Object::Ptr call(List::Ptr) = 0;
+
+ };
+
+ /**
+ * This class implements the most abstract way to work with functions. It
+ * implements pointing to functions of the form
+ * @code
+ * Kross::Api::Object::Ptr myfunc(Kross::Api::List::Ptr)
+ * @endcode
+ * where a low-level \a Object got returned that represents the returnvalue
+ * of the function-call, and a \a List instance is passed that may contain
+ * optional \a Object instances as parameters.
+ */
+ template<class INSTANCE>
+ class Function0 : public Function
+ {
+ private:
+ typedef Object::Ptr(INSTANCE::*Method)(List::Ptr);
+ INSTANCE* m_instance;
+ Method m_method;
+ public:
+ Function0(INSTANCE* instance, Method method)
+ : m_instance(instance), m_method(method) {}
+ Object::Ptr call(List::Ptr args)
+ { return (m_instance->*m_method)(args); }
+ };
+
+ /**
+ * Specialization of the \a Function0 which takes as additional parameter
+ * a const-value. This const-value will be hidden for the scripting backend
+ * and is only passed through on function-call.
+ *
+ * So, this class could be as example used to point to a function like;
+ * @code
+ * Kross::Api::Object::Ptr myfunc(Kross::Api::List::Ptr, int myinteger)
+ * @endcode
+ * and then we are able to point to the function with something like
+ * @code
+ * this->addFunction("myfunctionname",
+ * new Kross::Api::Function1< MYCLASS, int >(
+ * this, // pointer to an instance of MYCLASS
+ * &MYCLASS::myfunction, // the method which should be wrapped
+ * 17 // the const-value we like to pass to the function.
+ * ) );
+ * @endcode
+ * The defined integer myinteger which has the value 17 will be passed
+ * transparently to myfunc. The scripting-backend won't know that there
+ * exists such an additional integer at all. So, it's hidden and the user
+ * aka the scripting code won't be able to manipulate that additional
+ * value.
+ */
+ template<class INSTANCE, typename P1>
+ class Function1 : public Function
+ {
+ private:
+ typedef Object::Ptr(INSTANCE::*Method)(List::Ptr, P1);
+ INSTANCE* m_instance;
+ Method m_method;
+ P1 m_p1;
+ public:
+ Function1(INSTANCE* instance, Method method, P1 p1)
+ : m_instance(instance), m_method(method), m_p1(p1) {}
+ Object::Ptr call(List::Ptr args)
+ { return (m_instance->*m_method)(args, m_p1); }
+ };
+
+ /**
+ * Same as \a Function1 but with 2 additional parameters.
+ */
+ template<class INSTANCE, typename P1, typename P2>
+ class Function2 : public Function
+ {
+ private:
+ typedef Object::Ptr(INSTANCE::*Method)(List::Ptr, P1, P2);
+ INSTANCE* m_instance;
+ Method m_method;
+ P1 m_p1;
+ P2 m_p2;
+ public:
+ Function2(INSTANCE* instance, Method method, P1 p1, P2 p2)
+ : m_instance(instance), m_method(method), m_p1(p1), m_p2(p2) {}
+ Object::Ptr call(List::Ptr args)
+ { return (m_instance->*m_method)(args, m_p1, m_p2); }
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/interpreter.cpp b/lib/kross/api/interpreter.cpp
new file mode 100644
index 00000000..439063cd
--- /dev/null
+++ b/lib/kross/api/interpreter.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * interpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "interpreter.h"
+#include "script.h"
+#include "../main/manager.h"
+#include "../main/scriptcontainer.h"
+
+#include <klibloader.h>
+
+extern "C"
+{
+ typedef int (*def_interpreter_func)(Kross::Api::InterpreterInfo*);
+}
+
+using namespace Kross::Api;
+
+/*************************************************************************
+ * InterpreterInfo
+ */
+
+InterpreterInfo::InterpreterInfo(const QString& interpretername, const QString& library, const QString& wildcard, QStringList mimetypes, Option::Map options)
+ : m_interpretername(interpretername)
+ , m_library(library)
+ , m_wildcard(wildcard)
+ , m_mimetypes(mimetypes)
+ , m_options(options)
+ , m_interpreter(0)
+{
+}
+
+InterpreterInfo::~InterpreterInfo()
+{
+ for(Option::Map::Iterator it = m_options.begin(); it != m_options.end(); ++it)
+ delete it.data();
+
+ delete m_interpreter;
+ m_interpreter = 0;
+}
+
+const QString InterpreterInfo::getInterpretername()
+{
+ return m_interpretername;
+}
+
+const QString InterpreterInfo::getWildcard()
+{
+ return m_wildcard;
+}
+
+const QStringList InterpreterInfo::getMimeTypes()
+{
+ return m_mimetypes;
+}
+
+bool InterpreterInfo::hasOption(const QString& key)
+{
+ return m_options.contains(key);
+}
+
+InterpreterInfo::Option* InterpreterInfo::getOption(const QString name)
+{
+ return m_options[name];
+}
+
+const QVariant InterpreterInfo::getOptionValue(const QString name, QVariant defaultvalue)
+{
+ Option* o = m_options[name];
+ return o ? o->value : defaultvalue;
+}
+
+InterpreterInfo::Option::Map InterpreterInfo::getOptions()
+{
+ return m_options;
+}
+
+Interpreter* InterpreterInfo::getInterpreter()
+{
+ if(m_interpreter) // buffered
+ return m_interpreter;
+
+ krossdebug( QString("Loading the interpreter library for %1").arg(m_interpretername) );
+
+ // Load the krosspython library.
+ KLibLoader *libloader = KLibLoader::self();
+
+ KLibrary* library = libloader->globalLibrary( m_library.latin1() );
+ if(! library) {
+ /*
+ setException(
+ new Exception( QString("Could not load library \"%1\" for the \"%2\" interpreter.").arg(m_library).arg(m_interpretername) )
+ );
+ */
+ krosswarning( QString("Could not load library \"%1\" for the \"%2\" interpreter.").arg(m_library).arg(m_interpretername) );
+ return 0;
+ }
+
+ // Get the extern "C" krosspython_instance function.
+ def_interpreter_func interpreter_func;
+ interpreter_func = (def_interpreter_func) library->symbol("krossinterpreter");
+ if(! interpreter_func) {
+ //setException( new Exception("Failed to load symbol in krosspython library.") );
+ krosswarning("Failed to load the 'krossinterpreter' symbol from the library.");
+ }
+ else {
+ // and execute the extern krosspython_instance function.
+ m_interpreter = (Interpreter*) (interpreter_func)(this);
+ if(! m_interpreter) {
+ krosswarning("Failed to load the Interpreter instance from library.");
+ }
+ else {
+ // Job done. The library is loaded and our Interpreter* points
+ // to the external Kross::Python::Interpreter* instance.
+ krossdebug("Successfully loaded Interpreter instance from library.");
+ }
+ }
+
+ // finally unload the library.
+ library->unload();
+
+ return m_interpreter;
+}
+
+/*************************************************************************
+ * Interpreter
+ */
+
+Interpreter::Interpreter(InterpreterInfo* info)
+ : m_interpreterinfo(info)
+{
+}
+
+Interpreter::~Interpreter()
+{
+}
diff --git a/lib/kross/api/interpreter.h b/lib/kross/api/interpreter.h
new file mode 100644
index 00000000..5c73c303
--- /dev/null
+++ b/lib/kross/api/interpreter.h
@@ -0,0 +1,197 @@
+/***************************************************************************
+ * interpreter.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_INTERPRETER_H
+#define KROSS_API_INTERPRETER_H
+
+#include <qstring.h>
+#include <qmap.h>
+
+#include "object.h"
+
+namespace Kross { namespace Api {
+
+ // Forward declaration.
+ class Manager;
+ class ScriptContainer;
+ class Script;
+ class Interpreter;
+
+ /**
+ * While the \a Interpreter is the implemented interpreter this class
+ * is used to provide some abstract informations about each interpreter
+ * we are able to use within the \a Manager singelton.
+ */
+ class InterpreterInfo
+ {
+ public:
+
+ /**
+ * Each interpreter is able to define options we could
+ * use to manipulate the interpreter behaviour.
+ */
+ class Option
+ {
+ public:
+
+ /**
+ * Map of options.
+ */
+ typedef QMap<QString, Option*> Map;
+
+ /**
+ * Constructor.
+ *
+ * \param name The name the option has. This is the
+ * displayed title and isn't used internaly.
+ * \param comment A comment that describes the option.
+ * \param value The QVariant value this option has.
+ */
+ Option(const QString& name, const QString& comment, const QVariant& value)
+ : name(name), comment(comment), value(value) {}
+
+ /// The short name of the option.
+ QString name;
+
+ /// A description of the option.
+ QString comment;
+
+ /// The value the option has.
+ QVariant value;
+ };
+
+ /**
+ * Constructor.
+ */
+ InterpreterInfo(const QString& interpretername, const QString& library, const QString& wildcard, QStringList mimetypes, Option::Map options);
+
+ /**
+ * Destructor.
+ */
+ ~InterpreterInfo();
+
+ /**
+ * \return the name of the interpreter. For example "python" or "kjs".
+ */
+ const QString getInterpretername();
+
+ /**
+ * \return the file-wildcard used to determinate by this interpreter
+ * used scriptingfiles. Those filter will be used e.g. with
+ * KGlobal::dirs()->findAllResources() as filtermask. For example
+ * python just defines it as "*py".
+ */
+ const QString getWildcard();
+
+ /**
+ * List of mimetypes this interpreter supports.
+ *
+ * \return QStringList with mimetypes like
+ * "application/x-javascript".
+ */
+ const QStringList getMimeTypes();
+
+ /**
+ * \return true if an \a Option with that \p key exists else false.
+ */
+ bool hasOption(const QString& key);
+
+ /**
+ * \return the option defined with \p name .
+ */
+ Option* getOption(const QString name);
+
+ /**
+ * \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.
+ */
+ const QVariant getOptionValue(const QString name, QVariant defaultvalue = QVariant());
+
+ /**
+ * \return a map of options.
+ */
+ Option::Map getOptions();
+
+ /**
+ * \return the \a Interpreter instance this \a InterpreterInfo
+ * is the describer for.
+ */
+ Interpreter* getInterpreter();
+
+ private:
+ /// The name the interpreter has. Could be something like "python" or "kjs".
+ QString m_interpretername;
+ /// The name of the library to load for the interpreter.
+ QString m_library;
+ /// The file wildcard used to determinate extensions.
+ QString m_wildcard;
+ /// List of mimetypes this interpreter supports.
+ QStringList m_mimetypes;
+ /// A \a Option::Map with options.
+ Option::Map m_options;
+ /// The \a Interpreter instance.
+ Interpreter* m_interpreter;
+ };
+
+ /**
+ * Base class for interpreters.
+ *
+ * Each scripting backend needs to inheritate it's own
+ * interpreter from this class and implementate there
+ * backend related stuff.
+ * The Interpreter will be managed by the \a Kross::Manager
+ * class.
+ */
+ class Interpreter
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param info is the \a InterpreterInfo instance
+ * that describes this interpreter.
+ */
+ Interpreter(InterpreterInfo* info);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Interpreter();
+
+ /**
+ * Create and return a new interpreter dependend
+ * \a Script instance.
+ *
+ * \param scriptcontainer The \a ScriptContainer
+ * to use for the \a Script instance.
+ * \return The from \a Script inherited instance.
+ */
+ virtual Script* createScript(ScriptContainer* scriptcontainer) = 0;
+
+ protected:
+ /// The \a InterpreterInfo instance this interpreter belongs to.
+ InterpreterInfo* m_interpreterinfo;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/list.cpp b/lib/kross/api/list.cpp
new file mode 100644
index 00000000..ad901e5e
--- /dev/null
+++ b/lib/kross/api/list.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * list.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "list.h"
+#include "exception.h"
+
+using namespace Kross::Api;
+
+List::List(QValueList<Object::Ptr> value)
+ : Value< List, QValueList<Object::Ptr> >(value)
+{
+}
+
+List::~List()
+{
+}
+
+const QString List::getClassName() const
+{
+ return "Kross::Api::List";
+}
+
+const QString List::toString()
+{
+ QString s = "[";
+ QValueList<Object::Ptr> list = getValue();
+ for(QValueList<Object::Ptr>::Iterator it = list.begin(); it != list.end(); ++it)
+ s += "'" + (*it)->toString() + "', ";
+ return (s.endsWith(", ") ? s.left(s.length() - 2) : s) + "]";
+}
+
+Object::Ptr List::item(uint idx, Object* defaultobject)
+{
+ QValueList<Object::Ptr>& list = getValue();
+ if(idx >= list.count()) {
+ if(defaultobject)
+ return defaultobject;
+ krossdebug( QString("List::item index=%1 is out of bounds. Raising TypeException.").arg(idx) );
+ throw Exception::Ptr( new Exception(QString("List-index %1 out of bounds.").arg(idx)) );
+ }
+ return list[idx];
+}
+
+uint List::count()
+{
+ return getValue().count();
+}
+
+void List::append(Object::Ptr object)
+{
+ getValue().append(object);
+}
+
diff --git a/lib/kross/api/list.h b/lib/kross/api/list.h
new file mode 100644
index 00000000..d74246a0
--- /dev/null
+++ b/lib/kross/api/list.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ * list.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_LIST_H
+#define KROSS_API_LIST_H
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qintdict.h>
+
+#include "object.h"
+#include "value.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * The List class implementates \a Value to handle
+ * lists and collections.
+ */
+ class List : public Value< List, QValueList<Object::Ptr> >
+ {
+ friend class Value< List, QValueList<Object::Ptr> >;
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<List> Ptr;
+
+/*
+ operator QStringList () {
+ //QValueList<Object::Ptr> getValue()
+ krossdebug("999999999999 ...........................");
+ return QStringList();
+ }
+*/
+
+ /**
+ * Constructor.
+ *
+ * \param value The list of \a Object instances this
+ * list has initialy.
+ */
+ List(QValueList<Object::Ptr> value = QValueList<Object::Ptr>());
+
+ /**
+ * Destructor.
+ */
+ virtual ~List();
+
+ /**
+ * See \see Kross::Api::Object::getClassName()
+ */
+ virtual const QString getClassName() const;
+
+ /**
+ * \return a string representation of the whole list.
+ *
+ * \see Kross::Api::Object::toString()
+ */
+ virtual const QString toString();
+
+ /**
+ * Return the \a Object with defined index from the
+ * QValueList this list holds.
+ *
+ * \throw TypeException If index is out of bounds.
+ * \param idx The QValueList-index.
+ * \param defaultobject The default \a Object which should
+ * be used if there exists no item with such an
+ * index. This \a Object instance will be returned
+ * if not NULL and if the index is out of bounds. If
+ * its NULL a \a TypeException will be thrown.
+ * \return The \a Object instance.
+ */
+ Object::Ptr item(uint idx, Object* defaultobject = 0);
+
+ /**
+ * Return the number of items in the QValueList this
+ * list holds.
+ *
+ * \return The number of items.
+ */
+ uint count();
+
+ /**
+ * Append an \a Kross::Api::Object to the list.
+ *
+ * \param object The \a Kross::Api::Object instance to
+ * append to this list.
+ */
+ void append(Object::Ptr object);
+
+ template<typename TYPE>
+ static Object::Ptr toObject(TYPE t) { return t; }
+ };
+
+ /**
+ * This template class extends the \a List class with
+ * generic functionality to deal with lists.
+ */
+ template< class OBJECT >
+ class ListT : public List
+ {
+ public:
+ ListT() : List() {}
+ ListT(QValueList<OBJECT> values) : List(values) {}
+
+ template< typename TYPE >
+ ListT(QValueList<TYPE> values) : List()
+ {
+ QValueListIterator<TYPE> it(values.begin()), end(values.end());
+ for(; it != end; ++it)
+ this->append( new OBJECT(*it) );
+ }
+
+ template< typename TYPE >
+ ListT(QIntDict<TYPE> values) : List()
+ {
+ QIntDictIterator<TYPE> it( values );
+ TYPE *t;
+ while( (t = it.current()) != 0 ) {
+ this->append( new OBJECT(t) );
+ ++it;
+ }
+ }
+
+ template< typename TYPE >
+ ListT(const QPtrList<TYPE> values) : List()
+ {
+ QPtrListIterator<TYPE> it(values);
+ TYPE *t;
+ while( (t = it.current()) != 0 ) {
+ this->append( new OBJECT(t) );
+ ++it;
+ }
+ }
+
+ virtual ~ListT() {}
+
+ template<typename TYPE>
+ static Object::Ptr toObject(TYPE t)
+ {
+ return new ListT(t);
+ }
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/module.h b/lib/kross/api/module.h
new file mode 100644
index 00000000..127609e0
--- /dev/null
+++ b/lib/kross/api/module.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+ * module.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_MODULE_H
+#define KROSS_API_MODULE_H
+
+#include <qstring.h>
+
+#include "class.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * The Module class. Modules are managed in the \a Manager singleton
+ * instance and are implemented as in scripting plugins as main
+ * entry point to load and work with them.
+ */
+ class Module : public Class<Module>
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<Module> Ptr;
+
+ /**
+ * Constructor.
+ *
+ * \param name The name of this module.
+ * Each module needs a unique name cause
+ * the application using Kross identifies
+ * modules with there names.
+ */
+ explicit Module(const QString& name)
+ : Class<Module>(name)
+ {
+ krossdebug( QString("Kross::Api::Module %1 created").arg(name) );
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~Module()
+ {
+ krossdebug( QString("Kross::Api::Module %1 destroyed").arg(getName()) );
+ }
+
+ /**
+ * Method to load from \a Kross::Api::Object inherited classes
+ * this module implements from within other modules.
+ */
+ virtual Kross::Api::Object::Ptr get(const QString& /*name*/, void* /*pointer*/ = 0)
+ {
+ return 0;
+ }
+
+ };
+
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/object.cpp b/lib/kross/api/object.cpp
new file mode 100644
index 00000000..ff2e2fbd
--- /dev/null
+++ b/lib/kross/api/object.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * object.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2006 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "object.h"
+#include "list.h"
+#include "variant.h"
+//#include "function.h"
+#include "event.h"
+#include "exception.h"
+
+using namespace Kross::Api;
+
+Object::Object()
+ : KShared()
+{
+#ifdef KROSS_API_OBJECT_CTOR_DEBUG
+ krossdebug( QString("Kross::Api::Object::Constructor() name='%1' refcount='%2'").arg(m_name).arg(_KShared_count()) );
+#endif
+}
+
+Object::~Object()
+{
+#ifdef KROSS_API_OBJECT_DTOR_DEBUG
+ krossdebug( QString("Kross::Api::Object::Destructor() name='%1' refcount='%2'").arg(m_name).arg(_KShared_count()) );
+#endif
+ //removeAllChildren(); // not needed cause we use KShared to handle ref-couting and freeing.
+}
+
+const QString Object::toString()
+{
+ return QString("%1").arg(getClassName());
+}
+
+Object::Ptr Object::call(const QString& name, List::Ptr arguments)
+{
+ Q_UNUSED(arguments);
+
+#ifdef KROSS_API_OBJECT_CALL_DEBUG
+ krossdebug( QString("Kross::Api::Object::call(%1) name=%2 class=%3").arg(name).arg(getName()).arg(getClassName()) );
+#endif
+
+ if(name.isEmpty()) // return a self-reference if no functionname is defined.
+ return this;
+
+ throw Exception::Ptr( new Exception(QString("No callable object named '%2'").arg(name)) );
+}
+
diff --git a/lib/kross/api/object.h b/lib/kross/api/object.h
new file mode 100644
index 00000000..3c86ca4b
--- /dev/null
+++ b/lib/kross/api/object.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * object.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2006 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_OBJECT_H
+#define KROSS_API_OBJECT_H
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+#include <qvariant.h>
+//#include <qobject.h>
+#include <ksharedptr.h>
+
+#include "../main/krossconfig.h"
+
+namespace Kross { namespace Api {
+
+ // Forward declaration.
+ class List;
+
+ /**
+ * The common Object class all other object-classes are
+ * inheritated from.
+ *
+ * The Object class is used as base class to provide
+ * common functionality. It's similar to what we know
+ * in Python as PyObject or in Qt as QObject.
+ *
+ * Inherited from e.g. \a Value, \a Module and \a Class .
+ *
+ * This class implementates reference counting for shared
+ * objects. So, no need to take care of freeing objects.
+ */
+ class Object : public KShared
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<Object> Ptr;
+
+ /**
+ * Constructor.
+ */
+ explicit Object();
+
+ /**
+ * Destructor.
+ */
+ virtual ~Object();
+
+ /**
+ * Return the class name. This could be something
+ * like "Kross::Api::Object" for this object. The
+ * value is mainly used for display purposes.
+ *
+ * \return The name of this class.
+ */
+ virtual const QString getClassName() const = 0;
+
+ /**
+ * \return a string representation of the object or
+ * it's content. This method is mainly used for
+ * debugging and testing purposes.
+ */
+ virtual const QString toString();
+
+ /**
+ * Pass a call to the object and evaluated it recursive
+ * down the object-hierachy. Objects like \a Class are able
+ * to handle call's by just implementing this function.
+ * If the call is done the \a called() method will be
+ * executed recursive from bottom up the call hierachy.
+ *
+ * \throws TypeException if the object or the name
+ * is not callable.
+ * \param name Each call has a name that says what
+ * should be called. In the case of a \a Class
+ * the name is the functionname.
+ * \param arguments The list of arguments passed to
+ * the call.
+ * \return The call-result as \a Object::Ptr instance or
+ * NULL if the call has no result.
+ */
+ virtual Object::Ptr call(const QString& name, KSharedPtr<List> arguments);
+
+ /**
+ * Return a list of supported callable objects.
+ *
+ * \return List of supported calls.
+ */
+ virtual QStringList getCalls() { return QStringList(); }
+ //FIXME replace function with getChildren() functionality ?
+
+ /**
+ * Try to convert the \a Object instance to the
+ * template class T.
+ *
+ * \throw TypeException if the cast failed.
+ * \param object The Object to cast.
+ * \return The to a instance from template type T
+ * casted Object.
+ */
+ template<class T> static T* fromObject(Object::Ptr object);
+
+ /**
+ * This method got used by the \a ProxyFunction classes
+ * to translate an unknown \p TYPE to a \a Object instance.
+ * Classes like \a Value or \a ListT or \a Class are
+ * overwriting this method to transparently translate these
+ * passed type while this method just assumes that the
+ * type is already a \a Object instance.
+ */
+ template<typename TYPE>
+ static Object::Ptr toObject(TYPE t) { return t; }
+ };
+
+}}
+
+#include "exception.h"
+
+namespace Kross { namespace Api {
+
+template<class T> inline T* Object::fromObject(Object::Ptr object)
+{
+ T* t = (T*) object.data();
+ if(! t)
+ throw KSharedPtr<Exception>( new Exception(QString("Object \"%1\" invalid.").arg(object ? object->getClassName() : "")) );
+ return t;
+}
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/proxy.h b/lib/kross/api/proxy.h
new file mode 100644
index 00000000..f25a4845
--- /dev/null
+++ b/lib/kross/api/proxy.h
@@ -0,0 +1,342 @@
+/***************************************************************************
+ * proxy.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_PROXY_H
+#define KROSS_API_PROXY_H
+
+#include "../main/krossconfig.h"
+#include "object.h"
+#include "variant.h"
+#include "list.h"
+
+#include <qstring.h>
+
+namespace Kross { namespace Api {
+
+ /**
+ * \internal used struct to translate an argument-value dynamicly.
+ */
+ template<class OBJ>
+ struct ProxyArgTranslator {
+ OBJ* m_object;
+ ProxyArgTranslator(Kross::Api::Object* obj) {
+ m_object = Kross::Api::Object::fromObject<OBJ>(obj);
+ }
+ template<typename T>
+ inline operator T () {
+ return m_object->operator T();
+ }
+ };
+
+ /**
+ * \internal used struct to translate a return-value dynamicly.
+ */
+ struct ProxyRetTranslator {
+ template<class RETURNOBJ, typename TYPE>
+ inline static Object::Ptr cast(TYPE t) {
+ return RETURNOBJ::toObject(t);
+ }
+ };
+
+ /**
+ * The ProxyFunction template-class is used to publish any C/C++
+ * method (not only slots) of a struct or class instance as a
+ * a \a Function to Kross.
+ *
+ * With this class we don't need to have a method-wrapper for
+ * each single function what a) should reduce the code needed for
+ * wrappers and b) is more typesafe cause the connection to the
+ * C/C++ method is done on compiletime.
+ *
+ * Example how a ProxyFunction may got used;
+ * @code
+ * #include "../api/class.h"
+ * #include "../api/proxy.h"
+ * // The class which should be published.
+ * class MyClass : public Kross::Api::Class<MyClass> {
+ * public:
+ * MyClass(const QString& name) : Kross::Api::Class<MyClass>(name) {
+ * // publish the function myfunc, so that scripting-code is able
+ * // to call that method.
+ * this->addProxyFunction <
+ * Kross::Api::Variant, // the uint returnvalue is handled with Variant.
+ * Kross::Api::Variant, // the QString argument is handled with Variant too.
+ * MyClass // the MyClass* is handled implicit by our class.
+ * > ( "myfuncname", // the name the function should be published as.
+ * this, // pointer to the class-instance which has the method.
+ * &TestPluginObject::myfunc ); // pointer to the method itself.
+ * }
+ * virtual ~MyClass() {}
+ * virtual const QString getClassName() const { return "MyClass"; }
+ * private:
+ * uint myfunc(const QCString&, MyClass* myotherclass) {
+ * // This method will be published to the scripting backend. So, scripting
+ * // code is able to call this method.
+ * }
+ * }
+ * @endcode
+ */
+ template< class INSTANCE, // the objectinstance
+ typename METHOD, // the method-signature
+ class RETURNOBJ,// = Kross::Api::Object, // return-value
+ class ARG1OBJ = Kross::Api::Object, // first parameter-value
+ class ARG2OBJ = Kross::Api::Object, // second parameter-value
+ class ARG3OBJ = Kross::Api::Object, // theird parameter-value
+ class ARG4OBJ = Kross::Api::Object // forth parameter-value
+ >
+ class ProxyFunction : public Function
+ {
+ template<class PROXYFUNC, typename RETURNTYPE>
+ friend struct ProxyFunctionCaller;
+ private:
+ /// Pointer to the objectinstance which method should be called.
+ INSTANCE* m_instance;
+ /// Pointer to the method which should be called.
+ const METHOD m_method;
+
+ /// First default argument.
+ KSharedPtr<ARG1OBJ> m_defarg1;
+ /// Second default argument.
+ KSharedPtr<ARG2OBJ> m_defarg2;
+ /// Theird default argument.
+ KSharedPtr<ARG3OBJ> m_defarg3;
+ /// Forth default argument.
+ KSharedPtr<ARG4OBJ> m_defarg4;
+
+ /**
+ * \internal used struct that does the execution of the wrapped
+ * method.
+ */
+ template<class PROXYFUNC, typename RETURNTYPE>
+ struct ProxyFunctionCaller {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1, Kross::Api::Object* arg2, Kross::Api::Object* arg3, Kross::Api::Object* arg4) {
+ return ProxyRetTranslator::cast<RETURNTYPE>(
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1), ProxyArgTranslator<ARG2OBJ>(arg2), ProxyArgTranslator<ARG3OBJ>(arg3), ProxyArgTranslator<ARG4OBJ>(arg4) )
+ );
+ }
+ };
+
+ /**
+ * \internal template-specialization of the \a ProxyFunctionCaller
+ * above which handles void-returnvalues. We need to handle this
+ * special case seperatly cause compilers deny to return void :-/
+ */
+ template<class PROXYFUNC>
+ struct ProxyFunctionCaller<PROXYFUNC, void> {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1, Kross::Api::Object* arg2, Kross::Api::Object* arg3, Kross::Api::Object* arg4) {
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1), ProxyArgTranslator<ARG1OBJ>(arg2), ProxyArgTranslator<ARG3OBJ>(arg3), ProxyArgTranslator<ARG4OBJ>(arg4) );
+ return 0; // void return-value
+ }
+ };
+
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param instance The objectinstance to which the \p method
+ * belongs to.
+ * \param method The method-pointer.
+ */
+ ProxyFunction(INSTANCE* instance, const METHOD& method, ARG1OBJ* defarg1 = 0, ARG2OBJ* defarg2 = 0, ARG3OBJ* defarg3 = 0, ARG4OBJ* defarg4 = 0)
+ : m_instance(instance), m_method(method), m_defarg1(defarg1), m_defarg2(defarg2), m_defarg3(defarg3), m_defarg4(defarg4) {}
+
+ /**
+ * This method got called if the wrapped method should be executed.
+ *
+ * \param args The optional list of arguments passed to the
+ * execution-call.
+ * \return The returnvalue of the functioncall. It will be NULL if
+ * the functioncall doesn't provide us a returnvalue (e.g.
+ * if the function has void as returnvalue).
+ */
+ Object::Ptr call(List::Ptr args) {
+ return ProxyFunctionCaller<ProxyFunction, RETURNOBJ>::exec(this,
+ args->item(0, m_defarg1),
+ args->item(1, m_defarg2),
+ args->item(2, m_defarg3),
+ args->item(3, m_defarg4)
+ );
+ }
+ };
+
+ /**
+ * Template-specialization of the \a ProxyFunction above with three arguments.
+ */
+ template<class INSTANCE, typename METHOD, class RETURNOBJ, class ARG1OBJ, class ARG2OBJ, class ARG3OBJ>
+ class ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ, ARG2OBJ, ARG3OBJ> : public Function
+ {
+ template<class PROXYFUNC, typename RETURNTYPE>
+ friend struct ProxyFunctionCaller;
+ private:
+ INSTANCE* m_instance;
+ const METHOD m_method;
+ KSharedPtr<ARG1OBJ> m_defarg1;
+ KSharedPtr<ARG2OBJ> m_defarg2;
+ KSharedPtr<ARG3OBJ> m_defarg3;
+
+ template<class PROXYFUNC, typename RETURNTYPE>
+ struct ProxyFunctionCaller {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1, Kross::Api::Object* arg2, Kross::Api::Object* arg3) {
+ return ProxyRetTranslator::cast<RETURNTYPE>(
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1), ProxyArgTranslator<ARG2OBJ>(arg2), ProxyArgTranslator<ARG3OBJ>(arg3) )
+ );
+ }
+ };
+
+ template<class PROXYFUNC>
+ struct ProxyFunctionCaller<PROXYFUNC, void> {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1, Kross::Api::Object* arg2, Kross::Api::Object* arg3) {
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1), ProxyArgTranslator<ARG2OBJ>(arg2), ProxyArgTranslator<ARG3OBJ>(arg3) );
+ return 0;
+ }
+ };
+
+ public:
+ ProxyFunction(INSTANCE* instance, const METHOD& method, ARG1OBJ* defarg1 = 0, ARG2OBJ* defarg2 = 0, ARG3OBJ* defarg3 = 0)
+ : m_instance(instance), m_method(method), m_defarg1(defarg1), m_defarg2(defarg2), m_defarg3(defarg3) {}
+ Object::Ptr call(List::Ptr args) {
+ return ProxyFunctionCaller<ProxyFunction, RETURNOBJ>::exec(this,
+ args->item(0, m_defarg1), args->item(1, m_defarg2), args->item(2, m_defarg3)
+ );
+ }
+ };
+
+ /**
+ * Template-specialization of the \a ProxyFunction above with two arguments.
+ */
+ template<class INSTANCE, typename METHOD, class RETURNOBJ, class ARG1OBJ, class ARG2OBJ>
+ class ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ, ARG2OBJ> : public Function
+ {
+ template<class PROXYFUNC, typename RETURNTYPE>
+ friend struct ProxyFunctionCaller;
+ private:
+ INSTANCE* m_instance;
+ const METHOD m_method;
+ KSharedPtr<ARG1OBJ> m_defarg1;
+ KSharedPtr<ARG2OBJ> m_defarg2;
+
+ template<class PROXYFUNC, typename RETURNTYPE>
+ struct ProxyFunctionCaller {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1, Kross::Api::Object* arg2) {
+ return ProxyRetTranslator::cast<RETURNTYPE>(
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1), ProxyArgTranslator<ARG2OBJ>(arg2) )
+ );
+ }
+ };
+
+ template<class PROXYFUNC>
+ struct ProxyFunctionCaller<PROXYFUNC, void> {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1, Kross::Api::Object* arg2) {
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1), ProxyArgTranslator<ARG2OBJ>(arg2) );
+ return 0;
+ }
+ };
+
+ public:
+ ProxyFunction(INSTANCE* instance, const METHOD& method, ARG1OBJ* defarg1 = 0, ARG2OBJ* defarg2 = 0)
+ : m_instance(instance), m_method(method), m_defarg1(defarg1), m_defarg2(defarg2) {}
+ Object::Ptr call(List::Ptr args) {
+ return ProxyFunctionCaller<ProxyFunction, RETURNOBJ>::exec(this,
+ args->item(0, m_defarg1), args->item(1, m_defarg2)
+ );
+ }
+ };
+
+ /**
+ * Template-specialization of the \a ProxyFunction above with one argument.
+ */
+ template<class INSTANCE, typename METHOD, class RETURNOBJ, class ARG1OBJ>
+ class ProxyFunction<INSTANCE, METHOD, RETURNOBJ, ARG1OBJ> : public Function
+ {
+ template<class PROXYFUNC, typename RETURNTYPE>
+ friend struct ProxyFunctionCaller;
+ private:
+ INSTANCE* m_instance;
+ const METHOD m_method;
+ KSharedPtr<ARG1OBJ> m_defarg1;
+
+ template<class PROXYFUNC, typename RETURNTYPE>
+ struct ProxyFunctionCaller {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1) {
+ return ProxyRetTranslator::cast<RETURNTYPE>(
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1) )
+ );
+ }
+ };
+
+ template<class PROXYFUNC>
+ struct ProxyFunctionCaller<PROXYFUNC, void> {
+ inline static Object::Ptr exec(PROXYFUNC* self, Kross::Api::Object* arg1) {
+ ( (self->m_instance)->*(self->m_method) )( ProxyArgTranslator<ARG1OBJ>(arg1) );
+ return 0;
+ }
+ };
+
+ public:
+ ProxyFunction(INSTANCE* instance, const METHOD& method, ARG1OBJ* defarg1 = 0)
+ : m_instance(instance), m_method(method), m_defarg1(defarg1) {}
+ Object::Ptr call(List::Ptr args) {
+ return ProxyFunctionCaller<ProxyFunction, RETURNOBJ>::exec(this,
+ args->item(0, m_defarg1)
+ );
+ }
+ };
+
+ /**
+ * Template-specialization of the \a ProxyFunction above with no arguments.
+ */
+ template<class INSTANCE, typename METHOD, class RETURNOBJ>
+ class ProxyFunction<INSTANCE, METHOD, RETURNOBJ> : public Function
+ {
+ template<class PROXYFUNC, typename RETURNTYPE>
+ friend struct ProxyFunctionCaller;
+ private:
+ INSTANCE* m_instance;
+ const METHOD m_method;
+
+ template<class PROXYFUNC, typename RETURNTYPE>
+ struct ProxyFunctionCaller {
+ inline static Object::Ptr exec(PROXYFUNC* self) {
+ return ProxyRetTranslator::cast<RETURNTYPE>(
+ ( (self->m_instance)->*(self->m_method) )()
+ );
+ }
+ };
+
+ template<class PROXYFUNC>
+ struct ProxyFunctionCaller<PROXYFUNC, void> {
+ inline static Object::Ptr exec(PROXYFUNC* self) {
+ ( (self->m_instance)->*(self->m_method) )();
+ return 0;
+ }
+ };
+
+ public:
+ ProxyFunction(INSTANCE* instance, const METHOD& method)
+ : m_instance(instance), m_method(method) {}
+ Object::Ptr call(List::Ptr) {
+ return ProxyFunctionCaller<ProxyFunction, RETURNOBJ>::exec(this);
+ }
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/qtobject.cpp b/lib/kross/api/qtobject.cpp
new file mode 100644
index 00000000..c6eb082a
--- /dev/null
+++ b/lib/kross/api/qtobject.cpp
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * qtobject.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "qtobject.h"
+#include "object.h"
+#include "variant.h"
+#include "event.h"
+
+#include "../main/manager.h"
+#include "eventslot.h"
+#include "eventsignal.h"
+
+#include <qobject.h>
+#include <qsignal.h>
+//#include <qglobal.h>
+//#include <qobjectdefs.h>
+#include <qmetaobject.h>
+#include <private/qucom_p.h> // for the Qt QUObject API.
+
+using namespace Kross::Api;
+
+QtObject::QtObject(QObject* object, const QString& name)
+ : Kross::Api::Class<QtObject>(name.isEmpty() ? object->name() : name)
+ , m_object(object)
+{
+ // Walk through the signals and slots the QObject has
+ // and attach them as events to this QtObject.
+
+ QStrList slotnames = m_object->metaObject()->slotNames(false);
+ for(char* c = slotnames.first(); c; c = slotnames.next()) {
+ QCString s = c;
+ addChild(s, new EventSlot(s, object, s) );
+ }
+
+ QStrList signalnames = m_object->metaObject()->signalNames(false);
+ for(char* c = signalnames.first(); c; c = signalnames.next()) {
+ QCString s = c;
+ addChild(s, new EventSignal(s, object, s) );
+ }
+
+ // Add functions to wrap QObject methods into callable
+ // Kross objects.
+
+ addFunction("propertyNames", &QtObject::propertyNames);
+ addFunction("hasProperty", &QtObject::hasProperty);
+ addFunction("getProperty", &QtObject::getProperty);
+ addFunction("setProperty", &QtObject::setProperty);
+
+ addFunction("slotNames", &QtObject::slotNames);
+ addFunction("hasSlot", &QtObject::hasSlot);
+ addFunction("slot", &QtObject::callSlot);
+
+ addFunction("signalNames", &QtObject::signalNames);
+ addFunction("hasSignal", &QtObject::hasSignal);
+ addFunction("signal", &QtObject::emitSignal);
+
+ addFunction("connect", &QtObject::connectSignal);
+ addFunction("disconnect", &QtObject::disconnectSignal);
+}
+
+QtObject::~QtObject()
+{
+}
+
+const QString QtObject::getClassName() const
+{
+ return "Kross::Api::QtObject";
+}
+
+QObject* QtObject::getObject()
+{
+ return m_object;
+}
+
+QUObject* QtObject::toQUObject(const QString& signature, List::Ptr arguments)
+{
+ int startpos = signature.find("(");
+ int endpos = signature.findRev(")");
+ if(startpos < 0 || startpos > endpos)
+ throw Exception::Ptr( new Exception(QString("Invalid Qt signal or slot signature '%1'").arg(signature)) );
+
+ //QString sig = signature.left(startpos);
+ QString params = signature.mid(startpos + 1, endpos - startpos - 1);
+ QStringList paramlist = QStringList::split(",", params); // this will fail on something like myslot(QMap<QString,QString> arg), but we don't care jet.
+ uint paramcount = paramlist.size();
+
+ // The first item in the QUObject-array is for the returnvalue
+ // while everything >=1 are the passed parameters.
+ QUObject* uo = new QUObject[ paramcount + 1 ];
+ uo[0] = QUObject(); // empty placeholder for the returnvalue.
+
+//QString t;
+//for(int j=0; j<argcount; j++) t += "'" + Variant::toString(arguments->item(j)) + "' ";
+//krossdebug( QString("1 ---------------------: (%1) %2").arg(argcount).arg(t) );
+
+ // Fill parameters.
+ uint argcount = arguments ? arguments->count() : 0;
+ for(uint i = 0; i < paramcount; i++) {
+ if(paramlist[i].find("QString") >= 0) {
+ const QString s = (argcount > i) ? Variant::toString(arguments->item(i)) : QString::null;
+ //krossdebug(QString("EventSlot::toQUObject s=%1").arg(s));
+ static_QUType_QString.set( &(uo[i + 1]), s );
+ }
+ //TODO handle int, long, char*, QStringList, etc.
+ else {
+ throw Exception::Ptr( new Exception(QString("Unknown Qt signal or slot argument '%1' in signature '%2'.").arg(paramlist[i]).arg(signature)) );
+ }
+ }
+
+ return uo;
+}
+
+Kross::Api::Object::Ptr QtObject::propertyNames(Kross::Api::List::Ptr)
+{
+ return new Kross::Api::Variant(
+ QStringList::fromStrList(m_object->metaObject()->propertyNames(false)));
+}
+
+Kross::Api::Object::Ptr QtObject::hasProperty(Kross::Api::List::Ptr args)
+{
+ return new Kross::Api::Variant(
+ m_object->metaObject()->findProperty(Kross::Api::Variant::toString(args->item(0)).latin1(), false));
+}
+
+Kross::Api::Object::Ptr QtObject::getProperty(Kross::Api::List::Ptr args)
+{
+ QVariant variant = m_object->property(Kross::Api::Variant::toString(args->item(0)).latin1());
+ if(variant.type() == QVariant::Invalid)
+ return 0;
+ return new Kross::Api::Variant(variant);
+}
+
+Kross::Api::Object::Ptr QtObject::setProperty(Kross::Api::List::Ptr args)
+{
+ return new Kross::Api::Variant(
+ m_object->setProperty(
+ Kross::Api::Variant::toString(args->item(0)).latin1(),
+ Kross::Api::Variant::toVariant(args->item(1))
+ ));
+}
+
+Kross::Api::Object::Ptr QtObject::slotNames(Kross::Api::List::Ptr)
+{
+ return new Kross::Api::Variant(
+ QStringList::fromStrList(m_object->metaObject()->slotNames(false)));
+}
+
+Kross::Api::Object::Ptr QtObject::hasSlot(Kross::Api::List::Ptr args)
+{
+ return new Kross::Api::Variant(
+ bool(m_object->metaObject()->slotNames(false).find(
+ Kross::Api::Variant::toString(args->item(0)).latin1()
+ ) != -1));
+}
+
+Kross::Api::Object::Ptr QtObject::callSlot(Kross::Api::List::Ptr args)
+{
+//TODO just call the child event ?!
+ QString name = Kross::Api::Variant::toString(args->item(0));
+ int slotid = m_object->metaObject()->findSlot(name.latin1(), false);
+ if(slotid < 0)
+ throw Exception::Ptr( new Exception(QString("No such slot '%1'.").arg(name)) );
+
+ QUObject* uo = QtObject::toQUObject(name, args);
+ m_object->qt_invoke(slotid, uo);
+ delete [] uo;
+
+ return new Variant( QVariant(true,0) );
+}
+
+Kross::Api::Object::Ptr QtObject::signalNames(Kross::Api::List::Ptr)
+{
+ return new Kross::Api::Variant(
+ QStringList::fromStrList(m_object->metaObject()->signalNames(false)));
+}
+
+Kross::Api::Object::Ptr QtObject::hasSignal(Kross::Api::List::Ptr args)
+{
+ return new Kross::Api::Variant(
+ bool(m_object->metaObject()->signalNames(false).find(
+ Kross::Api::Variant::toString(args->item(0)).latin1()
+ ) != -1));
+}
+
+Kross::Api::Object::Ptr QtObject::emitSignal(Kross::Api::List::Ptr args)
+{
+ QString name = Kross::Api::Variant::toString(args->item(0));
+ int signalid = m_object->metaObject()->findSignal(name.latin1(), false);
+ if(signalid < 0)
+ throw Exception::Ptr( new Exception(QString("No such signal '%1'.").arg(name)) );
+ m_object->qt_invoke(signalid, 0); //TODO convert Kross::Api::List::Ptr => QUObject*
+ return 0;
+}
+
+Kross::Api::Object::Ptr QtObject::connectSignal(Kross::Api::List::Ptr args)
+{
+ QString signalname = Kross::Api::Variant::toString(args->item(0));
+ QString signalsignatur = QString("2%1").arg(signalname);
+ const char* signalsig = signalsignatur.latin1();
+
+ QtObject* obj = Kross::Api::Object::fromObject<Kross::Api::QtObject>(args->item(1));
+ QObject* o = obj->getObject();
+ if(! o)
+ throw Exception::Ptr( new Exception(QString("No such QObject receiver in '%1'.").arg(obj->getName())) );
+
+ QString slotname = Kross::Api::Variant::toString(args->item(2));
+ QString slotsignatur = QString("1%1").arg(slotname);
+ const char* slotsig = slotsignatur.latin1();
+
+ return new Kross::Api::Variant(
+ QObject::connect(m_object, signalsig, o, slotsig));
+}
+
+Kross::Api::Object::Ptr QtObject::disconnectSignal(Kross::Api::List::Ptr)
+{
+ //TODO
+ return 0;
+}
+
diff --git a/lib/kross/api/qtobject.h b/lib/kross/api/qtobject.h
new file mode 100644
index 00000000..29f493a4
--- /dev/null
+++ b/lib/kross/api/qtobject.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * qtobject.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_QTOBJECT_H
+#define KROSS_API_QTOBJECT_H
+
+#include "class.h"
+
+#include <qstring.h>
+#include <qobject.h>
+
+// Forward-declaration of the builtin Qt QUObject struct.
+struct QUObject;
+
+namespace Kross { namespace Api {
+
+ // Forward declarations.
+ class Object;
+ class Variant;
+ class ScriptContainer;
+ class ScriptContrainer;
+
+ /**
+ * Class to wrap \a QObject or inherited instances.
+ *
+ * This class publishs all SIGNAL's, SLOT's and Q_PROPERTY's
+ * the QObject has.
+ */
+ class QtObject : public Kross::Api::Class<QtObject>
+ {
+ public:
+
+ /**
+ * Shared pointer to implement reference-counting.
+ */
+ typedef KSharedPtr<QtObject> Ptr;
+
+ /**
+ * Constructor.
+ *
+ * \param object The \a QObject instance this
+ * class wraps.
+ * \param name The unique name this \a QtObject
+ * instance has. If not defined then the
+ * \a QObject::name() will be used.
+ */
+ QtObject(QObject* object, const QString& name = QString::null);
+
+ /**
+ * Destructor.
+ */
+ virtual ~QtObject();
+
+ /// \see Kross::Api::Object::getClassName()
+ virtual const QString getClassName() const;
+
+ /**
+ * Return the \a QObject instance this class wraps.
+ *
+ * \return The wrapped QObject.
+ */
+ QObject* getObject();
+
+ /**
+ * Build a Qt QUObject struct out of the Qt signal or
+ * slot signature and the passed \a List arguments.
+ *
+ * \throw RuntimeException If the try to translate \p arguments
+ * failed.
+ * \param signature The Qt signal or slot signature.
+ * \param arguments The optional \a List of arguments.
+ * \return A QUObject array.
+ */
+ static QUObject* toQUObject(const QString& signature, List::Ptr arguments);
+
+ private:
+ /// The wrapped QObject.
+ QObject* m_object;
+
+ // QProperty's
+
+ /// Return a list of property names.
+ Kross::Api::Object::Ptr propertyNames(Kross::Api::List::Ptr);
+ /// Return true if the property exists else false.
+ Kross::Api::Object::Ptr hasProperty(Kross::Api::List::Ptr);
+ /// Return a property.
+ Kross::Api::Object::Ptr getProperty(Kross::Api::List::Ptr);
+ /// Set a property.
+ Kross::Api::Object::Ptr setProperty(Kross::Api::List::Ptr);
+
+ // Slots
+
+ /// Return a list of slot names.
+ Kross::Api::Object::Ptr slotNames(Kross::Api::List::Ptr);
+ /// Return true if the slot exists else false.
+ Kross::Api::Object::Ptr hasSlot(Kross::Api::List::Ptr);
+ /// Call a slot.
+ Kross::Api::Object::Ptr callSlot(Kross::Api::List::Ptr);
+
+ // Signals
+
+ /// Return a list of signal names.
+ Kross::Api::Object::Ptr signalNames(Kross::Api::List::Ptr);
+ /// Return true if the signal exists else false.
+ Kross::Api::Object::Ptr hasSignal(Kross::Api::List::Ptr);
+ /// Emit a signal.
+ Kross::Api::Object::Ptr emitSignal(Kross::Api::List::Ptr);
+
+ /// Connect signal with a QObject slot.
+ Kross::Api::Object::Ptr connectSignal(Kross::Api::List::Ptr);
+ /// Disconnect signal from QObject slot.
+ Kross::Api::Object::Ptr disconnectSignal(Kross::Api::List::Ptr);
+
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/script.cpp b/lib/kross/api/script.cpp
new file mode 100644
index 00000000..d960ba43
--- /dev/null
+++ b/lib/kross/api/script.cpp
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * script.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "script.h"
+#include "object.h"
+#include "list.h"
+#include "interpreter.h"
+#include "exception.h"
+#include "../main/scriptcontainer.h"
+
+using namespace Kross::Api;
+
+Script::Script(Interpreter* const interpreter, ScriptContainer* const scriptcontainer)
+ : m_interpreter(interpreter)
+ , m_scriptcontainer(scriptcontainer)
+ , m_exception(0)
+{
+}
+
+Script::~Script()
+{
+}
+
+bool Script::hadException()
+{
+ return m_exception != 0;
+}
+
+Exception::Ptr Script::getException()
+{
+ return m_exception;
+}
+
+void Script::setException(Exception::Ptr e)
+{
+ m_exception = e;
+}
+
+void Script::clearException()
+{
+ m_exception = 0;
+}
+
diff --git a/lib/kross/api/script.h b/lib/kross/api/script.h
new file mode 100644
index 00000000..4f7d0c04
--- /dev/null
+++ b/lib/kross/api/script.h
@@ -0,0 +1,140 @@
+/***************************************************************************
+ * script.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_SCRIPT_H
+#define KROSS_API_SCRIPT_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "class.h"
+
+namespace Kross { namespace Api {
+
+ // Forward declarations.
+ class Object;
+ class Interpreter;
+ class ScriptContainer;
+ class List;
+ class Exception;
+
+ /**
+ * Base class for interpreter dependend functionality
+ * each script provides.
+ *
+ * Each \a ScriptContainer holds a pointer to a class
+ * that implements the \a Script functionality for the
+ * defined \a Interpreter .
+ */
+ class Script
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param interpreter The \a Interpreter instance
+ * that uses this \a Script instance.
+ * \param scriptcontainer The \a ScriptContainer instance
+ * this script is associated with.
+ */
+ Script(Interpreter* const interpreter, ScriptContainer* const scriptcontainer);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Script();
+
+ /**
+ * \return true if the script throwed an exception
+ * else false.
+ */
+ bool hadException();
+
+ /**
+ * \return the \a Exception the script throwed.
+ */
+ Exception::Ptr getException();
+
+ /**
+ * Set a new exception this script throwed.
+ *
+ * \param e The \a Exception .
+ */
+ void setException(Exception::Ptr e);
+
+ /**
+ * Clear previous exceptions. If called \a hadException()
+ * will return false again.
+ */
+ void clearException();
+
+ /**
+ * Execute the script.
+ *
+ * \throws Exception on error.
+ * \return The execution result. Could be NULL too.
+ */
+ virtual Kross::Api::Object::Ptr execute() = 0;
+
+ /**
+ * \return a list of callable functionnames this
+ * script spends.
+ */
+ virtual const QStringList& getFunctionNames() = 0;
+
+ /**
+ * Call a function.
+ *
+ * \throws Exception on error.
+ * \param name The name of the function to execute.
+ * \param args Optional arguments passed to the function.
+ * \return The result of the called function. Could be NULL.
+ */
+ virtual Kross::Api::Object::Ptr callFunction(const QString& name, Kross::Api::List::Ptr args) = 0;
+
+ /**
+ * \return a list of classnames.
+ */
+ virtual const QStringList& getClassNames() = 0;
+
+ /**
+ * Create and return a new class instance.
+ *
+ * \throws Exception on error.
+ * \param name The name of the class to create a instance of.
+ * \return The new classinstance.
+ */
+ virtual Kross::Api::Object::Ptr classInstance(const QString& name) = 0;
+
+ protected:
+ /// The \a Interpreter used to create this Script instance.
+ Interpreter* const m_interpreter;
+ /// The \a ScriptContainer associated with this Script.
+ ScriptContainer* const m_scriptcontainer;
+
+ private:
+ /// The \a Exception this script throwed.
+ Exception::Ptr m_exception;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/value.h b/lib/kross/api/value.h
new file mode 100644
index 00000000..544d4a36
--- /dev/null
+++ b/lib/kross/api/value.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * value.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_VALUE_H
+#define KROSS_API_VALUE_H
+
+#include <qstring.h>
+#include <qvariant.h>
+
+#include "object.h"
+
+namespace Kross { namespace Api {
+
+ /**
+ * Template class to represent values.
+ *
+ * Classes like \a Variant or \a List are implementing this
+ * class. That way we have a common base for all kind of
+ * values.
+ */
+ template<class T, class V>
+ class Value : public Object
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param value The initial value this
+ * Value has.
+ */
+ Value(V value)
+ : Object()
+ , m_value(value) {}
+
+ /**
+ * Destructor.
+ */
+ virtual ~Value() {}
+
+ //operator V&() const { return m_value; }
+
+ /**
+ * Return the value.
+ *
+ * \return The value this Value-class holds.
+ */
+ V& getValue() { return m_value; }
+ //operator V& () { return m_value; }
+
+ template<typename TYPE>
+ static Object::Ptr toObject(TYPE t) { return new T(t); }
+
+#if 0
+//do we need it anyway?
+ /**
+ * Set the value.
+ * The value is call-by-value cause it may
+ * contain some KShared and therefore
+ * we need to keep a local copy to keep
+ * it from disappearing.
+ *
+ * \param value The value to set.
+ */
+ void setValue(V& value) { m_value = value; }
+#endif
+
+ private:
+ V m_value;
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/api/variant.cpp b/lib/kross/api/variant.cpp
new file mode 100644
index 00000000..92c0e3cb
--- /dev/null
+++ b/lib/kross/api/variant.cpp
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * variant.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "variant.h"
+#include "list.h"
+
+#include <klocale.h>
+
+using namespace Kross::Api;
+
+Variant::Variant(const QVariant& value)
+ : Value<Variant, QVariant>(value)
+{
+}
+
+Variant::~Variant()
+{
+}
+
+const QString Variant::getClassName() const
+{
+ return "Kross::Api::Variant";
+}
+
+const QString Variant::toString()
+{
+ return getValue().toString();
+}
+
+/*
+const QString Variant::getVariantType(Object::Ptr object)
+{
+ switch( toVariant(object).type() ) {
+
+ case QVariant::CString:
+ case QVariant::String:
+ return "Kross::Api::Variant::String";
+ case QVariant::Map:
+ return "Kross::Api::Variant::Dict";
+ case QVariant::StringList:
+ case QVariant::List:
+ return "Kross::Api::Variant::List";
+ case QVariant::Double:
+ //return "Kross::Api::Variant::Double";
+ case QVariant::UInt:
+ //return "Kross::Api::Variant::UInt"; // python isn't able to differ between int and uint :-(
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Int:
+ return "Kross::Api::Variant::Integer";
+ case QVariant::Bool:
+ return "Kross::Api::Variant::Bool";
+ default: //Date, Time, DateTime, ByteArray, BitArray, Rect, Size, Color, Invalid, etc.
+ return "Kross::Api::Variant";
+ }
+}
+*/
+
+const QVariant& Variant::toVariant(Object::Ptr object)
+{
+ return Object::fromObject<Variant>( object.data() )->getValue();
+}
+
+const QString Variant::toString(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::String))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::String expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toString();
+}
+
+int Variant::toInt(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::Int))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::Int expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toInt();
+}
+
+uint Variant::toUInt(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::UInt))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::UInt expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toUInt();
+}
+
+double Variant::toDouble(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::Double))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::Double expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toDouble();
+}
+
+Q_LLONG Variant::toLLONG(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::LongLong))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::LLONG expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toLongLong();
+}
+
+Q_ULLONG Variant::toULLONG(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::ULongLong))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::ULLONG expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toULongLong();
+}
+
+bool Variant::toBool(Object::Ptr object)
+{
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::Bool))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::Bool expected, but got %1.").arg(variant.typeName()).latin1()) );
+ return variant.toBool();
+}
+
+QStringList Variant::toStringList(Object::Ptr object)
+{
+ List* list = dynamic_cast< List* >( object.data() );
+ if(list) {
+ QStringList l;
+ QValueList<Object::Ptr> valuelist = list->getValue();
+ QValueList<Object::Ptr>::Iterator it(valuelist.begin()), end(valuelist.end());
+ for(; it != end; ++it)
+ l.append( toString(*it) );
+ return l;
+ }
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::StringList))
+ throw Exception::Ptr( new Exception(QString("Kross::Api::Variant::StringList expected, but got '%1'.").arg(variant.typeName()).latin1()) );
+ return variant.toStringList();
+}
+
+QValueList<QVariant> Variant::toList(Object::Ptr object)
+{
+ List* list = dynamic_cast< List* >( object.data() );
+ if(list) {
+ QValueList<QVariant> l;
+ QValueList<Object::Ptr> valuelist = list->getValue();
+ QValueList<Object::Ptr>::Iterator it(valuelist.begin()), end(valuelist.end());
+ for(; it != end; ++it)
+ l.append( toVariant(*it) );
+ return l;
+ }
+ const QVariant& variant = toVariant(object);
+ if(! variant.canCast(QVariant::List))
+ throw Exception::Ptr( new Exception(i18n("Kross::Api::Variant::List expected, but got '%1'.").arg(variant.typeName()).latin1()) );
+ return variant.toList();
+}
diff --git a/lib/kross/api/variant.h b/lib/kross/api/variant.h
new file mode 100644
index 00000000..020e6e51
--- /dev/null
+++ b/lib/kross/api/variant.h
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * variant.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_API_VARIANT_H
+#define KROSS_API_VARIANT_H
+
+#include <qstring.h>
+#include <qvariant.h>
+
+#include "object.h"
+#include "value.h"
+#include "exception.h"
+
+namespace Kross { namespace Api {
+
+ class List;
+
+ /**
+ * Variant value to wrap a QVariant into a \a Kross::Api::Value
+ * to enable primitive types like strings or numerics.
+ */
+ class Variant : public Value<Variant, QVariant>
+ {
+ friend class Value<Variant, QVariant>;
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param value The initial QVariant-value
+ * this Variant-Object has.
+ * \param name The name this Value has.
+ */
+ Variant(const QVariant& value);
+
+ inline operator bool () { return getValue().toBool(); }
+ inline operator int () { return getValue().toInt(); }
+ inline operator uint () { return getValue().toUInt(); }
+ inline operator double () { return getValue().toDouble(); }
+ inline operator const char* () { return getValue().toString().latin1(); }
+
+ inline operator QString () { return getValue().toString(); }
+ inline operator const QString () { return getValue().toString(); }
+ inline operator const QString& () { return getValue().asString(); }
+
+ inline operator QCString () { return getValue().toCString(); }
+ inline operator const QCString () { return getValue().toCString(); }
+ inline operator const QCString& () { return getValue().asCString(); }
+
+ inline operator QVariant () { return getValue(); }
+ inline operator const QVariant () { return getValue(); }
+ inline operator const QVariant& () { return getValue(); }
+
+ /**
+ * Operator to return a QStringList.
+ *
+ * We can not just use getValue().toStringList() here cause maybe
+ * this Kross::Api::Variant is a Kross::Api::List which could be
+ * internaly used for list of strings as well. So, we use the
+ * toStringList() function which will take care of translating a
+ * Kross::Api::List to a QStringList if possible or to throw an
+ * exception if the Kross::Api::List isn't a QStringList.
+ */
+ inline operator QStringList () {
+ return toStringList(this);
+ }
+ inline operator QValueList<QVariant> () {
+ return toList(this);
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~Variant();
+
+ /// \see Kross::Api::Object::getClassName()
+ virtual const QString getClassName() const;
+
+ /**
+ * \return a string representation of the variant.
+ *
+ * \see Kross::Api::Object::toString()
+ */
+ virtual const QString toString();
+
+ /**
+ * Try to convert the given \a Object into
+ * a QVariant.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a QVariant converted object.
+ */
+ static const QVariant& toVariant(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a QString.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a QString converted object.
+ */
+ static const QString toString(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a int.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a int converted object.
+ */
+ static int toInt(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a uint.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a uint converted object.
+ */
+ static uint toUInt(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a uint.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a uint converted object.
+ */
+ static double toDouble(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a Q_LLONG.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a Q_LLONG converted object.
+ */
+ static Q_LLONG toLLONG(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a Q_ULLONG.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a Q_ULLONG converted object.
+ */
+ static Q_ULLONG toULLONG(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a boolean value.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a bool converted object.
+ */
+ static bool toBool(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a QStringList.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a QValueList converted object.
+ */
+ static QStringList toStringList(Object::Ptr object);
+
+ /**
+ * Try to convert the given \a Object into
+ * a QValueList of QVariant's.
+ *
+ * \throw TypeException If the convert failed.
+ * \param object The object to convert.
+ * \return The to a QValueList converted object.
+ */
+ static QValueList<QVariant> toList(Object::Ptr object);
+
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/configure.in.bot b/lib/kross/configure.in.bot
new file mode 100644
index 00000000..1d20501f
--- /dev/null
+++ b/lib/kross/configure.in.bot
@@ -0,0 +1,16 @@
+if test -z "$RUBY_LIBDIR" -a "x$compile_kross" = "xyes" ; then
+ echo ""
+ echo "Ruby development files were not found, or Ruby <= 1.8.1 was found,"
+ echo "Ruby scripting support for KOffice will not be built. If you don't"
+ echo "need Ruby scripting, you can ignore this message."
+ echo ""
+fi
+
+if test -z "$LIBPYTHON" -a -z "$PYTHONINC" -a $"x$compile_kross" = "xyes"; then
+ echo ""
+ echo "Python developement files were not found, Python scripting support for"
+ echo "KOffice will not be built. If you don't need Python scripting, you"
+ echo "can ignore this message"
+ echo ""
+fi
+
diff --git a/lib/kross/configure.in.in b/lib/kross/configure.in.in
new file mode 100644
index 00000000..47c2d2d3
--- /dev/null
+++ b/lib/kross/configure.in.in
@@ -0,0 +1,108 @@
+AC_ARG_ENABLE(scripting,
+ AC_HELP_STRING([--enable-scripting],
+ [build scripting library (Kross) [default=yes]]),
+ compile_kross=$enableval, compile_kross=yes)
+AM_CONDITIONAL(compile_kross, test "x$compile_kross" = "xyes")
+
+###############################
+# Check if Python is installed.
+
+if test "x$compile_kross" = "xyes" ; then
+ #KDE_CHECK_PYTHON(2.3)
+ KDE_CHECK_PYTHON
+fi
+
+# Compile the Kross python plugin only if both, $LIBPYTHON and
+# $PYTHONINC, are defined.
+AM_CONDITIONAL(compile_kross_python,
+ test -n "$LIBPYTHON" && test -n "$PYTHONINC")
+
+###############################
+# Check for Ruby
+
+if test "x$compile_kross" = "xyes" ; then
+ AC_CHECK_PROGS([RUBY], [ruby ruby1.8 ruby18], ruby)
+
+ if test -n "$RUBY"; then
+ AC_MSG_CHECKING(for Ruby dirs)
+ RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'`
+ RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'`
+ RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'`
+ RUBY_INCLUDEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"rubyincludedir"@:>@)'`
+ RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'`
+ RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'`
+ RUBY_ENABLESHARED=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"ENABLE_SHARED"@:>@)'`
+ AC_MSG_RESULT([
+ archdir $RUBY_ARCHDIR,
+ sitearchdir $RUBY_SITEARCHDIR,
+ sitedir $RUBY_SITEDIR,
+ includedir $RUBY_INCLUDEDIR,
+ libdir $RUBY_LIBDIR,
+ librubyarg $RUBY_LIBRUBYARG,
+ rubysharedenabled $RUBY_ENABLESHARED])
+ AC_SUBST(RUBY_ARCHDIR)
+ AC_SUBST(RUBY_SITEARCHDIR)
+ AC_SUBST(RUBY_SITEDIR)
+ AC_SUBST(RUBY_INCLUDEDIR)
+ AC_SUBST(RUBY_LIBDIR)
+ AC_SUBST(RUBY_LIBRUBYARG)
+ AC_SUBST(RUBY_ENABLESHARED)
+
+ AC_MSG_CHECKING(for Ruby header)
+
+ if test ! -r $RUBY_INCLUDEDIR/ruby.h; then
+ # if $RUBY_INCLUDEDIR is not valid try to use $RUBY_ARCHDIR
+ RUBY_INCLUDEDIR=$RUBY_ARCHDIR
+ fi
+
+ if test ! -r $RUBY_INCLUDEDIR/ruby.h; then
+ RUBY_LIBDIR=""
+ AC_MSG_RESULT([not found])
+ else
+ AC_MSG_RESULT([found]) # header
+
+ AC_MSG_CHECKING(Ruby shared library)
+ if test "x$RUBY_ENABLESHARED" != "xyes" ; then
+ AC_MSG_RESULT([shared library not found])
+ RUBY_LIBDIR=""
+ else
+ if test -z "$RUBY_LIBRUBYARG" ; then
+ AC_MSG_RESULT([link argument not found])
+ RUBY_LIBDIR=""
+ else
+ AC_MSG_RESULT([found]) # shared library link arg
+
+ AC_MSG_CHECKING([if C++ program with ruby can be compiled])
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS -I$RUBY_INCLUDEDIR"
+ AC_CACHE_VAL(ruby_build,
+ [
+ AC_TRY_COMPILE([
+ #include <ruby.h>
+ #include <version.h>
+ ],[
+
+#if(RUBY_VERSION_MAJOR==1 && RUBY_VERSION_MINOR == 8 && RUBY_VERSION_TEENY <= 1)
+#error "need at least ruby 1.8.2\n"
+#endif
+
+ ruby_init();
+ return 0;
+ ], ruby_build=yes,
+ ruby_build=no)
+ ])
+ AC_MSG_RESULT($ruby_build)
+ if test "$ruby_build" = "no"; then
+ RUBY_LIBDIR=""
+ fi
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ AC_LANG_RESTORE
+ fi # have ruby shared lib argument
+ fi # have shared lib
+ fi # have ruby header
+ fi # have ruby
+fi # compiling kross
+
+AM_CONDITIONAL(compile_kross_ruby, test -n "$RUBY_LIBDIR")
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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "scriptguiclient.h"
+#include "manager.h"
+#include "../api/interpreter.h"
+#include "wdgscriptsmanager.h"
+
+#include <kapplication.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+#include <kmimetype.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <ktar.h>
+#include <kstandarddirs.h>
+
+#include <kio/netaccess.h>
+
+using namespace Kross::Api;
+
+namespace Kross { namespace Api {
+
+ /// @internal
+ class ScriptGUIClientPrivate
+ {
+ public:
+ /**
+ * The \a KXMLGUIClient that is parent of the \a ScriptGUIClient
+ * instance.
+ */
+ KXMLGUIClient* guiclient;
+
+ /**
+ * The optional parent 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 (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#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 <cberger@cberger.net>
+ * 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 <cberger@cberger.net>
+ * 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>
diff --git a/lib/kross/python/Makefile.am b/lib/kross/python/Makefile.am
new file mode 100644
index 00000000..5eff2abe
--- /dev/null
+++ b/lib/kross/python/Makefile.am
@@ -0,0 +1,33 @@
+include $(top_srcdir)/lib/kross/Makefile.global
+
+kde_module_LTLIBRARIES = krosspython.la
+
+krosspython_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries) $(LIBPYTHON) $(PYTHONLIB) -module $(VER_INFO)
+
+noinst_HEADERS = \
+ pythonextension.h \
+ pythonmodule.h \
+ pythonobject.h \
+ pythonscript.h \
+ pythonsecurity.h \
+ pythoninterpreter.h \
+ pythonconfig.h
+
+krosspython_la_SOURCES = \
+ pythonextension.cpp \
+ pythonmodule.cpp \
+ pythonobject.cpp \
+ pythonscript.cpp \
+ pythonsecurity.cpp \
+ pythoninterpreter.cpp
+
+krosspython_la_LIBADD = \
+ $(LIB_QT) \
+ $(LIB_KDECORE) \
+ cxx/libkrosspythoncxx.la \
+ ../api/libkrossapi.la \
+ ../main/libkrossmain.la
+
+INCLUDES = $(KROSS_INCLUDES) $(PYTHONINC) $(all_includes)
+METASOURCES = AUTO
+SUBDIRS = cxx scripts .
diff --git a/lib/kross/python/cxx/Config.hxx b/lib/kross/python/cxx/Config.hxx
new file mode 100644
index 00000000..65bbc2d3
--- /dev/null
+++ b/lib/kross/python/cxx/Config.hxx
@@ -0,0 +1,74 @@
+#ifndef __PyCXX_config_hh__
+#define __PyCXX_config_hh__
+
+//
+// Microsoft VC++ 6.0 has no traits
+//
+#if defined( _MSC_VER )
+
+# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1
+
+#elif defined( __GNUC__ )
+# if __GNUC__ >= 3
+# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1
+# else
+# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 0
+#endif
+
+//
+// Assume all other compilers do
+//
+#else
+
+// Macros to deal with deficiencies in compilers
+# define STANDARD_LIBRARY_HAS_ITERATOR_TRAITS 1
+#endif
+
+#if STANDARD_LIBRARY_HAS_ITERATOR_TRAITS
+# define random_access_iterator_parent(itemtype) std::iterator<std::random_access_iterator_tag,itemtype,int>
+#else
+# define random_access_iterator_parent(itemtype) std::random_access_iterator<itemtype, int>
+#endif
+
+//
+// Which C++ standard is in use?
+//
+#if defined( _MSC_VER )
+# if _MSC_VER <= 1200
+// MSVC++ 6.0
+# define PYCXX_ISO_CPP_LIB 0
+# define STR_STREAM <strstream>
+# define TEMPLATE_TYPENAME class
+# else
+# define PYCXX_ISO_CPP_LIB 1
+# define STR_STREAM <sstream>
+# define TEMPLATE_TYPENAME typename
+# endif
+#elif defined( __GNUC__ )
+# if __GNUC__ >= 3
+# define PYCXX_ISO_CPP_LIB 1
+# define STR_STREAM <sstream>
+# define TEMPLATE_TYPENAME typename
+# else
+# define PYCXX_ISO_CPP_LIB 0
+# define STR_STREAM <strstream>
+# define TEMPLATE_TYPENAME class
+# endif
+#endif
+
+#if PYCXX_ISO_CPP_LIB
+# define STR_STREAM <sstream>
+# define OSTRSTREAM ostringstream
+# define EXPLICIT_TYPENAME typename
+# define EXPLICIT_CLASS class
+# define TEMPLATE_TYPENAME typename
+#else
+# define STR_STREAM <strstream>
+# define OSTRSTREAM ostrstream
+# define EXPLICIT_TYPENAME
+# define EXPLICIT_CLASS
+# define TEMPLATE_TYPENAME class
+#endif
+
+
+#endif // __PyCXX_config_hh__
diff --git a/lib/kross/python/cxx/Exception.hxx b/lib/kross/python/cxx/Exception.hxx
new file mode 100644
index 00000000..afcff489
--- /dev/null
+++ b/lib/kross/python/cxx/Exception.hxx
@@ -0,0 +1,212 @@
+//----------------------------------*-C++-*----------------------------------//
+// Copyright 1998 The Regents of the University of California.
+// All rights reserved. See LEGAL.LLNL for full text and disclaimer.
+//---------------------------------------------------------------------------//
+
+#ifndef __CXX_Exception_h
+#define __CXX_Exception_h
+
+#include "Python.h"
+#include "Config.hxx"
+#include "IndirectPythonInterface.hxx"
+
+#include <string>
+#include <iostream>
+
+// This mimics the Python structure, in order to minimize confusion
+namespace Py
+ {
+ class ExtensionExceptionType;
+
+ class Exception
+ {
+ public:
+ Exception( ExtensionExceptionType &exception, const std::string& reason );
+
+ explicit Exception ()
+ {}
+
+ Exception (const std::string& reason)
+ {
+ PyErr_SetString (Py::_Exc_RuntimeError(), reason.c_str());
+ }
+
+ Exception (PyObject* exception, const std::string& reason)
+ {
+ PyErr_SetString (exception, reason.c_str());
+ }
+
+
+ void clear() // clear the error
+ // technically but not philosophically const
+ {
+ PyErr_Clear();
+ }
+ };
+
+
+ // Abstract
+ class StandardError: public Exception
+ {
+ protected:
+ explicit StandardError()
+ {}
+ };
+
+ class LookupError: public StandardError
+ {
+ protected:
+ explicit LookupError()
+ {}
+ };
+
+ class ArithmeticError: public StandardError
+ {
+ protected:
+ explicit ArithmeticError()
+ {}
+ };
+
+ class EnvironmentError: public StandardError
+ {
+ protected:
+ explicit EnvironmentError()
+ {}
+ };
+
+ // Concrete
+
+ class TypeError: public StandardError
+ {
+ public:
+ TypeError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_TypeError(),reason.c_str());
+ }
+ };
+
+ class IndexError: public LookupError
+ {
+ public:
+ IndexError (const std::string& reason)
+ : LookupError()
+ {
+ PyErr_SetString (Py::_Exc_IndexError(), reason.c_str());
+ }
+ };
+
+ class AttributeError: public StandardError
+ {
+ public:
+ AttributeError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_AttributeError(), reason.c_str());
+ }
+ };
+
+ class NameError: public StandardError
+ {
+ public:
+ NameError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_NameError(), reason.c_str());
+ }
+ };
+
+ class RuntimeError: public StandardError
+ {
+ public:
+ RuntimeError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_RuntimeError(), reason.c_str());
+ }
+ };
+
+ class SystemError: public StandardError
+ {
+ public:
+ SystemError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_SystemError(),reason.c_str());
+ }
+ };
+
+ class KeyError: public LookupError
+ {
+ public:
+ KeyError (const std::string& reason)
+ : LookupError()
+ {
+ PyErr_SetString (Py::_Exc_KeyError(),reason.c_str());
+ }
+ };
+
+
+ class ValueError: public StandardError
+ {
+ public:
+ ValueError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_ValueError(), reason.c_str());
+ }
+ };
+
+ class OverflowError: public ArithmeticError
+ {
+ public:
+ OverflowError (const std::string& reason)
+ : ArithmeticError()
+ {
+ PyErr_SetString (Py::_Exc_OverflowError(), reason.c_str());
+ }
+ };
+
+ class ZeroDivisionError: public ArithmeticError
+ {
+ public:
+ ZeroDivisionError (const std::string& reason)
+ : ArithmeticError()
+ {
+ PyErr_SetString (Py::_Exc_ZeroDivisionError(), reason.c_str());
+ }
+ };
+
+ class FloatingPointError: public ArithmeticError
+ {
+ public:
+ FloatingPointError (const std::string& reason)
+ : ArithmeticError()
+ {
+ PyErr_SetString (Py::_Exc_FloatingPointError(), reason.c_str());
+ }
+ };
+
+ class MemoryError: public StandardError
+ {
+ public:
+ MemoryError (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_MemoryError(), reason.c_str());
+ }
+ };
+
+ class SystemExit: public StandardError
+ {
+ public:
+ SystemExit (const std::string& reason)
+ : StandardError()
+ {
+ PyErr_SetString (Py::_Exc_SystemExit(),reason.c_str());
+ }
+ };
+
+ }// Py
+
+#endif
diff --git a/lib/kross/python/cxx/Extensions.hxx b/lib/kross/python/cxx/Extensions.hxx
new file mode 100644
index 00000000..69ce9a14
--- /dev/null
+++ b/lib/kross/python/cxx/Extensions.hxx
@@ -0,0 +1,756 @@
+//----------------------------------*-C++-*----------------------------------//
+// Copyright 1998 The Regents of the University of California.
+// All rights reserved. See LEGAL.LLNL for full text and disclaimer.
+//---------------------------------------------------------------------------//
+
+#ifndef __CXX_Extensions__h
+#define __CXX_Extensions__h
+
+
+#ifdef _MSC_VER
+// disable warning C4786: symbol greater than 255 character,
+// okay to ignore
+#pragma warning(disable: 4786)
+#endif
+
+
+#include "Config.hxx"
+#include "Objects.hxx"
+
+extern "C"
+ {
+ extern PyObject py_object_initializer;
+ }
+
+#include <vector>
+#include <map>
+
+namespace Py
+ {
+ class ExtensionModuleBase;
+
+ // Make an Exception Type for use in raising custom exceptions
+ class ExtensionExceptionType : public Object
+ {
+ public:
+ ExtensionExceptionType();
+ virtual ~ExtensionExceptionType();
+
+ // call init to create the type
+ void init( ExtensionModuleBase &module, const std::string& name );
+ };
+
+
+ class MethodTable
+ {
+ public:
+ MethodTable();
+ virtual ~MethodTable();
+
+ void add(const char* method_name, PyCFunction f, const char* doc="", int flag=1);
+ PyMethodDef* table();
+
+ protected:
+ std::vector<PyMethodDef> t; // accumulator of PyMethodDef's
+ PyMethodDef *mt; // Actual method table produced when full
+
+ static PyMethodDef method (const char* method_name, PyCFunction f, int flags = 1, const char* doc="");
+
+ private:
+ //
+ // prevent the compiler generating these unwanted functions
+ //
+ MethodTable(const MethodTable& m); //unimplemented
+ void operator=(const MethodTable& m); //unimplemented
+
+ }; // end class MethodTable
+
+ extern "C"
+ {
+ typedef PyObject *(*method_varargs_call_handler_t)( PyObject *_self, PyObject *_args );
+ typedef PyObject *(*method_keyword_call_handler_t)( PyObject *_self, PyObject *_args, PyObject *_dict );
+ }
+
+ template<class T>
+ class MethodDefExt : public PyMethodDef
+ {
+ public:
+ typedef Object (T::*method_varargs_function_t)( const Tuple &args );
+ typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
+
+ MethodDefExt
+ (
+ const char *_name,
+ method_varargs_function_t _function,
+ method_varargs_call_handler_t _handler,
+ const char *_doc
+ )
+ {
+ ext_meth_def.ml_name = const_cast<char *>(_name);
+ ext_meth_def.ml_meth = _handler;
+ ext_meth_def.ml_flags = METH_VARARGS;
+ ext_meth_def.ml_doc = const_cast<char *>(_doc);
+
+ ext_varargs_function = _function;
+ ext_keyword_function = NULL;
+ }
+
+ MethodDefExt
+ (
+ const char *_name,
+ method_keyword_function_t _function,
+ method_keyword_call_handler_t _handler,
+ const char *_doc
+ )
+ {
+ ext_meth_def.ml_name = const_cast<char *>(_name);
+ ext_meth_def.ml_meth = method_varargs_call_handler_t( _handler );
+ ext_meth_def.ml_flags = METH_VARARGS|METH_KEYWORDS;
+ ext_meth_def.ml_doc = const_cast<char *>(_doc);
+
+ ext_varargs_function = NULL;
+ ext_keyword_function = _function;
+ }
+
+ ~MethodDefExt()
+ {}
+
+ PyMethodDef ext_meth_def;
+ method_varargs_function_t ext_varargs_function;
+ method_keyword_function_t ext_keyword_function;
+ };
+
+ class ExtensionModuleBase
+ {
+ public:
+ ExtensionModuleBase( const char *name );
+ virtual ~ExtensionModuleBase();
+
+ Module module(void) const; // only valid after initialize() has been called
+ Dict moduleDictionary(void) const; // only valid after initialize() has been called
+
+ virtual Object invoke_method_keyword( const std::string &_name, const Tuple &_args, const Dict &_keywords ) = 0;
+ virtual Object invoke_method_varargs( const std::string &_name, const Tuple &_args ) = 0;
+
+ const std::string &name() const;
+ const std::string &fullName() const;
+
+ protected:
+ // Initialize the module
+ void initialize( const char *module_doc );
+
+ const std::string module_name;
+ const std::string full_module_name;
+ MethodTable method_table;
+
+ private:
+
+ //
+ // prevent the compiler generating these unwanted functions
+ //
+ ExtensionModuleBase( const ExtensionModuleBase & ); //unimplemented
+ void operator=( const ExtensionModuleBase & ); //unimplemented
+
+ };
+
+ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords );
+ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args );
+ extern "C" void do_not_dealloc( void * );
+
+
+ template<TEMPLATE_TYPENAME T>
+ class ExtensionModule : public ExtensionModuleBase
+ {
+ public:
+ ExtensionModule( const char *name )
+ : ExtensionModuleBase( name )
+ {}
+ virtual ~ExtensionModule()
+ {}
+
+ protected:
+ typedef Object (T::*method_varargs_function_t)( const Tuple &args );
+ typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
+ typedef std::map<std::string,MethodDefExt<T> *> method_map_t;
+
+ static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" )
+ {
+ method_map_t &mm = methods();
+
+ MethodDefExt<T> *method_definition = new MethodDefExt<T>
+ (
+ name,
+ function,
+ method_varargs_call_handler,
+ doc
+ );
+
+ mm[std::string( name )] = method_definition;
+ }
+
+ static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" )
+ {
+ method_map_t &mm = methods();
+
+ MethodDefExt<T> *method_definition = new MethodDefExt<T>
+ (
+ name,
+ function,
+ method_keyword_call_handler,
+ doc
+ );
+
+ mm[std::string( name )] = method_definition;
+ }
+
+ void initialize( const char *module_doc="" )
+ {
+ ExtensionModuleBase::initialize( module_doc );
+ Dict dict( moduleDictionary() );
+
+ //
+ // put each of the methods into the modules dictionary
+ // so that we get called back at the function in T.
+ //
+ method_map_t &mm = methods();
+ EXPLICIT_TYPENAME method_map_t::iterator i;
+
+ for( i=mm.begin(); i != mm.end(); ++i )
+ {
+ MethodDefExt<T> *method_definition = (*i).second;
+
+ static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc );
+
+ Tuple args( 2 );
+ args[0] = Object( self );
+ args[1] = String( (*i).first );
+
+ PyObject *func = PyCFunction_New
+ (
+ &method_definition->ext_meth_def,
+ new_reference_to( args )
+ );
+
+ dict[ (*i).first ] = Object( func );
+ }
+ }
+
+ protected: // Tom Malcolmson reports that derived classes need access to these
+
+ static method_map_t &methods(void)
+ {
+ static method_map_t *map_of_methods = NULL;
+ if( map_of_methods == NULL )
+ map_of_methods = new method_map_t;
+
+ return *map_of_methods;
+ }
+
+
+ // this invoke function must be called from within a try catch block
+ virtual Object invoke_method_keyword( const std::string &name, const Tuple &args, const Dict &keywords )
+ {
+ method_map_t &mm = methods();
+ MethodDefExt<T> *meth_def = mm[ name ];
+ if( meth_def == NULL )
+ {
+ std::string error_msg( "CXX - cannot invoke keyword method named " );
+ error_msg += name;
+ throw RuntimeError( error_msg );
+ }
+
+ // cast up to the derived class
+ T *self = static_cast<T *>(this);
+
+ return (self->*meth_def->ext_keyword_function)( args, keywords );
+ }
+
+ // this invoke function must be called from within a try catch block
+ virtual Object invoke_method_varargs( const std::string &name, const Tuple &args )
+ {
+ method_map_t &mm = methods();
+ MethodDefExt<T> *meth_def = mm[ name ];
+ if( meth_def == NULL )
+ {
+ std::string error_msg( "CXX - cannot invoke varargs method named " );
+ error_msg += name;
+ throw RuntimeError( error_msg );
+ }
+
+ // cast up to the derived class
+ T *self = static_cast<T *>(this);
+
+ return (self->*meth_def->ext_varargs_function)( args );
+ }
+
+ private:
+ //
+ // prevent the compiler generating these unwanted functions
+ //
+ ExtensionModule( const ExtensionModule<T> & ); //unimplemented
+ void operator=( const ExtensionModule<T> & ); //unimplemented
+ };
+
+
+ class PythonType
+ {
+ public:
+ // if you define one sequence method you must define
+ // all of them except the assigns
+
+ PythonType (size_t base_size, int itemsize, const char *default_name );
+ virtual ~PythonType ();
+
+ const char *getName () const;
+ const char *getDoc () const;
+
+ PyTypeObject* type_object () const;
+ void name (const char* nam);
+ void doc (const char* d);
+ void dealloc(void (*f)(PyObject*));
+
+ void supportPrint(void);
+ void supportGetattr(void);
+ void supportSetattr(void);
+ void supportGetattro(void);
+ void supportSetattro(void);
+ void supportCompare(void);
+ void supportRepr(void);
+ void supportStr(void);
+ void supportHash(void);
+ void supportCall(void);
+
+ void supportSequenceType(void);
+ void supportMappingType(void);
+ void supportNumberType(void);
+ void supportBufferType(void);
+
+ protected:
+ PyTypeObject *table;
+ PySequenceMethods *sequence_table;
+ PyMappingMethods *mapping_table;
+ PyNumberMethods *number_table;
+ PyBufferProcs *buffer_table;
+
+ void init_sequence();
+ void init_mapping();
+ void init_number();
+ void init_buffer();
+
+ private:
+ //
+ // prevent the compiler generating these unwanted functions
+ //
+ PythonType (const PythonType& tb); // unimplemented
+ void operator=(const PythonType& t); // unimplemented
+
+ }; // end of PythonType
+
+
+
+ // Class PythonExtension is what you inherit from to create
+ // a new Python extension type. You give your class itself
+ // as the template paramter.
+
+ // There are two ways that extension objects can get destroyed.
+ // 1. Their reference count goes to zero
+ // 2. Someone does an explicit delete on a pointer.
+ // In (1) the problem is to get the destructor called
+ // We register a special deallocator in the Python type object
+ // (see behaviors()) to do this.
+ // In (2) there is no problem, the dtor gets called.
+
+ // PythonExtension does not use the usual Python heap allocator,
+ // instead using new/delete. We do the setting of the type object
+ // and reference count, usually done by PyObject_New, in the
+ // base class ctor.
+
+ // This special deallocator does a delete on the pointer.
+
+
+ class PythonExtensionBase : public PyObject
+ {
+ public:
+ PythonExtensionBase();
+ virtual ~PythonExtensionBase();
+
+ public:
+ virtual int print( FILE *, int );
+ virtual Object getattr( const char * ) = 0;
+ virtual int setattr( const char *, const Object & );
+ virtual Object getattro( const Object & );
+ virtual int setattro( const Object &, const Object & );
+ virtual int compare( const Object & );
+ virtual Object repr();
+ virtual Object str();
+ virtual long hash();
+ virtual Object call( const Object &, const Object & );
+
+ // Sequence methods
+ virtual int sequence_length();
+ virtual Object sequence_concat( const Object & );
+ virtual Object sequence_repeat( int );
+ virtual Object sequence_item( int );
+ virtual Object sequence_slice( int, int );
+ virtual int sequence_ass_item( int, const Object & );
+ virtual int sequence_ass_slice( int, int, const Object & );
+
+ // Mapping
+ virtual int mapping_length();
+ virtual Object mapping_subscript( const Object & );
+ virtual int mapping_ass_subscript( const Object &, const Object & );
+
+ // Number
+ virtual int number_nonzero();
+ virtual Object number_negative();
+ virtual Object number_positive();
+ virtual Object number_absolute();
+ virtual Object number_invert();
+ virtual Object number_int();
+ virtual Object number_float();
+ virtual Object number_long();
+ virtual Object number_oct();
+ virtual Object number_hex();
+ virtual Object number_add( const Object & );
+ virtual Object number_subtract( const Object & );
+ virtual Object number_multiply( const Object & );
+ virtual Object number_divide( const Object & );
+ virtual Object number_remainder( const Object & );
+ virtual Object number_divmod( const Object & );
+ virtual Object number_lshift( const Object & );
+ virtual Object number_rshift( const Object & );
+ virtual Object number_and( const Object & );
+ virtual Object number_xor( const Object & );
+ virtual Object number_or( const Object & );
+ virtual Object number_power( const Object &, const Object & );
+
+ // Buffer
+ virtual int buffer_getreadbuffer( int, void** );
+ virtual int buffer_getwritebuffer( int, void** );
+ virtual int buffer_getsegcount( int* );
+
+ private:
+ void missing_method( void );
+ static PyObject *method_call_handler( PyObject *self, PyObject *args );
+ };
+
+ template<TEMPLATE_TYPENAME T>
+ class PythonExtension: public PythonExtensionBase
+ {
+ public:
+ static PyTypeObject* type_object()
+ {
+ return behaviors().type_object();
+ }
+
+ static int check( PyObject *p )
+ {
+ // is p like me?
+ return p->ob_type == type_object();
+ }
+
+ static int check( const Object& ob )
+ {
+ return check( ob.ptr());
+ }
+
+
+ //
+ // every object needs getattr implemented
+ // to support methods
+ //
+ virtual Object getattr( const char *name )
+ {
+ return getattr_methods( name );
+ }
+
+ protected:
+ explicit PythonExtension()
+ : PythonExtensionBase()
+ {
+ #ifdef PyObject_INIT
+ (void)PyObject_INIT( this, type_object() );
+ #else
+ ob_refcnt = 1;
+ ob_type = type_object();
+ #endif
+
+ // every object must support getattr
+ behaviors().supportGetattr();
+ }
+
+ virtual ~PythonExtension()
+ {}
+
+ static PythonType &behaviors()
+ {
+ static PythonType* p;
+ if( p == NULL )
+ {
+#if defined( _CPPRTTI )
+ const char *default_name = (typeid ( T )).name();
+#else
+ const char *default_name = "unknown";
+#endif
+ p = new PythonType( sizeof( T ), 0, default_name );
+ p->dealloc( extension_object_deallocator );
+ }
+
+ return *p;
+ }
+
+
+ typedef Object (T::*method_varargs_function_t)( const Tuple &args );
+ typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
+ typedef std::map<std::string,MethodDefExt<T> *> method_map_t;
+
+ // support the default attributes, __name__, __doc__ and methods
+ virtual Object getattr_default( const char *_name )
+ {
+ std::string name( _name );
+
+ if( name == "__name__" && type_object()->tp_name != NULL )
+ {
+ return Py::String( type_object()->tp_name );
+ }
+ else if( name == "__doc__" && type_object()->tp_doc != NULL )
+ {
+ return Py::String( type_object()->tp_doc );
+ }
+
+// trying to fake out being a class for help()
+// else if( name == "__bases__" )
+// {
+// return Py::Tuple(0);
+// }
+// else if( name == "__module__" )
+// {
+// return Py::Nothing();
+// }
+// else if( name == "__dict__" )
+// {
+// return Py::Dict();
+// }
+ else
+ {
+ return getattr_methods( _name );
+ }
+ }
+
+ // turn a name into function object
+ virtual Object getattr_methods( const char *_name )
+ {
+ std::string name( _name );
+
+ method_map_t &mm = methods();
+
+ if( name == "__methods__" )
+ {
+ List methods;
+
+ for( EXPLICIT_TYPENAME method_map_t::iterator i = mm.begin(); i != mm.end(); ++i )
+ methods.append( String( (*i).first ) );
+
+ return methods;
+ }
+
+ // see if name exists
+ if( mm.find( name ) == mm.end() )
+ throw AttributeError( "method '" + name + "' does not exist." );
+
+ Tuple self( 2 );
+
+ self[0] = Object( this );
+ self[1] = String( name );
+
+ MethodDefExt<T> *method_definition = mm[ name ];
+
+ PyObject *func = PyCFunction_New( &method_definition->ext_meth_def, self.ptr() );
+
+ return Object(func, true);
+ }
+
+ static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" )
+ {
+ method_map_t &mm = methods();
+
+ MethodDefExt<T> *method_definition = new MethodDefExt<T>
+ (
+ name,
+ function,
+ method_varargs_call_handler,
+ doc
+ );
+
+ mm[std::string( name )] = method_definition;
+ }
+
+ static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" )
+ {
+ method_map_t &mm = methods();
+
+ MethodDefExt<T> *method_definition = new MethodDefExt<T>
+ (
+ name,
+ function,
+ method_keyword_call_handler,
+ doc
+ );
+
+ mm[std::string( name )] = method_definition;
+ }
+
+ private:
+ static method_map_t &methods(void)
+ {
+ static method_map_t *map_of_methods = NULL;
+ if( map_of_methods == NULL )
+ map_of_methods = new method_map_t;
+
+ return *map_of_methods;
+ }
+
+ static PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords )
+ {
+ try
+ {
+ Tuple self_and_name_tuple( _self_and_name_tuple );
+
+ PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
+ T *self = static_cast<T *>( self_in_cobject );
+
+ String name( self_and_name_tuple[1] );
+
+ method_map_t &mm = methods();
+ MethodDefExt<T> *meth_def = mm[ name ];
+ if( meth_def == NULL )
+ return 0;
+
+ Tuple args( _args );
+
+ // _keywords may be NULL so be careful about the way the dict is created
+ Dict keywords;
+ if( _keywords != NULL )
+ keywords = Dict( _keywords );
+
+ Object result( (self->*meth_def->ext_keyword_function)( args, keywords ) );
+
+ return new_reference_to( result.ptr() );
+ }
+ catch( Exception & )
+ {
+ return 0;
+ }
+ }
+
+ static PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args )
+ {
+ try
+ {
+ Tuple self_and_name_tuple( _self_and_name_tuple );
+
+ PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
+ T *self = static_cast<T *>( self_in_cobject );
+
+ String name( self_and_name_tuple[1] );
+
+ method_map_t &mm = methods();
+ MethodDefExt<T> *meth_def = mm[ name ];
+ if( meth_def == NULL )
+ return 0;
+
+ Tuple args( _args );
+
+ Object result;
+
+ // TMM: 7Jun'01 - Adding try & catch in case of STL debug-mode exceptions.
+ #ifdef _STLP_DEBUG
+ try
+ {
+ result = (self->*meth_def->ext_varargs_function)( args );
+ }
+ catch (std::__stl_debug_exception)
+ {
+ // throw cxx::RuntimeError( sErrMsg );
+ throw cxx::RuntimeError( "Error message not set yet." );
+ }
+ #else
+ result = (self->*meth_def->ext_varargs_function)( args );
+ #endif // _STLP_DEBUG
+
+ return new_reference_to( result.ptr() );
+ }
+ catch( Exception & )
+ {
+ return 0;
+ }
+ }
+
+ static void extension_object_deallocator ( PyObject* t )
+ {
+ delete (T *)( t );
+ }
+
+ //
+ // prevent the compiler generating these unwanted functions
+ //
+ explicit PythonExtension( const PythonExtension<T>& other );
+ void operator=( const PythonExtension<T>& rhs );
+ };
+
+ //
+ // ExtensionObject<T> is an Object that will accept only T's.
+ //
+ template<TEMPLATE_TYPENAME T>
+ class ExtensionObject: public Object
+ {
+ public:
+
+ explicit ExtensionObject ( PyObject *pyob )
+ : Object( pyob )
+ {
+ validate();
+ }
+
+ ExtensionObject( const ExtensionObject<T>& other )
+ : Object( *other )
+ {
+ validate();
+ }
+
+ ExtensionObject( const Object& other )
+ : Object( *other )
+ {
+ validate();
+ }
+
+ ExtensionObject& operator= ( const Object& rhs )
+ {
+ return (*this = *rhs );
+ }
+
+ ExtensionObject& operator= ( PyObject* rhsp )
+ {
+ if( ptr() == rhsp )
+ return *this;
+ set( rhsp );
+ return *this;
+ }
+
+ virtual bool accepts ( PyObject *pyob ) const
+ {
+ return ( pyob && T::check( pyob ));
+ }
+
+ //
+ // Obtain a pointer to the PythonExtension object
+ //
+ T *extensionObject(void)
+ {
+ return static_cast<T *>( ptr() );
+ }
+ };
+
+ } // Namespace Py
+// End of CXX_Extensions.h
+#endif
diff --git a/lib/kross/python/cxx/IndirectPythonInterface.cxx b/lib/kross/python/cxx/IndirectPythonInterface.cxx
new file mode 100644
index 00000000..caaa0913
--- /dev/null
+++ b/lib/kross/python/cxx/IndirectPythonInterface.cxx
@@ -0,0 +1,550 @@
+//
+// IndirectPythonInterface.cxx
+//
+#undef _XOPEN_SOURCE
+#include "IndirectPythonInterface.hxx"
+
+namespace Py
+{
+bool _Buffer_Check( PyObject *op ) { return (op)->ob_type == _Buffer_Type(); }
+bool _CFunction_Check( PyObject *op ) { return (op)->ob_type == _CFunction_Type(); }
+bool _Class_Check( PyObject *op ) { return (op)->ob_type == _Class_Type(); }
+bool _CObject_Check( PyObject *op ) { return (op)->ob_type == _CObject_Type(); }
+bool _Complex_Check( PyObject *op ) { return (op)->ob_type == _Complex_Type(); }
+bool _Dict_Check( PyObject *op ) { return (op)->ob_type == _Dict_Type(); }
+bool _File_Check( PyObject *op ) { return (op)->ob_type == _File_Type(); }
+bool _Float_Check( PyObject *op ) { return (op)->ob_type == _Float_Type(); }
+bool _Function_Check( PyObject *op ) { return (op)->ob_type == _Function_Type(); }
+bool _Instance_Check( PyObject *op ) { return (op)->ob_type == _Instance_Type(); }
+bool _Int_Check( PyObject *op ) { return (op)->ob_type == _Int_Type(); }
+bool _List_Check( PyObject *o ) { return o->ob_type == _List_Type(); }
+bool _Long_Check( PyObject *op ) { return (op)->ob_type == _Long_Type(); }
+bool _Method_Check( PyObject *op ) { return (op)->ob_type == _Method_Type(); }
+bool _Module_Check( PyObject *op ) { return (op)->ob_type == _Module_Type(); }
+bool _Range_Check( PyObject *op ) { return (op)->ob_type == _Range_Type(); }
+bool _Slice_Check( PyObject *op ) { return (op)->ob_type == _Slice_Type(); }
+bool _String_Check( PyObject *o ) { return o->ob_type == _String_Type(); }
+bool _TraceBack_Check( PyObject *v ) { return (v)->ob_type == _TraceBack_Type(); }
+bool _Tuple_Check( PyObject *op ) { return (op)->ob_type == _Tuple_Type(); }
+bool _Type_Check( PyObject *op ) { return (op)->ob_type == _Type_Type(); }
+
+#if PY_MAJOR_VERSION >= 2
+bool _Unicode_Check( PyObject *op ) { return (op)->ob_type == _Unicode_Type(); }
+#endif
+
+
+
+#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL)
+
+#if defined(MS_WINDOWS)
+#include <windows.h>
+
+
+static HMODULE python_dll;
+
+static PyObject *ptr__Exc_ArithmeticError = NULL;
+static PyObject *ptr__Exc_AssertionError = NULL;
+static PyObject *ptr__Exc_AttributeError = NULL;
+static PyObject *ptr__Exc_EnvironmentError = NULL;
+static PyObject *ptr__Exc_EOFError = NULL;
+static PyObject *ptr__Exc_Exception = NULL;
+static PyObject *ptr__Exc_FloatingPointError = NULL;
+static PyObject *ptr__Exc_ImportError = NULL;
+static PyObject *ptr__Exc_IndexError = NULL;
+static PyObject *ptr__Exc_IOError = NULL;
+static PyObject *ptr__Exc_KeyboardInterrupt = NULL;
+static PyObject *ptr__Exc_KeyError = NULL;
+static PyObject *ptr__Exc_LookupError = NULL;
+static PyObject *ptr__Exc_MemoryError = NULL;
+static PyObject *ptr__Exc_MemoryErrorInst = NULL;
+static PyObject *ptr__Exc_NameError = NULL;
+static PyObject *ptr__Exc_NotImplementedError = NULL;
+static PyObject *ptr__Exc_OSError = NULL;
+static PyObject *ptr__Exc_OverflowError = NULL;
+static PyObject *ptr__Exc_RuntimeError = NULL;
+static PyObject *ptr__Exc_StandardError = NULL;
+static PyObject *ptr__Exc_SyntaxError = NULL;
+static PyObject *ptr__Exc_SystemError = NULL;
+static PyObject *ptr__Exc_SystemExit = NULL;
+static PyObject *ptr__Exc_TypeError = NULL;
+static PyObject *ptr__Exc_ValueError = NULL;
+static PyObject *ptr__Exc_ZeroDivisionError = NULL;
+
+#ifdef MS_WINDOWS
+static PyObject *ptr__Exc_WindowsError = NULL;
+#endif
+
+#if PY_MAJOR_VERSION >= 2
+static PyObject *ptr__Exc_IndentationError = NULL;
+static PyObject *ptr__Exc_TabError = NULL;
+static PyObject *ptr__Exc_UnboundLocalError = NULL;
+static PyObject *ptr__Exc_UnicodeError = NULL;
+#endif
+
+static PyObject *ptr__PyNone = NULL;
+
+static PyTypeObject *ptr__Buffer_Type = NULL;
+static PyTypeObject *ptr__CFunction_Type = NULL;
+static PyTypeObject *ptr__Class_Type = NULL;
+static PyTypeObject *ptr__CObject_Type = NULL;
+static PyTypeObject *ptr__Complex_Type = NULL;
+static PyTypeObject *ptr__Dict_Type = NULL;
+static PyTypeObject *ptr__File_Type = NULL;
+static PyTypeObject *ptr__Float_Type = NULL;
+static PyTypeObject *ptr__Function_Type = NULL;
+static PyTypeObject *ptr__Instance_Type = NULL;
+static PyTypeObject *ptr__Int_Type = NULL;
+static PyTypeObject *ptr__List_Type = NULL;
+static PyTypeObject *ptr__Long_Type = NULL;
+static PyTypeObject *ptr__Method_Type = NULL;
+static PyTypeObject *ptr__Module_Type = NULL;
+static PyTypeObject *ptr__Range_Type = NULL;
+static PyTypeObject *ptr__Slice_Type = NULL;
+static PyTypeObject *ptr__String_Type = NULL;
+static PyTypeObject *ptr__TraceBack_Type = NULL;
+static PyTypeObject *ptr__Tuple_Type = NULL;
+static PyTypeObject *ptr__Type_Type = NULL;
+
+#if PY_MAJOR_VERSION >= 2
+static PyTypeObject *ptr__Unicode_Type = NULL;
+#endif
+
+static int *ptr_Py_DebugFlag = NULL;
+static int *ptr_Py_InteractiveFlag = NULL;
+static int *ptr_Py_OptimizeFlag = NULL;
+static int *ptr_Py_NoSiteFlag = NULL;
+static int *ptr_Py_TabcheckFlag = NULL;
+static int *ptr_Py_VerboseFlag = NULL;
+
+#if PY_MAJOR_VERSION >= 2
+static int *ptr_Py_UnicodeFlag = NULL;
+#endif
+
+static char **ptr__Py_PackageContext = NULL;
+
+#ifdef Py_REF_DEBUG
+int *ptr_Py_RefTotal;
+#endif
+
+
+//--------------------------------------------------------------------------------
+class GetAddressException
+ {
+public:
+ GetAddressException( const char *_name )
+ : name( _name )
+ {}
+ virtual ~GetAddressException() {}
+ const char *name;
+ };
+
+
+//--------------------------------------------------------------------------------
+static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name )
+ {
+ FARPROC addr = GetProcAddress( python_dll, name );
+ if( addr == NULL )
+ throw GetAddressException( name );
+
+ return *(PyObject **)addr;
+ }
+
+static PyObject *GetPyObject_As_PyObjectPointer( const char *name )
+ {
+ FARPROC addr = GetProcAddress( python_dll, name );
+ if( addr == NULL )
+ throw GetAddressException( name );
+
+ return (PyObject *)addr;
+ }
+
+static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name )
+ {
+ FARPROC addr = GetProcAddress( python_dll, name );
+ if( addr == NULL )
+ throw GetAddressException( name );
+
+ return *(PyTypeObject **)addr;
+ }
+
+static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name )
+ {
+ FARPROC addr = GetProcAddress( python_dll, name );
+ if( addr == NULL )
+ throw GetAddressException( name );
+
+ return (PyTypeObject *)addr;
+ }
+
+static int *GetInt_as_IntPointer( const char *name )
+ {
+ FARPROC addr = GetProcAddress( python_dll, name );
+ if( addr == NULL )
+ throw GetAddressException( name );
+
+ return (int *)addr;
+ }
+
+static char **GetCharPointer_as_CharPointerPointer( const char *name )
+ {
+ FARPROC addr = GetProcAddress( python_dll, name );
+ if( addr == NULL )
+ throw GetAddressException( name );
+
+ return (char **)addr;
+ }
+
+
+#ifdef _DEBUG
+static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL";
+#else
+static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL";
+#endif
+
+//--------------------------------------------------------------------------------
+bool InitialisePythonIndirectInterface()
+ {
+ char python_dll_name[sizeof(python_dll_name_format)];
+
+ sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION );
+
+ python_dll = LoadLibrary( python_dll_name );
+ if( python_dll == NULL )
+ return false;
+
+ try
+ {
+#ifdef Py_REF_DEBUG
+ ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" );
+#endif
+ ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" );
+ ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" );
+ ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" );
+ ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" );
+ ptr_Py_TabcheckFlag = GetInt_as_IntPointer( "Py_TabcheckFlag" );
+ ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" );
+#if PY_MAJOR_VERSION >= 2
+ ptr_Py_UnicodeFlag = GetInt_as_IntPointer( "Py_UnicodeFlag" );
+#endif
+ ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" );
+
+ ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" );
+ ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" );
+ ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" );
+ ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" );
+ ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" );
+ ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" );
+ ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" );
+ ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" );
+ ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" );
+ ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" );
+ ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" );
+ ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" );
+ ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" );
+ ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" );
+ ptr__Exc_MemoryErrorInst = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryErrorInst" );
+ ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" );
+ ptr__Exc_NotImplementedError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" );
+ ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" );
+ ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" );
+ ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" );
+ ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" );
+ ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" );
+ ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" );
+ ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" );
+ ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" );
+ ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" );
+#ifdef MS_WINDOWS
+ ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" );
+#endif
+ ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" );
+
+#if PY_MAJOR_VERSION >= 2
+ ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" );
+ ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" );
+ ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" );
+ ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" );
+#endif
+ ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" );
+
+ ptr__Buffer_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBuffer_Type" );
+ ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" );
+ ptr__Class_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyClass_Type" );
+ ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" );
+ ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" );
+ ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" );
+ ptr__File_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFile_Type" );
+ ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" );
+ ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" );
+ ptr__Instance_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInstance_Type" );
+ ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" );
+ ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" );
+ ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" );
+ ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" );
+ ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" );
+ ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" );
+ ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" );
+ ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" );
+ ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" );
+ ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" );
+ ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" );
+
+#if PY_MAJOR_VERSION >= 2
+ ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" );
+#endif
+ }
+ catch( GetAddressException &e )
+ {
+ OutputDebugString( python_dll_name );
+ OutputDebugString( " does not contain symbol ");
+ OutputDebugString( e.name );
+ OutputDebugString( "\n" );
+
+ return false;
+ }
+
+ return true;
+ }
+
+//
+// Wrap variables as function calls
+//
+PyObject * _Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; }
+PyObject * _Exc_AssertionError() { return ptr__Exc_AssertionError; }
+PyObject * _Exc_AttributeError() { return ptr__Exc_AttributeError; }
+PyObject * _Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; }
+PyObject * _Exc_EOFError() { return ptr__Exc_EOFError; }
+PyObject * _Exc_Exception() { return ptr__Exc_Exception; }
+PyObject * _Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; }
+PyObject * _Exc_ImportError() { return ptr__Exc_ImportError; }
+PyObject * _Exc_IndexError() { return ptr__Exc_IndexError; }
+PyObject * _Exc_IOError() { return ptr__Exc_IOError; }
+PyObject * _Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; }
+PyObject * _Exc_KeyError() { return ptr__Exc_KeyError; }
+PyObject * _Exc_LookupError() { return ptr__Exc_LookupError; }
+PyObject * _Exc_MemoryError() { return ptr__Exc_MemoryError; }
+PyObject * _Exc_MemoryErrorInst() { return ptr__Exc_MemoryErrorInst; }
+PyObject * _Exc_NameError() { return ptr__Exc_NameError; }
+PyObject * _Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; }
+PyObject * _Exc_OSError() { return ptr__Exc_OSError; }
+PyObject * _Exc_OverflowError() { return ptr__Exc_OverflowError; }
+PyObject * _Exc_RuntimeError() { return ptr__Exc_RuntimeError; }
+PyObject * _Exc_StandardError() { return ptr__Exc_StandardError; }
+PyObject * _Exc_SyntaxError() { return ptr__Exc_SyntaxError; }
+PyObject * _Exc_SystemError() { return ptr__Exc_SystemError; }
+PyObject * _Exc_SystemExit() { return ptr__Exc_SystemExit; }
+PyObject * _Exc_TypeError() { return ptr__Exc_TypeError; }
+PyObject * _Exc_ValueError() { return ptr__Exc_ValueError; }
+#ifdef MS_WINDOWS
+PyObject * _Exc_WindowsError() { return ptr__Exc_WindowsError; }
+#endif
+PyObject * _Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; }
+
+#if PY_MAJOR_VERSION >= 2
+PyObject * _Exc_IndentationError() { return ptr__Exc_IndentationError; }
+PyObject * _Exc_TabError() { return ptr__Exc_TabError; }
+PyObject * _Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; }
+PyObject * _Exc_UnicodeError() { return ptr__Exc_UnicodeError; }
+#endif
+
+//
+// wrap items in Object.h
+//
+PyObject * _None() { return ptr__PyNone; }
+
+
+PyTypeObject * _Buffer_Type() { return ptr__Buffer_Type; }
+PyTypeObject * _CFunction_Type() { return ptr__CFunction_Type; }
+PyTypeObject * _Class_Type() { return ptr__Class_Type; }
+PyTypeObject * _CObject_Type() { return ptr__CObject_Type; }
+PyTypeObject * _Complex_Type() { return ptr__Complex_Type; }
+PyTypeObject * _Dict_Type() { return ptr__Dict_Type; }
+PyTypeObject * _File_Type() { return ptr__File_Type; }
+PyTypeObject * _Float_Type() { return ptr__Float_Type; }
+PyTypeObject * _Function_Type() { return ptr__Function_Type; }
+PyTypeObject * _Instance_Type() { return ptr__Instance_Type; }
+PyTypeObject * _Int_Type() { return ptr__Int_Type; }
+PyTypeObject * _List_Type() { return ptr__List_Type; }
+PyTypeObject * _Long_Type() { return ptr__Long_Type; }
+PyTypeObject * _Method_Type() { return ptr__Method_Type; }
+PyTypeObject * _Module_Type() { return ptr__Module_Type; }
+PyTypeObject * _Range_Type() { return ptr__Range_Type; }
+PyTypeObject * _Slice_Type() { return ptr__Slice_Type; }
+PyTypeObject * _String_Type() { return ptr__String_Type; }
+PyTypeObject * _TraceBack_Type() { return ptr__TraceBack_Type; }
+PyTypeObject * _Tuple_Type() { return ptr__Tuple_Type; }
+PyTypeObject * _Type_Type() { return ptr__Type_Type; }
+
+#if PY_MAJOR_VERSION >= 2
+PyTypeObject * _Unicode_Type() { return ptr__Unicode_Type; }
+#endif
+
+char *__Py_PackageContext() { return *ptr__Py_PackageContext; }
+
+
+//
+// wrap the Python Flag variables
+//
+int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; }
+int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; }
+int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; }
+int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; }
+int &_Py_TabcheckFlag() { return *ptr_Py_TabcheckFlag; }
+int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; }
+#if PY_MAJOR_VERSION >= 2
+int &_Py_UnicodeFlag() { return *ptr_Py_UnicodeFlag; }
+#endif
+
+void _XINCREF( PyObject *op )
+ {
+ // This function must match the contents of Py_XINCREF(op)
+ if( op == NULL )
+ return;
+
+#ifdef Py_REF_DEBUG
+ (*ptr_Py_RefTotal)++;
+#endif
+ (op)->ob_refcnt++;
+
+ }
+
+void _XDECREF( PyObject *op )
+ {
+ // This function must match the contents of Py_XDECREF(op);
+ if( op == NULL )
+ return;
+
+#ifdef Py_REF_DEBUG
+ (*ptr_Py_RefTotal)--;
+#endif
+
+ if (--(op)->ob_refcnt == 0)
+ _Py_Dealloc((PyObject *)(op));
+ }
+
+
+#else
+#error "Can only delay load under Win32"
+#endif
+
+#else
+
+//
+// Duplicated these declarations from rangeobject.h which is missing the
+// extern "C". This has been reported as a bug upto and include 2.1
+//
+extern "C" DL_IMPORT(PyTypeObject) PyRange_Type;
+extern "C" DL_IMPORT(PyObject *) PyRange_New(long, long, long, int);
+
+
+//================================================================================
+//
+// Map onto Macros
+//
+//================================================================================
+
+//
+// Wrap variables as function calls
+//
+
+PyObject * _Exc_ArithmeticError() { return ::PyExc_ArithmeticError; }
+PyObject * _Exc_AssertionError() { return ::PyExc_AssertionError; }
+PyObject * _Exc_AttributeError() { return ::PyExc_AttributeError; }
+PyObject * _Exc_EnvironmentError() { return ::PyExc_EnvironmentError; }
+PyObject * _Exc_EOFError() { return ::PyExc_EOFError; }
+PyObject * _Exc_Exception() { return ::PyExc_Exception; }
+PyObject * _Exc_FloatingPointError() { return ::PyExc_FloatingPointError; }
+PyObject * _Exc_ImportError() { return ::PyExc_ImportError; }
+PyObject * _Exc_IndexError() { return ::PyExc_IndexError; }
+PyObject * _Exc_IOError() { return ::PyExc_IOError; }
+PyObject * _Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; }
+PyObject * _Exc_KeyError() { return ::PyExc_KeyError; }
+PyObject * _Exc_LookupError() { return ::PyExc_LookupError; }
+PyObject * _Exc_MemoryError() { return ::PyExc_MemoryError; }
+PyObject * _Exc_MemoryErrorInst() { return ::PyExc_MemoryErrorInst; }
+PyObject * _Exc_NameError() { return ::PyExc_NameError; }
+PyObject * _Exc_NotImplementedError() { return ::PyExc_NotImplementedError; }
+PyObject * _Exc_OSError() { return ::PyExc_OSError; }
+PyObject * _Exc_OverflowError() { return ::PyExc_OverflowError; }
+PyObject * _Exc_RuntimeError() { return ::PyExc_RuntimeError; }
+PyObject * _Exc_StandardError() { return ::PyExc_StandardError; }
+PyObject * _Exc_SyntaxError() { return ::PyExc_SyntaxError; }
+PyObject * _Exc_SystemError() { return ::PyExc_SystemError; }
+PyObject * _Exc_SystemExit() { return ::PyExc_SystemExit; }
+PyObject * _Exc_TypeError() { return ::PyExc_TypeError; }
+PyObject * _Exc_ValueError() { return ::PyExc_ValueError; }
+PyObject * _Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; }
+
+#ifdef MS_WINDOWS
+PyObject * _Exc_WindowsError() { return ::PyExc_WindowsError; }
+#endif
+
+
+#if PY_MAJOR_VERSION >= 2
+PyObject * _Exc_IndentationError() { return ::PyExc_IndentationError; }
+PyObject * _Exc_TabError() { return ::PyExc_TabError; }
+PyObject * _Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; }
+PyObject * _Exc_UnicodeError() { return ::PyExc_UnicodeError; }
+#endif
+
+
+//
+// wrap items in Object.h
+//
+PyObject * _None() { return &::_Py_NoneStruct; }
+
+PyTypeObject * _Buffer_Type() { return &PyBuffer_Type; }
+PyTypeObject * _CFunction_Type() { return &PyCFunction_Type; }
+PyTypeObject * _Class_Type() { return &PyClass_Type; }
+PyTypeObject * _CObject_Type() { return &PyCObject_Type; }
+PyTypeObject * _Complex_Type() { return &PyComplex_Type; }
+PyTypeObject * _Dict_Type() { return &PyDict_Type; }
+PyTypeObject * _File_Type() { return &PyFile_Type; }
+PyTypeObject * _Float_Type() { return &PyFloat_Type; }
+PyTypeObject * _Function_Type() { return &PyFunction_Type; }
+PyTypeObject * _Instance_Type() { return &PyInstance_Type; }
+PyTypeObject * _Int_Type() { return &PyInt_Type; }
+PyTypeObject * _List_Type() { return &PyList_Type; }
+PyTypeObject * _Long_Type() { return &PyLong_Type; }
+PyTypeObject * _Method_Type() { return &PyMethod_Type; }
+PyTypeObject * _Module_Type() { return &PyModule_Type; }
+PyTypeObject * _Range_Type() { return &PyRange_Type; }
+PyTypeObject * _Slice_Type() { return &PySlice_Type; }
+PyTypeObject * _String_Type() { return &PyString_Type; }
+PyTypeObject * _TraceBack_Type() { return &PyTraceBack_Type; }
+PyTypeObject * _Tuple_Type() { return &PyTuple_Type; }
+PyTypeObject * _Type_Type() { return &PyType_Type; }
+
+#if PY_MAJOR_VERSION >= 2
+PyTypeObject * _Unicode_Type() { return &PyUnicode_Type; }
+#endif
+
+//
+// wrap flags
+//
+int &_Py_DebugFlag() { return Py_DebugFlag; }
+int &_Py_InteractiveFlag() { return Py_InteractiveFlag; }
+int &_Py_OptimizeFlag() { return Py_OptimizeFlag; }
+int &_Py_NoSiteFlag() { return Py_NoSiteFlag; }
+int &_Py_TabcheckFlag() { return Py_TabcheckFlag; }
+int &_Py_VerboseFlag() { return Py_VerboseFlag; }
+#if PY_MAJOR_VERSION >= 2
+int &_Py_UnicodeFlag() { return Py_UnicodeFlag; }
+#endif
+char *__Py_PackageContext() { return _Py_PackageContext; }
+
+//
+// Needed to keep the abstactions for delayload interface
+//
+void _XINCREF( PyObject *op )
+ {
+ Py_XINCREF(op);
+ }
+
+void _XDECREF( PyObject *op )
+ {
+ Py_XDECREF(op);
+ }
+
+#endif
+}
diff --git a/lib/kross/python/cxx/IndirectPythonInterface.hxx b/lib/kross/python/cxx/IndirectPythonInterface.hxx
new file mode 100644
index 00000000..8f2d275d
--- /dev/null
+++ b/lib/kross/python/cxx/IndirectPythonInterface.hxx
@@ -0,0 +1,156 @@
+#ifndef __CXX_INDIRECT_PYTHON_INTERFACE__HXX__
+#define __CXX_INDIRECT_PYTHON_INTERFACE__HXX__
+
+#include <Python.h>
+
+namespace Py
+{
+bool InitialisePythonIndirectInterface();
+
+//
+// Wrap Exception variables as function calls
+//
+PyObject * _Exc_Exception();
+PyObject * _Exc_StandardError();
+PyObject * _Exc_ArithmeticError();
+PyObject * _Exc_LookupError();
+
+PyObject * _Exc_AssertionError();
+PyObject * _Exc_AttributeError();
+PyObject * _Exc_EOFError();
+PyObject * _Exc_FloatingPointError();
+PyObject * _Exc_EnvironmentError();
+PyObject * _Exc_IOError();
+PyObject * _Exc_OSError();
+PyObject * _Exc_ImportError();
+PyObject * _Exc_IndexError();
+PyObject * _Exc_KeyError();
+PyObject * _Exc_KeyboardInterrupt();
+PyObject * _Exc_MemoryError();
+PyObject * _Exc_NameError();
+PyObject * _Exc_OverflowError();
+PyObject * _Exc_RuntimeError();
+PyObject * _Exc_NotImplementedError();
+PyObject * _Exc_SyntaxError();
+PyObject * _Exc_SystemError();
+PyObject * _Exc_SystemExit();
+PyObject * _Exc_TypeError();
+PyObject * _Exc_ValueError();
+PyObject * _Exc_ZeroDivisionError();
+#ifdef MS_WINDOWS
+PyObject * _Exc_WindowsError();
+#endif
+
+PyObject * _Exc_MemoryErrorInst();
+
+#if PY_MAJOR_VERSION >= 2
+PyObject * _Exc_IndentationError();
+PyObject * _Exc_TabError();
+PyObject * _Exc_UnboundLocalError();
+PyObject * _Exc_UnicodeError();
+#endif
+
+//
+// Wrap Object variables as function calls
+//
+PyObject * _None();
+
+
+//
+// Wrap Type variables as function calls
+//
+PyTypeObject * _List_Type();
+bool _List_Check( PyObject *o );
+
+PyTypeObject * _Buffer_Type();
+bool _Buffer_Check( PyObject *op );
+
+PyTypeObject * _Class_Type();
+bool _Class_Check( PyObject *op );
+
+PyTypeObject * _Instance_Type();
+bool _Instance_Check( PyObject *op );
+
+PyTypeObject * _Method_Type();
+bool _Method_Check( PyObject *op );
+
+PyTypeObject * _CObject_Type();
+bool _CObject_Check( PyObject *op );
+
+PyTypeObject * _Complex_Type();
+bool _Complex_Check( PyObject *op );
+
+PyTypeObject * _Dict_Type();
+bool _Dict_Check( PyObject *op );
+
+PyTypeObject * _File_Type();
+bool _File_Check( PyObject *op );
+
+PyTypeObject * _Float_Type();
+bool _Float_Check( PyObject *op );
+
+PyTypeObject * _Frame_Type();
+bool _Frame_Check( PyObject *op );
+
+PyTypeObject * _Function_Type();
+bool _Function_Check( PyObject *op );
+
+PyTypeObject * _Int_Type();
+bool _Int_Check( PyObject *op );
+
+PyTypeObject * _List_Type();
+bool _List_Check( PyObject *op );
+
+PyTypeObject * _Long_Type();
+bool _Long_Check( PyObject *op );
+
+PyTypeObject * _CFunction_Type();
+bool _CFunction_Check( PyObject *op );
+
+PyTypeObject * _Module_Type();
+bool _Module_Check( PyObject *op );
+
+PyTypeObject * _Type_Type();
+bool _Type_Check( PyObject *op );
+
+PyTypeObject * _Range_Type();
+bool _Range_Check( PyObject *op );
+
+PyTypeObject * _Slice_Type();
+bool _Slice_Check( PyObject *op );
+
+PyTypeObject * _String_Type();
+bool _String_Check( PyObject *op );
+
+PyTypeObject * _Unicode_Type();
+bool _Unicode_Check( PyObject *op );
+
+PyTypeObject * _TraceBack_Type();
+bool _TraceBack_Check( PyObject *v );
+
+PyTypeObject * _Tuple_Type();
+bool _Tuple_Check( PyObject *op );
+
+#if PY_MAJOR_VERSION >= 2
+PyTypeObject * _Unicode_Type();
+bool _Unicode_Check( PyObject *op );
+#endif
+
+int &_Py_DebugFlag();
+int &_Py_InteractiveFlag();
+int &_Py_OptimizeFlag();
+int &_Py_NoSiteFlag();
+int &_Py_TabcheckFlag();
+int &_Py_VerboseFlag();
+
+#if PY_MAJOR_VERSION >= 2
+int &_Py_UnicodeFlag();
+#endif
+
+void _XINCREF( PyObject *op );
+void _XDECREF( PyObject *op );
+
+char *__Py_PackageContext();
+}
+
+#endif // __CXX_INDIRECT_PYTHON_INTERFACE__HXX__
diff --git a/lib/kross/python/cxx/Legal.html b/lib/kross/python/cxx/Legal.html
new file mode 100755
index 00000000..cf6a530f
--- /dev/null
+++ b/lib/kross/python/cxx/Legal.html
@@ -0,0 +1,40 @@
+<html>
+
+<head>
+<title>Legal Notice</title>
+<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
+</head>
+
+<body>
+
+<h1>Legal Notice</h1>
+
+<p>*** Legal Notice for all LLNL-contributed files *** </p>
+
+<p>Copyright (c) 1996. The Regents of the University of California. All rights reserved. </p>
+
+<p>Permission to use, copy, modify, and distribute this software for any purpose without
+fee is hereby granted, provided that this entire notice is included in all copies of any
+software which is or includes a copy or modification of this software and in all copies of
+the supporting documentation for such software. </p>
+
+<p>This work was produced at the University of California, Lawrence Livermore National
+Laboratory under contract no. W-7405-ENG-48 between the U.S. Department of Energy and The
+Regents of the University of California for the operation of UC LLNL. </p>
+
+<h2>DISCLAIMER </h2>
+
+<p>This software was prepared as an account of work sponsored by an agency of the United
+States Government. Neither the United States Government nor the University of California
+nor any of their employees, makes any warranty, express or implied, or assumes any
+liability or responsibility for the accuracy, completeness, or usefulness of any
+information, apparatus, product, or process disclosed, or represents that its use would
+not infringe privately-owned rights. Reference herein to any specific commercial products,
+process, or service by trade name, trademark, manufacturer, or otherwise, does not
+necessarily constitute or imply its endorsement, recommendation, or favoring by the United
+States Government or the University of California. The views and opinions of authors
+expressed herein do not necessarily state or reflect those of the United States Government
+or the University of California, and shall not be used for advertising or product
+endorsement purposes.</p>
+</body>
+</html>
diff --git a/lib/kross/python/cxx/Makefile.am b/lib/kross/python/cxx/Makefile.am
new file mode 100644
index 00000000..d1c72c87
--- /dev/null
+++ b/lib/kross/python/cxx/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/lib/kross/Makefile.global
+
+noinst_LTLIBRARIES = libkrosspythoncxx.la
+
+libkrosspythoncxx_la_SOURCES = \
+ cxxsupport.cxx \
+ cxx_extensions.cxx \
+ cxxextensions.c \
+ IndirectPythonInterface.cxx
+
+libkrosspythoncxx_la_LDFLAGS = $(LIBPYTHON) $(all_libraries) -Wnounresolved
+
+METASOURCES = AUTO
+INCLUDES = $(KROSS_INCLUDES) $(PYTHONINC) $(all_includes)
+SUBDIRS = .
+
+clean:
+ @rm -f *.o 2> /dev/null
+ @rm -f $(BIN) 2> /dev/null
diff --git a/lib/kross/python/cxx/Objects.hxx b/lib/kross/python/cxx/Objects.hxx
new file mode 100644
index 00000000..41648320
--- /dev/null
+++ b/lib/kross/python/cxx/Objects.hxx
@@ -0,0 +1,2804 @@
+//----------------------------------*-C++-*----------------------------------//
+// Copyright 1998 The Regents of the University of California.
+// All rights reserved. See LEGAL.LLNL for full text and disclaimer.
+//---------------------------------------------------------------------------//
+
+#ifndef __CXX_Objects__h
+#define __CXX_Objects__h
+
+// Prevent warnings
+#if defined(_XOPEN_SOURCE)
+#undef _XOPEN_SOURCE
+#endif
+
+#include "Python.h"
+#include "Config.hxx"
+#include "Exception.hxx"
+
+
+#include <iostream>
+#include STR_STREAM
+#include <string>
+#include <iterator>
+#include <utility>
+#include <typeinfo>
+
+namespace Py
+ {
+ typedef int sequence_index_type; // type of an index into a sequence
+
+ // Forward declarations
+ class Object;
+ class Type;
+ template<TEMPLATE_TYPENAME T> class SeqBase;
+ class String;
+ class List;
+ template<TEMPLATE_TYPENAME T> class MapBase;
+
+ // new_reference_to also overloaded below on Object
+ inline PyObject* new_reference_to(PyObject* p)
+ {
+ Py::_XINCREF(p);
+ return p;
+ }
+
+ // returning Null() from an extension method triggers a
+ // Python exception
+ inline PyObject* Null()
+ {
+ return (static_cast<PyObject*>(0));
+ }
+
+ //===========================================================================//
+ // class Object
+ // The purpose of this class is to serve as the most general kind of
+ // Python object, for the purpose of writing C++ extensions in Python
+ // Objects hold a PyObject* which they own. This pointer is always a
+ // valid pointer to a Python object. In children we must maintain this behavior.
+ //
+ // Instructions on how to make your own class MyType descended from Object:
+ // (0) Pick a base class, either Object or perhaps SeqBase<T> or MapBase<T>.
+ // This example assumes Object.
+
+ // (1) Write a routine int MyType_Check (PyObject *) modeled after PyInt_Check,
+ // PyFloat_Check, etc.
+
+ // (2) Add method accepts:
+ // virtual bool accepts (PyObject *pyob) const {
+ // return pyob && MyType_Check (pyob);
+ // }
+
+ // (3) Include the following constructor and copy constructor
+ //
+ /*
+ explicit MyType (PyObject *pyob): Object(pyob) {
+ validate();
+ }
+
+ MyType(const Object& other): Object(other.ptr()) {
+ validate();
+ }
+ */
+
+ // Alernate version for the constructor to allow for construction from owned pointers:
+ /*
+ explicit MyType (PyObject *pyob): Object(pyob) {
+ validate();
+ }
+ */
+
+ // You may wish to add other constructors; see the classes below for examples.
+ // Each constructor must use "set" to set the pointer
+ // and end by validating the pointer you have created.
+
+ // (4) Each class needs at least these two assignment operators:
+ /*
+ MyType& operator= (const Object& rhs) {
+ return (*this = *rhs);
+ }
+
+ Mytype& operator= (PyObject* rhsp) {
+ if(ptr() == rhsp) return *this;
+ set(rhsp);
+ return *this;
+ }
+ */
+ // Note on accepts: constructors call the base class
+ // version of a virtual when calling the base class constructor,
+ // so the test has to be done explicitly in a descendent.
+
+ // If you are inheriting from PythonExtension<T> to define an object
+ // note that it contains PythonExtension<T>::check
+ // which you can use in accepts when writing a wrapper class.
+ // See Demo/range.h and Demo/range.cxx for an example.
+
+ class Object
+ {
+ private:
+ // the pointer to the Python object
+ // Only Object sets this directly.
+ // The default constructor for Object sets it to Py_None and
+ // child classes must use "set" to set it
+ //
+ PyObject* p;
+
+ protected:
+
+ void set (PyObject* pyob, bool owned = false)
+ {
+ release();
+ p = pyob;
+ if (!owned)
+ {
+ Py::_XINCREF (p);
+ }
+ validate();
+ }
+
+ void release ()
+ {
+ Py::_XDECREF (p);
+ p = 0;
+ }
+
+ void validate()
+ {
+ // release pointer if not the right type
+ if (! accepts (p))
+ {
+ release ();
+ if(PyErr_Occurred())
+ { // Error message already set
+ throw Exception();
+ }
+ // Better error message if RTTI available
+#if defined( _CPPRTTI )
+ std::string s("Error creating object of type ");
+ s += (typeid (*this)).name();
+ throw TypeError (s);
+#else
+ throw TypeError ("CXX: type error.");
+#endif
+ }
+ }
+
+ public:
+ // Constructor acquires new ownership of pointer unless explicitly told not to.
+ explicit Object (PyObject* pyob=Py::_None(), bool owned = false): p (pyob)
+ {
+ if(!owned)
+ {
+ Py::_XINCREF (p);
+ }
+ validate();
+ }
+
+ // Copy constructor acquires new ownership of pointer
+ Object (const Object& ob): p(ob.p)
+ {
+ Py::_XINCREF (p);
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+ Object& operator= (const Object& rhs)
+ {
+ set(rhs.p);
+ return *this;
+ }
+
+ Object& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+
+ // Destructor
+ virtual ~Object ()
+ {
+ release ();
+ }
+
+ // Loaning the pointer to others, retain ownership
+ PyObject* operator* () const
+ {
+ return p;
+ }
+
+ // Explicit reference_counting changes
+ void increment_reference_count()
+ {
+ Py::_XINCREF(p);
+ }
+
+ void decrement_reference_count()
+ {
+ // not allowed to commit suicide, however
+ if(reference_count() == 1)
+ throw RuntimeError("Object::decrement_reference_count error.");
+ Py::_XDECREF(p);
+ }
+ // Would like to call this pointer() but messes up STL in SeqBase<T>
+ PyObject* ptr () const
+ {
+ return p;
+ }
+
+ //
+ // Queries
+ //
+
+ // Can pyob be used in this object's constructor?
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return (pyob != 0);
+ }
+
+ int reference_count () const
+ { // the reference count
+ return p ? p->ob_refcnt : 0;
+ }
+
+ Type type () const; // the type object associated with this one
+
+ String str () const; // the str() representation
+
+ std::string as_string() const;
+
+ String repr () const; // the repr () representation
+
+ List dir () const; // the dir() list
+
+ bool hasAttr (const std::string& s) const
+ {
+ return PyObject_HasAttrString (p, const_cast<char*>(s.c_str())) ? true: false;
+ }
+
+ Object getAttr (const std::string& s) const
+ {
+ return Object (PyObject_GetAttrString (p, const_cast<char*>(s.c_str())), true);
+ }
+
+ Object getItem (const Object& key) const
+ {
+ return Object (PyObject_GetItem(p, *key), true);
+ }
+
+ long hashValue () const
+ {
+ return PyObject_Hash (p);
+ }
+
+ //
+ // int print (FILE* fp, int flags=Py_Print_RAW)
+ // {
+ // return PyObject_Print (p, fp, flags);
+ // }
+ //
+ bool is(PyObject *pother) const
+ { // identity test
+ return p == pother;
+ }
+
+ bool is(const Object& other) const
+ { // identity test
+ return p == other.p;
+ }
+
+ bool isCallable () const
+ {
+ return PyCallable_Check (p) != 0;
+ }
+
+ bool isInstance () const
+ {
+ return PyInstance_Check (p) != 0;
+ }
+
+ bool isDict () const
+ {
+ return Py::_Dict_Check (p);
+ }
+
+ bool isList () const
+ {
+ return Py::_List_Check (p);
+ }
+
+ bool isMapping () const
+ {
+ return PyMapping_Check (p) != 0;
+ }
+
+ bool isNumeric () const
+ {
+ return PyNumber_Check (p) != 0;
+ }
+
+ bool isSequence () const
+ {
+ return PySequence_Check (p) != 0;
+ }
+
+ bool isTrue () const
+ {
+ return PyObject_IsTrue (p) != 0;
+ }
+
+ bool isType (const Type& t) const;
+
+ bool isTuple() const
+ {
+ return Py::_Tuple_Check(p);
+ }
+
+ bool isString() const
+ {
+ return Py::_String_Check(p) || Py::_Unicode_Check(p);
+ }
+
+ bool isUnicode() const
+ {
+ return Py::_Unicode_Check(p);
+ }
+
+ // Commands
+ void setAttr (const std::string& s, const Object& value)
+ {
+ if(PyObject_SetAttrString (p, const_cast<char*>(s.c_str()), *value) == -1)
+ throw AttributeError ("getAttr failed.");
+ }
+
+ void delAttr (const std::string& s)
+ {
+ if(PyObject_DelAttrString (p, const_cast<char*>(s.c_str())) == -1)
+ throw AttributeError ("delAttr failed.");
+ }
+
+ // PyObject_SetItem is too weird to be using from C++
+ // so it is intentionally omitted.
+
+ void delItem (const Object& /*key*/)
+ {
+ //if(PyObject_DelItem(p, *key) == -1)
+ // failed to link on Windows?
+ throw KeyError("delItem failed.");
+ }
+ // Equality and comparison use PyObject_Compare
+
+ bool operator==(const Object& o2) const
+ {
+ int k = PyObject_Compare (p, *o2);
+ if (PyErr_Occurred()) throw Exception();
+ return k == 0;
+ }
+
+ bool operator!=(const Object& o2) const
+ {
+ int k = PyObject_Compare (p, *o2);
+ if (PyErr_Occurred()) throw Exception();
+ return k != 0;
+
+ }
+
+ bool operator>=(const Object& o2) const
+ {
+ int k = PyObject_Compare (p, *o2);
+ if (PyErr_Occurred()) throw Exception();
+ return k >= 0;
+ }
+
+ bool operator<=(const Object& o2) const
+ {
+ int k = PyObject_Compare (p, *o2);
+ if (PyErr_Occurred()) throw Exception();
+ return k <= 0;
+ }
+
+ bool operator<(const Object& o2) const
+ {
+ int k = PyObject_Compare (p, *o2);
+ if (PyErr_Occurred()) throw Exception();
+ return k < 0;
+ }
+
+ bool operator>(const Object& o2) const
+ {
+ int k = PyObject_Compare (p, *o2);
+ if (PyErr_Occurred()) throw Exception();
+ return k > 0;
+ }
+ };
+ // End of class Object
+ inline PyObject* new_reference_to(const Object& g)
+ {
+ PyObject* p = g.ptr();
+ Py::_XINCREF(p);
+ return p;
+ }
+
+ // Nothing() is what an extension method returns if
+ // there is no other return value.
+ inline Object Nothing()
+ {
+ return Object(Py::_None());
+ }
+
+ // Python special None value
+ inline Object None()
+ {
+ return Object(Py::_None());
+ }
+
+ // TMM: 31May'01 - Added the #ifndef so I can exlude iostreams.
+#ifndef CXX_NO_IOSTREAMS
+ std::ostream& operator<< (std::ostream& os, const Object& ob);
+#endif
+
+ // Class Type
+ class Type: public Object
+ {
+ public:
+ explicit Type (PyObject* pyob, bool owned = false): Object(pyob, owned)
+ {
+ validate();
+ }
+
+ Type (const Object& ob): Object(*ob)
+ {
+ validate();
+ }
+
+ Type(const Type& t): Object(t)
+ {
+ validate();
+ }
+
+ Type& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Type& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Type_Check (pyob);
+ }
+ };
+
+
+ //
+ // Convert an owned Python pointer into a CXX Object
+ //
+ inline Object asObject (PyObject *p)
+ {
+ return Object(p, true);
+ }
+
+
+
+
+ // ===============================================
+ // class Int
+ class Int: public Object
+ {
+ public:
+ // Constructor
+ explicit Int (PyObject *pyob, bool owned = false): Object (pyob, owned)
+ {
+ validate();
+ }
+
+ Int (const Int& ob): Object(*ob)
+ {
+ validate();
+ }
+
+ // create from long
+ explicit Int (long v = 0L): Object(PyInt_FromLong(v), true)
+ {
+ validate();
+ }
+
+ // create from int
+ explicit Int (int v)
+ {
+ long w = v;
+ set(PyInt_FromLong(w), true);
+ validate();
+ }
+
+ Int (const Object& ob)
+ {
+ set(PyNumber_Int(*ob), true);
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+
+ Int& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Int& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (PyNumber_Int(rhsp), true);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Int_Check (pyob);
+ }
+ // convert to long
+ operator long() const
+ {
+ return PyInt_AsLong (ptr());
+ }
+ // assign from an int
+ Int& operator= (int v)
+ {
+ set (PyInt_FromLong (long(v)), true);
+ return *this;
+ }
+ // assign from long
+ Int& operator= (long v)
+ {
+ set (PyInt_FromLong (v), true);
+ return *this;
+ }
+ };
+
+ // ===============================================
+ // class Long
+ class Long: public Object
+ {
+ public:
+ // Constructor
+ explicit Long (PyObject *pyob, bool owned = false): Object (pyob, owned)
+ {
+ validate();
+ }
+
+ Long (const Long& ob): Object(ob.ptr())
+ {
+ validate();
+ }
+
+ // create from long
+ explicit Long (long v = 0L)
+ : Object(PyLong_FromLong(v), true)
+ {
+ validate();
+ }
+ // create from int
+ explicit Long (int v)
+ : Object(PyLong_FromLong(static_cast<long>(v)), true)
+ {
+ validate();
+ }
+
+ // create from unsigned long
+ explicit Long (unsigned long v)
+ : Object(PyLong_FromUnsignedLong(v), true)
+ {
+ validate();
+ }
+
+ // try to create from any object
+ Long (const Object& ob)
+ : Object(PyNumber_Long(*ob), true)
+ {
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+
+ Long& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Long& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (PyNumber_Long(rhsp), true);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Long_Check (pyob);
+ }
+ // convert to long
+ operator long() const
+ {
+ return PyLong_AsLong (ptr());
+ }
+ operator double() const
+ {
+ return PyLong_AsDouble (ptr());
+ }
+ operator unsigned long() const
+ {
+ return PyLong_AsUnsignedLong (ptr());
+ }
+ // assign from an int
+ Long& operator= (int v)
+ {
+ set(PyLong_FromLong (long(v)), true);
+ return *this;
+ }
+ // assign from long
+ Long& operator= (long v)
+ {
+ set(PyLong_FromLong (v), true);
+ return *this;
+ }
+ // assign from unsigned long
+ Long& operator= (unsigned long v)
+ {
+ set(PyLong_FromUnsignedLong (v), true);
+ return *this;
+ }
+ };
+
+ // ===============================================
+ // class Float
+ //
+ class Float: public Object
+ {
+ public:
+ // Constructor
+ explicit Float (PyObject *pyob, bool owned = false): Object(pyob, owned)
+ {
+ validate();
+ }
+
+ Float (const Float& f): Object(f)
+ {
+ validate();
+ }
+
+ // make from double
+ explicit Float (double v=0.0)
+ : Object(PyFloat_FromDouble (v), true)
+ {
+ validate();
+ }
+
+ // try to make from any object
+ Float (const Object& ob)
+ : Object(PyNumber_Float(*ob), true)
+ {
+ validate();
+ }
+
+ Float& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Float& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (PyNumber_Float(rhsp), true);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Float_Check (pyob);
+ }
+ // convert to double
+ operator double () const
+ {
+ return PyFloat_AsDouble (ptr());
+ }
+ // assign from a double
+ Float& operator= (double v)
+ {
+ set(PyFloat_FromDouble (v), true);
+ return *this;
+ }
+ // assign from an int
+ Float& operator= (int v)
+ {
+ set(PyFloat_FromDouble (double(v)), true);
+ return *this;
+ }
+ // assign from long
+ Float& operator= (long v)
+ {
+ set(PyFloat_FromDouble (double(v)), true);
+ return *this;
+ }
+ // assign from an Int
+ Float& operator= (const Int& iob)
+ {
+ set(PyFloat_FromDouble (double(long(iob))), true);
+ return *this;
+ }
+ };
+
+ // ===============================================
+ // class Complex
+ class Complex: public Object
+ {
+ public:
+ // Constructor
+ explicit Complex (PyObject *pyob, bool owned = false): Object(pyob, owned)
+ {
+ validate();
+ }
+
+ Complex (const Complex& f): Object(f)
+ {
+ validate();
+ }
+
+ // make from double
+ explicit Complex (double v=0.0, double w=0.0)
+ :Object(PyComplex_FromDoubles (v, w), true)
+ {
+ validate();
+ }
+
+ Complex& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Complex& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Complex_Check (pyob);
+ }
+ // convert to Py_complex
+ operator Py_complex () const
+ {
+ return PyComplex_AsCComplex (ptr());
+ }
+ // assign from a Py_complex
+ Complex& operator= (const Py_complex& v)
+ {
+ set(PyComplex_FromCComplex (v), true);
+ return *this;
+ }
+ // assign from a double
+ Complex& operator= (double v)
+ {
+ set(PyComplex_FromDoubles (v, 0.0), true);
+ return *this;
+ }
+ // assign from an int
+ Complex& operator= (int v)
+ {
+ set(PyComplex_FromDoubles (double(v), 0.0), true);
+ return *this;
+ }
+ // assign from long
+ Complex& operator= (long v)
+ {
+ set(PyComplex_FromDoubles (double(v), 0.0), true);
+ return *this;
+ }
+ // assign from an Int
+ Complex& operator= (const Int& iob)
+ {
+ set(PyComplex_FromDoubles (double(long(iob)), 0.0), true);
+ return *this;
+ }
+
+ double real() const
+ {
+ return PyComplex_RealAsDouble(ptr());
+ }
+
+ double imag() const
+ {
+ return PyComplex_ImagAsDouble(ptr());
+ }
+ };
+ // Sequences
+ // Sequences are here represented as sequences of items of type T.
+ // The base class SeqBase<T> represents that.
+ // In basic Python T is always "Object".
+
+ // seqref<T> is what you get if you get elements from a non-const SeqBase<T>.
+ // Note: seqref<T> could probably be a nested class in SeqBase<T> but that might stress
+ // some compilers needlessly. Simlarly for mapref later.
+
+ // While this class is not intended for enduser use, it needs some public
+ // constructors for the benefit of the STL.
+
+ // See Scott Meyer's More Essential C++ for a description of proxies.
+ // This application is even more complicated. We are doing an unusual thing
+ // in having a double proxy. If we want the STL to work
+ // properly we have to compromise by storing the rvalue inside. The
+ // entire Object API is repeated so that things like s[i].isList() will
+ // work properly.
+
+ // Still, once in a while a weird compiler message may occur using expressions like x[i]
+ // Changing them to Object(x[i]) helps the compiler to understand that the
+ // conversion of a seqref to an Object is wanted.
+
+ template<TEMPLATE_TYPENAME T>
+ class seqref
+ {
+ protected:
+ SeqBase<T>& s; // the sequence
+ int offset; // item number
+ T the_item; // lvalue
+ public:
+
+ seqref (SeqBase<T>& seq, sequence_index_type j)
+ : s(seq), offset(j), the_item (s.getItem(j))
+ {}
+
+ seqref (const seqref<T>& range)
+ : s(range.s), offset(range.offset), the_item(range.the_item)
+ {}
+
+ // TMM: added this seqref ctor for use with STL algorithms
+ seqref (Object& obj)
+ : s(dynamic_cast< SeqBase<T>&>(obj))
+ , offset( NULL )
+ , the_item(s.getItem(offset))
+ {}
+ ~seqref()
+ {}
+
+ operator T() const
+ { // rvalue
+ return the_item;
+ }
+
+ seqref<T>& operator=(const seqref<T>& rhs)
+ { //used as lvalue
+ the_item = rhs.the_item;
+ s.setItem(offset, the_item);
+ return *this;
+ }
+
+ seqref<T>& operator=(const T& ob)
+ { // used as lvalue
+ the_item = ob;
+ s.setItem(offset, ob);
+ return *this;
+ }
+
+ // forward everything else to the item
+ PyObject* ptr () const
+ {
+ return the_item.ptr();
+ }
+
+ int reference_count () const
+ { // the reference count
+ return the_item.reference_count();
+ }
+
+ Type type () const
+ {
+ return the_item.type();
+ }
+
+ String str () const;
+
+ String repr () const;
+
+ bool hasAttr (const std::string& attr_name) const
+ {
+ return the_item.hasAttr(attr_name);
+ }
+
+ Object getAttr (const std::string& attr_name) const
+ {
+ return the_item.getAttr(attr_name);
+ }
+
+ Object getItem (const Object& key) const
+ {
+ return the_item.getItem(key);
+ }
+
+ long hashValue () const
+ {
+ return the_item.hashValue();
+ }
+
+ bool isCallable () const
+ {
+ return the_item.isCallable();
+ }
+
+ bool isInstance () const
+ {
+ return the_item.isInstance();
+ }
+
+ bool isDict () const
+ {
+ return the_item.isDict();
+ }
+
+ bool isList () const
+ {
+ return the_item.isList();
+ }
+
+ bool isMapping () const
+ {
+ return the_item.isMapping();
+ }
+
+ bool isNumeric () const
+ {
+ return the_item.isNumeric();
+ }
+
+ bool isSequence () const
+ {
+ return the_item.isSequence();
+ }
+
+ bool isTrue () const
+ {
+ return the_item.isTrue();
+ }
+
+ bool isType (const Type& t) const
+ {
+ return the_item.isType (t);
+ }
+
+ bool isTuple() const
+ {
+ return the_item.isTuple();
+ }
+
+ bool isString() const
+ {
+ return the_item.isString();
+ }
+ // Commands
+ void setAttr (const std::string& attr_name, const Object& value)
+ {
+ the_item.setAttr(attr_name, value);
+ }
+
+ void delAttr (const std::string& attr_name)
+ {
+ the_item.delAttr(attr_name);
+ }
+
+ void delItem (const Object& key)
+ {
+ the_item.delItem(key);
+ }
+
+ bool operator==(const Object& o2) const
+ {
+ return the_item == o2;
+ }
+
+ bool operator!=(const Object& o2) const
+ {
+ return the_item != o2;
+ }
+
+ bool operator>=(const Object& o2) const
+ {
+ return the_item >= o2;
+ }
+
+ bool operator<=(const Object& o2) const
+ {
+ return the_item <= o2;
+ }
+
+ bool operator<(const Object& o2) const
+ {
+ return the_item < o2;
+ }
+
+ bool operator>(const Object& o2) const
+ {
+ return the_item > o2;
+ }
+ }; // end of seqref
+
+
+ // class SeqBase<T>
+ // ...the base class for all sequence types
+
+ template<TEMPLATE_TYPENAME T>
+ class SeqBase: public Object
+ {
+ public:
+ // STL definitions
+ typedef size_t size_type;
+ typedef seqref<T> reference;
+ typedef T const_reference;
+ typedef seqref<T>* pointer;
+ typedef int difference_type;
+ typedef T value_type; // TMM: 26Jun'01
+
+ virtual size_type max_size() const
+ {
+ return std::string::npos; // ?
+ }
+
+ virtual size_type capacity() const
+ {
+ return size();
+ }
+
+ virtual void swap(SeqBase<T>& c)
+ {
+ SeqBase<T> temp = c;
+ c = ptr();
+ set(temp.ptr());
+ }
+
+ virtual size_type size () const
+ {
+ return PySequence_Length (ptr());
+ }
+
+ explicit SeqBase<T> ()
+ :Object(PyTuple_New(0), true)
+ {
+ validate();
+ }
+
+ explicit SeqBase<T> (PyObject* pyob, bool owned=false)
+ : Object(pyob, owned)
+ {
+ validate();
+ }
+
+ SeqBase<T> (const Object& ob): Object(ob)
+ {
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+
+ SeqBase<T>& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ SeqBase<T>& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && PySequence_Check (pyob);
+ }
+
+ size_type length () const
+ {
+ return PySequence_Length (ptr());
+ }
+
+ // Element access
+ const T operator[](sequence_index_type index) const
+ {
+ return getItem(index);
+ }
+
+ seqref<T> operator[](sequence_index_type index)
+ {
+ return seqref<T>(*this, index);
+ }
+
+ virtual T getItem (sequence_index_type i) const
+ {
+ return T(asObject(PySequence_GetItem (ptr(), i)));
+ }
+
+ virtual void setItem (sequence_index_type i, const T& ob)
+ {
+ if (PySequence_SetItem (ptr(), i, *ob) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ SeqBase<T> repeat (int count) const
+ {
+ return SeqBase<T> (PySequence_Repeat (ptr(), count), true);
+ }
+
+ SeqBase<T> concat (const SeqBase<T>& other) const
+ {
+ return SeqBase<T> (PySequence_Concat(ptr(), *other), true);
+ }
+
+ // more STL compatability
+ const T front () const
+ {
+ return getItem(0);
+ }
+
+ seqref<T> front()
+ {
+ return seqref<T>(this, 0);
+ }
+
+ const T back () const
+ {
+ return getItem(size()-1);
+ }
+
+ seqref<T> back()
+ {
+ return seqref<T>(this, size()-1);
+ }
+
+ void verify_length(size_type required_size) const
+ {
+ if (size() != required_size)
+ throw IndexError ("Unexpected SeqBase<T> length.");
+ }
+
+ void verify_length(size_type min_size, size_type max_size) const
+ {
+ size_type n = size();
+ if (n < min_size || n > max_size)
+ throw IndexError ("Unexpected SeqBase<T> length.");
+ }
+
+ class iterator
+ : public random_access_iterator_parent(seqref<T>)
+ {
+ protected:
+ friend class SeqBase<T>;
+ SeqBase<T>* seq;
+ int count;
+
+ public:
+ ~iterator ()
+ {}
+
+ iterator ()
+ : seq( 0 )
+ , count( 0 )
+ {}
+
+ iterator (SeqBase<T>* s, int where)
+ : seq( s )
+ , count( where )
+ {}
+
+ iterator (const iterator& other)
+ : seq( other.seq )
+ , count( other.count )
+ {}
+
+ bool eql (const iterator& other) const
+ {
+ return (*seq == *other.seq) && (count == other.count);
+ }
+
+ bool neq (const iterator& other) const
+ {
+ return (*seq != *other.seq) || (count != other.count);
+ }
+
+ bool lss (const iterator& other) const
+ {
+ return (count < other.count);
+ }
+
+ bool gtr (const iterator& other) const
+ {
+ return (count > other.count);
+ }
+
+ bool leq (const iterator& other) const
+ {
+ return (count <= other.count);
+ }
+
+ bool geq (const iterator& other) const
+ {
+ return (count >= other.count);
+ }
+
+ seqref<T> operator*()
+ {
+ return seqref<T>(*seq, count);
+ }
+
+ seqref<T> operator[] (sequence_index_type i)
+ {
+ return seqref<T>(*seq, count + i);
+ }
+
+ iterator& operator=(const iterator& other)
+ {
+ if (this == &other) return *this;
+ seq = other.seq;
+ count = other.count;
+ return *this;
+ }
+
+ iterator operator+(int n) const
+ {
+ return iterator(seq, count + n);
+ }
+
+ iterator operator-(int n) const
+ {
+ return iterator(seq, count - n);
+ }
+
+ iterator& operator+=(int n)
+ {
+ count = count + n;
+ return *this;
+ }
+
+ iterator& operator-=(int n)
+ {
+ count = count - n;
+ return *this;
+ }
+
+ int operator-(const iterator& other) const
+ {
+ if (*seq != *other.seq)
+ throw RuntimeError ("SeqBase<T>::iterator comparison error");
+ return count - other.count;
+ }
+
+ // prefix ++
+ iterator& operator++ ()
+ { count++; return *this;}
+ // postfix ++
+ iterator operator++ (int)
+ { return iterator(seq, count++);}
+ // prefix --
+ iterator& operator-- ()
+ { count--; return *this;}
+ // postfix --
+ iterator operator-- (int)
+ { return iterator(seq, count--);}
+
+ std::string diagnose() const
+ {
+ std::OSTRSTREAM oss;
+ oss << "iterator diagnosis " << seq << ", " << count << std::ends;
+ return std::string(oss.str());
+ }
+ }; // end of class SeqBase<T>::iterator
+
+ iterator begin ()
+ {
+ return iterator(this, 0);
+ }
+
+ iterator end ()
+ {
+ return iterator(this, length());
+ }
+
+ class const_iterator
+ : public random_access_iterator_parent(const Object)
+ {
+ protected:
+ friend class SeqBase<T>;
+ const SeqBase<T>* seq;
+ sequence_index_type count;
+
+ public:
+ ~const_iterator ()
+ {}
+
+ const_iterator ()
+ : seq( 0 )
+ , count( 0 )
+ {}
+
+ const_iterator (const SeqBase<T>* s, int where)
+ : seq( s )
+ , count( where )
+ {}
+
+ const_iterator(const const_iterator& other)
+ : seq( other.seq )
+ , count( other.count )
+ {}
+
+ const T operator*() const
+ {
+ return seq->getItem(count);
+ }
+
+ const T operator[] (sequence_index_type i) const
+ {
+ return seq->getItem(count + i);
+ }
+
+ const_iterator& operator=(const const_iterator& other)
+ {
+ if (this == &other) return *this;
+ seq = other.seq;
+ count = other.count;
+ return *this;
+ }
+
+ const_iterator operator+(int n) const
+ {
+ return const_iterator(seq, count + n);
+ }
+
+ bool eql (const const_iterator& other) const
+ {
+ return (*seq == *other.seq) && (count == other.count);
+ }
+
+ bool neq (const const_iterator& other) const
+ {
+ return (*seq != *other.seq) || (count != other.count);
+ }
+
+ bool lss (const const_iterator& other) const
+ {
+ return (count < other.count);
+ }
+
+ bool gtr (const const_iterator& other) const
+ {
+ return (count > other.count);
+ }
+
+ bool leq (const const_iterator& other) const
+ {
+ return (count <= other.count);
+ }
+
+ bool geq (const const_iterator& other) const
+ {
+ return (count >= other.count);
+ }
+
+ const_iterator operator-(int n)
+ {
+ return const_iterator(seq, count - n);
+ }
+
+ const_iterator& operator+=(int n)
+ {
+ count = count + n;
+ return *this;
+ }
+
+ const_iterator& operator-=(int n)
+ {
+ count = count - n;
+ return *this;
+ }
+
+ int operator-(const const_iterator& other) const
+ {
+ if (*seq != *other.seq)
+ throw RuntimeError ("SeqBase<T>::const_iterator::- error");
+ return count - other.count;
+ }
+ // prefix ++
+ const_iterator& operator++ ()
+ { count++; return *this;}
+ // postfix ++
+ const_iterator operator++ (int)
+ { return const_iterator(seq, count++);}
+ // prefix --
+ const_iterator& operator-- ()
+ { count--; return *this;}
+ // postfix --
+ const_iterator operator-- (int)
+ { return const_iterator(seq, count--);}
+ }; // end of class SeqBase<T>::const_iterator
+
+ const_iterator begin () const
+ {
+ return const_iterator(this, 0);
+ }
+
+ const_iterator end () const
+ {
+ return const_iterator(this, length());
+ }
+ };
+
+ // Here's an important typedef you might miss if reading too fast...
+ typedef SeqBase<Object> Sequence;
+
+ template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator< (const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator> (const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator<=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator>=(const EXPLICIT_TYPENAME SeqBase<T>::iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::iterator& right);
+
+ template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator< (const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator> (const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator<=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator>=(const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& left, const EXPLICIT_TYPENAME SeqBase<T>::const_iterator& right);
+
+
+ extern bool operator==(const Sequence::iterator& left, const Sequence::iterator& right);
+ extern bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right);
+ extern bool operator< (const Sequence::iterator& left, const Sequence::iterator& right);
+ extern bool operator> (const Sequence::iterator& left, const Sequence::iterator& right);
+ extern bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right);
+ extern bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right);
+
+ extern bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
+ extern bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
+ extern bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right);
+ extern bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right);
+ extern bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
+ extern bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right);
+
+ // ==================================================
+ // class Char
+ // Python strings return strings as individual elements.
+ // I'll try having a class Char which is a String of length 1
+ //
+ typedef std::basic_string<Py_UNICODE> unicodestring;
+ extern Py_UNICODE unicode_null_string[1];
+
+ class Char: public Object
+ {
+ public:
+ explicit Char (PyObject *pyob, bool owned = false): Object(pyob, owned)
+ {
+ validate();
+ }
+
+ Char (const Object& ob): Object(ob)
+ {
+ validate();
+ }
+
+ Char (const std::string& v = "")
+ :Object(PyString_FromStringAndSize (const_cast<char*>(v.c_str()),1), true)
+ {
+ validate();
+ }
+
+ Char (char v)
+ : Object(PyString_FromStringAndSize (&v, 1), true)
+ {
+ validate();
+ }
+
+ Char (Py_UNICODE v)
+ : Object(PyUnicode_FromUnicode (&v, 1), true)
+ {
+ validate();
+ }
+ // Assignment acquires new ownership of pointer
+ Char& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Char& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob)) && PySequence_Length (pyob) == 1;
+ }
+
+ // Assignment from C string
+ Char& operator= (const std::string& v)
+ {
+ set(PyString_FromStringAndSize (const_cast<char*>(v.c_str()),1), true);
+ return *this;
+ }
+
+ Char& operator= (char v)
+ {
+ set(PyString_FromStringAndSize (&v, 1), true);
+ return *this;
+ }
+
+ Char& operator= (const unicodestring& v)
+ {
+ set(PyUnicode_FromUnicode (const_cast<Py_UNICODE*>(v.data()),1), true);
+ return *this;
+ }
+
+ Char& operator= (Py_UNICODE v)
+ {
+ set(PyUnicode_FromUnicode (&v, 1), true);
+ return *this;
+ }
+
+ // Conversion
+ operator String() const;
+
+ operator std::string () const
+ {
+ return std::string(PyString_AsString (ptr()));
+ }
+ };
+
+ class String: public SeqBase<Char>
+ {
+ public:
+ virtual size_type capacity() const
+ {
+ return max_size();
+ }
+
+ explicit String (PyObject *pyob, bool owned = false): SeqBase<Char>(pyob, owned)
+ {
+ validate();
+ }
+
+ String (const Object& ob): SeqBase<Char>(ob)
+ {
+ validate();
+ }
+
+ String()
+ : SeqBase<Char>( PyString_FromStringAndSize( "", 0 ), true )
+ {
+ validate();
+ }
+
+ String( const std::string& v )
+ : SeqBase<Char>( PyString_FromStringAndSize( const_cast<char*>(v.data()),
+ static_cast<int>( v.length() ) ), true )
+ {
+ validate();
+ }
+
+ String( const char *s, const char *encoding, const char *error="strict" )
+ : SeqBase<Char>( PyUnicode_Decode( s, strlen( s ), encoding, error ), true )
+ {
+ validate();
+ }
+
+ String( const char *s, int len, const char *encoding, const char *error="strict" )
+ : SeqBase<Char>( PyUnicode_Decode( s, len, encoding, error ), true )
+ {
+ validate();
+ }
+
+ String( const std::string &s, const char *encoding, const char *error="strict" )
+ : SeqBase<Char>( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true )
+ {
+ validate();
+ }
+
+ String( const std::string& v, std::string::size_type vsize )
+ : SeqBase<Char>(PyString_FromStringAndSize( const_cast<char*>(v.data()),
+ static_cast<int>( vsize ) ), true)
+ {
+ validate();
+ }
+
+ String( const char *v, int vsize )
+ : SeqBase<Char>(PyString_FromStringAndSize( const_cast<char*>(v), vsize ), true )
+ {
+ validate();
+ }
+
+ String( const char* v )
+ : SeqBase<Char>( PyString_FromString( v ), true )
+ {
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+ String& operator= ( const Object& rhs )
+ {
+ return *this = *rhs;
+ }
+
+ String& operator= (PyObject* rhsp)
+ {
+ if( ptr() == rhsp )
+ return *this;
+ set (rhsp);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && (Py::_String_Check(pyob) || Py::_Unicode_Check(pyob));
+ }
+
+ // Assignment from C string
+ String& operator= (const std::string& v)
+ {
+ set( PyString_FromStringAndSize( const_cast<char*>( v.data() ),
+ static_cast<int>( v.length() ) ), true );
+ return *this;
+ }
+ String& operator= (const unicodestring& v)
+ {
+ set( PyUnicode_FromUnicode( const_cast<Py_UNICODE*>( v.data() ),
+ static_cast<int>( v.length() ) ), true );
+ return *this;
+ }
+
+
+ // Encode
+ String encode( const char *encoding, const char *error="strict" )
+ {
+ if( isUnicode() )
+ {
+ return String( PyUnicode_AsEncodedString( ptr(), encoding, error ) );
+ }
+ else
+ {
+ return String( PyString_AsEncodedObject( ptr(), encoding, error ) );
+ }
+ }
+
+ String decode( const char *encoding, const char *error="strict" )
+ {
+ return Object( PyString_AsDecodedObject( ptr(), encoding, error ) );
+ }
+
+ // Queries
+ virtual size_type size () const
+ {
+ if( isUnicode() )
+ {
+ return static_cast<size_type>( PyUnicode_GET_SIZE (ptr()) );
+ }
+ else
+ {
+ return static_cast<size_type>( PyString_Size (ptr()) );
+ }
+ }
+
+ operator std::string () const
+ {
+ return as_std_string();
+ }
+
+ std::string as_std_string() const
+ {
+ if( isUnicode() )
+ {
+ throw TypeError("cannot return std::string from Unicode object");
+ }
+ else
+ {
+ return std::string( PyString_AsString( ptr() ), static_cast<size_type>( PyString_Size( ptr() ) ) );
+ }
+ }
+
+ unicodestring as_unicodestring() const
+ {
+ if( isUnicode() )
+ {
+ return unicodestring( PyUnicode_AS_UNICODE( ptr() ),
+ static_cast<size_type>( PyUnicode_GET_SIZE( ptr() ) ) );
+ }
+ else
+ {
+ throw TypeError("can only return unicodestring from Unicode object");
+ }
+ }
+ };
+
+ // ==================================================
+ // class Tuple
+ class Tuple: public Sequence
+ {
+ public:
+ virtual void setItem (sequence_index_type offset, const Object&ob)
+ {
+ // note PyTuple_SetItem is a thief...
+ if(PyTuple_SetItem (ptr(), offset, new_reference_to(ob)) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ // Constructor
+ explicit Tuple (PyObject *pyob, bool owned = false): Sequence (pyob, owned)
+ {
+ validate();
+ }
+
+ Tuple (const Object& ob): Sequence(ob)
+ {
+ validate();
+ }
+
+ // New tuple of a given size
+ explicit Tuple (int size = 0)
+ {
+ set(PyTuple_New (size), true);
+ validate ();
+ for (sequence_index_type i=0; i < size; i++)
+ {
+ if(PyTuple_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1)
+ {
+ throw Exception();
+ }
+ }
+ }
+ // Tuple from any sequence
+ explicit Tuple (const Sequence& s)
+ {
+ sequence_index_type limit( sequence_index_type( s.length() ) );
+
+ set(PyTuple_New (limit), true);
+ validate();
+
+ for(sequence_index_type i=0; i < limit; i++)
+ {
+ if(PyTuple_SetItem (ptr(), i, new_reference_to(s[i])) == -1)
+ {
+ throw Exception();
+ }
+ }
+ }
+ // Assignment acquires new ownership of pointer
+
+ Tuple& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Tuple& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Tuple_Check (pyob);
+ }
+
+ Tuple getSlice (int i, int j) const
+ {
+ return Tuple (PySequence_GetSlice (ptr(), i, j), true);
+ }
+
+ };
+
+ // ==================================================
+ // class List
+
+ class List: public Sequence
+ {
+ public:
+ // Constructor
+ explicit List (PyObject *pyob, bool owned = false): Sequence(pyob, owned)
+ {
+ validate();
+ }
+ List (const Object& ob): Sequence(ob)
+ {
+ validate();
+ }
+ // Creation at a fixed size
+ List (int size = 0)
+ {
+ set(PyList_New (size), true);
+ validate();
+ for (sequence_index_type i=0; i < size; i++)
+ {
+ if(PyList_SetItem (ptr(), i, new_reference_to(Py::_None())) == -1)
+ {
+ throw Exception();
+ }
+ }
+ }
+
+ // List from a sequence
+ List (const Sequence& s): Sequence()
+ {
+ int n = s.length();
+ set(PyList_New (n), true);
+ validate();
+ for (sequence_index_type i=0; i < n; i++)
+ {
+ if(PyList_SetItem (ptr(), i, new_reference_to(s[i])) == -1)
+ {
+ throw Exception();
+ }
+ }
+ }
+
+ virtual size_type capacity() const
+ {
+ return max_size();
+ }
+ // Assignment acquires new ownership of pointer
+
+ List& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ List& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_List_Check (pyob);
+ }
+
+ List getSlice (int i, int j) const
+ {
+ return List (PyList_GetSlice (ptr(), i, j), true);
+ }
+
+ void setSlice (int i, int j, const Object& v)
+ {
+ if(PyList_SetSlice (ptr(), i, j, *v) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ void append (const Object& ob)
+ {
+ if(PyList_Append (ptr(), *ob) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ void insert (int i, const Object& ob)
+ {
+ if(PyList_Insert (ptr(), i, *ob) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ void sort ()
+ {
+ if(PyList_Sort(ptr()) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ void reverse ()
+ {
+ if(PyList_Reverse(ptr()) == -1)
+ {
+ throw Exception();
+ }
+ }
+ };
+
+
+ // Mappings
+ // ==================================================
+ template<TEMPLATE_TYPENAME T>
+ class mapref
+ {
+ protected:
+ MapBase<T>& s; // the map
+ Object key; // item key
+ T the_item;
+
+ public:
+ mapref<T> (MapBase<T>& map, const std::string& k)
+ : s(map), the_item()
+ {
+ key = String(k);
+ if(map.hasKey(key)) the_item = map.getItem(key);
+ };
+
+ mapref<T> (MapBase<T>& map, const Object& k)
+ : s(map), key(k), the_item()
+ {
+ if(map.hasKey(key)) the_item = map.getItem(key);
+ };
+
+ ~mapref()
+ {}
+
+ // MapBase<T> stuff
+ // lvalue
+ mapref<T>& operator=(const mapref<T>& other)
+ {
+ if(this == &other) return *this;
+ the_item = other.the_item;
+ s.setItem(key, other.the_item);
+ return *this;
+ };
+
+ mapref<T>& operator= (const T& ob)
+ {
+ the_item = ob;
+ s.setItem (key, ob);
+ return *this;
+ }
+
+ // rvalue
+ operator T() const
+ {
+ return the_item;
+ }
+
+ // forward everything else to the_item
+ PyObject* ptr () const
+ {
+ return the_item.ptr();
+ }
+
+ int reference_count () const
+ { // the mapref count
+ return the_item.reference_count();
+ }
+
+ Type type () const
+ {
+ return the_item.type();
+ }
+
+ String str () const
+ {
+ return the_item.str();
+ }
+
+ String repr () const
+ {
+ return the_item.repr();
+ }
+
+ bool hasAttr (const std::string& attr_name) const
+ {
+ return the_item.hasAttr(attr_name);
+ }
+
+ Object getAttr (const std::string& attr_name) const
+ {
+ return the_item.getAttr(attr_name);
+ }
+
+ Object getItem (const Object& k) const
+ {
+ return the_item.getItem(k);
+ }
+
+ long hashValue () const
+ {
+ return the_item.hashValue();
+ }
+
+ bool isCallable () const
+ {
+ return the_item.isCallable();
+ }
+
+ bool isList () const
+ {
+ return the_item.isList();
+ }
+
+ bool isMapping () const
+ {
+ return the_item.isMapping();
+ }
+
+ bool isNumeric () const
+ {
+ return the_item.isNumeric();
+ }
+
+ bool isSequence () const
+ {
+ return the_item.isSequence();
+ }
+
+ bool isTrue () const
+ {
+ return the_item.isTrue();
+ }
+
+ bool isType (const Type& t) const
+ {
+ return the_item.isType (t);
+ }
+
+ bool isTuple() const
+ {
+ return the_item.isTuple();
+ }
+
+ bool isString() const
+ {
+ return the_item.isString();
+ }
+
+ // Commands
+ void setAttr (const std::string& attr_name, const Object& value)
+ {
+ the_item.setAttr(attr_name, value);
+ }
+
+ void delAttr (const std::string& attr_name)
+ {
+ the_item.delAttr(attr_name);
+ }
+
+ void delItem (const Object& k)
+ {
+ the_item.delItem(k);
+ }
+ }; // end of mapref
+
+ // TMM: now for mapref<T>
+ template< class T >
+ bool operator==(const mapref<T>& left, const mapref<T>& right)
+ {
+ return true; // NOT completed.
+ }
+
+ template< class T >
+ bool operator!=(const mapref<T>& left, const mapref<T>& right)
+ {
+ return true; // not completed.
+ }
+
+ template<TEMPLATE_TYPENAME T>
+ class MapBase: public Object
+ {
+ protected:
+ explicit MapBase<T>()
+ {}
+ public:
+ // reference: proxy class for implementing []
+ // TMM: 26Jun'01 - the types
+ // If you assume that Python mapping is a hash_map...
+ // hash_map::value_type is not assignable, but
+ // (*it).second = data must be a valid expression
+ typedef size_t size_type;
+ typedef Object key_type;
+ typedef mapref<T> data_type;
+ typedef std::pair< const T, T > value_type;
+ typedef std::pair< const T, mapref<T> > reference;
+ typedef const std::pair< const T, const T > const_reference;
+ typedef std::pair< const T, mapref<T> > pointer;
+
+ // Constructor
+ explicit MapBase<T> (PyObject *pyob, bool owned = false): Object(pyob, owned)
+ {
+ validate();
+ }
+
+ // TMM: 02Jul'01 - changed MapBase<T> to Object in next line
+ MapBase<T> (const Object& ob): Object(ob)
+ {
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+ MapBase<T>& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ MapBase<T>& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && PyMapping_Check(pyob);
+ }
+
+ // Clear -- PyMapping Clear is missing
+ //
+
+ void clear ()
+ {
+ List k = keys();
+ for(List::iterator i = k.begin(); i != k.end(); i++)
+ {
+ delItem(*i);
+ }
+ }
+
+ virtual size_type size() const
+ {
+ return PyMapping_Length (ptr());
+ }
+
+ // Element Access
+ T operator[](const std::string& key) const
+ {
+ return getItem(key);
+ }
+
+ T operator[](const Object& key) const
+ {
+ return getItem(key);
+ }
+
+ mapref<T> operator[](const std::string& key)
+ {
+ return mapref<T>(*this, key);
+ }
+
+ mapref<T> operator[](const Object& key)
+ {
+ return mapref<T>(*this, key);
+ }
+
+ int length () const
+ {
+ return PyMapping_Length (ptr());
+ }
+
+ bool hasKey (const std::string& s) const
+ {
+ return PyMapping_HasKeyString (ptr(),const_cast<char*>(s.c_str())) != 0;
+ }
+
+ bool hasKey (const Object& s) const
+ {
+ return PyMapping_HasKey (ptr(), s.ptr()) != 0;
+ }
+
+ T getItem (const std::string& s) const
+ {
+ return T(
+ asObject(PyMapping_GetItemString (ptr(),const_cast<char*>(s.c_str())))
+ );
+ }
+
+ T getItem (const Object& s) const
+ {
+ return T(
+ asObject(PyObject_GetItem (ptr(), s.ptr()))
+ );
+ }
+
+ virtual void setItem (const char *s, const Object& ob)
+ {
+ if (PyMapping_SetItemString (ptr(), const_cast<char*>(s), *ob) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ virtual void setItem (const std::string& s, const Object& ob)
+ {
+ if (PyMapping_SetItemString (ptr(), const_cast<char*>(s.c_str()), *ob) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ virtual void setItem (const Object& s, const Object& ob)
+ {
+ if (PyObject_SetItem (ptr(), s.ptr(), ob.ptr()) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ void delItem (const std::string& s)
+ {
+ if (PyMapping_DelItemString (ptr(), const_cast<char*>(s.c_str())) == -1)
+ {
+ throw Exception();
+ }
+ }
+
+ void delItem (const Object& s)
+ {
+ if (PyMapping_DelItem (ptr(), *s) == -1)
+ {
+ throw Exception();
+ }
+ }
+ // Queries
+ List keys () const
+ {
+ return List(PyMapping_Keys(ptr()), true);
+ }
+
+ List values () const
+ { // each returned item is a (key, value) pair
+ return List(PyMapping_Values(ptr()), true);
+ }
+
+ List items () const
+ {
+ return List(PyMapping_Items(ptr()), true);
+ }
+
+ // iterators for MapBase<T>
+ // Added by TMM: 2Jul'01 - NOT COMPLETED
+ // There is still a bug. I decided to stop, before fixing the bug, because
+ // this can't be halfway efficient until Python gets built-in iterators.
+ // My current soln is to iterate over the map by getting a copy of its keys
+ // and iterating over that. Not a good solution.
+
+ // The iterator holds a MapBase<T>* rather than a MapBase<T> because that's
+ // how the sequence iterator is implemented and it works. But it does seem
+ // odd to me - we are iterating over the map object, not the reference.
+
+#if 0 // here is the test code with which I found the (still existing) bug
+ typedef cxx::Dict d_t;
+ d_t d;
+ cxx::String s1("blah");
+ cxx::String s2("gorf");
+ d[ "one" ] = s1;
+ d[ "two" ] = s1;
+ d[ "three" ] = s2;
+ d[ "four" ] = s2;
+
+ d_t::iterator it;
+ it = d.begin(); // this (using the assignment operator) is causing
+ // a problem; if I just use the copy ctor it works fine.
+ for( ; it != d.end(); ++it )
+ {
+ d_t::value_type vt( *it );
+ cxx::String rs = vt.second.repr();
+ std::string ls = rs.operator std::string();
+ fprintf( stderr, "%s\n", ls );
+ }
+#endif // 0
+
+ class iterator
+ {
+ // : public forward_iterator_parent( std::pair<const T,T> ) {
+ protected:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::pair< const T, T > value_type;
+ typedef int difference_type;
+ typedef std::pair< const T, mapref<T> > pointer;
+ typedef std::pair< const T, mapref<T> > reference;
+
+ friend class MapBase<T>;
+ //
+ MapBase<T>* map;
+ List keys; // for iterating over the map
+ List::iterator pos; // index into the keys
+
+ public:
+ ~iterator ()
+ {}
+
+ iterator ()
+ : map( 0 )
+ , keys()
+ , pos()
+ {}
+
+ iterator (MapBase<T>* m, bool end = false )
+ : map( m )
+ , keys( m->keys() )
+ , pos( end ? keys.end() : keys.begin() )
+ {}
+
+ iterator (const iterator& other)
+ : map( other.map )
+ , keys( other.keys )
+ , pos( other.pos )
+ {}
+
+ reference operator*()
+ {
+ Object key = *pos;
+ return std::make_pair(key, mapref<T>(*map,key));
+ }
+
+ iterator& operator=(const iterator& other)
+ {
+ if (this == &other)
+ return *this;
+ map = other.map;
+ keys = other.keys;
+ pos = other.pos;
+ return *this;
+ }
+
+ bool eql(const iterator& right) const
+ {
+ return *map == *right.map && pos == right.pos;
+ }
+ bool neq( const iterator& right ) const
+ {
+ return *map != *right.map || pos != right.pos;
+ }
+
+ // pointer operator->() {
+ // return ;
+ // }
+
+ // prefix ++
+ iterator& operator++ ()
+ { pos++; return *this;}
+ // postfix ++
+ iterator operator++ (int)
+ { return iterator(map, keys, pos++);}
+ // prefix --
+ iterator& operator-- ()
+ { pos--; return *this;}
+ // postfix --
+ iterator operator-- (int)
+ { return iterator(map, keys, pos--);}
+
+ std::string diagnose() const
+ {
+ std::OSTRSTREAM oss;
+ oss << "iterator diagnosis " << map << ", " << pos << std::ends;
+ return std::string(oss.str());
+ }
+ }; // end of class MapBase<T>::iterator
+
+ iterator begin ()
+ {
+ return iterator(this);
+ }
+
+ iterator end ()
+ {
+ return iterator(this, true);
+ }
+
+ class const_iterator
+ {
+ protected:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef const std::pair< const T, T > value_type;
+ typedef int difference_type;
+ typedef const std::pair< const T, T > pointer;
+ typedef const std::pair< const T, T > reference;
+
+ friend class MapBase<T>;
+ const MapBase<T>* map;
+ List keys; // for iterating over the map
+ List::iterator pos; // index into the keys
+
+ public:
+ ~const_iterator ()
+ {}
+
+ const_iterator ()
+ : map( 0 )
+ , keys()
+ , pos()
+ {}
+
+ const_iterator (const MapBase<T>* m, List k, List::iterator p )
+ : map( m )
+ , keys( k )
+ , pos( p )
+ {}
+
+ const_iterator(const const_iterator& other)
+ : map( other.map )
+ , keys( other.keys )
+ , pos( other.pos )
+ {}
+
+ bool eql(const const_iterator& right) const
+ {
+ return *map == *right.map && pos == right.pos;
+ }
+ bool neq( const const_iterator& right ) const
+ {
+ return *map != *right.map || pos != right.pos;
+ }
+
+
+ // const_reference operator*() {
+ // Object key = *pos;
+ // return std::make_pair( key, map->[key] );
+ // GCC < 3 barfes on this line at the '['.
+ // }
+
+ const_iterator& operator=(const const_iterator& other)
+ {
+ if (this == &other) return *this;
+ map = other.map;
+ keys = other.keys;
+ pos = other.pos;
+ return *this;
+ }
+
+ // prefix ++
+ const_iterator& operator++ ()
+ { pos++; return *this;}
+ // postfix ++
+ const_iterator operator++ (int)
+ { return const_iterator(map, keys, pos++);}
+ // prefix --
+ const_iterator& operator-- ()
+ { pos--; return *this;}
+ // postfix --
+ const_iterator operator-- (int)
+ { return const_iterator(map, keys, pos--);}
+ }; // end of class MapBase<T>::const_iterator
+
+ const_iterator begin () const
+ {
+ return const_iterator(this, 0);
+ }
+
+ const_iterator end () const
+ {
+ return const_iterator(this, length());
+ }
+
+ }; // end of MapBase<T>
+
+ typedef MapBase<Object> Mapping;
+
+ template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME MapBase<T>::iterator& left, const EXPLICIT_TYPENAME MapBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME MapBase<T>::iterator& left, const EXPLICIT_TYPENAME MapBase<T>::iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator==(const EXPLICIT_TYPENAME MapBase<T>::const_iterator& left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator& right);
+ template <TEMPLATE_TYPENAME T> bool operator!=(const EXPLICIT_TYPENAME MapBase<T>::const_iterator& left, const EXPLICIT_TYPENAME MapBase<T>::const_iterator& right);
+
+ extern bool operator==(const Mapping::iterator& left, const Mapping::iterator& right);
+ extern bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right);
+ extern bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right);
+ extern bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right);
+
+
+ // ==================================================
+ // class Dict
+ class Dict: public Mapping
+ {
+ public:
+ // Constructor
+ explicit Dict (PyObject *pyob, bool owned=false): Mapping (pyob, owned)
+ {
+ validate();
+ }
+ Dict (const Dict& ob): Mapping(ob)
+ {
+ validate();
+ }
+ // Creation
+ Dict ()
+ {
+ set(PyDict_New (), true);
+ validate();
+ }
+ // Assignment acquires new ownership of pointer
+
+ Dict& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Dict& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set(rhsp);
+ return *this;
+ }
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && Py::_Dict_Check (pyob);
+ }
+ };
+
+ class Callable: public Object
+ {
+ protected:
+ explicit Callable (): Object()
+ {}
+ public:
+ // Constructor
+ explicit Callable (PyObject *pyob, bool owned = false): Object (pyob, owned)
+ {
+ validate();
+ }
+
+ Callable (const Object& ob): Object(ob)
+ {
+ validate();
+ }
+
+ // Assignment acquires new ownership of pointer
+
+ Callable& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Callable& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set (rhsp);
+ return *this;
+ }
+
+ // Membership
+ virtual bool accepts (PyObject *pyob) const
+ {
+ return pyob && PyCallable_Check (pyob);
+ }
+
+ // Call
+ Object apply(const Tuple& args) const
+ {
+ return asObject(PyObject_CallObject(ptr(), args.ptr()));
+ }
+
+ // Call with keywords
+ Object apply(const Tuple& args, const Dict& kw) const
+ {
+ return asObject( PyEval_CallObjectWithKeywords( ptr(), args.ptr(), kw.ptr() ) );
+ }
+
+ Object apply(PyObject* pargs = 0) const
+ {
+ return apply (Tuple(pargs));
+ }
+ };
+
+ class Module: public Object
+ {
+ public:
+ explicit Module (PyObject* pyob, bool owned = false): Object (pyob, owned)
+ {
+ validate();
+ }
+
+ // Construct from module name
+ explicit Module (const std::string&s): Object()
+ {
+ PyObject *m = PyImport_AddModule( const_cast<char *>(s.c_str()) );
+ set( m, false );
+ validate ();
+ }
+
+ // Copy constructor acquires new ownership of pointer
+ Module (const Module& ob): Object(*ob)
+ {
+ validate();
+ }
+
+ Module& operator= (const Object& rhs)
+ {
+ return (*this = *rhs);
+ }
+
+ Module& operator= (PyObject* rhsp)
+ {
+ if(ptr() == rhsp) return *this;
+ set(rhsp);
+ return *this;
+ }
+
+ Dict getDict()
+ {
+ return Dict(PyModule_GetDict(ptr()));
+ // Caution -- PyModule_GetDict returns borrowed reference!
+ }
+ };
+
+ // Numeric interface
+ inline Object operator+ (const Object& a)
+ {
+ return asObject(PyNumber_Positive(*a));
+ }
+ inline Object operator- (const Object& a)
+ {
+ return asObject(PyNumber_Negative(*a));
+ }
+
+ inline Object abs(const Object& a)
+ {
+ return asObject(PyNumber_Absolute(*a));
+ }
+
+ inline std::pair<Object,Object> coerce(const Object& a, const Object& b)
+ {
+ PyObject *p1, *p2;
+ p1 = *a;
+ p2 = *b;
+ if(PyNumber_Coerce(&p1,&p2) == -1)
+ {
+ throw Exception();
+ }
+ return std::pair<Object,Object>(asObject(p1), asObject(p2));
+ }
+
+ inline Object operator+ (const Object& a, const Object& b)
+ {
+ return asObject(PyNumber_Add(*a, *b));
+ }
+ inline Object operator+ (const Object& a, int j)
+ {
+ return asObject(PyNumber_Add(*a, *Int(j)));
+ }
+ inline Object operator+ (const Object& a, double v)
+ {
+ return asObject(PyNumber_Add(*a, *Float(v)));
+ }
+ inline Object operator+ (int j, const Object& b)
+ {
+ return asObject(PyNumber_Add(*Int(j), *b));
+ }
+ inline Object operator+ (double v, const Object& b)
+ {
+ return asObject(PyNumber_Add(*Float(v), *b));
+ }
+
+ inline Object operator- (const Object& a, const Object& b)
+ {
+ return asObject(PyNumber_Subtract(*a, *b));
+ }
+ inline Object operator- (const Object& a, int j)
+ {
+ return asObject(PyNumber_Subtract(*a, *Int(j)));
+ }
+ inline Object operator- (const Object& a, double v)
+ {
+ return asObject(PyNumber_Subtract(*a, *Float(v)));
+ }
+ inline Object operator- (int j, const Object& b)
+ {
+ return asObject(PyNumber_Subtract(*Int(j), *b));
+ }
+ inline Object operator- (double v, const Object& b)
+ {
+ return asObject(PyNumber_Subtract(*Float(v), *b));
+ }
+
+ inline Object operator* (const Object& a, const Object& b)
+ {
+ return asObject(PyNumber_Multiply(*a, *b));
+ }
+ inline Object operator* (const Object& a, int j)
+ {
+ return asObject(PyNumber_Multiply(*a, *Int(j)));
+ }
+ inline Object operator* (const Object& a, double v)
+ {
+ return asObject(PyNumber_Multiply(*a, *Float(v)));
+ }
+ inline Object operator* (int j, const Object& b)
+ {
+ return asObject(PyNumber_Multiply(*Int(j), *b));
+ }
+ inline Object operator* (double v, const Object& b)
+ {
+ return asObject(PyNumber_Multiply(*Float(v), *b));
+ }
+
+ inline Object operator/ (const Object& a, const Object& b)
+ {
+ return asObject(PyNumber_Divide(*a, *b));
+ }
+ inline Object operator/ (const Object& a, int j)
+ {
+ return asObject(PyNumber_Divide(*a, *Int(j)));
+ }
+ inline Object operator/ (const Object& a, double v)
+ {
+ return asObject(PyNumber_Divide(*a, *Float(v)));
+ }
+ inline Object operator/ (int j, const Object& b)
+ {
+ return asObject(PyNumber_Divide(*Int(j), *b));
+ }
+ inline Object operator/ (double v, const Object& b)
+ {
+ return asObject(PyNumber_Divide(*Float(v), *b));
+ }
+
+ inline Object operator% (const Object& a, const Object& b)
+ {
+ return asObject(PyNumber_Remainder(*a, *b));
+ }
+ inline Object operator% (const Object& a, int j)
+ {
+ return asObject(PyNumber_Remainder(*a, *Int(j)));
+ }
+ inline Object operator% (const Object& a, double v)
+ {
+ return asObject(PyNumber_Remainder(*a, *Float(v)));
+ }
+ inline Object operator% (int j, const Object& b)
+ {
+ return asObject(PyNumber_Remainder(*Int(j), *b));
+ }
+ inline Object operator% (double v, const Object& b)
+ {
+ return asObject(PyNumber_Remainder(*Float(v), *b));
+ }
+
+ inline Object type(const Exception&) // return the type of the error
+ {
+ PyObject *ptype, *pvalue, *ptrace;
+ PyErr_Fetch(&ptype, &pvalue, &ptrace);
+ Object result(ptype);
+ PyErr_Restore(ptype, pvalue, ptrace);
+ return result;
+ }
+
+ inline Object value(const Exception&) // return the value of the error
+ {
+ PyObject *ptype, *pvalue, *ptrace;
+ PyErr_Fetch(&ptype, &pvalue, &ptrace);
+ Object result;
+ if(pvalue) result = pvalue;
+ PyErr_Restore(ptype, pvalue, ptrace);
+ return result;
+ }
+
+ inline Object trace(const Exception&) // return the traceback of the error
+ {
+ PyObject *ptype, *pvalue, *ptrace;
+ PyErr_Fetch(&ptype, &pvalue, &ptrace);
+ Object result;
+ if(ptrace) result = ptrace;
+ PyErr_Restore(ptype, pvalue, ptrace);
+ return result;
+ }
+
+
+
+template<TEMPLATE_TYPENAME T>
+String seqref<T>::str () const
+ {
+ return the_item.str();
+ }
+
+template<TEMPLATE_TYPENAME T>
+String seqref<T>::repr () const
+ {
+ return the_item.repr();
+ }
+
+
+ } // namespace Py
+#endif // __CXX_Objects__h
diff --git a/lib/kross/python/cxx/PyCXX.html b/lib/kross/python/cxx/PyCXX.html
new file mode 100644
index 00000000..566974c1
--- /dev/null
+++ b/lib/kross/python/cxx/PyCXX.html
@@ -0,0 +1,2131 @@
+<html>
+
+<head>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<title>Writing Python Extensions in C++</title>
+<style>
+H1, H2, H3, H4 {color: #000099;
+ background-color: lightskyblue}
+h3 {position: relative; left: 20px}
+
+p {position: relative; left: 20px; margin-right: 20px}
+pre {color: #0000cc; background-color: #eeeeee; position: relative; left: 40px; margin-right: 80px;
+ border-style: solid; border-color: black; border-width: thin}
+kbd {color: #990000}
+p cite, ol cite, ul cite {font-family: monospace; font-style: normal; font-size: normal}
+li var, pre var, p var, kbd var {color: #009900; font-style: italic}
+li samp, pre samp, p samp, kbd samp {color: #009900; font-weight: bold}
+li p {position: relative; left: 0}
+table { position: relative; left: 20px; border: solid #888888 1px; background-color: #eeeeee}
+table th {border: solid #888888 1px; background-color: #88dd88; color: black}
+table td {border: solid #888888 1px}
+table td.code {border: solid #888888 1px;font-family: monospace; font-style: normal; font-size: normal}
+p.param {background-color: #eeeeee; border-top: lightskyblue solid 4}
+</style>
+
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<h1 ALIGN="center">Writing Python Extensions in C++</h1>
+
+<p ALIGN="CENTER">Barry Scott<br>
+Reading, Berkshire, England<br>
+<a href="mailto:barry@barrys-emacs.org">barry@barrys-emacs.org</a><br>
+</p>
+
+<p ALIGN="CENTER">Paul F. Dubois, <a href="mailto:dubois1@llnl.gov">dubois1@llnl.gov</a><br>
+Lawrence Livermore National Laboratory<br>
+Livermore, California, U.S.A.</p>
+
+
+<p>PyCXX is designed to make it easier to extend Python with C++</p>
+
+
+<p>PyCXX is a set of C++ facilities to make it easier to write Python extensions.
+The chief way in which PyCXX makes it easier to write Python extensions is that it greatly
+increases the probability that your program will not make a reference-counting error and
+will not have to continually check error returns from the Python C API. PyCXX
+integrates Python with C++ in these ways: </p>
+
+<ul>
+ <li>C++ exception handling is relied on to detect errors and clean up. In a complicated
+ function this is often a tremendous problem when writing in C. With PyCXX, we let the
+ compiler keep track of what objects need to be dereferenced when an error occurs.
+ <li>The Standard Template Library (STL) and its many algorithms plug and play with Python
+ containers such as lists and tuples.
+ <li>The optional CXX_Extensions facility allows you to replace the clumsy C tables with
+ objects and method calls that define your modules and extension objects.
+</ul>
+
+<h3>Download and Installation</h3>
+
+<p>Download PyCXX from <a href="http://sourceforge.net/projects/cxx/">http://sourceforge.net/projects/cxx/</a>.</p>
+
+<p>The distribution layout is:</p>
+<table>
+<tr><th>Directory</th><th>Description</th></tr>
+<tr><td class=code>.</td><td>Makefile for Unix and Windows, Release documentation</td>
+<tr><td class=code>./CXX</td><td>Header files</td>
+<tr><td class=code>./Src</td><td>Source files</td>
+<tr><td class=code>./Doc</td><td>Documentation</td>
+<tr><td class=code>./Demo</td><td>Testing and Demonstartion files</td>
+</table>
+
+<p>To use PyCXX you use its include files and add its source routines to your module.</p>
+
+<p>Installation:</p>
+<ul>
+<li>Install the PyCXX files into a directory of your choice. For example:<br>
+Windows: <cite>C:\PyCXX</cite><br>
+Unix: <cite>/usr/local/PyCXX</cite>
+<li>Tell your compiler where the PyCXX header files are:<br>
+Windows: <cite>cl /I=C:\PyCXX ...</cite><br>
+Unix: <cite>g++ -I/usr/local/PyCXX ...</cite>
+<li>Include PyCXX headers files in your code using the CXX prefix:<br>
+<cite>#include &quot;CXX/Object.hxx&quot;</cite>
+</ul>
+
+<p>The header file CXX/config.h may need to be adjusted for the
+compiler you use. As of this writing, only a fairly obscure reference to part of the
+standard library needs this adjustment. Unlike prior releases, PyCXX now assumes namespace
+support and a standard C++ library. </p>
+
+<h3>Use of namespaces</h3>
+
+<p>All PyCXX assets are in namespace &quot;Py&quot;. You need to include
+the Py:: prefix when referring to them, or include the statement:</p>
+
+<p>using namespace Py;</p>
+
+<h2>Wrappers for standard objects: CXX_Objects.h</h2>
+
+<p>Header file CXX_Objects.h requires adding file Src/cxxsupport.cxx to
+your module sources. CXX_Objects provides a set of wrapper classes that allow you access
+to most of the Python C API using a C++ notation that closely resembles Python. For
+example, this Python:</p>
+
+<pre>d = {}
+d["a"] = 1
+d["b"] = 2
+alist = d.keys()
+print alist</pre>
+
+<p>Can be written in C++:</p>
+
+<pre>Dict d;
+List alist;
+d["a"] = Int(1);
+d["b"] = Int(2);
+alist = d.keys();
+std::cout &lt;&lt; alist &lt;&lt; std::endl;
+</pre>
+
+<p>You can optionally use the CXX/Extensions.hxx facility described later
+to define Python extension modules and extension objects.</p>
+
+<h3>We avoid programming with Python object pointers</h3>
+
+<p>The essential idea is that we avoid, as much as possible, programming with pointers to
+Python objects, that is, variables of type <cite>PyObject*</cite>. Instead,
+we use instances of a family of C++ classes that represent the
+usual Python objects. This family is easily extendible to include new kinds of Python
+objects.</p>
+
+<p>For example, consider the case in which we wish to write a method, taking a single
+integer argument, that will create a Python <cite>dict</cite>
+ and insert into it that the integer plus one under the key <cite>value</cite>.
+ In C we might do that as follows:</p>
+
+<pre>static PyObject* mymodule_addvalue (PyObject* self, PyObject* args)
+ {
+ PyObject *d;
+ PyObject* f;
+ int k;
+ PyArgs_ParseTuple(args, &quot;i&quot;, &amp;k);
+ d = PyDict_New();
+ if (!d)
+ return NULL;
+
+ f = PyInt_NEW(k+1);
+ if(!f)
+ {
+ Py_DECREF(d); /* have to get rid of d first */
+ return NULL;
+ }
+ if(PyDict_SetItemString(d, &quot;value&quot;, f) == -1)
+ {
+ Py_DECREF(f);
+ Py_DECREF(d);
+ return NULL;
+ }
+
+ return d;
+ }</pre>
+
+<p>If you have written a significant Python extension, this tedium looks all too familiar.
+The vast bulk of the coding is error checking and cleanup. Now compare the same thing
+written in C++ using CXX/Objects.hxx. The things with Python-like names (Int, Dict, Tuple) are
+from CXX/Objects.hxx.</p>
+
+<pre>static PyObject* mymodule_addvalue (PyObject* self, PyObject* pargs)
+ {
+ try {
+ Tuple args(pargs);
+ args.verify_length(1);
+
+ Dict d;
+ Int k = args[0];
+ d[&quot;value&quot;] = k + 1;
+
+ return new_reference_to(d);
+ }
+ catch (const PyException&amp;)
+ {
+ return NULL;
+ }
+ }</pre>
+
+<p>If there are not the right number of arguments or the argument is not an
+integer, an exception is thrown. In this case we choose to catch it and convert it into a
+Python exception. The C++ exception handling mechanism takes care all the cleanup.</p>
+
+<p>Note that the creation of the <cite>Int k</cite> got the first argument <em>and</em> verified
+that it is an <cite>Int</cite>.</p>
+
+<p>Just to peek ahead, if you wrote this method in an
+ExtensionModule-derived module of your own, it would be a method and it could be written
+even more simply:</p>
+
+<pre>
+Object addvalue (Object &amp; self, const Tuple &amp; args)
+ {
+ args.verify_length(1);
+ Dict d;
+ Int k = args[0];
+ d["value"] = k + 1;
+ return d;
+ }
+</pre>
+
+<h2>The basic concept is to wrap Python pointers</h2>
+
+
+<p>The basic concept of CXX/Objects.hxx is to create a wrapper around
+each <cite>PyObject *</cite> so that the reference counting can be
+done automatically, thus eliminating the most frequent source of errors. In addition, we
+can then add methods and operators so that Python objects can be manipulated in C++
+much like you would in Python.</p>
+
+<p>Each <cite>Object</cite> contains a <cite>PyObject *</cite>
+to which it owns a reference. When an <cite>Object</cite> is destroyed, it releases its ownership on
+the pointer. Since C++ calls the destructors on objects that are about to go out of scope,
+we are guaranteed that we will keep the reference counts right even if we unexpectedly
+leave a routine with an exception.</p>
+
+<p>As a matter of philosophy, CXX/Objects.hxx prevents the creation of instances of its
+classes unless the instance will be a valid instance of its class. When an attempt is made
+to create an object that will not be valid, an exception is thrown.</p>
+
+<p>Class <cite>Object</cite> represents the most general kind of Python object. The rest of the classes
+that represent Python objects inherit from it.</p>
+
+<pre>Object
+ Type
+ Int
+ Float
+ Long
+ Complex
+ Char
+ Sequence -&gt; SeqBase&lt;T&gt;
+ String
+ Tuple
+ List
+ Mapping -&gt; MapBase&lt;T&gt;
+ Dict
+ Callable
+ Module</pre>
+
+<p>There are several constructors for each of these classes. For example, you can create
+an <cite>Int</cite> from an integer as in</p>
+
+<pre>Int s(3)</pre>
+
+<p>However, you can also create an instance of one of these classes using any <cite>PyObject*</cite> or
+another <cite>Object</cite>. If the corresponding Python object does not actually have the type
+desired, an exception is thrown. This is accomplished as follows. Class <cite>Object</cite> defines a
+virtual function <cite>accepts</cite>:</p>
+
+<pre>virtual bool accepts(PyObject* p)</pre>
+
+<p>The base class version of <cite>accepts</cite> returns true for any pointer p except 0. This means
+we can create an Object using any <cite>PyObject *</cite>, or from any other
+<cite>Object</cite>. However, if we attempt to create an <cite>Int</cite> from a <cite>PyObject *</cite>,
+the overridding version
+of <cite>accepts</cite> in class <cite>Int</cite> will only accept pointers that correspond to Python ints.
+Therefore if we have a <cite>Tuple t</cite> and we wish to get the first element and be sure it is an
+<cite>Int</cite>, we do</p>
+
+<pre>Int first_element = t[0]</pre>
+
+<p>This will not only accomplish the goal of extracting the first element of the <cite>Tuple t</cite>,
+but it will ensure that the result is an <cite>Int</cite>. If not, an exception is thrown. The
+exception mechanism is discussed later.</p>
+
+<h2>Class Object</h2>
+
+<p>Class <cite>Object</cite> serves as the base class for the other classes. Its default constructor
+constructs a <cite>Py_None</cite>, the unique object of Python type <cite>None</cite>. The interface to <cite>Object</cite>
+consists of a large number of methods corresponding to the operations that are defined for
+every Python object. In each case, the methods throw an exception if anything goes
+wrong.</p>
+
+<p>There is no method corresponding to <cite>PyObject_SetItem</cite> with an arbitrary Python object
+as a key. Instead, create an instance of a more specific child of <cite>Object</cite> and use the
+appropriate facilities.</p>
+
+<p>The comparison operators use the Python comparison function to compare values. The
+method <cite>is</cite> is available to test for absolute identity.</p>
+
+<p>A conversion to standard library string type <cite>std::string</cite> is supplied using method
+<cite>as_string</cite>. Stream output of PyCXX <cite>Object</cite> instances uses this conversion,
+which in turn uses the Python object's str() representation.</p>
+
+<p>All the numeric operators are defined on all possible combinations of <cite>Object</cite>,
+<cite>long</cite>, and <cite>double</cite>. These use the corresponding Python operators,
+and should the operation fail for some reason, an exception is thrown.</p>
+
+<h3>Dealing with pointers returned by the Python C API</h3>
+
+<p>Often, <cite>PyObject *</cite> pointers are acquired from some function,
+particularly functions in the Python C API. If you wish to make an object from the pointer
+returned by such a function, you need to know if the function returns you an <i>owned</i>
+or <i>unowned</i> reference. Unowned references are unusual but there are some cases where
+unowned references are returned.</p>
+
+<p>Usually, <cite>Object</cite> and its children acquire a new reference when constructed from a
+<cite>PyObject *</cite>. This is usually not the right behavior if the reference comes from one
+of the Python C API calls.</p>
+
+<p>If p is an owned reference, you can add the boolean <cite>true</cite> as an extra
+argument in the creation routine, <cite>Object(p, true)</cite>, or use the function <cite>asObject(p)</cite> which
+returns an <cite>Object</cite> created using the owned reference. For example, the routine
+<cite>PyString_FromString</cite> returns an owned reference to a Python string object. You could write:</p>
+
+<pre>Object w = asObject( PyString_FromString("my string") );</pre>
+
+<p>or using the constructor,</p>
+
+<pre>Object w( PyString_FromString("my string"), true );</pre>
+
+<p>In fact, you would never do this, since PyCXX has a class String and you can just say: </p>
+
+<pre>String w( "my string" );</pre>
+
+<p>Indeed, since most of the Python C API is similarly embodied in <cite>Object</cite>
+and its descendents, you probably will not use asObject all that often.</p>
+<h3>Table 1: Class Object</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Returns</th>
+ <th>Name(signature)</th>
+ <th>Comment</th>
+ </tr>
+ <tr>
+ <td colspan="3"><p align="center"><strong>Basic Methods</strong></td>
+ </tr>
+ <tr>
+ <td class=code>explicit </td>
+ <td class=code>Object (PyObject* pyob=Py_None, bool owned=false) </td>
+ <td>Construct from pointer. </td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Object (const Object&amp; ob)</td>
+ <td>Copycons; acquires an owned reference.</td>
+ </tr>
+ <tr>
+ <td class=code>Object&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs) </td>
+ <td>Acquires an owned reference.</td>
+ </tr>
+ <tr>
+ <td class=code>Object&amp;</td>
+ <td class=code>operator= (PyObject* rhsp) </td>
+ <td>Acquires an owned reference.</td>
+ </tr>
+ <tr>
+ <td class=code>virtual</td>
+ <td class=code>~Object () </td>
+ <td>Releases the reference.</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>increment_reference_count() </td>
+ <td>Explicitly increment the count</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>decrement_reference_count()</td>
+ <td>Explicitly decrement count but not to zero</td>
+ </tr>
+ <tr>
+ <td class=code>PyObject*</td>
+ <td class=code>operator* () const</td>
+ <td>Lends the pointer</td>
+ </tr>
+ <tr>
+ <td class=code>PyObject*</td>
+ <td class=code>ptr () const</td>
+ <td>Lends the pointer</td>
+ </tr>
+ <tr>
+ <td class=code>virtual bool</td>
+ <td class=code>accepts (PyObject *pyob) const</td>
+ <td>Would assignment of pyob to this object succeed?</td>
+ </tr>
+ <tr>
+ <td class=code>std::string</td>
+ <td class=code>as_string() const</td>
+ <td>str() representation</td>
+ </tr>
+ <tr>
+ <td colspan="3" align="center"><strong>Python API Interface</strong></td>
+ </tr>
+ <tr>
+ <td class=code>int</td>
+ <td class=code>reference_count () const </td>
+ <td>reference count</td>
+ </tr>
+ <tr>
+ <td class=code>Type</td>
+ <td class=code>type () const</td>
+ <td>associated type object</td>
+ </tr>
+ <tr>
+ <td class=code>String</td>
+ <td class=code>str () const</td>
+ <td>str() representation</td>
+ </tr>
+ <tr>
+ <td class=code>String</td>
+ <td class=code>repr () const</td>
+ <td>repr () representation</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>hasAttr (const std::string&amp; s) const</td>
+ <td>hasattr(this, s)</td>
+ </tr>
+ <tr>
+ <td class=code>Object</td>
+ <td class=code>getAttr (const std::string&amp; s) const</td>
+ <td>getattr(this, s)</td>
+ </tr>
+ <tr>
+ <td class=code>Object</td>
+ <td class=code>getItem (const Object&amp; key) const</td>
+ <td>getitem(this, key)</td>
+ </tr>
+ <tr>
+ <td class=code>long</td>
+ <td class=code>hashValue () const</td>
+ <td>hash(this)</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>setAttr (const std::string&amp; s,<br>const Object&amp; value)</td>
+ <td>this.s = value</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>delAttr (const std::string&amp; s) </td>
+ <td>del this.s</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>delItem (const Object&amp; key) </td>
+ <td>del this[key]</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isCallable () const</td>
+ <td>does this have callable behavior?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isList () const</td>
+ <td>is this a Python list?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isMapping () const</td>
+ <td>does this have mapping behaviors?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isNumeric () const</td>
+ <td>does this have numeric behaviors?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isSequence () const </td>
+ <td>does this have sequence behaviors?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isTrue () const</td>
+ <td>is this true in the Python sense?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isType (const Type&amp; t) const</td>
+ <td>is type(this) == t?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isTuple() const</td>
+ <td>is this a Python tuple?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isString() const</td>
+ <td>is this a Python string?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isUnicode() const</td>
+ <td>is this a Python Unicode string?</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>isDict() const</td>
+ <td>is this a Python dictionary?</td>
+ </tr>
+ <tr>
+ <td colspan="3" align="center"><strong>Comparison Operators</strong></td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>is(PyObject* pother) const</td>
+ <td>test for identity</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>is(const Object&amp; other) const</td>
+ <td>test for identity</td>
+ </tr>
+ <tr>
+ <td class=code>bool </td>
+ <td class=code>operator==(const Object&amp; o2) const</td>
+ <td>Comparisons use Python cmp</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>operator!=(const Object&amp; o2) const</td>
+ <td>Comparisons use Python cmp</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>operator&gt;=(const Object&amp; o2) const</td>
+ <td>Comparisons use Python cmp</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>operator&lt;=(const Object&amp; o2) const </td>
+ <td>Comparisons use Python cmp</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>operator&lt;(const Object&amp; o2) const</td>
+ <td>Comparisons use Python cmp</td>
+ </tr>
+ <tr>
+ <td class=code>bool</td>
+ <td class=code>operator&gt;(const Object&amp; o2) const</td>
+ <td>Comparisons use Python cmp</td>
+ </tr>
+</table>
+
+<h1>The Basic Types</h1>
+
+<p>Corresponding to each of the basic Python types is a class that inherits from Object.
+Here are the interfaces for those types. Each of them inherits from Object and therefore
+has all of the inherited methods listed for Object. Where a virtual function is overridden
+in a class, the name is underlined. </p>
+
+<h2>Class Type</h2>
+
+<p>Class Type corresponds to Python type objects. There is no default constructor.</p>
+
+<h3>Table 2: class Type</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Returns</th>
+ <th>Name and Signature</th>
+ <th>Comments</th>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Type (PyObject* pyob, bool owned = false)</td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Type (const Object&amp; ob)</td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Type(const Type&amp; t)</td>
+ <td>Copycons</td>
+ </tr>
+ <tr>
+ <td class=code>Type&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs) </td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>Type&amp;</td>
+ <td class=code>operator= (PyObject* rhsp) </td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>virtual bool</td>
+ <td class=code><u>accepts</u> (PyObject *pyob) const</td>
+ <td>Uses PyType_Check</td>
+ </tr>
+</table>
+
+<h2>Class Int</h2>
+
+<p>Class Int, derived publically from Object, corresponds to Python ints. Note that the
+latter correspond to C long ints. Class Int has an implicit user-defined conversion to
+long int. All constructors, on the other hand, are explicit. The default constructor
+creates a Python int zero.</p>
+
+<h3>Table 3: class Int</h3>
+
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Returns</td>
+ <th>Name and Signature</td>
+ <th>Comments</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Int (PyObject *pyob, bool owned= false, bool owned = false)</td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Int (const Int&amp; ob)</td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Int (long v = 0L)</td>
+ <td>Construct from long</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Int (int v)</td>
+ <td>Contruct from int</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Int (const Object&amp; ob)</td>
+ <td>Copycons</td>
+ </tr>
+ <tr>
+ <td class=code>Int&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>Int&amp;</td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>virtual bool&nbsp;&nbsp; </td>
+ <td class=code> (PyObject *pyob) const </td>
+ <td>Based on PyInt_Check</td>
+ </tr>
+ <tr>
+ <td class=code>long</td>
+ <td class=code>operator long() const </td>
+ <td><em>Implicit</em> conversion to long int</td>
+ </tr>
+ <tr>
+ <td class=code>Int&amp;</td>
+ <td class=code>operator= (int v)</td>
+ <td>Assign from int</td>
+ </tr>
+ <tr>
+ <td class=code>Int&amp;</td>
+ <td class=code>operator= (long v) </td>
+ <td>Assign from long</td>
+ </tr>
+</table>
+
+<hr>
+
+<h2>Class Long</h2>
+
+<p>Class Long, derived publically from Object, corresponds to Python type long. In Python,
+a long is an integer type of unlimited size, and is usually used for applications such as
+cryptography, not as a normal integer. Implicit conversions to both double and long are
+provided, although the latter may of course fail if the number is actually too big. All
+constructors are explicit. The default constructor produces a Python long zero.</p>
+
+<h3>Table 4: Class Long</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Returns</td>
+ <th>Name and Signature</td>
+ <th>Comments</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Long (PyObject *pyob</a>, bool owned = false)</td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Long (const Int&amp; ob)</td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Long (long v = 0L)</td>
+ <td>Construct from long</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Long (int v)</td>
+ <td>Contruct from int</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Long (const Object&amp; ob)</td>
+ <td>Copycons</td>
+ </tr>
+ <tr>
+ <td class=code>Long&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>Long&amp;</td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>virtual bool</td>
+ <td class=code>(PyObject *pyob) const </td>
+ <td>Based on PyLong_Check</td>
+ </tr>
+ <tr>
+ <td class=code>double</td>
+ <td class=code>operator double() const </td>
+ <td><em>Implicit</em> conversion to double</td>
+ </tr>
+ <tr>
+ <td class=code>long</td>
+ <td class=code>operator long() const</td>
+ <td><em>Implicit</em> conversion to long</td>
+ </tr>
+ <tr>
+ <td class=code>Long&amp;</td>
+ <td class=code>operator= (int v)</td>
+ <td>Assign from int</td>
+ </tr>
+ <tr>
+ <td class=code>Long&amp;</td>
+ <td class=code>operator= (long v) </td>
+ <td>Assign from long</td>
+ </tr>
+</table>
+
+<h2>Class Float</h2>
+
+<p>Class Float corresponds to Python floats, which in turn correspond to C double. The
+default constructor produces the Python float 0.0. </p>
+
+<h3>Table 5: Class Float</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Returns</td>
+ <th>Name and Signature</td>
+ <th>Comments</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Float (PyObject *pyob</a>, bool owned = false)
+ </td>
+ <td>Constructor</td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>Float (const Float&amp; f)&nbsp;&nbsp; </td>
+ <td>Construct from float</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Float (double v=0.0)</td>
+ <td>Construct from double</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Float (const Object&amp; ob)</td>
+ <td>Copycons</td>
+ </tr>
+ <tr>
+ <td class=code>Float&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>Float&amp;</td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>virtual bool </td>
+ <td class=code>accepts (PyObject *pyob) const</td>
+ <td>Based on PyFloat_Check</td>
+ </tr>
+ <tr>
+ <td class=code>double </td>
+ <td class=code>operator double () const</td>
+ <td><em>Implicit</em> conversion to double</td>
+ </tr>
+ <tr>
+ <td class=code>Float&amp; </td>
+ <td class=code>operator= (double v)</td>
+ <td>Assign from double</td>
+ </tr>
+ <tr>
+ <td class=code>Float&amp; </td>
+ <td class=code>operator= (int v)</td>
+ <td>Assign from int</td>
+ </tr>
+ <tr>
+ <td class=code>Float&amp; </td>
+ <td class=code>operator= (long v)</td>
+ <td>Assign from long</td>
+ </tr>
+ <tr>
+ <td class=code>Float&amp; </td>
+ <td class=code>operator= (const Int&amp; iob)</td>
+ <td>Assign from Int</td>
+ </tr>
+</table>
+
+<h1>Sequences</h1>
+
+<p>PyCXX implements a quite sophisticated wrapper class for Python sequences. While every
+effort has been made to disguise the sophistication, it may pop up in the form of obscure
+compiler error messages, so in this documentation we will first detail normal usage and
+then discuss what is under the hood.</p>
+
+<p>The basic idea is that we would like the subscript operator [] to work properly, and to
+be able to use STL-style iterators and STL algorithms across the elements of the sequence.</p>
+
+<p>Sequences are implemented in terms of a templated base class, SeqBase&lt;T&gt;. The
+parameter T is the answer to the question, sequence of what? For Lists, for example, T is
+Object, because the most specific thing we know about an element of a List is simply that
+it is an Object. (Class List is defined below; it is a descendent of Object that holds a
+pointer to a Python list). For strings, T is Char, which is a wrapper in turn of Python
+strings whose length is one.</p>
+
+<p>For convenience, the word <strong>Sequence</strong> is a typedef of SeqBase&lt;Object&gt;.</p>
+
+<h2>General sequences</h2>
+
+<p>Suppose you are writing an extension module method that expects the first argument to
+be any kind of Python sequence, and you wish to return the length of that sequence. You
+might write:</p>
+
+<pre>static PyObject*
+my_module_seqlen (PyObject *self, PyObject* args) {
+ try
+ {
+ Tuple t(args); // set up a Tuple pointing to the arguments.
+ if(t.length() != 1)
+ throw PyException(&quot;Incorrect number of arguments to seqlen.&quot;);
+ Sequence s = t[0]; // get argument and be sure it is a sequence
+ return new_reference_to(Int(s.length()));
+ }
+ catch(const PyException&amp;)
+ {
+ return Py_Null;
+ }
+}</pre>
+
+<p>As we will explain later, the try/catch structure converts any errors, such as the
+first argument not being a sequence, into a Python exception.</p>
+
+<h3>Subscripting</h3>
+
+<p>When a sequence is subscripted, the value returned is a special kind of object which
+serves as a proxy object. The general idea of proxy objects is discussed in Scott Meyers'
+book, &quot;More Effective C++&quot;. Proxy objects are necessary because when one
+subscripts a sequence it is not clear whether the value is to be used or the location
+assigned to. Our proxy object is even more complicated than normal because a sequence
+reference such as s[i] is not a direct reference to the i'th object of s. </p>
+
+<p>In normal use, you are not supposed to notice this magic going on behind your back. You
+write:</p>
+
+<pre>Object t;
+Sequence s;
+s[2] = t + s[1]</pre>
+
+<p>and here is what happens: s[1] returns a proxy object. Since there is no addition
+operator in Object that takes a proxy as an argument, the compiler decides to invoke an
+automatic conversion of the proxy to an Object, which returns the desired component of s.
+The addition takes place, and then there is an assignment operator in the proxy class
+created by the s[2], and that assignment operator stuffs the result into the 2 component
+of s.</p>
+
+<p>It is possible to fool this mechanism and end up with a compiler failing to admit that
+a s[i] is an Object. If that happens, you can work around it by writing Object(s[i]),
+which makes the desired implicit conversion, explicit.</p>
+
+<h3>Iterators</h3>
+
+<p>Each sequence class provides the following interface. The class seqref&lt;T&gt; is the
+proxy class. We omit the details of the iterator, const_iterator, and seqref&lt;T&gt;
+here. See CXX_Objects.h if necessary. The purpose of most of this interface is to satisfy
+requirements of the STL.</p>
+
+<h3>The SeqBase&lt;T&gt; Interface</h3>
+
+<p>SeqBase&lt;T&gt; inherits from Object.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ </tr>
+ <tr>
+ <td class=code>typedef int </td>
+ <td class=code>size_type</td>
+ </tr>
+ <tr>
+ <td class=code>typedef seqref&lt;T&gt;</td>
+ <td class=code>reference</td>
+ </tr>
+ <tr>
+ <td class=code>typedef T </td>
+ <td class=code>const_reference</td>
+ </tr>
+ <tr>
+ <td class=code>typedef seqref&lt;T&gt;*</td>
+ <td class=code>pointer</td>
+ </tr>
+ <tr>
+ <td class=code>typedef int </td>
+ <td class=code>difference_type</td>
+ </tr>
+ <tr>
+ <td class=code>virtual size_type</td>
+ <td class=code>max_size() const</td>
+ </tr>
+ <tr>
+ <td class=code>virtual size_type </td>
+ <td class=code>capacity() const;</td>
+ </tr>
+ <tr>
+ <td class=code>virtual void </td>
+ <td class=code>swap(SeqBase&lt;T&gt;&amp; c);</td>
+ </tr>
+ <tr>
+ <td class=code>virtual size_type </td>
+ <td class=code>size () const;</td>
+ </tr>
+ <tr>
+ <td class=code>explicit </td>
+ <td class=code>SeqBase&lt;T&gt; ();</td>
+ </tr>
+ <tr>
+ <td class=code>explicit </td>
+ <td class=code>SeqBase&lt;T&gt; (PyObject* pyob, bool owned = false);</td>
+ </tr>
+ <tr>
+ <td class=code>explicit </td>
+ <td class=code>SeqBase&lt;T&gt; (const Object&amp; ob);</td>
+ </tr>
+ <tr>
+ <td class=code>SeqBase&lt;T&gt;&amp; </td>
+ <td class=code>operator= (const Object&amp; rhs);</td>
+ </tr>
+ <tr>
+ <td class=code>SeqBase&lt;T&gt;&amp; </td>
+ <td class=code>operator= (PyObject* rhsp);</td>
+ </tr>
+ <tr>
+ <td class=code>virtual bool </td>
+ <td class=code>accepts (PyObject *pyob) const;</td>
+ </tr>
+ <tr>
+ <td class=code>size_type </td>
+ <td class=code>length () const ;</td>
+ </tr>
+ <tr>
+ <td class=code>const T </td>
+ <td class=code>operator[](size_type index) const; </td>
+ </tr>
+ <tr>
+ <td class=code>seqref&lt;T&gt; </td>
+ <td class=code>operator[](size_type index); </td>
+ </tr>
+ <tr>
+ <td class=code>virtual T </td>
+ <td class=code>getItem (size_type i) const;</td>
+ </tr>
+ <tr>
+ <td class=code>virtual void </td>
+ <td class=code>setItem (size_type i, const T&amp; ob);</td>
+ </tr>
+ <tr>
+ <td class=code>SeqBase&lt;T&gt; </td>
+ <td class=code>repeat (int count) const;</td>
+ </tr>
+ <tr>
+ <td class=code>SeqBase&lt;T&gt; </td>
+ <td class=code>concat (const SeqBase&lt;T&gt;&amp; other) const ;</td>
+ </tr>
+ <tr>
+ <td class=code>const T </td>
+ <td class=code>front () const;</td>
+ </tr>
+ <tr>
+ <td class=code>seqref&lt;T&gt; </td>
+ <td class=code>front();</td>
+ </tr>
+ <tr>
+ <td class=code>const T </td>
+ <td class=code>back () const;</td>
+ </tr>
+ <tr>
+ <td class=code>seqref&lt;T&gt; </td>
+ <td class=code>back(); </td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>verify_length(size_type required_size);</td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>verify_length(size_type min_size, size_type max_size);</td>
+ </tr>
+ <tr>
+ <td class=code>class</td>
+ <td class=code>iterator;</td>
+ </tr>
+ <tr>
+ <td class=code>iterator </td>
+ <td class=code>begin (); </td>
+ </tr>
+ <tr>
+ <td class=code>iterator </td>
+ <td class=code>end ();</td>
+ </tr>
+ <tr>
+ <td class=code>class </td>
+ <td class=code>const_iterator;</td>
+ </tr>
+ <tr>
+ <td class=code>const_iterator </td>
+ <td class=code>begin () const;</td>
+ </tr>
+ <tr>
+ <td class=code>const_iterator </td>
+ <td class=code>end () const;</td>
+ </tr>
+</table>
+
+<p>Any heir of class Object that has a sequence behavior should inherit from class
+SeqBase&lt;T&gt;, where T is specified as the type of object that represents the
+individual elements of the sequence. The requirements on T are that it has a constructor
+that takes a PyObject* as an argument, that it has a default constructor, a copy
+constructor, and an assignment operator. In short, any properly defined heir of Object
+will work. </p>
+
+<h2>Classes Char and String</h2>
+
+<p>Python strings are unusual in that they are immutable sequences of characters. However,
+there is no character type per se; rather, when subscripted strings return a string of
+length one. To simulate this, we define two classes Char and String. The Char class
+represents a Python string object of length one. The String class represents a Python
+string, and its elements make up a sequence of Char's.</p>
+
+<p>The user interface for Char is limited. Unlike String, for example, it is not a
+sequence.</p>
+
+<h3>The Char interface</h3>
+
+<p>Char inherits from Object.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Char (PyObject *pyob, bool owned = false)</td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>Char (const Object&amp; ob) </td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>Char (const std::string&amp; v = &quot;&quot;) </td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>Char (char v)</td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>Char (Py_UNICODE v)</td>
+ </tr>
+ <tr>
+ <td class=code>Char&amp;</td>
+ <td class=code>operator= (const std::string&amp; v)</td>
+ </tr>
+ <tr>
+ <td class=code>Char&amp;</td>
+ <td class=code>operator= (char v) </td>
+ </tr>
+ <tr>
+ <td class=code>Char&amp;</td>
+ <td class=code>operator= (Py_UNICODE v) </td>
+ </tr>
+ <tr>
+ <td class=code>Char&amp;</td>
+ <td class=code>operator= (std::basic_string<Py_UNICODE> v) </td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>operator String() const</td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>operator std::string () const </td>
+ </tr>
+</table>
+
+<h3>The String Interface</h3>
+
+<p>String inherits from SeqBase&lt;Char&gt;.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ </tr>
+ <tr>
+ <td class=code>explicit </td>
+ <td class=code>String (PyObject *pyob, bool owned = false)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const Object&amp; ob)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const std::string&amp; v = &quot;&quot;)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const std::string&amp; v, const char *encoding, const char *error=&quot;strict&quot;)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const char *s, const char *encoding, const char *error=&quot;strict&quot;)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const char *s, int len, const char *encoding, const char *error=&quot;strict&quot;)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const std::string&amp; v, std::string::size_type vsize)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>String (const char* v)</td>
+ </tr>
+ <tr>
+ <td class=code>String&amp;</td>
+ <td class=code>operator= (const std::string&amp; v) </td>
+ </tr>
+ <tr>
+ <td class=code>std::string</td>
+ <td class=code>operator std::string () const</td>
+ </tr>
+ <tr>
+ <td class=code>String</td>
+ <td class=code>encode( const char *encoding, const char *error=&quot;strict&quot; )</td>
+ </tr>
+ <tr>
+ <td class=code>String</td>
+ <td class=code>decode( const char *encoding, const char *error=&quot;strict&quot; )</td>
+ </tr>
+ <tr>
+ <td class=code>std::string</td>
+ <td class=code>as_std_string() const</td>
+ </tr>
+ <tr>
+ <td class=code>unicodestring</td>
+ <td class=code>as_unicodestring() const</td>
+ </tr>
+</table>
+
+<h2>Class Tuple</h2>
+
+<p>Class Tuple represents Python tuples. A Tuple is a Sequence. There are two kinds of
+constructors: one takes a PyObject* as usual, the other takes an integer number as an
+argument and returns a Tuple of that length, each component initialized to Py_None. The
+default constructor produces an empty Tuple. </p>
+
+<p>Tuples are not immutable, but attempts to assign to their components will fail if the
+reference count is not 1. That is, it is safe to set the elements of a Tuple you have just
+made, but not thereafter.</p>
+
+<p>Example: create a Tuple containing (1, 2, 4)</p>
+
+<pre>Tuple t(3)
+t[0] = Int(1)
+t[1] = Int(2)
+t[2] = Int(4)</pre>
+
+<p>Example: create a Tuple from a list:</p>
+
+<pre>Dict d
+...
+Tuple t(d.keys())</pre>
+
+<h3>The Tuple Interface</h3>
+
+<p>Tuple inherits from Sequence.. Special run-time checks prevent modification if the
+reference count is greater than one.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>virtual void</td>
+ <td class=code>setItem (int offset, const Object&amp;ob) </td>
+ <td>setItem is overriden to handle tuples properly. </td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Tuple (PyObject *pyob, bool owned = false)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>Tuple (const Object&amp; ob)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Tuple (int size = 0)</td>
+ <td>Create a tuple of the given size. Items initialize to Py_None. Default is an empty
+ tuple.</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Tuple (const Sequence&amp; s)</td>
+ <td>Create a tuple from any sequence.</td>
+ </tr>
+ <tr>
+ <td class=code>Tuple&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>Tuple&amp;</td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>Tuple</td>
+ <td class=code>getSlice (int i, int j) const </td>
+ <td>Equivalent to python's t[i:j]</td>
+ </tr>
+</table>
+
+<h2>Class List</h2>
+
+<p>Class List represents a Python list, and the methods available faithfully reproduce the
+Python API for lists. A List is a Sequence.</p>
+
+<h3>The List Interface</h3>
+
+<p>List inherits from Sequence.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>List (PyObject *pyob, bool owned = false)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>List (const Object&amp; ob)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>List (int size = 0)</td>
+ <td>Create a list of the given size. Items initialized to Py_None. Default is an empty list.</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>List (const Sequence&amp; s)</td>
+ <td>Create a list from any sequence.</td>
+ </tr>
+ <tr>
+ <td class=code>List&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>List&amp;</td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>List</td>
+ <td class=code>getSlice (int i, int j) const</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>setSlice (int i, int j, const Object&amp; v) </td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>append (const Object&amp; ob)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>insert (int i, const Object&amp; ob)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>sort ()</td>
+ <td>Sorts the list in place, using Python's member function. You can also use
+ the STL sort function on any List instance.</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>reverse ()</td>
+ <td>Reverses the list in place, using Python's member function.</td>
+ </tr>
+</table>
+
+<h1>Mappings</h1>
+
+<p>A class MapBase&lt;T&gt; is used as the base class for Python objects with a mapping
+behavior. The key behavior of this class is the ability to set and use items by
+subscripting with strings. A proxy class mapref&lt;T&gt; is defined to produce the correct
+behavior for both use and assignment.</p>
+
+<p>For convenience, <cite>Mapping</cite> is a typedef for <cite>MapBase&lt;Object&gt;</cite>.</p>
+
+<h3>The MapBase&lt;T&gt; interface</h3>
+
+<p>MapBase&lt;T&gt; inherits from Object. T should be chosen to reflect the kind of
+element returned by the mapping.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>T</td>
+ <td class=code>operator[](const std::string&amp; key) const</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>mapref&lt;T&gt; </td>
+ <td class=code>operator[](const std::string&amp; key)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>int</td>
+ <td class=code>length () const</td>
+ <td>Number of entries.</td>
+ </tr>
+ <tr>
+ <td class=code>int</td>
+ <td class=code>hasKey (const std::string&amp; s) const </td>
+ <td>Is m[s] defined?</td>
+ </tr>
+ <tr>
+ <td class=code>T</td>
+ <td class=code>getItem (const std::string&amp; s) const</td>
+ <td>m[s]</td>
+ </tr>
+ <tr>
+ <td class=code>virtual void</td>
+ <td class=code>setItem (const std::string&amp; s, const Object&amp; ob)</td>
+ <td>m[s] = ob</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>delItem (const std::string&amp; s)</td>
+ <td>del m[s]</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>delItem (const Object&amp; s)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>List</td>
+ <td class=code>keys () const</td>
+ <td>A list of the keys.</td>
+ </tr>
+ <tr>
+ <td class=code>List</td>
+ <td class=code>values () const</td>
+ <td>A list of the values.</td>
+ </tr>
+ <tr>
+ <td class=code>List</td>
+ <td class=code>items () const</td>
+ <td>Each item is a key-value pair.</td>
+ </tr>
+</table>
+
+<h2>Class Dict</h2>
+
+<p>Class Dict represents Python dictionarys. A Dict is a Mapping. Assignment to
+subscripts can be used to set the components.</p>
+
+<pre>Dict d
+d[&quot;Paul Dubois&quot;] = &quot;(925)-422-5426&quot;</pre>
+
+<h3>Interface for Class Dict</h3>
+
+<p>Dict inherits from MapBase&lt;Object&gt;.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Dict (PyObject *pyob</a>, bool owned = false)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>Dict (const Dict&amp; ob)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>Dict () </td>
+ <td>Creates an empty dictionary</td>
+ </tr>
+ <tr>
+ <td class=code>Dict&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>Dict&amp;</td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td></td>
+ </tr>
+</table>
+
+<h1>Other classes and facilities.</h1>
+
+<p>Class Callable provides an interface to those Python objects that support a call
+method. Class Module holds a pointer to a module. If you want to create an extension
+module, however, see the extension facility. There is a large set of numeric operators.</p>
+
+<h3>Interface to class Callable</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Callable (PyObject *pyob</a>, bool owned = false)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>Callable&amp; </td>
+ <td class=code>operator= (const Object&amp; rhs)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>Callable&amp; </td>
+ <td class=code>operator= (PyObject* rhsp)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>Object</td>
+ <td class=code>apply(const Tuple&amp; args) const</td>
+ <td>Call the object with the given arguments</td>
+ </tr>
+ <tr>
+ <td class=code>Object</td>
+ <td class=code>apply(PyObject* pargs = 0) const </td>
+ <td>Call the object with args as the arguments. Checks that pargs is a tuple.</td>
+ </tr>
+</table>
+
+<h3>Interface to class Module</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Module (PyObject* pyob, bool owned = false)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>Module (const std::string name)</td>
+ <td>Construct from name of module; does the import if needed.</td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td class=code>Module (const Module&amp; ob) </td>
+ <td>Copy constructor</td>
+ </tr>
+ <tr>
+ <td class=code>Module&amp;</td>
+ <td class=code>operator= (const Object&amp; rhs) </td>
+ <td>Assignment</td>
+ </tr>
+ <tr>
+ <td class=code>Module&amp;</td>
+ <td class=code>operator= (PyObject* rhsp) </td>
+ <td>Assignment</td>
+ </tr>
+</table>
+
+<h3>Numeric interface</h3>
+
+<p>Unary operators for plus and minus, and binary operators +, -, *, /, and % are defined
+for pairs of objects and for objects with scalar integers or doubles (in either
+order). Functions abs(ob) and coerce(o1, o2) are also defined. </p>
+
+<p>The signature for coerce is:</p>
+
+<pre>inline std::pair&lt;Object,Object&gt; coerce(const Object&amp; a, const Object&amp; b)</pre>
+
+<p>Unlike the C API function, this simply returns the pair after coercion.</p>
+
+<h3>Stream I/O</h3>
+
+<p>Any object can be printed using stream I/O, using std::ostream&amp; operator&lt;&lt;
+(std::ostream&amp; os, const Object&amp; ob). The object's str() representation is
+converted to a standard string which is passed to std::ostream&amp; operator&lt;&lt;
+(std::ostream&amp; os, const std::string&amp;).</p>
+
+<h2>Exceptions</h2>
+
+<p>The Python exception facility and the C++ exception facility can be merged via the use
+of try/catch blocks in the bodies of extension objects and module functions.</p>
+
+<h3>Class Exception and its children</h3>
+
+<p>A set of classes is provided. Each is derived from class Exception, and represents a
+particular sort of Python exception, such as IndexError, RuntimeError, ValueError. Each of
+them (other than Exception) has a constructor which takes an explanatory string as an
+argument, and is used in a throw statement such as:</p>
+
+<pre>throw IndexError(&quot;Index too large in MyObject access.&quot;);</pre>
+
+<p>If in using a routine from the Python API, you discover that it has returned a NULL
+indicating an error, then Python has already set the error message. In that case you
+merely throw Exception.</p>
+
+<h3>List of Exceptions</h3>
+
+<p>The exception hierarchy mirrors the Python exception hierarchy. The concrete exception
+classes are shown here.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</th>
+ <th>Interface for class Exception</th>
+ </tr>
+ <tr>
+ <td class=code>explicit </td>
+ <td class=code>Exception()</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>Exception (const std::string&amp; reason) </td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>Exception (PyObject* exception, const std::string&amp; reason) </td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>clear()</td>
+ </tr>
+ <tr>
+ <td class=code></td>
+ <td>Constructors for other children of class Exception</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>TypeError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>IndexError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>AttributeError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>NameError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>RuntimeError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>SystemError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>KeyError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>ValueError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>OverflowError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>ZeroDivisionError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>MemoryError (const std::string&amp; reason)</td>
+ </tr>
+ <tr>
+ <td class=code> </td>
+ <td class=code>SystemExit (const std::string&amp; reason)</td>
+ </tr>
+</table>
+
+<h2>Using Exceptions in extension methods</h2>
+
+<p>The exception facility allows you to integrate the C++ and Python exception mechanisms.
+To do this, you must use the style described below when writing module methods in the old
+C style. </p>
+
+<p>Note: If using the ExtensionModule or PythonExtension mechanisms described below, the
+method handlers include exception handling so that you only need to use exceptions
+explicitly in unusual cases.</p>
+
+<h3>Catching Exceptions from the Python API or PyCXX.</h3>
+
+<p>When writing an extension module method, you can use the following boilerplate. Any
+exceptions caused by the Python API or PyCXX itself will be converted into a Python
+exception. Note that Exception is the most general of the exceptions listed above, and
+therefore this one catch clause will serve to catch all of them. You may wish to catch
+other exceptions, not in the Exception family, in the same way. If so, you need to make
+sure you set the error in Python before returning.</p>
+
+<pre>static PyObject *
+some_module_method(PyObject* self, PyObject* args)
+{
+ Tuple a(args); // we know args is a Tuple
+ try {
+ ...calculate something from a...
+ return ...something, usually of the form new_reference_to(some Object);
+ }
+ catch(const Exception&amp;) {
+ //Exception caught, passing it on to Python
+ return Null ();
+ }
+}
+</pre>
+
+<h3>How to clear an Exception</h3>
+
+<p>If you anticipate that an Exception may be thrown and wish to recover from it, change
+the catch phrase to set a reference to an Exception, and use the method clear() from class
+Exception to clear it.:</p>
+
+<pre>catch(Exception&amp; e)
+ {
+ e.clear();
+ ...now decide what to do about it...
+ }
+</pre>
+
+<h2>Extension Facilities</h2>
+
+<p>CXX/Extensions.hxx provides facilities for:
+
+<ul>
+ <li>Creating a Python extension module</li>
+ <li>Creating new Python extension types</li>
+</ul>
+
+<p>These facilities use CXX/Objects.hxx and its support file cxxsupport.cxx.</p>
+
+<p>If you use CXX/Extensions.hxx you must also include source files cxxextensions.c and
+cxx_extensions.cxx</p>
+
+<h3>Creating an Python extension module</h3>
+
+<p>The usual method of creating a Python extension module is to declare and initialize its
+method table in C. This requires knowledge of the correct form for the table and the order
+in which entries are to be made into it, and requires casts to get everything to compile
+without warning. The PyCXX header file CXX/Extensions.h offers a simpler method. Here is a
+sample usage, in which a module named &quot;example&quot; is created. Note that two
+details are necessary:
+
+<ul>
+ <li>The initialization function must be declared to have external C linkage and to have the
+ expected name. This is a requirement imposed by Python</li>
+ <li>The ExtensionModule object must have a storage class that survives the call to the
+ initialization function. This is most easily accomplished by using a static local inside
+ the initialization function, as in initexample below.</li>
+</ul>
+
+<p>To create an extension module, you inherit from class ExtensionModule templated on
+yourself: In the constructor, you make calls to register methods of this class with Python
+as extension module methods. In this example, two methods are added (this is a simplified
+form of the example in Demo/example.cxx):</p>
+
+<pre>class example_module : public ExtensionModule&lt;example_module&gt;
+{
+public:
+ example_module()
+ : ExtensionModule&lt;example_module&gt;( &quot;example&quot; )
+ {
+ add_varargs_method(&quot;sum&quot;, &amp;example_module::ex_sum, &quot;sum(arglist) = sum of arguments&quot;);
+ add_varargs_method(&quot;test&quot;, &amp;example_module::ex_test, &quot;test(arglist) runs a test suite&quot;);
+
+ initialize( &quot;documentation for the example module&quot; );
+ }
+
+ virtual ~example_module() {}
+
+private:
+ Object ex_sum(const Tuple &amp;a) { ... }
+ Object ex_test(const Tuple &amp;a) { ... }
+};
+</pre>
+
+<p>To initialize the extension, you just instantiate one static instance (static so it
+does not destroy itself!):</p>
+
+<pre>void initexample()
+{
+static example_module* example = new example_module;
+}</pre>
+
+<p>The methods can be written to take Tuples as arguments and return Objects. If
+exceptions occur they are trapped for you and a Python exception is generated. So, for
+example, the implementation of ex_sum might be:</p>
+
+<pre>Object ex_sum (const Tuple &amp;a)
+ {
+ Float f(0.0);
+ for( int i = 0; i &lt; a.length(); i++ )
+ {
+ Float g(a[i]);
+ f = f + g;
+ }
+ return f;
+ }</pre>
+
+<p>class ExtensionModule contains methods to return itself as a Module object, or to
+return its dictionary.</p>
+
+<h3>Interface to class ExtensionModule</h3>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>explicit</td>
+ <td class=code>ExtensionModule (char* name) </td>
+ <td>Create an extension module named &quot;name&quot;</td>
+ </tr>
+ <tr>
+ <td class=code>virtual </td>
+ <td class=code>~ExtensionModule () </td>
+ <td>Destructor</td>
+ </tr>
+ <tr>
+ <td class=code>Dict</td>
+ <td class=code>moduleDictionary() const</td>
+ <td>Returns the module dictionary; module must be initialized.</td>
+ </tr>
+ <tr>
+ <td class=code>Module</td>
+ <td class=code>module() const</td>
+ <td>This module as a Module.</td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>add_varargs_method (char *name, method_varargs_function_t method, char *documentation=&quot;&quot;)</td>
+ <td>Add a method to the module.</td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>add_keyword_method (char *name, method_keyword_function_t method, char *documentation=&quot;&quot;</td>
+ <td>Add a method that takes keywords</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>initialize() (protected, call from constructor)</td>
+ <td>Initialize the module once all methods have been added. </td>
+ </tr>
+</table>
+
+<p>The signatures above are:</p>
+
+<pre>typedef Object (T::*method_varargs_function_t)( const Tuple &amp;args );
+typedef Object (T::*method_keyword_function_t)( const Tuple &amp;args, const Dict &amp;kws
+);</pre>
+
+<p>That is, the methods take a Tuple or a Tuple and a Dict, and return an Object. The
+example below has an &amp; in front of the name of the method; we found one compiler that
+needed this.</p>
+
+<h2>Creating a Python extension type</h2>
+
+<p>One of the great things about Python is the way you can create your own object types
+and have Python welcome them as first-class citizens. Unfortunately, part of the way you
+have to do this is not great. Key to the process is the creation of a Python &quot;type
+object&quot;. All instances of this type must share a reference to this one unique type
+object. The type object itself has a multitude of &quot;slots&quot; into which the
+addresses of functions can be added in order to give the object the desired behavior. </p>
+
+<p>Creating extension objects is of course harder since you must specify
+how the object behaves and give it methods. This is shown in some detail in the example
+range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo. If you have never
+created a Python extension before, you should read the Extension manual first and be very
+familiar with Python's &quot;special class methods&quot;. Then what follows will make more
+sense.</p>
+
+<p>The basic idea is to inherit from PythonExtension templated on your self</p>
+
+<pre>class MyObject: public PythonExtension&lt;MyObject&gt; {...}</pre>
+
+<p>As a consequence:
+
+<ul>
+ <li>MyObject is a child of PyObject, so that a MyObject* is-a PyObject*. </li>
+ <li>A static method <cite>check(PyObject*)</cite> is created in class MyObject. This function
+ returns a boolean, testing whether or not the argument is in fact a pointer to an instance
+ of MyObject.</li>
+ <li>The user can connect methods of MyObject to Python so that they are methods on MyObject
+ objects. Each such method has the signature:<br>
+ Object method_name (const Tuple&amp; args).</li>
+ <li>The user can override virtual methods of PythonExtension in order to set behaviors.</li>
+ <li>A method is created to handle the deletion of an instance if and when its reference
+ count goes to zero. This method ensures the calling of the class destructor ~MyObject(),
+ if any, and releases the memory (see below).</li>
+ <li>Both automatic and heap-based instances of MyObject can be created.</li>
+</ul>
+
+<h3>Sample usage of PythonExtension</h3>
+
+<p>Here is a brief overview. You create a class that inherits from PythonExtension
+templated upon itself. You override various methods from PythonExtension to implement
+behaviors, such as getattr, sequence_item, etc. You can also add methods to the object
+that are usable from Python using a similar scheme as for module methods above. </p>
+
+<p>One of the consequences of inheriting from PythonExtension is that you are inheriting
+from PyObject itself. So your class is-a PyObject and instances of it can be passed to the
+Python C API. Note: this example uses the namespace feature of PyCXX.</p>
+
+<p>Hint: You can avoid needing to specify the Py:: prefix if you include the C++ statement
+<cite>using Py;</cite> at the top of your files.</p>
+
+<pre>class range: public Py::PythonExtension&lt;range&gt; {
+public:
+ ... constructors, data, etc.
+ ... methods not callable from Python
+ // initializer, see below
+ static void init_type();
+ // override functions from PythonExtension
+ virtual Py::Object repr();
+ virtual Py::Object getattr( const char *name );
+
+ virtual int sequence_length();
+ virtual Py::Object sequence_item( int i );
+ virtual Py::Object sequence_concat( const Py::Object &amp;j );
+ virtual Py::Object sequence_slice( int i, int j );
+
+ // define python methods of this object
+ Py::Object amethod (const Py::Tuple&amp; args);
+ Py::Object value (const Py::Tuple&amp; args);
+ Py::Object assign (const Py::Tuple&amp; args);
+};</pre>
+
+<p>
+To initialize the type we provide a static method that we can call from some module's
+initializer. We set the name, doc string, and indicate which behaviors range objects
+support. Then we adds the methods.</p>
+
+<pre>void range::init_type()
+{
+ behaviors().name(&quot;range&quot;);
+ behaviors().doc(&quot;range objects: start, stop, step&quot;);
+ behaviors().supportRepr();
+ behaviors().supportGetattr();
+ behaviors().supportSequenceType();
+
+ add_varargs_method(&quot;amethod&quot;, &amp;range::amethod,
+ &quot;demonstrate how to document amethod&quot;);
+ add_varargs_method(&quot;assign&quot;, &amp;range::assign);
+ add_varargs_method(&quot;value&quot;, &amp;range::value);
+}</pre>
+</a>
+
+<p>Do not forget to add the call range::init_type() to some module's init function. You will want
+a method in some module that can create range objects, too.</p>
+
+<h3>Interface to PythonExtension &lt;T&gt;</h3>
+
+<p>Your extension class T inherits PythonExtension&lt;T&gt;.</p>
+
+<table cellspacing=0 cellpadding=3px width="95%">
+ <tr>
+ <th>Type</td>
+ <th>Name</td>
+ <th>Comment</td>
+ </tr>
+ <tr>
+ <td class=code>virtual </td>
+ <td class=code>~PythonExtension&lt;T&gt;() </td>
+ <td>Destructor</td>
+ </tr>
+ <tr>
+ <td class=code>PyTypeObject* </td>
+ <td class=code>type_object() const</td>
+ <td>Returns the object type object.</td>
+ </tr>
+ <tr>
+ <td class=code>int</td>
+ <td class=code>check (PyObject* p)</td>
+ <td>Is p a T?</td>
+ </tr>
+ <tr>
+ <td colspan="3"><strong>Protected </strong></td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>add_varargs_method (char *name, method_keyword_function_t method, char *documentation=&quot;&quot;</td>
+ <td>Add a method that takes arguments</td>
+ </tr>
+ <tr>
+ <td class=code>void </td>
+ <td class=code>add_keyword_method (char *name, method_keyword_function_t method, char *documentation=&quot;&quot;</td>
+ <td>Add a method that takes keywords</td>
+ </tr>
+ <tr>
+ <td class=code>static PythonType&amp;</td>
+ <td class=code>behaviors()</td>
+ <td>The type object</td>
+ </tr>
+ <tr>
+ <td class=code>void</td>
+ <td class=code>initialize() (protected, call from constructor)</td>
+ <td>Initialize the module once all methods have been added. </td>
+ </tr>
+</table>
+
+<p>As before the signatures for the methods are Object mymethod(const Tuple&amp;
+args) and Object mykeywordmethod (const Tuple&amp; args, const Dict&amp; keys). In this
+case, the methods must be methods of T.</p>
+
+<p>To set the behaviors of the object you override some or all of these methods from
+PythonExtension&lt;T&gt;:</p>
+
+<pre> virtual int print( FILE *, int );
+ virtual Object getattr( const char * );
+ virtual int setattr( const char *, const Object &amp; );
+ virtual Object getattro( const Object &amp; );
+ virtual int setattro( const Object &amp;, const Object &amp; );
+ virtual int compare( const Object &amp; );
+ virtual Object repr();
+ virtual Object str();
+ virtual long hash();
+ virtual Object call( const Object &amp;, const Object &amp; );
+
+ // Sequence methods
+ virtual int sequence_length();
+ virtual Object sequence_concat( const Object &amp; );
+ virtual Object sequence_repeat( int );
+ virtual Object sequence_item( int );
+ virtual Object sequence_slice( int, int );
+ virtual int sequence_ass_item( int, const Object &amp; );
+ virtual int sequence_ass_slice( int, int, const Object &amp; );
+
+ // Mapping
+ virtual int mapping_length();
+ virtual Object mapping_subscript( const Object &amp; );
+ virtual int mapping_ass_subscript( const Object &amp;, const Object &amp; );
+
+ // Number
+ virtual int number_nonzero();
+ virtual Object number_negative();
+ virtual Object number_positive();
+ virtual Object number_absolute();
+ virtual Object number_invert();
+ virtual Object number_int();
+ virtual Object number_float();
+ virtual Object number_long();
+ virtual Object number_oct();
+ virtual Object number_hex();
+ virtual Object number_add( const Object &amp; );
+ virtual Object number_subtract( const Object &amp; );
+ virtual Object number_multiply( const Object &amp; );
+ virtual Object number_divide( const Object &amp; );
+ virtual Object number_remainder( const Object &amp; );
+ virtual Object number_divmod( const Object &amp; );
+ virtual Object number_lshift( const Object &amp; );
+ virtual Object number_rshift( const Object &amp; );
+ virtual Object number_and( const Object &amp; );
+ virtual Object number_xor( const Object &amp; );
+ virtual Object number_or( const Object &amp; );
+ virtual Object number_power( const Object &amp;, const Object &amp; );
+
+ // Buffer
+ virtual int buffer_getreadbuffer( int, void** );
+ virtual int buffer_getwritebuffer( int, void** );
+ virtual int buffer_getsegcount( int* );</pre>
+
+<p>Note that dealloc is not one of the functions you can override. That is what your
+destructor is for. As noted below, dealloc behavior is provided for you by
+PythonExtension.</p>
+
+<h3>Type initialization</h3>
+
+<p>To initialize your type, supply a static public member function that can be called
+from the extension module. In that function, obtain the PythonType object by calling
+behaviors() and apply appropriate &quot;support&quot; methods from PythonType to turn on
+the support for that behavior or set of behaviors.</p>
+
+<pre> void supportPrint(void);
+ void supportGetattr(void);
+ void supportSetattr(void);
+ void supportGetattro(void);
+ void supportSetattro(void);
+ void supportCompare(void);
+ void supportRepr(void);
+ void supportStr(void);
+ void supportHash(void);
+ void supportCall(void);
+
+ void supportSequenceType(void);
+ void supportMappingType(void);
+ void supportNumberType(void);
+ void supportBufferType(void);</pre>
+
+<p>Then call add_varargs_method or add_keyword_method to add any methods desired to the
+object.</p>
+
+<h3>Notes on memory management and extension objects</h3>
+
+<p>Normal Python objects exist only on the heap. That is unfortunate, as object creation
+and destruction can be relatively expensive. Class PythonExtension allows creation of both
+local and heap-based objects.</p>
+
+<p>If an extension object is created using operator new, as in:</p>
+
+<pre>range* my_r_ref = new range(1, 20, 3)</pre>
+
+<p>then the entity my_r_ref can be thought of as &quot;owning&quot; the reference created
+in the new object. Thus, the object will never have a reference count of zero. If the
+creator wishes to delete this object, they should either make sure the reference count is
+1 and then do delete my_r_ref, or decrement the reference with Py_DECREF(my_r_ref).</p>
+
+<p>Should my_r_ref give up ownership by being used in an Object constructor, all will
+still be well. When the Object goes out of scope its destructor will be called, and that
+will decrement the reference count, which in turn will trigger the special dealloc routine
+that calls the destructor and deletes the pointer.</p>
+
+<p>If the object is created with automatic scope, as in:</p>
+
+<pre>range my_r(1, 20, 3)</pre>
+
+<p>then my_r can be thought of as owning the reference, and when my_r goes out of scope
+the object will be destroyed. Of course, care must be taken not to have kept any permanent
+reference to this object. Fortunately, in the case of an exception, the C++ exception
+facility will call the destructor of my_r. Naturally, care must be taken not to end up
+with a dangling reference, but such objects can be created and destroyed more efficiently
+than heap-based PyObjects.</p>
+
+<h2>Putting it all together</h2>
+
+<p>The Demo directory of the distribution contains an extensive example of how to use many
+of the facilities in PyCXX. It also serves as a test routine. This test is not completely
+exhaustive but does excercise much of the facility.</p>
+
+<h2>Acknowledgment</h2>
+
+<p>Thank you to Geoffrey Furnish for patiently teaching me the finer points of C++ and its
+template facility, and his critique of PyCXX in particular. With version 4 I welcome Barry
+Scott as co-author. -- Paul Dubois</p>
+
+</body>
+</html>
diff --git a/lib/kross/python/cxx/README.html b/lib/kross/python/cxx/README.html
new file mode 100644
index 00000000..d698725a
--- /dev/null
+++ b/lib/kross/python/cxx/README.html
@@ -0,0 +1,436 @@
+<html>
+
+<head>
+<title>PyCXX README</title>
+
+<style>
+H1, H2, H3, H4 {color: #000099;
+ background-color: lightskyblue}
+h3 {position: relative; left: 20px}
+
+p {position: relative; left: 20px; margin-right: 20px}
+pre {color: #0000cc; background-color: #eeeeee; position: relative; left: 40px; margin-right: 80px;
+ border-style: solid; border-color: black; border-width: thin}
+kbd {color: #990000}
+p cite, ol cite, ul cite {font-family: monospace; font-style: normal; font-size: normal}
+li var, pre var, p var, kbd var {color: #009900; font-style: italic}
+li samp, pre samp, p samp, kbd samp {color: #009900; font-weight: bold}
+li p {position: relative; left: 0}
+table { position: relative; left: 20px; border: solid #888888 1px; background-color: #eeeeee}
+table th {border: solid #888888 1px; background-color: #88dd88; color: black}
+table td {border: solid #888888 1px}
+table td.code {border: solid #888888 1px;font-family: monospace; font-style: normal; font-size: normal}
+p.param {background-color: #eeeeee; border-top: lightskyblue solid 4}
+</style>
+</head>
+
+<body>
+
+<h1>PyCXX -- Python C++ Extensions Support</h1>
+
+<h2>Installation using distutils</h2>
+
+<h3>Windows Installation and Demo</h3>
+<ol>
+<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz">
+http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz</a>
+<li>Expand the archive into a directory of your choosing C:\ for example. Note: WinZip can expand .tar.gz files.
+<li>Install the PyCXX files:
+<ol>
+<li><pre>C:> cd \pycxx_5_3_1</pre>
+<li><pre>C:\pycxx_5_3_1> python setup.py install</pre>
+</ol>
+<li>Install the PyCXX Demo:
+<ol>
+<li><pre>C:> cd \PYCXX_5_3_1\Demo</pre>
+<li><pre>C:\PYCXX_5_3_1\Demo> python setup.py install</pre>
+</ol>
+<li>Run the demo:
+<ol>
+<li><pre>C:> python</pre>
+<li><pre>&gt;&gt;&gt; import CXX.example</pre>
+<li><pre>&gt;&gt;&gt; CXX.example.test()</pre>
+<li><pre>&gt;&gt;&gt; r = CXX.example.range( 11, 100, 13 )</pre>
+<li><pre>&gt;&gt;&gt; for i in r: print i</pre>
+<li><pre>...</pre>
+</ol>
+</ul>
+</ol>
+
+
+<h3>Unix Installation and Demo</h3>
+<p>Note: distutils is not available for Python 1.5.2</p>
+
+<ol>
+<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz">
+http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz</a>
+<li>Login as root. root access is typically needed on Unix systems to install the PyCXX files into the Python directories.
+<li>Expand the archive into a directory of your choosing ~\ for example.
+<li>Install the PyCXX files:
+<ol>
+<li><pre># cd ~\PYCXX_5_3_1</pre>
+<li><pre># python setup.py install</pre>
+</ol>
+<li>Install the PyCXX Demo:
+<ol>
+<li><pre># cd ~\PYCXX_5_3_1\Demo</pre>
+<li><pre># python setup.py install</pre>
+</ol>
+<li>Run the demo:
+<ol>
+<li><pre>~ python</pre>
+<li><pre>&gt;&gt;&gt; import CXX.example</pre>
+<li><pre>&gt;&gt;&gt; CXX.example.test()</pre>
+<li><pre>&gt;&gt;&gt; r = CXX.example.range( 11, 100, 13 )</pre>
+<li><pre>&gt;&gt;&gt; for i in r: print i</pre>
+<li><pre>...</pre>
+</ol>
+</ul>
+</ol>
+
+<h2>Installation using Project and Makefile</h2>
+
+<p>If you cannot or do not wish to use the distutils methods to work with PyCXX a set
+of Makefiles and Project files are provided.</p>
+
+<h3>Windows Installation and Demo</h3>
+<p>
+<ol>
+<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz">
+http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz</a>
+<li>Expand the archive into a directory of your choosing C:\ for example. WinZip can expand .tar.gz files.
+<li>Build the example. Using Microsoft Visual C++ 6.0 load the workspace corresponsing to the version of
+Python you wish the work with.
+<ul>
+<li>example_py15.dsw - Python 1.5.2
+<li>example_py20.dsw - Python 2.0 and 2.0.1
+<li>example_py21.dsw - Python 2.1 and 2.1.1
+<li>example_py22.dsw - Python 2.2 and its maintanence release
+<li>example_py23.dsw - Python 2.3 and its maintanence release
+</ul>
+<li>Run the example. (I'll assume you are testing Python 2.3)
+<ul>
+<li>cd c:\PYCXX_5_3_1\pyds23
+<li>c:\python21\python -c "import example;example.test()"
+</ul>
+</ol>
+</p>
+<h3>Unix Installation and Demo</h3>
+<p>
+<ol>
+<li>Fetch <a href="http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz">
+http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz</a>
+<li>Expand the archive into a directory of your choosing ~/ for example.
+<li>Select to makefile for your system and python version.
+<ul>
+<li>example_freebsd_py15.mak - FreeBSD Python 1.5.2 (see <a href="#note_1_5_2">note</a> below)
+<li>example_freebsd_py20.mak - FreeBSD Python 2.0, 2.0.1
+<li>example_freebsd_py21.mak - FreeBSD Python 2.1, 2.1.1
+<li>example_freebsd_py22.mak - FreeBSD Python 2.2
+<li>example_linux_py15.mak - Linux Python 1.5.2
+<li>example_linux_py20.mak - Linux Python 2.0, 2.0.1
+<li>example_linux_py21.mak - Linux Python 2.1, 2.1.1
+<li>example_linux_py22.mak - Linux Python 2.2
+</ul>
+<li>Build the example. Use GNU make<br>
+$ make -f <var>example-makefile</var> example.so
+<li>Run the example.<br>
+$ make -f <var>example-makefile</var> test
+</ol>
+</p>
+
+<p><a id="note_1_5_2">Note:</a> The Unix version of python 1.5.2 may need to be rebuilt so that C++ is support.
+If you get reports of undefined symbols like cout or cerr then its likely that python
+is not compiled and linked to support C and C++.</p>
+
+<p>To create a makefile for another vendors Unix follow these steps:</p>
+<ol>
+<li>copy one of the example make files above.
+<li>edit the variables to match your Python installation and C++ compile needs
+<li>Proceed to build and test as above.
+</ol>
+<p>Note: most of the makefile rules to build PyCXX and its example are contained in example_common.mak.
+</p>
+
+<h2>Revision History</h2>
+<h3>Version 5.3.1 (19-Jan-2005)</h3>
+<p>Support GCC4 and Microsoft .NET 2003 aka MSVC 7.1
+
+<h3>Version 5.3 (21-Oct-2004)</h3>
+<p>String object now support python string and unicode string objects.
+<p>Fix most bugs reported on SourceForge
+
+<h3>Version 5.2 (27-Nov-2003)</h3>
+<p>PyCXX supports Python version 2.3, 2.2, 2.1, 2.0 and 1.5.2 on Windows and Unix.</p>
+<p>Fixed problems with keyword functions.</p>
+<p>Improve Extension API to give access to names and docs
+<p>Support GCC 3.</p>
+<p>Added support for custom Exceptions</p>
+<p></p>
+
+<h3>Version 5.1 (2-Aug-2001)</h3>
+<p>I'm using the name PyCXX for this package, CXX is far to close to a compilers name.</p>
+
+<p>PyCXX supports Python version 2.2, 2.1.1, 2.1, 2.0, 2.0.1 and 1.5.2 on Windows and Unix.</p>
+
+<p>New in this release:</p>
+<ul>
+<li>Support for the Windows Linker /DELAYLOAD feature. Enable this feature by
+defining PY_WIN32_DELAYLOAD_PYTHON_DLL when compiling IndirectPythonInterface.cxx
+<li>Remove "CXX/Array.hxx" and associated code - its does not belong in PyCXX
+<li>Work on the docs. Mostly to clean up the HTML to allow more extensive work.
+<li>Reformated the sources to a consistent style. The mix of styles and tabs sizes
+was making working on the sources error prone.
+<li>Added workaround to setup.py to allow GCC to compile c++ code.
+<li>Added Microsoft Visual C++ 6.0 project files for 1.5, 2.0 and 2.1 builds
+<li>Added Unix make files for Linux (tested on RedHat 7.1) and FreeBSD (tested on 4.3)
+<li>Merged changes from Tom Malcolmson
+</ul>
+
+<h3>(July 9, 2000)</h3>
+<p>Renamed all header files to reflect the CXX include name space and that they are
+C++ header files.
+<p>
+<table cellspacing=0 cellpadding=3px>
+<tr><th>Old</th><th>New</th></tr>
+<tr><td>#include "CXX_Config.h"</td><td>#include "CXX/Config.hxx"</td>
+<tr><td>#include "CXX_Exception.h"</td><td>#include "CXX/Exception.hxx"</td>
+<tr><td>#include "CXX_Extensions.h"</td><td>#include "CXX/Extensions.hxx"</td>
+<tr><td>#include "CXX_Objects.h"</td><td>#include "CXX/Objects.hxx"</td>
+</table>
+
+<h3>Version 5 (May 18, 2000)</h3>
+<p>This version adds Distutils support for installation and some code cleanup.</p>
+
+<h3>Version 4 (October 11, 1999)</h3>
+
+<p>This version contains a massive revision to the part of CXX that supports creating
+extension objects and extension modules. Barry Scott contributed these changes.</p>
+
+<p>CXX has always consisted of two parts: the basic CXX_Objects.h and the more
+experimental CXX_Extensions.h. We will describe the changes to CXX_Objects first, and then
+the changes to CXX_Extensions.h.</p>
+
+<h3>Changes to CXX_Objects</h3>
+
+<h4>1. Owned option eliminates need for FromAPI in most cases</h4>
+
+<p>Object's constructor from PyObject* and method set have a new (backward compatible)
+signature:</p>
+
+<pre>
+Object (PyObject* pyob, bool owned = false);
+void set(PyObject* pyob, bool owned = false);
+</pre>
+
+<p>Users may call these with owned = true if they own the reference pyob already and want
+the Object instance to take over ownership.</p>
+
+<p>A new inline function Object asObject(PyObject* pyob) returns Object(pyob, true); thus,
+one way to construct an object from a pointer returned by the Python API is to call
+asObject on it. </p>
+
+<p>Previously a class FromAPI was provided to solve the problem of taking over an owned
+reference. FromAPI will be eliminated in the next release. It is no longer used by CXX
+itself or its demos. The new mechanism is much cleaner and more efficient.</p>
+
+<p>Other classes in CXX have been given the same &quot;owned&quot; option on their
+constructors: Int, Float, Long, Complex, SeqBase&lt;T&gt;, Tuple, List, Dict, Module,
+Callable.</p>
+
+<h4>2. Namespace support in compiler assumed</h4>
+
+<p>Since EGCS / GCC now supports namespaces and the standard library, the need for
+CXX_config.h is almost gone. We have eliminated all the macros except for one obscure one
+dealing with iterator traits in the standard library.</p>
+
+<h3>Changes to CXX_Extensions</h3>
+
+<p>The changes to CXX_Extensions.h are not backward compatible. However, they simplify
+coding so much that we think it is worth the disruption.</p>
+
+<h4>1. Creating an extension module</h4>
+
+<p>To create an extension module, you inherit from class ExtensionModule templated on
+yourself: In the constructor, you make calls to register methods of this class with Python
+as extension module methods. In this example, two methods are added (this is a simplified
+form of the example in Demo/example.cxx):</p>
+
+<pre>class example_module : public ExtensionModule&lt;example_module&gt;
+{
+public:
+ example_module()
+ : ExtensionModule&lt;example_module&gt;( &quot;example&quot; )
+ {
+ add_varargs_method(&quot;sum&quot;, &amp;example_module::ex_sum, &quot;sum(arglist) = sum of arguments&quot;);
+ add_varargs_method(&quot;test&quot;, &amp;example_module::ex_test, &quot;test(arglist) runs a test suite&quot;);
+
+ initialize( &quot;documentation for the example module&quot; );
+ }
+
+ virtual ~example_module() {}
+
+private:
+ Object ex_sum (const Tuple &amp;a) { ... }
+ Object ex_test( const Tuple &amp;a) { ... }
+};
+</pre>
+
+<p>To initialize the extension, you just instantiate one static instance (static so it
+doesn't destroy itself!):</p>
+
+<pre>
+void initexample()
+ {
+ static example_module* example = new example_module;
+ }
+</pre>
+
+<p>The methods can be written to take Tuples as arguments and return Objects. If
+exceptions occur they are trapped for you and a Python exception is generated. So, for
+example, the implementation of ex_sum might be:</p>
+
+<pre>
+Object ex_sum (const Tuple &amp;a)
+ {
+ Float f(0.0);
+ for( int i = 0; i &lt; a.length(); i++ )
+ {
+ Float g(a[i]);
+ f = f + g;
+ }
+ return f;
+ }
+</pre>
+
+<p>class ExtensionModule contains methods to return itself as a Module object, or to
+return its dictionary.</p>
+
+<h4>Creating extension objects</h4>
+
+<p>Creating extension objects is of course harder since you must specify how the object
+behaves and give it methods. This is shown in some detail in the example range.h and range.cxx,
+with the test routine rangetest.cxx, in directory Demo.</p>
+
+<p>Here is a brief overview. You create a class that inherits from PythonExtension
+templated upon itself. You override various methods from PythonExtension to implement
+behaviors, such as getattr, sequence_item, etc. You can also add methods to the object
+that are usable from Python using a similar scheme as for module methods above. </p>
+
+<p>One of the consequences of inheriting from PythonExtension is that you are inheriting
+from PyObject itself. So your class is-a PyObject and instances of it can be passed to the
+Python C API. Note: this example uses the namespace feature of CXX. The Py:: 's are not
+required if you use the namespace instead.</p>
+
+<pre>
+class range: public Py::PythonExtension&lt;range&gt; {
+public:
+ ... constructors, etc.
+
+ ... methods
+ // initializer, see below
+ static void init_type();
+ // override functions from PythonExtension
+ virtual Py::Object repr();
+ virtual Py::Object getattr( const char *name );
+
+ virtual int sequence_length();
+ virtual Py::Object sequence_item( int i );
+ virtual Py::Object sequence_concat( const Py::Object &amp;j );
+ virtual Py::Object sequence_slice( int i, int j );
+
+ // define python methods of this object
+ Py::Object amethod (const Py::Tuple&amp; args);
+ Py::Object value (const Py::Tuple&amp; args);
+ Py::Object assign (const Py::Tuple&amp; args);
+};
+</pre>
+
+<p>
+To initialize the type you provide a static method that you can call from some module's
+initializer. This method sets the name, doc string, and indicates which behaviors it
+supports. It then adds the methods.</p>
+
+<pre>
+void range::init_type()
+{
+ behaviors().name(&quot;range&quot;);
+ behaviors().doc(&quot;range objects: start, stop, step&quot;);
+ behaviors().supportRepr();
+ behaviors().supportGetattr();
+ behaviors().supportSequenceType();
+
+ add_varargs_method(&quot;amethod&quot;, &amp;range::amethod,
+ &quot;demonstrate how to document amethod&quot;);
+ add_varargs_method(&quot;assign&quot;, &amp;range::assign);
+ add_varargs_method(&quot;value&quot;, &amp;range::value);
+}
+</pre>
+
+<h3>Version 3 (June 18, 1999)</h3>
+
+<p>1. CXX compiles with EGCS snapshot 19990616. EGCS requires a standard library class
+random_access_iterator that is not yet available in some other compilers (such as Windows
+VC6). Therefore a new switch:</p>
+
+<p>STANDARD_LIBRARY_HAS_ITERATOR_TRAITS</p>
+
+<p>has been added to CXX_Config.h that you may need to toggle if you get an error on the
+two lines that mention random_access_iterator. The current definition is correct for VC6
+and EGCS-19990616. </p>
+
+<p>2. A new constructor was added to Module to allow construction from a string containing
+the module name. A test was added for this to the demo.</p>
+
+<h3>Version 2 (Dec. 28, 1998)</h3>
+
+<p>Fixed definition of extension type to match 1.5.2. This version will presumably not
+compile with older versions of Python. This can be fixed by using the previous version's
+definition. I did not take the time to find out what these new &quot;flags&quot; are for
+nor put in any methods to deal with them.</p>
+
+<h3>Version 1</h3>
+
+<p>This is an experimental set of files for supporting the creation of Python extensions
+in C++. </p>
+
+<p>Documentation is in progress at <a href="http://xfiles.llnl.gov">http://xfiles.llnl.gov</a>.
+</p>
+
+<p>To use CXX you use the header files in Include, such as CXX_Objects.h or
+CXX_Extensions.h. You must include the sources in Src in your sources to supply parts of
+the CXX classes required.</p>
+
+<p>A demo is included. The Setup file in this directory compiles this demo named
+&quot;example&quot;. To try the demo, which is also a test routine, you import example and
+then execute:</p>
+
+<pre>
+example.test()
+</pre>
+
+<p>You can also play with the extension object whose constructor is named &quot;range&quot;:</p>
+
+<pre>
+s = range(1, 100, 2)
+print s[2] # should print 5
+</pre>
+
+<p>Compilation with Microsoft Visual C++ 5.0 will succeed but only if you have Service
+Pack 3 installed. Compilation has been known to succeed on a Unix system using KCC by
+using:</p>
+
+<pre>
+setenv CCC &quot;KCC -x&quot;
+</pre>
+
+<p>before running makethis.py.</p>
+
+<p>There is also a python.cxx file for making a stand-alone Python containing this
+example, as well as a similar file arraytest.cxx for testing Array.</p>
+
+<p>Comments to barry@barrys-emacs.org, please.</p>
+
+<p>Barry Scott</p>
+</body>
+</html>
diff --git a/lib/kross/python/cxx/Readme.Kross.txt b/lib/kross/python/cxx/Readme.Kross.txt
new file mode 100644
index 00000000..ec00230a
--- /dev/null
+++ b/lib/kross/python/cxx/Readme.Kross.txt
@@ -0,0 +1,16 @@
+Kross uses PyCXX 5.3.1 (http://cxx.sourceforge.net/)
+to access the Python C API.
+
+Following patches where applied and send back to the PyCXX team.
+
+- Unsigned patch
+ http://sourceforge.net/tracker/index.php?func=detail&aid=1085205&group_id=3180&atid=303180
+- isInstance patch
+ http://sourceforge.net/tracker/index.php?func=detail&aid=1178048&group_id=3180&atid=303180
+- dir patch
+ http://sourceforge.net/tracker/index.php?func=detail&aid=1186676&group_id=3180&atid=303180
+- fixed typos
+ http://sourceforge.net/tracker/index.php?func=detail&aid=1266579&group_id=3180&atid=103180
+ http://sourceforge.net/tracker/index.php?func=detail&aid=1293777&group_id=3180&atid=103180
+
+I also changed the includes to get PyCXX compiled the way we use it.
diff --git a/lib/kross/python/cxx/Version.txt b/lib/kross/python/cxx/Version.txt
new file mode 100644
index 00000000..27be42b3
--- /dev/null
+++ b/lib/kross/python/cxx/Version.txt
@@ -0,0 +1 @@
+PyCxx 5.3.1
diff --git a/lib/kross/python/cxx/cxx_extensions.cxx b/lib/kross/python/cxx/cxx_extensions.cxx
new file mode 100644
index 00000000..f9c942ad
--- /dev/null
+++ b/lib/kross/python/cxx/cxx_extensions.cxx
@@ -0,0 +1,1287 @@
+#include "Extensions.hxx"
+#include "Exception.hxx"
+
+#include <assert.h>
+
+namespace Py
+{
+
+//================================================================================
+//
+// Implementation of MethodTable
+//
+//================================================================================
+
+PyMethodDef MethodTable::method( const char* method_name, PyCFunction f, int flags, const char* doc )
+ {
+ PyMethodDef m;
+ m.ml_name = const_cast<char*>( method_name );
+ m.ml_meth = f;
+ m.ml_flags = flags;
+ m.ml_doc = const_cast<char*>( doc );
+ return m;
+ }
+
+MethodTable::MethodTable()
+ {
+ t.push_back( method( 0, 0, 0, 0 ) );
+ mt = 0;
+ }
+
+MethodTable::~MethodTable()
+ {
+ delete [] mt;
+ }
+
+void MethodTable::add( const char* method_name, PyCFunction f, const char* doc, int flag )
+ {
+ if( !mt )
+ {
+ t.insert( t.end()-1, method( method_name, f, flag, doc ) );
+ }
+ else
+ {
+ throw RuntimeError( "Too late to add a module method!" );
+ }
+ }
+
+PyMethodDef* MethodTable::table()
+ {
+ if( !mt )
+ {
+ int t1size = t.size();
+ mt = new PyMethodDef[t1size];
+ int j = 0;
+ for( std::vector<PyMethodDef>::iterator i = t.begin(); i != t.end(); i++ )
+ {
+ mt[j++] = *i;
+ }
+ }
+ return mt;
+ }
+
+//================================================================================
+//
+// Implementation of ExtensionModule
+//
+//================================================================================
+ExtensionModuleBase::ExtensionModuleBase( const char *name )
+ : module_name( name )
+ , full_module_name( __Py_PackageContext() != NULL ? std::string( __Py_PackageContext() ) : module_name )
+ , method_table()
+ {}
+
+ExtensionModuleBase::~ExtensionModuleBase()
+ {}
+
+const std::string &ExtensionModuleBase::name() const
+ {
+ return module_name;
+ }
+
+const std::string &ExtensionModuleBase::fullName() const
+ {
+ return full_module_name;
+ }
+
+class ExtensionModuleBasePtr : public PythonExtension<ExtensionModuleBasePtr>
+ {
+public:
+ ExtensionModuleBasePtr( ExtensionModuleBase *_module )
+ : module( _module )
+ {}
+ virtual ~ExtensionModuleBasePtr()
+ {}
+
+ ExtensionModuleBase *module;
+ };
+
+
+void ExtensionModuleBase::initialize( const char *module_doc )
+ {
+ PyObject *module_ptr = new ExtensionModuleBasePtr( this );
+
+ Py_InitModule4
+ (
+ const_cast<char *>( module_name.c_str() ), // name
+ method_table.table(), // methods
+ const_cast<char *>( module_doc ), // docs
+ module_ptr, // pass to functions as "self"
+ PYTHON_API_VERSION // API version
+ );
+ }
+
+Py::Module ExtensionModuleBase::module(void) const
+ {
+ return Module( full_module_name );
+ }
+
+Py::Dict ExtensionModuleBase::moduleDictionary(void) const
+ {
+ return module().getDict();
+ }
+
+//--------------------------------------------------------------------------------
+
+//================================================================================
+//
+// Implementation of PythonType
+//
+//================================================================================
+
+extern "C"
+ {
+ static void standard_dealloc(PyObject* p);
+ //
+ // All the following functions redirect the call from Python
+ // onto the matching virtual function in PythonExtensionBase
+ //
+ static int print_handler (PyObject*, FILE *, int);
+ static PyObject* getattr_handler (PyObject*, char*);
+ static int setattr_handler (PyObject*, char*, PyObject*);
+ static PyObject* getattro_handler (PyObject*, PyObject*);
+ static int setattro_handler (PyObject*, PyObject*, PyObject*);
+ static int compare_handler (PyObject*, PyObject*);
+ static PyObject* repr_handler (PyObject*);
+ static PyObject* str_handler (PyObject*);
+ static long hash_handler (PyObject*);
+ static PyObject* call_handler (PyObject*, PyObject*, PyObject*);
+
+#if PY_VERSION_HEX < 0x02050000
+ typedef int Py_ssize_t;
+#endif
+ // Sequence methods
+ static Py_ssize_t sequence_length_handler(PyObject*);
+ static PyObject* sequence_concat_handler(PyObject*,PyObject*);
+ static PyObject* sequence_repeat_handler(PyObject*, Py_ssize_t);
+ static PyObject* sequence_item_handler(PyObject*, Py_ssize_t);
+ static PyObject* sequence_slice_handler(PyObject*, Py_ssize_t, Py_ssize_t);
+ static int sequence_ass_item_handler(PyObject*, Py_ssize_t, PyObject*);
+ static int sequence_ass_slice_handler(PyObject*, Py_ssize_t, Py_ssize_t, PyObject*);
+ // Mapping
+ static Py_ssize_t mapping_length_handler(PyObject*);
+ static PyObject* mapping_subscript_handler(PyObject*, PyObject*);
+ static int mapping_ass_subscript_handler(PyObject*, PyObject*, PyObject*);
+
+ // Numeric methods
+ static int number_nonzero_handler (PyObject*);
+ static PyObject* number_negative_handler (PyObject*);
+ static PyObject* number_positive_handler (PyObject*);
+ static PyObject* number_absolute_handler (PyObject*);
+ static PyObject* number_invert_handler (PyObject*);
+ static PyObject* number_int_handler (PyObject*);
+ static PyObject* number_float_handler (PyObject*);
+ static PyObject* number_long_handler (PyObject*);
+ static PyObject* number_oct_handler (PyObject*);
+ static PyObject* number_hex_handler (PyObject*);
+ static PyObject* number_add_handler (PyObject*, PyObject*);
+ static PyObject* number_subtract_handler (PyObject*, PyObject*);
+ static PyObject* number_multiply_handler (PyObject*, PyObject*);
+ static PyObject* number_divide_handler (PyObject*, PyObject*);
+ static PyObject* number_remainder_handler (PyObject*, PyObject*);
+ static PyObject* number_divmod_handler (PyObject*, PyObject*);
+ static PyObject* number_lshift_handler (PyObject*, PyObject*);
+ static PyObject* number_rshift_handler (PyObject*, PyObject*);
+ static PyObject* number_and_handler (PyObject*, PyObject*);
+ static PyObject* number_xor_handler (PyObject*, PyObject*);
+ static PyObject* number_or_handler (PyObject*, PyObject*);
+ static PyObject* number_power_handler(PyObject*, PyObject*, PyObject*);
+
+ // Buffer
+ static Py_ssize_t buffer_getreadbuffer_handler (PyObject*, Py_ssize_t, void**);
+ static Py_ssize_t buffer_getwritebuffer_handler (PyObject*, Py_ssize_t, void**);
+ static Py_ssize_t buffer_getsegcount_handler (PyObject*, Py_ssize_t*);
+ }
+
+
+extern "C" void standard_dealloc( PyObject* p )
+ {
+ PyMem_DEL( p );
+ }
+
+void PythonType::supportSequenceType()
+ {
+ if( !sequence_table )
+ {
+ sequence_table = new PySequenceMethods;
+ table->tp_as_sequence = sequence_table;
+ sequence_table->sq_length = sequence_length_handler;
+ sequence_table->sq_concat = sequence_concat_handler;
+ sequence_table->sq_repeat = sequence_repeat_handler;
+ sequence_table->sq_item = sequence_item_handler;
+ sequence_table->sq_slice = sequence_slice_handler;
+
+ sequence_table->sq_ass_item = sequence_ass_item_handler; // BAS setup seperately?
+ sequence_table->sq_ass_slice = sequence_ass_slice_handler; // BAS setup seperately?
+ }
+ }
+
+void PythonType::supportMappingType()
+ {
+ if( !mapping_table )
+ {
+ mapping_table = new PyMappingMethods;
+ table->tp_as_mapping = mapping_table;
+ mapping_table->mp_length = mapping_length_handler;
+ mapping_table->mp_subscript = mapping_subscript_handler;
+ mapping_table->mp_ass_subscript = mapping_ass_subscript_handler; // BAS setup seperately?
+ }
+ }
+
+void PythonType::supportNumberType()
+ {
+ if( !number_table )
+ {
+ number_table = new PyNumberMethods;
+ table->tp_as_number = number_table;
+ number_table->nb_add = number_add_handler;
+ number_table->nb_subtract = number_subtract_handler;
+ number_table->nb_multiply = number_multiply_handler;
+ number_table->nb_divide = number_divide_handler;
+ number_table->nb_remainder = number_remainder_handler;
+ number_table->nb_divmod = number_divmod_handler;
+ number_table->nb_power = number_power_handler;
+ number_table->nb_negative = number_negative_handler;
+ number_table->nb_positive = number_positive_handler;
+ number_table->nb_absolute = number_absolute_handler;
+ number_table->nb_nonzero = number_nonzero_handler;
+ number_table->nb_invert = number_invert_handler;
+ number_table->nb_lshift = number_lshift_handler;
+ number_table->nb_rshift = number_rshift_handler;
+ number_table->nb_and = number_and_handler;
+ number_table->nb_xor = number_xor_handler;
+ number_table->nb_or = number_or_handler;
+ number_table->nb_coerce = 0;
+ number_table->nb_int = number_int_handler;
+ number_table->nb_long = number_long_handler;
+ number_table->nb_float = number_float_handler;
+ number_table->nb_oct = number_oct_handler;
+ number_table->nb_hex = number_hex_handler;
+ }
+ }
+
+void PythonType::supportBufferType()
+ {
+ if( !buffer_table )
+ {
+ buffer_table = new PyBufferProcs;
+ table->tp_as_buffer = buffer_table;
+ buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler;
+ buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler;
+ buffer_table->bf_getsegcount = buffer_getsegcount_handler;
+ }
+ }
+
+// if you define one sequence method you must define
+// all of them except the assigns
+
+PythonType::PythonType( size_t basic_size, int itemsize, const char *default_name )
+ : table( new PyTypeObject )
+ , sequence_table( NULL )
+ , mapping_table( NULL )
+ , number_table( NULL )
+ , buffer_table( NULL )
+ {
+ *reinterpret_cast<PyObject*>( table ) = py_object_initializer;
+ table->ob_type = _Type_Type();
+ table->ob_size = 0;
+ table->tp_name = const_cast<char *>( default_name );
+ table->tp_basicsize = basic_size;
+ table->tp_itemsize = itemsize;
+ table->tp_dealloc = ( destructor ) standard_dealloc;
+ table->tp_print = 0;
+ table->tp_getattr = 0;
+ table->tp_setattr = 0;
+ table->tp_compare = 0;
+ table->tp_repr = 0;
+ table->tp_as_number = 0;
+ table->tp_as_sequence = 0;
+ table->tp_as_mapping = 0;
+ table->tp_hash = 0;
+ table->tp_call = 0;
+ table->tp_str = 0;
+ table->tp_getattro = 0;
+ table->tp_setattro = 0;
+ table->tp_as_buffer = 0;
+ table->tp_flags = 0L;
+ table->tp_doc = 0;
+#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 0)
+ // first use in 2.0
+ table->tp_traverse = 0L;
+ table->tp_clear = 0L;
+#else
+ table->tp_xxx5 = 0L;
+ table->tp_xxx6 = 0L;
+#endif
+#if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1)
+ // first defined in 2.1
+ table->tp_richcompare = 0L;
+ table->tp_weaklistoffset = 0L;
+#else
+ table->tp_xxx7 = 0L;
+ table->tp_xxx8 = 0L;
+#endif
+
+#ifdef COUNT_ALLOCS
+ table->tp_alloc = 0;
+ table->tp_free = 0;
+ table->tp_maxalloc = 0;
+ table->tp_next = 0;
+#endif
+ }
+
+PythonType::~PythonType( )
+ {
+ delete table;
+ delete sequence_table;
+ delete mapping_table;
+ delete number_table;
+ delete buffer_table;
+ }
+
+PyTypeObject* PythonType::type_object( ) const
+ {return table;}
+
+void PythonType::name( const char* nam )
+ {
+ table->tp_name = const_cast<char *>( nam );
+ }
+
+const char *PythonType::getName() const
+ {
+ return table->tp_name;
+ }
+
+void PythonType::doc( const char* d )
+ {
+ table->tp_doc = const_cast<char *>( d );
+ }
+
+const char *PythonType::getDoc() const
+ {
+ return table->tp_doc;
+ }
+
+void PythonType::dealloc( void( *f )( PyObject* ))
+ {
+ table->tp_dealloc = f;
+ }
+
+void PythonType::supportPrint()
+ {
+ table->tp_print = print_handler;
+ }
+
+void PythonType::supportGetattr()
+ {
+ table->tp_getattr = getattr_handler;
+ }
+
+void PythonType::supportSetattr()
+ {
+ table->tp_setattr = setattr_handler;
+ }
+
+void PythonType::supportGetattro()
+ {
+ table->tp_getattro = getattro_handler;
+ }
+
+void PythonType::supportSetattro()
+ {
+ table->tp_setattro = setattro_handler;
+ }
+
+void PythonType::supportCompare()
+ {
+ table->tp_compare = compare_handler;
+ }
+
+void PythonType::supportRepr()
+ {
+ table->tp_repr = repr_handler;
+ }
+
+void PythonType::supportStr()
+ {
+ table->tp_str = str_handler;
+ }
+
+void PythonType::supportHash()
+ {
+ table->tp_hash = hash_handler;
+ }
+
+void PythonType::supportCall()
+ {
+ table->tp_call = call_handler;
+ }
+
+//--------------------------------------------------------------------------------
+//
+// Handlers
+//
+//--------------------------------------------------------------------------------
+extern "C" int print_handler( PyObject *self, FILE *fp, int flags )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->print( fp, flags );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* getattr_handler( PyObject *self, char *name )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->getattr( name ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" int setattr_handler( PyObject *self, char *name, PyObject *value )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->setattr( name, Py::Object( value ) );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* getattro_handler( PyObject *self, PyObject *name )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->getattro( Py::Object( name ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->setattro( Py::Object( name ), Py::Object( value ) );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" int compare_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->compare( Py::Object( other ) );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* repr_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->repr() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* str_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->str() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" long hash_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->hash();
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* call_handler( PyObject *self, PyObject *args, PyObject *kw )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->call( Py::Object( args ), Py::Object( kw ) ) );
+ if( kw != NULL )
+ return new_reference_to( p->call( Py::Object( args ), Py::Object( kw ) ) );
+ else
+ return new_reference_to( p->call( Py::Object( args ), Py::Object() ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+
+// Sequence methods
+extern "C" Py_ssize_t sequence_length_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->sequence_length();
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* sequence_concat_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->sequence_concat( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* sequence_repeat_handler( PyObject *self, Py_ssize_t count )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->sequence_repeat( count ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* sequence_item_handler( PyObject *self, Py_ssize_t index )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->sequence_item( index ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* sequence_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->sequence_slice( first, last ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" int sequence_ass_item_handler( PyObject *self, Py_ssize_t index, PyObject *value )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->sequence_ass_item( index, Py::Object( value ) );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" int sequence_ass_slice_handler( PyObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *value )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->sequence_ass_slice( first, last, Py::Object( value ) );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+// Mapping
+extern "C" Py_ssize_t mapping_length_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->mapping_length();
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* mapping_subscript_handler( PyObject *self, PyObject *key )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->mapping_subscript( Py::Object( key ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" int mapping_ass_subscript_handler( PyObject *self, PyObject *key, PyObject *value )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->mapping_ass_subscript( Py::Object( key ), Py::Object( value ) );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+// Number
+extern "C" int number_nonzero_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->number_nonzero();
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_negative_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_negative() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_positive_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_positive() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_absolute_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_absolute() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_invert_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_invert() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_int_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_int() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_float_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_float() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_long_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_long() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_oct_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_oct() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_hex_handler( PyObject *self )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_hex() );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_add_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_add( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_subtract_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_subtract( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_multiply_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_multiply( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_divide_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_divide( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_remainder_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_remainder( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_divmod_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_divmod( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_lshift_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_lshift( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_rshift_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_rshift( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_and_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_and( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_xor_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_xor( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_or_handler( PyObject *self, PyObject *other )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_or( Py::Object( other ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+extern "C" PyObject* number_power_handler( PyObject *self, PyObject *x1, PyObject *x2 )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return new_reference_to( p->number_power( Py::Object( x1 ), Py::Object( x2 ) ) );
+ }
+ catch( Py::Exception & )
+ {
+ return NULL; // indicate error
+ }
+ }
+
+// Buffer
+extern "C" Py_ssize_t buffer_getreadbuffer_handler( PyObject *self, Py_ssize_t index, void **pp )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->buffer_getreadbuffer( index, pp );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" Py_ssize_t buffer_getwritebuffer_handler( PyObject *self, Py_ssize_t index, void **pp )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ return p->buffer_getwritebuffer( index, pp );
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+extern "C" Py_ssize_t buffer_getsegcount_handler( PyObject *self, Py_ssize_t *count )
+ {
+ try
+ {
+ PythonExtensionBase *p = static_cast<PythonExtensionBase *>( self );
+ int i_count = *count;
+ Py_ssize_t r = p->buffer_getsegcount( &i_count );
+ *count = i_count;
+ return r;
+ }
+ catch( Py::Exception & )
+ {
+ return -1; // indicate error
+ }
+ }
+
+
+//================================================================================
+//
+// Implementation of PythonExtensionBase
+//
+//================================================================================
+#define missing_method( method ) \
+throw RuntimeError( "Extension object does not support method " #method );
+
+PythonExtensionBase::PythonExtensionBase()
+ {
+ }
+
+PythonExtensionBase::~PythonExtensionBase()
+ {
+ assert( ob_refcnt == 0 );
+ }
+
+int PythonExtensionBase::print( FILE *, int )
+ { missing_method( print ); return -1; }
+
+int PythonExtensionBase::setattr( const char*, const Py::Object & )
+ { missing_method( setattr ); return -1; }
+
+Py::Object PythonExtensionBase::getattro( const Py::Object & )
+ { missing_method( getattro ); return Py::Nothing(); }
+
+int PythonExtensionBase::setattro( const Py::Object &, const Py::Object & )
+ { missing_method( setattro ); return -1; }
+
+int PythonExtensionBase::compare( const Py::Object & )
+ { missing_method( compare ); return -1; }
+
+Py::Object PythonExtensionBase::repr()
+ { missing_method( repr ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::str()
+ { missing_method( str ); return Py::Nothing(); }
+
+long PythonExtensionBase::hash()
+ { missing_method( hash ); return -1; }
+
+Py::Object PythonExtensionBase::call( const Py::Object &, const Py::Object & )
+ { missing_method( call ); return Py::Nothing(); }
+
+
+// Sequence methods
+int PythonExtensionBase::sequence_length()
+ { missing_method( sequence_length ); return -1; }
+
+Py::Object PythonExtensionBase::sequence_concat( const Py::Object & )
+ { missing_method( sequence_concat ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::sequence_repeat( int )
+ { missing_method( sequence_repeat ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::sequence_item( int )
+ { missing_method( sequence_item ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::sequence_slice( int, int )
+ { missing_method( sequence_slice ); return Py::Nothing(); }
+
+int PythonExtensionBase::sequence_ass_item( int, const Py::Object & )
+ { missing_method( sequence_ass_item ); return -1; }
+
+int PythonExtensionBase::sequence_ass_slice( int, int, const Py::Object & )
+ { missing_method( sequence_ass_slice ); return -1; }
+
+
+// Mapping
+int PythonExtensionBase::mapping_length()
+ { missing_method( mapping_length ); return -1; }
+
+Py::Object PythonExtensionBase::mapping_subscript( const Py::Object & )
+ { missing_method( mapping_subscript ); return Py::Nothing(); }
+
+int PythonExtensionBase::mapping_ass_subscript( const Py::Object &, const Py::Object & )
+ { missing_method( mapping_ass_subscript ); return -1; }
+
+
+// Number
+int PythonExtensionBase::number_nonzero()
+ { missing_method( number_nonzero ); return -1; }
+
+Py::Object PythonExtensionBase::number_negative()
+ { missing_method( number_negative ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_positive()
+ { missing_method( number_positive ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_absolute()
+ { missing_method( number_absolute ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_invert()
+ { missing_method( number_invert ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_int()
+ { missing_method( number_int ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_float()
+ { missing_method( number_float ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_long()
+ { missing_method( number_long ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_oct()
+ { missing_method( number_oct ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_hex()
+ { missing_method( number_hex ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_add( const Py::Object & )
+ { missing_method( number_add ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_subtract( const Py::Object & )
+ { missing_method( number_subtract ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_multiply( const Py::Object & )
+ { missing_method( number_multiply ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_divide( const Py::Object & )
+ { missing_method( number_divide ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_remainder( const Py::Object & )
+ { missing_method( number_remainder ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_divmod( const Py::Object & )
+ { missing_method( number_divmod ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_lshift( const Py::Object & )
+ { missing_method( number_lshift ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_rshift( const Py::Object & )
+ { missing_method( number_rshift ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_and( const Py::Object & )
+ { missing_method( number_and ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_xor( const Py::Object & )
+ { missing_method( number_xor ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_or( const Py::Object & )
+ { missing_method( number_or ); return Py::Nothing(); }
+
+Py::Object PythonExtensionBase::number_power( const Py::Object &, const Py::Object & )
+ { missing_method( number_power ); return Py::Nothing(); }
+
+
+// Buffer
+int PythonExtensionBase::buffer_getreadbuffer( int, void** )
+ { missing_method( buffer_getreadbuffer ); return -1; }
+
+int PythonExtensionBase::buffer_getwritebuffer( int, void** )
+ { missing_method( buffer_getwritebuffer ); return -1; }
+
+int PythonExtensionBase::buffer_getsegcount( int* )
+ { missing_method( buffer_getsegcount ); return -1; }
+
+//--------------------------------------------------------------------------------
+//
+// Method call handlers for
+// PythonExtensionBase
+// ExtensionModuleBase
+//
+//--------------------------------------------------------------------------------
+
+extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords )
+ {
+ try
+ {
+ Tuple self_and_name_tuple( _self_and_name_tuple );
+
+ PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
+ void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject );
+ if( self_as_void == NULL )
+ return NULL;
+
+ ExtensionModuleBase *self = static_cast<ExtensionModuleBase *>( self_as_void );
+
+ String py_name( self_and_name_tuple[1] );
+ std::string name( py_name.as_std_string() );
+
+ Tuple args( _args );
+ if( _keywords == NULL )
+ {
+ Dict keywords; // pass an empty dict
+
+ Object result( self->invoke_method_keyword( name, args, keywords ) );
+ return new_reference_to( result.ptr() );
+ }
+ else
+ {
+ Dict keywords( _keywords );
+
+ Object result( self->invoke_method_keyword( name, args, keywords ) );
+ return new_reference_to( result.ptr() );
+ }
+ }
+ catch( Exception & )
+ {
+ return 0;
+ }
+ }
+
+extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args )
+ {
+ try
+ {
+ Tuple self_and_name_tuple( _self_and_name_tuple );
+
+ PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
+ void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject );
+ if( self_as_void == NULL )
+ return NULL;
+
+ ExtensionModuleBase *self = static_cast<ExtensionModuleBase *>( self_as_void );
+
+ String py_name( self_and_name_tuple[1] );
+ std::string name( py_name.as_std_string() );
+
+ Tuple args( _args );
+
+ Object result( self->invoke_method_varargs( name, args ) );
+
+ return new_reference_to( result.ptr() );
+ }
+ catch( Exception & )
+ {
+ return 0;
+ }
+ }
+
+extern "C" void do_not_dealloc( void * )
+ {}
+
+
+//--------------------------------------------------------------------------------
+//
+// ExtensionExceptionType
+//
+//--------------------------------------------------------------------------------
+ExtensionExceptionType::ExtensionExceptionType()
+ : Py::Object()
+ {
+ }
+
+void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::string& name )
+ {
+ std::string module_name( module.fullName() );
+ module_name += ".";
+ module_name += name;
+
+ set( PyErr_NewException( const_cast<char *>( module_name.c_str() ), NULL, NULL ), true );
+ }
+
+ExtensionExceptionType::~ExtensionExceptionType()
+ {
+ }
+
+Exception::Exception( ExtensionExceptionType &exception, const std::string& reason )
+ {
+ PyErr_SetString (exception.ptr(), reason.c_str());
+ }
+
+
+} // end of namespace Py
diff --git a/lib/kross/python/cxx/cxxextensions.c b/lib/kross/python/cxx/cxxextensions.c
new file mode 100644
index 00000000..6f369b2d
--- /dev/null
+++ b/lib/kross/python/cxx/cxxextensions.c
@@ -0,0 +1,19 @@
+/*
+ Copyright 1998 The Regents of the University of California.
+ All rights reserved. See Legal.htm for full text and disclaimer.
+*/
+
+#include "Python.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+PyObject py_object_initializer = {PyObject_HEAD_INIT(0)};
+#ifdef __cplusplus
+}
+#endif
+
+
+
+
+
+
diff --git a/lib/kross/python/cxx/cxxsupport.cxx b/lib/kross/python/cxx/cxxsupport.cxx
new file mode 100644
index 00000000..61329b60
--- /dev/null
+++ b/lib/kross/python/cxx/cxxsupport.cxx
@@ -0,0 +1,142 @@
+//----------------------------------*-C++-*----------------------------------//
+// Copyright 1998 The Regents of the University of California.
+// All rights reserved. See Legal.htm for full text and disclaimer.
+//---------------------------------------------------------------------------//
+
+#include "Objects.hxx"
+namespace Py {
+
+Py_UNICODE unicode_null_string[1] = { 0 };
+
+Type Object::type () const
+ {
+ return Type (PyObject_Type (p), true);
+ }
+
+String Object::str () const
+ {
+ return String (PyObject_Str (p), true);
+ }
+
+String Object::repr () const
+ {
+ return String (PyObject_Repr (p), true);
+ }
+
+std::string Object::as_string() const
+ {
+ return static_cast<std::string>(str());
+ }
+
+List Object::dir () const
+ {
+ return List (PyObject_Dir (p), true);
+ }
+
+bool Object::isType (const Type& t) const
+ {
+ return type ().ptr() == t.ptr();
+ }
+
+Char::operator String() const
+ {
+ return String(ptr());
+ }
+
+// TMM: non-member operaters for iterators - see above
+// I've also made a bug fix in respect to the cxx code
+// (dereffed the left.seq and right.seq comparison)
+bool operator==(const Sequence::iterator& left, const Sequence::iterator& right)
+ {
+ return left.eql( right );
+ }
+
+bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right)
+ {
+ return left.neq( right );
+ }
+
+bool operator< (const Sequence::iterator& left, const Sequence::iterator& right)
+ {
+ return left.lss( right );
+ }
+
+bool operator> (const Sequence::iterator& left, const Sequence::iterator& right)
+ {
+ return left.gtr( right );
+ }
+
+bool operator<=(const Sequence::iterator& left, const Sequence::iterator& right)
+ {
+ return left.leq( right );
+ }
+
+bool operator>=(const Sequence::iterator& left, const Sequence::iterator& right)
+ {
+ return left.geq( right );
+ }
+
+// now for const_iterator
+bool operator==(const Sequence::const_iterator& left, const Sequence::const_iterator& right)
+ {
+ return left.eql( right );
+ }
+
+bool operator!=(const Sequence::const_iterator& left, const Sequence::const_iterator& right)
+ {
+ return left.neq( right );
+ }
+
+bool operator< (const Sequence::const_iterator& left, const Sequence::const_iterator& right)
+ {
+ return left.lss( right );
+ }
+
+bool operator> (const Sequence::const_iterator& left, const Sequence::const_iterator& right)
+ {
+ return left.gtr( right );
+ }
+
+bool operator<=(const Sequence::const_iterator& left, const Sequence::const_iterator& right)
+ {
+ return left.leq( right );
+ }
+
+bool operator>=(const Sequence::const_iterator& left, const Sequence::const_iterator& right)
+ {
+ return left.geq( right );
+ }
+
+// For mappings:
+bool operator==(const Mapping::iterator& left, const Mapping::iterator& right)
+ {
+ return left.eql( right );
+ }
+
+bool operator!=(const Mapping::iterator& left, const Mapping::iterator& right)
+ {
+ return left.neq( right );
+ }
+
+// now for const_iterator
+bool operator==(const Mapping::const_iterator& left, const Mapping::const_iterator& right)
+ {
+ return left.eql( right );
+ }
+
+bool operator!=(const Mapping::const_iterator& left, const Mapping::const_iterator& right)
+ {
+ return left.neq( right );
+ }
+
+// TMM: 31May'01 - Added the #ifndef so I can exclude iostreams.
+#ifndef CXX_NO_IOSTREAMS
+// output
+
+std::ostream& operator<< (std::ostream& os, const Object& ob)
+ {
+ return (os << static_cast<std::string>(ob.str()));
+ }
+#endif
+
+} // Py
diff --git a/lib/kross/python/pythonconfig.h b/lib/kross/python/pythonconfig.h
new file mode 100644
index 00000000..64b4eefb
--- /dev/null
+++ b/lib/kross/python/pythonconfig.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * pythonconfig.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_CONFIG_H
+#define KROSS_PYTHON_CONFIG_H
+
+#include "../main/krossconfig.h"
+
+// Prevent warnings
+#if defined(_XOPEN_SOURCE)
+ #undef _XOPEN_SOURCE
+#endif
+#if defined(_POSIX_C_SOURCE)
+ #undef _POSIX_C_SOURCE
+#endif
+
+// The Python.h needs to be included first.
+#include <Python.h>
+#include <object.h>
+#include <compile.h>
+#include <eval.h>
+#include <frameobject.h>
+
+// Include the PyCXX stuff.
+#include "cxx/Config.hxx"
+#include "cxx/Objects.hxx"
+#include "cxx/Extensions.hxx"
+
+namespace Kross {
+
+/**
+ * The Python plugin for the \a Kross scripting framework.
+ *
+ * The code in this namespace manage the embedded python
+ * interpreter and python-scripts.
+ *
+ * There is no dependency to e.g. the \a Kross::KexiDB
+ * wrapper. Everything is handled through the common
+ * \a Kross::Api bridge. Therefore this interpreter-
+ * implementation should be able to make all defined
+ * wrappers accessible by the python scripting
+ * language.
+ *
+ * Internaly we use PyCXX - a set of classes to help
+ * create extensions of python in the C++ language - to
+ * access the python c api. Any python version since
+ * 2.0 is supported.
+ *
+ * \author Sebastian Sauer
+ * \sa http://www.python.org
+ * \sa http://cxx.sourceforge.net
+ */
+namespace Python {
+
+ // The version of this python plugin. This will be exported
+ // to the scripting code. That way we're able to write
+ // scripting code for different incompatible Kross python
+ // bindings by checking the version. You should increment
+ // this number only if you really know what you're doing.
+ #define KROSS_PYTHON_VERSION 1
+
+ // Enable debugging for Kross::Python::PythonScript
+ //#define KROSS_PYTHON_SCRIPT_CTOR_DEBUG
+ //#define KROSS_PYTHON_SCRIPT_DTOR_DEBUG
+ //#define KROSS_PYTHON_SCRIPT_INIT_DEBUG
+ //#define KROSS_PYTHON_SCRIPT_FINALIZE_DEBUG
+ //#define KROSS_PYTHON_SCRIPT_EXEC_DEBUG
+ //#define KROSS_PYTHON_SCRIPT_CALLFUNC_DEBUG
+ //#define KROSS_PYTHON_SCRIPT_CLASSINSTANCE_DEBUG
+
+ // Enable debugging for Kross::Python::PythonModule
+ //#define KROSS_PYTHON_MODULE_DEBUG
+
+ // Enable debugging for Kross::Python::PythonExtension
+ //#define KROSS_PYTHON_EXTENSION_CTOR_DEBUG
+ //#define KROSS_PYTHON_EXTENSION_DTOR_DEBUG
+
+ //#define KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
+ //#define KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+
+ //#define KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
+ //#define KROSS_PYTHON_EXTENSION_GETATTRMETHOD_DEBUG
+ //#define KROSS_PYTHON_EXTENSION_SETATTR_DEBUG
+
+ //#define KROSS_PYTHON_EXTENSION_CALL_DEBUG
+
+}}
+
+#endif
diff --git a/lib/kross/python/pythonextension.cpp b/lib/kross/python/pythonextension.cpp
new file mode 100644
index 00000000..59d9aaed
--- /dev/null
+++ b/lib/kross/python/pythonextension.cpp
@@ -0,0 +1,445 @@
+/***************************************************************************
+ * pythonextension.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "pythonextension.h"
+#include "pythonobject.h"
+
+#include "../api/variant.h"
+#include "../api/dict.h"
+#include "../api/exception.h"
+
+using namespace Kross::Python;
+
+PythonExtension::PythonExtension(Kross::Api::Object::Ptr object)
+ : Py::PythonExtension<PythonExtension>()
+ , m_object(object)
+{
+#ifdef KROSS_PYTHON_EXTENSION_CTOR_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::Constructor objectname='%1' objectclass='%2'").arg(m_object->getName()).arg(m_object->getClassName()) );
+#endif
+
+ behaviors().name("KrossPythonExtension");
+ /*
+ behaviors().doc(
+ "The common KrossPythonExtension object enables passing "
+ "of Kross::Api::Object's from C/C++ to Python and "
+ "backwards in a transparent way."
+ );
+ */
+ behaviors().supportGetattr();
+
+ m_proxymethod = new Py::MethodDefExt<PythonExtension>(
+ "", // methodname, not needed cause we use the method only internaly.
+ 0, // method that should handle the callback, not needed cause proxyhandler will handle it.
+ Py::method_varargs_call_handler_t( proxyhandler ), // callback handler
+ "" // documentation
+ );
+}
+
+PythonExtension::~PythonExtension()
+{
+#ifdef KROSS_PYTHON_EXTENSION_DTOR_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::Destructor objectname='%1' objectclass='%2'").arg(m_object->getName()).arg(m_object->getClassName()) );
+#endif
+ delete m_proxymethod;
+}
+
+#if 0
+Py::Object PythonExtension::str()
+{
+ Kross::Api::Callable* callable = dynamic_cast< Kross::Api::Callable* >(m_object);
+ QString s = callable ? callable->getName() : m_object->getClassName();
+ return toPyObject(s.isEmpty() ? : s);
+}
+
+Py::Object PythonExtension::repr()
+{
+ return toPyObject( m_object->toString() );
+}
+#endif
+
+Py::Object PythonExtension::getattr(const char* n)
+{
+#ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::getattr name='%1'").arg(n) );
+#endif
+
+ if(n[0] == '_') {
+ if(!strcmp(n, "__methods__")) {
+ Py::List methods;
+ QStringList calls = m_object->getCalls();
+ for(QStringList::Iterator it = calls.begin(); it != calls.end(); ++it) {
+#ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::getattr name='%1' callable='%2'").arg(n).arg(*it) );
+#endif
+ methods.append(Py::String( (*it).latin1() ));
+ }
+ return methods;
+ }
+
+ if(!strcmp(n, "__members__")) {
+ Py::List members;
+ Kross::Api::Callable* callable = dynamic_cast<Kross::Api::Callable*>(m_object.data());
+ if(callable) {
+ QMap<QString, Kross::Api::Object::Ptr> children = callable->getChildren();
+ QMap<QString, Kross::Api::Object::Ptr>::Iterator it( children.begin() );
+ for(; it != children.end(); ++it) {
+#ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::getattr n='%1' child='%2'").arg(n).arg(it.key()) );
+#endif
+ members.append(Py::String( it.key().latin1() ));
+ }
+ }
+ return members;
+ }
+
+ //if(n == "__dict__") { krosswarning( QString("PythonExtension::getattr(%1) __dict__").arg(n) ); return Py::None(); }
+ //if(n == "__class__") { krosswarning( QString("PythonExtension::getattr(%1) __class__").arg(n) ); return Py::None(); }
+
+#ifdef KROSS_PYTHON_EXTENSION_GETATTR_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::getattr name='%1' is a internal name.").arg(n) );
+#endif
+ return Py::PythonExtension<PythonExtension>::getattr_methods(n);
+ }
+
+ // Redirect the call to our static proxy method which will take care
+ // of handling the call.
+ Py::Tuple self(2);
+ self[0] = Py::Object(this);
+ self[1] = Py::String(n);
+ return Py::Object(PyCFunction_New( &m_proxymethod->ext_meth_def, self.ptr() ), true);
+}
+
+/*
+Py::Object PythonExtension::getattr_methods(const char* n)
+{
+#ifdef KROSS_PYTHON_EXTENSION_GETATTRMETHOD_DEBUG
+ krossdebug( QString("PythonExtension::getattr_methods name=%1").arg(n) );
+#endif
+ return Py::PythonExtension<PythonExtension>::getattr_methods(n);
+}
+
+int PythonExtension::setattr(const char* name, const Py::Object& value)
+{
+#ifdef KROSS_PYTHON_EXTENSION_SETATTR_DEBUG
+ krossdebug( QString("PythonExtension::setattr name=%1 value=%2").arg(name).arg(value.as_string().c_str()) );
+#endif
+ return Py::PythonExtension<PythonExtension>::setattr(name, value);
+}
+*/
+
+Kross::Api::List::Ptr PythonExtension::toObject(const Py::Tuple& tuple)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toObject(Py::Tuple)") );
+#endif
+
+ QValueList<Kross::Api::Object::Ptr> l;
+ uint size = tuple.size();
+ for(uint i = 0; i < size; i++)
+ l.append( toObject( tuple[i] ) );
+ return new Kross::Api::List(l);
+}
+
+Kross::Api::List::Ptr PythonExtension::toObject(const Py::List& list)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toObject(Py::List)") );
+#endif
+
+ QValueList<Kross::Api::Object::Ptr> l;
+ uint length = list.length();
+ for(uint i = 0; i < length; i++)
+ l.append( toObject( list[i] ) );
+ return new Kross::Api::List(l);
+}
+
+Kross::Api::Dict::Ptr PythonExtension::toObject(const Py::Dict& dict)
+{
+ QMap<QString, Kross::Api::Object::Ptr> map;
+ Py::List l = dict.keys();
+ uint length = l.length();
+ for(Py::List::size_type i = 0; i < length; ++i) {
+ const char* n = l[i].str().as_string().c_str();
+ map.replace(n, toObject( dict[n] ));
+ }
+ return new Kross::Api::Dict(map);
+}
+
+Kross::Api::Object::Ptr PythonExtension::toObject(const Py::Object& object)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toObject(Py::Object) object='%1'").arg(object.as_string().c_str()) );
+#endif
+ if(object == Py::None())
+ return 0;
+ PyTypeObject *type = (PyTypeObject*) object.type().ptr();
+#ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toObject(Py::Object) type='%1'").arg(type->tp_name) );
+#endif
+ if(type == &PyInt_Type)
+ return new Kross::Api::Variant(int(Py::Int(object)));
+ if(type == &PyBool_Type)
+ return new Kross::Api::Variant(QVariant(object.isTrue(),0));
+ if(type == &PyLong_Type)
+ return new Kross::Api::Variant(Q_LLONG(long(Py::Long(object))));
+ if(type == &PyFloat_Type)
+ return new Kross::Api::Variant(double(Py::Float(object)));
+
+ if( PyType_IsSubtype(type,&PyString_Type) ) {
+#ifdef Py_USING_UNICODE
+ /* TODO
+ if(type == &PyUnicode_Type) {
+ Py::unicodestring u = Py::String(object).as_unicodestring();
+ std::string s;
+ std::copy(u.begin(), u.end(), std::back_inserter(s));
+ return new Kross::Api::Variant(s.c_str());
+ }
+ */
+#endif
+ return new Kross::Api::Variant(object.as_string().c_str());
+ }
+
+ if(type == &PyTuple_Type)
+ return toObject(Py::Tuple(object)).data();
+ if(type == &PyList_Type)
+ return toObject(Py::List(object)).data();
+ if(type == &PyDict_Type)
+ return toObject(Py::Dict(object.ptr())).data();
+
+ if(object.isInstance())
+ return new PythonObject(object);
+
+ Py::ExtensionObject<PythonExtension> extobj(object);
+ PythonExtension* extension = extobj.extensionObject();
+ if(! extension) {
+ krosswarning("EXCEPTION in PythonExtension::toObject(): Failed to determinate PythonExtension object.");
+ throw Py::Exception("Failed to determinate PythonExtension object.");
+ }
+ if(! extension->m_object) {
+ krosswarning("EXCEPTION in PythonExtension::toObject(): Failed to convert the PythonExtension object into a Kross::Api::Object.");
+ throw Py::Exception("Failed to convert the PythonExtension object into a Kross::Api::Object.");
+ }
+
+#ifdef KROSS_PYTHON_EXTENSION_TOOBJECT_DEBUG
+ krossdebug( "Kross::Python::PythonExtension::toObject(Py::Object) successfully converted into Kross::Api::Object." );
+#endif
+ return extension->m_object;
+}
+
+const Py::Object PythonExtension::toPyObject(const QString& s)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyObject(QString)") );
+#endif
+ return s.isNull() ? Py::String() : Py::String(s.latin1());
+}
+
+const Py::List PythonExtension::toPyObject(const QStringList& list)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyObject(QStringList)") );
+#endif
+ Py::List l;
+ for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
+ l.append(toPyObject(*it));
+ return l;
+}
+
+const Py::Dict PythonExtension::toPyObject(const QMap<QString, QVariant>& map)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyObject(QMap<QString,QVariant>)") );
+#endif
+ Py::Dict d;
+ for(QMap<QString, QVariant>::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it)
+ d.setItem(it.key().latin1(), toPyObject(it.data()));
+ return d;
+}
+
+const Py::List PythonExtension::toPyObject(const QValueList<QVariant>& list)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyObject(QValueList<QVariant>)") );
+#endif
+ Py::List l;
+ for(QValueList<QVariant>::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
+ l.append(toPyObject(*it));
+ return l;
+}
+
+const Py::Object PythonExtension::toPyObject(const QVariant& variant)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyObject(QVariant) typename='%1'").arg(variant.typeName()) );
+#endif
+
+ switch(variant.type()) {
+ case QVariant::Invalid:
+ return Py::None();
+ case QVariant::Bool:
+ return Py::Int(variant.toBool());
+ case QVariant::Int:
+ return Py::Int(variant.toInt());
+ case QVariant::UInt:
+ return Py::Long((unsigned long)variant.toUInt());
+ case QVariant::Double:
+ return Py::Float(variant.toDouble());
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ case QVariant::ByteArray:
+ case QVariant::BitArray:
+ case QVariant::CString:
+ case QVariant::String:
+ return toPyObject(variant.toString());
+ case QVariant::StringList:
+ return toPyObject(variant.toStringList());
+ case QVariant::Map:
+ return toPyObject(variant.toMap());
+ case QVariant::List:
+ return toPyObject(variant.toList());
+
+ // To handle following both cases is a bit difficult
+ // cause Python doesn't spend an easy possibility
+ // for such large numbers (TODO maybe BigInt?). So,
+ // we risk overflows here, but well...
+ case QVariant::LongLong: {
+ Q_LLONG l = variant.toLongLong();
+ //return (l < 0) ? Py::Long((long)l) : Py::Long((unsigned long)l);
+ return Py::Long((long)l);
+ //return Py::Long(PyLong_FromLong( (long)l ), true);
+ } break;
+ case QVariant::ULongLong: {
+ return Py::Long((unsigned long)variant.toULongLong());
+ } break;
+
+ default: {
+ krosswarning( QString("Kross::Python::PythonExtension::toPyObject(QVariant) Not possible to convert the QVariant type '%1' to a Py::Object.").arg(variant.typeName()) );
+ return Py::None();
+ }
+ }
+}
+
+const Py::Object PythonExtension::toPyObject(Kross::Api::Object::Ptr object)
+{
+ if(! object) {
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug("Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is NULL => Py::None");
+#endif
+ return Py::None();
+ }
+
+ const QString classname = object->getClassName();
+ if(classname == "Kross::Api::Variant") {
+ QVariant v = static_cast<Kross::Api::Variant*>( object.data() )->getValue();
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::Variant %1").arg(v.toString()) );
+#endif
+ return toPyObject(v);
+ }
+
+ if(classname == "Kross::Api::List") {
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug("Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::List");
+#endif
+ Py::List pylist;
+ Kross::Api::List* list = static_cast<Kross::Api::List*>( object.data() );
+ QValueList<Kross::Api::Object::Ptr> valuelist = list->getValue();
+ for(QValueList<Kross::Api::Object::Ptr>::Iterator it = valuelist.begin(); it != valuelist.end(); ++it)
+ pylist.append( toPyObject(*it) ); // recursive
+ return pylist;
+ }
+
+ if(classname == "Kross::Api::Dict") {
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug("Kross::Python::PythonExtension::toPyObject(Kross::Api::Object) is Kross::Api::Dict");
+#endif
+ Py::Dict pydict;
+ Kross::Api::Dict* dict = static_cast<Kross::Api::Dict*>( object.data() );
+ QMap<QString, Kross::Api::Object::Ptr> valuedict = dict->getValue();
+ for(QMap<QString, Kross::Api::Object::Ptr>::Iterator it = valuedict.begin(); it != valuedict.end(); ++it) {
+ const char* n = it.key().latin1();
+ pydict[ n ] = toPyObject( it.data() ); // recursive
+ }
+ return pydict;
+ }
+
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Trying to handle PythonExtension::toPyObject(%1) as PythonExtension").arg(object->getClassName()) );
+#endif
+ return Py::asObject( new PythonExtension(object) );
+}
+
+const Py::Tuple PythonExtension::toPyTuple(Kross::Api::List::Ptr list)
+{
+#ifdef KROSS_PYTHON_EXTENSION_TOPYOBJECT_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::toPyTuple(Kross::Api::List) name='%1'").arg(list ? list->getName() : "NULL") );
+#endif
+ uint count = list ? list->count() : 0;
+ Py::Tuple tuple(count);
+ for(uint i = 0; i < count; i++)
+ tuple.setItem(i, toPyObject(list->item(i)));
+ return tuple;
+}
+
+PyObject* PythonExtension::proxyhandler(PyObject *_self_and_name_tuple, PyObject *args)
+{
+ Py::Tuple tuple(_self_and_name_tuple);
+ PythonExtension *self = static_cast<PythonExtension*>( tuple[0].ptr() );
+ QString methodname = Py::String(tuple[1]).as_string().c_str();
+
+ try {
+ Kross::Api::List::Ptr arguments = toObject( Py::Tuple(args) );
+
+#ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::proxyhandler methodname='%1' arguments='%2'").arg(methodname).arg(arguments->toString()) );
+#endif
+
+ Kross::Api::Callable* callable = dynamic_cast<Kross::Api::Callable*>(self->m_object.data());
+ if(callable && callable->hasChild(methodname)) {
+#ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::proxyhandler methodname='%1' is a child object of '%2'.").arg(methodname).arg(self->m_object->getName()) );
+#endif
+ Py::Object result = toPyObject( callable->getChild(methodname)->call(QString::null, arguments) );
+ result.increment_reference_count();
+ return result.ptr();
+ }
+#ifdef KROSS_PYTHON_EXTENSION_CALL_DEBUG
+ krossdebug( QString("Kross::Python::PythonExtension::proxyhandler try to call function with methodname '%1' in object '%2'.").arg(methodname).arg(self->m_object->getName()) );
+#endif
+ Py::Object result = toPyObject( self->m_object->call(methodname, arguments) );
+ result.increment_reference_count();
+ return result.ptr();
+ }
+ catch(Py::Exception& e) {
+ const QString err = Py::value(e).as_string().c_str();
+ krosswarning( QString("Py::Exception in Kross::Python::PythonExtension::proxyhandler %1").arg(err) );
+ //throw e;
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ const QString err = e->toString();
+ krosswarning( QString("Kross::Api::Exception in Kross::Python::PythonExtension::proxyhandler %1").arg(err) );
+ // Don't throw here cause it will end in a crash deep in python. The
+ // error is already handled anyway.
+ //throw Py::Exception( (char*) e->toString().latin1() );
+ }
+
+ return Py_None;
+}
diff --git a/lib/kross/python/pythonextension.h b/lib/kross/python/pythonextension.h
new file mode 100644
index 00000000..02e42587
--- /dev/null
+++ b/lib/kross/python/pythonextension.h
@@ -0,0 +1,221 @@
+/***************************************************************************
+ * pythonextension.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_EXTENSION_H
+#define KROSS_PYTHON_EXTENSION_H
+
+#include "pythonconfig.h"
+
+#include "../api/object.h"
+#include "../api/list.h"
+#include "../api/dict.h"
+#include "../api/class.h"
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qmap.h>
+#include <qvariant.h>
+
+namespace Kross { namespace Python {
+
+ // Forward declaration.
+ class PythonScript;
+
+ /**
+ * The PythonExtension is a wrapper-object to let C++ and
+ * Python interact together.
+ * Instances of this class are used everytime if we send
+ * or got something to/from python.
+ */
+ class PythonExtension : public Py::PythonExtension<PythonExtension>
+ {
+ friend class PythonScript;
+ friend class PythonObject;
+ friend class PythonModule;
+
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param object The \a Kross::Api::Object object
+ * this instance is the wrapper for.
+ */
+ explicit PythonExtension(Kross::Api::Object::Ptr object);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PythonExtension();
+
+#if 0
+ /**
+ * Overloaded method to return the string-representation
+ * of this object.
+ *
+ * \return The string representation.
+ */
+ virtual Py::Object str();
+
+ /**
+ * Overloaded method to return the string-representation
+ * of the value this object has.
+ *
+ * \return A string representation of the value.
+ */
+ virtual Py::Object repr();
+#endif
+
+ /**
+ * Overloaded method to handle attribute calls
+ * from within python.
+ *
+ * \param name The name of the attribute that
+ * should be handled.
+ * \return An \a Py::Object that could be
+ * a value or a callable object. Python
+ * will decide what to do with the
+ * returnvalue.
+ */
+ virtual Py::Object getattr(const char* name);
+
+ //virtual Py::Object getattr_methods(const char* name);
+ //virtual int setattr(const char* name, const Py::Object& value);
+
+ private:
+
+ /**
+ * Converts a \a Py::Tuple into a \a Kross::Api::List .
+ *
+ * \param tuple The Py::Tuple to convert.
+ * \return The to a Kross::Api::List converted Py::Tuple .
+ */
+ static Kross::Api::List::Ptr toObject(const Py::Tuple& tuple);
+
+ /**
+ * Converts a \a Py::List into a \a Kross::Api::List .
+ *
+ * \param list The Py::List to convert.
+ * \return The to a Kross::Api::List converted Py::List .
+ */
+ static Kross::Api::List::Ptr toObject(const Py::List& list);
+
+ /**
+ * Converts a \a Py::Dict into a \a Kross::Api::Dict .
+ *
+ * \param dict The Py::Dict to convert.
+ * \return The to a Kross::Api::Dict converted Py::Dict .
+ */
+ static Kross::Api::Dict::Ptr toObject(const Py::Dict& dict);
+
+ /**
+ * Converts a \a Py::Object into a \a Kross::Api::Object.
+ *
+ * \param object The Py::Object to convert.
+ * \return The to a Kross::Api::Object converted Py::Object.
+ */
+ static Kross::Api::Object::Ptr toObject(const Py::Object& object);
+
+ /**
+ * Converts a QString to a Py::Object. If
+ * the QString isNull() then Py::None() will
+ * be returned.
+ *
+ * \param s The QString to convert.
+ * \return The to a Py::String converted QString.
+ */
+ static const Py::Object toPyObject(const QString& s);
+
+ /**
+ * Converts a QStringList to a Py::List.
+ *
+ * \param list The QStringList to convert.
+ * \return The to a Py::List converted QStringList.
+ */
+ static const Py::List toPyObject(const QStringList& list);
+
+ /**
+ * Converts a QMap to a Py::Dict.
+ *
+ * \param map The QMap to convert.
+ * \return The to a Py::Dict converted QMap.
+ */
+ static const Py::Dict toPyObject(const QMap<QString, QVariant>& map);
+
+ /**
+ * Converts a QValueList to a Py::List.
+ *
+ * \param list The QValueList to convert.
+ * \return The to a Py::List converted QValueList.
+ */
+ static const Py::List toPyObject(const QValueList<QVariant>& list);
+
+ /**
+ * Converts a QVariant to a Py::Object.
+ *
+ * \param variant The QVariant to convert.
+ * \return The to a Py::Object converted QVariant.
+ */
+ static const Py::Object toPyObject(const QVariant& variant);
+
+ /**
+ * Converts a \a Kross::Api::Object to a Py::Object.
+ *
+ * \param object The Kross::Api::Object to convert.
+ * \return The to a Py::Object converted Kross::Api::Object.
+ */
+ static const Py::Object toPyObject(Kross::Api::Object::Ptr object);
+
+ /**
+ * Converts a \a Kross::Api::List into a Py::Tuple.
+ *
+ * \param list The Kross::Api::List to convert.
+ * \return The to a Py::Tuple converted Kross::Api::List.
+ */
+ static const Py::Tuple toPyTuple(Kross::Api::List::Ptr list);
+
+ /// The \a Kross::Api::Object this PythonExtension wraps.
+ Kross::Api::Object::Ptr m_object;
+
+ /**
+ * The proxymethod which will handle all calls to our
+ * \a PythonExtension instance.
+ */
+ Py::MethodDefExt<PythonExtension>* m_proxymethod;
+
+ /**
+ * The static proxy-handler which will be used to dispatch
+ * a call to our \a PythonExtension instance and redirect
+ * the call to the matching method.
+ *
+ * \param _self_and_name_tuple A tuple containing as first
+ * argument a reference to our \a PythonExtension
+ * instance.
+ * \param _args The optional passed arguments for the method
+ * which should be called.
+ * \return The returnvalue of the methodcall.
+ */
+ static PyObject* proxyhandler(PyObject* _self_and_name_tuple, PyObject* _args);
+ };
+
+}}
+
+#endif
diff --git a/lib/kross/python/pythoninterpreter.cpp b/lib/kross/python/pythoninterpreter.cpp
new file mode 100644
index 00000000..92f627dd
--- /dev/null
+++ b/lib/kross/python/pythoninterpreter.cpp
@@ -0,0 +1,255 @@
+/***************************************************************************
+ * pythoninterpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "pythoninterpreter.h"
+#include "pythonscript.h"
+#include "pythonmodule.h"
+#include "pythonsecurity.h"
+//#include "pythonextension.h"
+#include "../api/variant.h"
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#if defined(Q_WS_WIN)
+ #define PYPATHDELIMITER ";"
+#else
+ #define PYPATHDELIMITER ":"
+#endif
+
+extern "C"
+{
+ /**
+ * Exported and loadable function as entry point to use
+ * the \a PythonInterpreter.
+ * The krosspython library the \a PythonInterpreter is part
+ * will be loaded dynamicly at runtime from e.g.
+ * \a Kross::Api::Manager::getInterpreter and this exported
+ * function will be used to return an instance of the
+ * \a PythonInterpreter implementation.
+ */
+ void* krossinterpreter(Kross::Api::InterpreterInfo* info)
+ {
+ try {
+ return new Kross::Python::PythonInterpreter(info);
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ Kross::krosswarning("krossinterpreter(Kross::Api::InterpreterInfo* info): Unhandled exception.");
+ }
+ return 0;
+ }
+}
+
+using namespace Kross::Python;
+
+namespace Kross { namespace Python {
+
+ /// \internal
+ class PythonInterpreterPrivate
+ {
+ public:
+
+ /// The __main__ python module.
+ PythonModule* mainmodule;
+
+ /// The \a PythonSecurity python module to wrap the RestrictedPython functionality.
+ PythonSecurity* security;
+ };
+
+}}
+
+PythonInterpreter::PythonInterpreter(Kross::Api::InterpreterInfo* info)
+ : Kross::Api::Interpreter(info)
+ , d(new PythonInterpreterPrivate())
+{
+ // Initialize the python interpreter.
+ initialize();
+
+ // Set name of the program.
+ Py_SetProgramName(const_cast<char*>("Kross"));
+
+ /*
+ // Set arguments.
+ //char* comm[0];
+ const char* comm = const_cast<char*>("kross"); // name.
+ PySys_SetArgv(1, comm);
+ */
+
+ // In the python sys.path are all module-directories are
+ // listed in.
+ QString path;
+
+ // First import the sys-module to remember it's sys.path
+ // list in our path QString.
+ Py::Module sysmod( PyImport_ImportModule("sys"), true );
+ Py::Dict sysmoddict = sysmod.getDict();
+ Py::Object syspath = sysmoddict.getItem("path");
+ if(syspath.isList()) {
+ Py::List syspathlist = syspath;
+ for(Py::List::iterator it = syspathlist.begin(); it != syspathlist.end(); ++it)
+ if( (*it).isString() )
+ path.append( QString(Py::String(*it).as_string().c_str()) + PYPATHDELIMITER );
+ }
+ else
+ path = Py_GetPath();
+
+ // Determinate additional module-paths we like to add.
+ // First add the global Kross modules-path.
+ QStringList krossdirs = KGlobal::dirs()->findDirs("data", "kross/python");
+ for(QStringList::Iterator krossit = krossdirs.begin(); krossit != krossdirs.end(); ++krossit)
+ path.append(*krossit + PYPATHDELIMITER);
+ // Then add the application modules-path.
+ QStringList appdirs = KGlobal::dirs()->findDirs("appdata", "kross/python");
+ for(QStringList::Iterator appit = appdirs.begin(); appit != appdirs.end(); ++appit)
+ path.append(*appit + PYPATHDELIMITER);
+
+ // Set the extended sys.path.
+ PySys_SetPath( (char*) path.latin1() );
+
+ krossdebug(QString("Python ProgramName: %1").arg(Py_GetProgramName()));
+ krossdebug(QString("Python ProgramFullPath: %1").arg(Py_GetProgramFullPath()));
+ krossdebug(QString("Python Version: %1").arg(Py_GetVersion()));
+ krossdebug(QString("Python Platform: %1").arg(Py_GetPlatform()));
+ krossdebug(QString("Python Prefix: %1").arg(Py_GetPrefix()));
+ krossdebug(QString("Python ExecPrefix: %1").arg(Py_GetExecPrefix()));
+ krossdebug(QString("Python Path: %1").arg(Py_GetPath()));
+ krossdebug(QString("Python System Path: %1").arg(path));
+
+ // Initialize the main module.
+ d->mainmodule = new PythonModule(this);
+
+ // The main dictonary.
+ Py::Dict moduledict = d->mainmodule->getDict();
+ //TODO moduledict["KrossPythonVersion"] = Py::Int(KROSS_PYTHON_VERSION);
+
+ // Prepare the interpreter.
+ QString s =
+ "import sys\n"
+ //"sys.setdefaultencoding('latin-1')\n"
+
+ // Dirty hack to get sys.argv defined. Needed for e.g. TKinter.
+ "sys.argv = ['']\n"
+
+ // On the try to read something from stdin always return an empty
+ // string. That way such reads don't block our script.
+ "import cStringIO\n"
+ "sys.stdin = cStringIO.StringIO()\n"
+
+ // Class to redirect something. We use this class e.g. to redirect
+ // <stdout> and <stderr> to a c++ event.
+ "class Redirect:\n"
+ " def __init__(self, target):\n"
+ " self.target = target\n"
+ " def write(self, s):\n"
+ " self.target.call(s)\n"
+
+ // Wrap builtin __import__ method. All import requests are
+ // first redirected to our PythonModule.import method and
+ // if the call returns None, then we call the original
+ // python import mechanism.
+ "import __builtin__\n"
+ "import __main__\n"
+ "class Importer:\n"
+ " def __init__(self):\n"
+ " self.realImporter = __builtin__.__import__\n"
+ " __builtin__.__import__ = self._import\n"
+ " def _import(self, name, globals=None, locals=None, fromlist=[]):\n"
+ " mod = __main__._import(name, globals, locals, fromlist)\n"
+ " if mod != None: return mod\n"
+ " return self.realImporter(name, globals, locals, fromlist)\n"
+ "Importer()\n"
+ ;
+
+ PyObject* pyrun = PyRun_String(s.latin1(), Py_file_input, moduledict.ptr(), moduledict.ptr());
+ if(! pyrun) {
+ Py::Object errobj = Py::value(Py::Exception()); // get last error
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to prepare the __main__ module: %1").arg(errobj.as_string().c_str())) );
+ }
+ Py_XDECREF(pyrun); // free the reference.
+
+ // Initialize the RestrictedPython module.
+ d->security = new PythonSecurity(this);
+}
+
+PythonInterpreter::~PythonInterpreter()
+{
+ // Free the zope security module.
+ delete d->security; d->security = 0;
+ // Free the main module.
+ delete d->mainmodule; d->mainmodule = 0;
+ // Finalize the python interpreter.
+ finalize();
+ // Delete the private d-pointer.
+ delete d;
+}
+
+void PythonInterpreter::initialize()
+{
+ // Initialize python.
+ Py_Initialize();
+
+ /* Not needed cause we use the >= Python 2.3 GIL-mechanism.
+ PyThreadState* d->globalthreadstate, d->threadstate;
+ // First we have to initialize threading if python supports it.
+ PyEval_InitThreads();
+ // The main thread. We don't use it later.
+ d->globalthreadstate = PyThreadState_Swap(NULL);
+ d->globalthreadstate = PyEval_SaveThread();
+ // We use an own sub-interpreter for each thread.
+ d->threadstate = Py_NewInterpreter();
+ // Note that this application has multiple threads.
+ // It maintains a separate interp (sub-interpreter) for each thread.
+ PyThreadState_Swap(d->threadstate);
+ // Work done, release the lock.
+ PyEval_ReleaseLock();
+ */
+}
+
+void PythonInterpreter::finalize()
+{
+ /* Not needed cause we use the >= Python 2.3 GIL-mechanism.
+ // Lock threads.
+ PyEval_AcquireLock();
+ // Free the used thread.
+ PyEval_ReleaseThread(d->threadstate);
+ // Set back to rememberd main thread.
+ PyThreadState_Swap(d->globalthreadstate);
+ // Work done, unlock.
+ PyEval_ReleaseLock();
+ */
+
+ // Finalize python.
+ Py_Finalize();
+}
+
+Kross::Api::Script* PythonInterpreter::createScript(Kross::Api::ScriptContainer* scriptcontainer)
+{
+ return new PythonScript(this, scriptcontainer);
+}
+
+PythonModule* PythonInterpreter::mainModule()
+{
+ return d->mainmodule;
+}
+
+PythonSecurity* PythonInterpreter::securityModule()
+{
+ return d->security;
+}
+
diff --git a/lib/kross/python/pythoninterpreter.h b/lib/kross/python/pythoninterpreter.h
new file mode 100644
index 00000000..7c4088fa
--- /dev/null
+++ b/lib/kross/python/pythoninterpreter.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * pythoninterpreter.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_INTERPRETER_H
+#define KROSS_PYTHON_INTERPRETER_H
+
+#include "pythonconfig.h"
+#include "../api/object.h"
+#include "../api/interpreter.h"
+#include "../main/manager.h"
+//#include "../api/script.h"
+#include "../main/scriptcontainer.h"
+
+#include <qstring.h>
+
+namespace Kross { namespace Python {
+
+ // Forward declarations.
+ class PythonSecurity;
+ class PythonModule;
+ class PythonInterpreterPrivate;
+
+ /**
+ * Python interpreter bridge.
+ *
+ * Implements an \a Kross::Api::Interpreter for the python
+ * interpreter.
+ */
+ class PythonInterpreter : public Kross::Api::Interpreter
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param info The \a Kross::Api::InterpreterInfo instance
+ * which describes the \a PythonInterpreter for
+ * applications using Kross.
+ */
+ PythonInterpreter(Kross::Api::InterpreterInfo* info);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PythonInterpreter();
+
+ /**
+ * \return a \a PythonScript instance.
+ */
+ virtual Kross::Api::Script* createScript(Kross::Api::ScriptContainer* scriptcontainer);
+
+ /**
+ * \return the \a MainModule instance.
+ */
+ PythonModule* mainModule();
+
+ /**
+ * \return the \a PythonSecurity instance.
+ */
+ PythonSecurity* securityModule();
+
+ private:
+ /// Internal d-pointer class.
+ PythonInterpreterPrivate* d;
+
+ /// Initialize the python interpreter.
+ inline void initialize();
+ /// Finalize the python interpreter.
+ inline void finalize();
+ };
+
+}}
+
+#endif
diff --git a/lib/kross/python/pythonmodule.cpp b/lib/kross/python/pythonmodule.cpp
new file mode 100644
index 00000000..b54eb73f
--- /dev/null
+++ b/lib/kross/python/pythonmodule.cpp
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * pythonmodule.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "pythonmodule.h"
+#include "pythoninterpreter.h"
+
+#include <qregexp.h>
+
+using namespace Kross::Python;
+
+namespace Kross { namespace Python {
+
+ /// @internal
+ class PythonModulePrivate
+ {
+ public:
+
+ /**
+ * The \a PythonInterpreter instance this module is
+ * part of.
+ */
+ PythonInterpreter* m_interpreter;
+
+ /**
+ * List of \a PythonExtension instances accessible
+ * via this \a PythonModule instance.
+ */
+ QMap<QString, PythonExtension*> m_modules;
+
+ };
+
+}}
+
+PythonModule::PythonModule(PythonInterpreter* interpreter)
+ : Py::ExtensionModule<PythonModule>("__main__")
+ , d(new PythonModulePrivate())
+{
+#ifdef KROSS_PYTHON_MODULE_DEBUG
+ krossdebug( QString("Kross::Python::PythonModule::Constructor") );
+#endif
+
+ d->m_interpreter = interpreter;
+
+ add_varargs_method("_import", &PythonModule::import, "FIXME: Documentation");
+
+ initialize("The PythonModule is the __main__ python environment used as global object namespace.");
+}
+
+PythonModule::~PythonModule()
+{
+#ifdef KROSS_PYTHON_MODULE_DEBUG
+ krossdebug( QString("Kross::Python::PythonModule::Destructor name='%1'").arg(name().c_str()) );
+#endif
+
+ delete d;
+}
+
+Py::Dict PythonModule::getDict()
+{
+ return moduleDictionary();
+}
+
+Py::Object PythonModule::import(const Py::Tuple& args)
+{
+ if(args.size() > 0) {
+ QString modname = args[0].as_string().c_str();
+ if(modname.startsWith("kross")) {
+#ifdef KROSS_PYTHON_MODULE_DEBUG
+ krossdebug( QString("Kross::Python::PythonModule::import() module=%1").arg(modname) );
+#endif
+ if( modname.find( QRegExp("[^a-zA-Z0-9\\_\\-]") ) >= 0 ) {
+ krosswarning( QString("Denied import of Kross module '%1' cause of untrusted chars.").arg(modname) );
+ }
+ else {
+ Kross::Api::Module::Ptr module = Kross::Api::Manager::scriptManager()->loadModule(modname);
+ if(module)
+ return PythonExtension::toPyObject( Kross::Api::Object::Ptr(module) );
+ krosswarning( QString("Loading of Kross module '%1' failed.").arg(modname) );
+ }
+
+ }
+ }
+ return Py::None();
+}
diff --git a/lib/kross/python/pythonmodule.h b/lib/kross/python/pythonmodule.h
new file mode 100644
index 00000000..1775ae68
--- /dev/null
+++ b/lib/kross/python/pythonmodule.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * pythonmodule.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_MODULE_H
+#define KROSS_PYTHON_MODULE_H
+
+#include "pythonconfig.h"
+#include "../api/object.h"
+#include "../api/script.h"
+#include "pythonextension.h"
+
+#include <qstring.h>
+
+namespace Kross { namespace Python {
+
+ // Forward declaration.
+ class PythonInterpreter;
+ class PythonModulePrivate;
+
+ /**
+ * The PythonModule is the __main__ python environment
+ * used as global object namespace.
+ *
+ * The module also spends access to the whole Kross
+ * functionality and manages all the PythonExtension
+ * modules.
+ */
+ class PythonModule : public Py::ExtensionModule<PythonModule>
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param interpreter The \a PythonInterpreter instance
+ * used to create this PythonModule.
+ */
+ PythonModule(PythonInterpreter* interpreter);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PythonModule();
+
+ /**
+ * \return the dictonary this PythonModule has.
+ */
+ Py::Dict getDict();
+
+ private:
+ /// Internal d-pointer class.
+ PythonModulePrivate* d;
+
+ /// Import hook used to load external kross libs on demand.
+ Py::Object import(const Py::Tuple&);
+ };
+
+}}
+
+#endif
diff --git a/lib/kross/python/pythonobject.cpp b/lib/kross/python/pythonobject.cpp
new file mode 100644
index 00000000..d59087b3
--- /dev/null
+++ b/lib/kross/python/pythonobject.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * pythonobject.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "pythonobject.h"
+#include "pythonextension.h"
+
+using namespace Kross::Python;
+
+PythonObject::PythonObject(const Py::Object& object)
+ : Kross::Api::Object()
+ , m_pyobject(object)
+{
+ krossdebug( QString("PythonObject::PythonObject() constructor") );
+
+ Py::List x( object.dir() );
+ for(Py::Sequence::iterator i= x.begin(); i != x.end(); ++i) {
+ std::string s = (*i).str();
+ if(s == "__init__")
+ continue;
+
+ //if(! m_pyobject.hasAttr( (*i).str() )) continue;
+ Py::Object o = m_pyobject.getAttr(s);
+
+ QString t;
+ if(o.isCallable()) t += "isCallable ";
+ if(o.isDict()) t += "isDict ";
+ if(o.isList()) t += "isList ";
+ if(o.isMapping()) t += "isMapping ";
+ if(o.isNumeric()) t += "isNumeric ";
+ if(o.isSequence()) t += "isSequence ";
+ if(o.isTrue()) t += "isTrue ";
+ if(o.isInstance()) t += "isInstance ";
+ krossdebug( QString("PythonObject::PythonObject() method '%1' (%2)").arg( (*i).str().as_string().c_str() ).arg(t) );
+
+ if(o.isCallable())
+ m_calls.append( (*i).str().as_string().c_str() );
+ }
+}
+
+PythonObject::~PythonObject()
+{
+}
+
+const QString PythonObject::getClassName() const
+{
+ return "Kross::Python::PythonObject";
+}
+
+Kross::Api::Object::Ptr PythonObject::call(const QString& name, Kross::Api::List::Ptr arguments)
+{
+ krossdebug( QString("PythonObject::call(%1)").arg(name) );
+
+ if(m_pyobject.isInstance()) {
+ //if(! m_calls.contains(n)) throw ...
+
+ PyObject* r = PyObject_CallMethod(m_pyobject.ptr(), (char*) name.latin1(), 0);
+ if(! r) { //FIXME happens too if e.g. number of arguments doesn't match !!!
+ Py::Object errobj = Py::value(Py::Exception()); // get last error
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to call method '%1': %2").arg(name).arg(errobj.as_string().c_str())) );
+ }
+ Py::Object result(r, true);
+
+ //krossdebug( QString("PythonObject::call(%1) call return value = '%2'").arg(name).arg(result.as_string().c_str()) );
+ return PythonExtension::toObject(result);
+ }
+ /*TODO??? ELSE create class instance for class-definitions???
+ Kross::Api::ClassBase* clazz = new Kross::Api::ClassBase("", this);
+ return new PythonExtension(clazz);
+ */
+
+ return Kross::Api::Object::call(name, arguments);
+}
+
+QStringList PythonObject::getCalls()
+{
+ return m_calls;
+}
+
diff --git a/lib/kross/python/pythonobject.h b/lib/kross/python/pythonobject.h
new file mode 100644
index 00000000..6d33da26
--- /dev/null
+++ b/lib/kross/python/pythonobject.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * pythonobject.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_OBJECT_H
+#define KROSS_PYTHON_OBJECT_H
+
+#include "pythonconfig.h"
+#include "../api/object.h"
+#include "../api/list.h"
+#include "pythonextension.h"
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+namespace Kross { namespace Python {
+
+ /**
+ * The PythonObject class is used for Instances of Python
+ * Classes by the \a PythonExtension class.
+ */
+ class PythonObject : public Kross::Api::Object
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param object The Py::Object this \a PythonObject
+ * provides access to.
+ */
+ explicit PythonObject(const Py::Object& object);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PythonObject();
+
+ /**
+ * Return the class name. This could be something
+ * like "Kross::Python::PythonObject" for this
+ * object. The value is mainly used for display
+ * purposes.
+ *
+ * \return The name of this class.
+ */
+ virtual const QString getClassName() const;
+
+ /**
+ * Pass a call to the object. Objects like \a Class
+ * are able to handle call's by just implementating
+ * this function.
+ *
+ * \throws TypeException if the object or the name
+ * is not callable.
+ * \param name Each call has a name that says what
+ * should be called. In the case of a \a Class
+ * the name is the functionname.
+ * \param arguments The list of arguments passed to
+ * the call.
+ * \return The call-result as Object* instance or
+ * NULL if the call has no result.
+ */
+ virtual Kross::Api::Object::Ptr call(const QString& name, Kross::Api::List::Ptr arguments);
+
+ /**
+ * Return a list of supported callable objects.
+ *
+ * \return List of supported calls.
+ */
+ virtual QStringList getCalls();
+
+ private:
+ const Py::Object m_pyobject;
+ QStringList m_calls;
+ };
+
+}}
+
+#endif
diff --git a/lib/kross/python/pythonscript.cpp b/lib/kross/python/pythonscript.cpp
new file mode 100644
index 00000000..082b5440
--- /dev/null
+++ b/lib/kross/python/pythonscript.cpp
@@ -0,0 +1,460 @@
+/***************************************************************************
+ * pythonscript.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "pythonscript.h"
+#include "pythonmodule.h"
+#include "pythoninterpreter.h"
+#include "pythonsecurity.h"
+#include "../main/scriptcontainer.h"
+
+//#include <kapplication.h>
+
+using namespace Kross::Python;
+
+namespace Kross { namespace Python {
+
+ /// @internal
+ class PythonScriptPrivate
+ {
+ public:
+
+ /**
+ * The \a Py::Module instance this \a PythonScript
+ * has as local context.
+ */
+ Py::Module* m_module;
+
+ /**
+ * The PyCodeObject object representing the
+ * compiled python code. Internaly we first
+ * compile the python code and later execute
+ * it.
+ */
+ Py::Object* m_code;
+
+ /**
+ * A list of functionnames.
+ */
+ QStringList m_functions;
+
+ /**
+ * A list of classnames.
+ */
+ QStringList m_classes;
+ };
+
+}}
+
+PythonScript::PythonScript(Kross::Api::Interpreter* interpreter, Kross::Api::ScriptContainer* scriptcontainer)
+ : Kross::Api::Script(interpreter, scriptcontainer)
+ , d(new PythonScriptPrivate())
+{
+#ifdef KROSS_PYTHON_SCRIPT_CTOR_DEBUG
+ krossdebug("PythonScript::PythonScript() Constructor.");
+#endif
+ d->m_module = 0;
+ d->m_code = 0;
+}
+
+PythonScript::~PythonScript()
+{
+#ifdef KROSS_PYTHON_SCRIPT_DTOR_DEBUG
+ krossdebug("PythonScript::~PythonScript() Destructor.");
+#endif
+ finalize();
+ delete d;
+}
+
+void PythonScript::initialize()
+{
+ finalize();
+ clearException(); // clear previously thrown exceptions.
+
+ try {
+ if(m_scriptcontainer->getCode().isNull())
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Invalid scripting code for script '%1'").arg( m_scriptcontainer->getName() )) );
+
+ if(m_scriptcontainer->getName().isNull())
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Name for the script is invalid!")) );
+
+ PyObject* pymod = PyModule_New( (char*) m_scriptcontainer->getName().latin1() );
+ d->m_module = new Py::Module(pymod, true);
+ if(! d->m_module)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to initialize local module context for script '%1'").arg( m_scriptcontainer->getName() )) );
+
+#ifdef KROSS_PYTHON_SCRIPT_INIT_DEBUG
+ krossdebug( QString("PythonScript::initialize() module='%1' refcount='%2'").arg(d->m_module->as_string().c_str()).arg(d->m_module->reference_count()) );
+#endif
+
+ // Set the "self" variable to point to the ScriptContainer
+ // we are using for the script. That way we are able to
+ // simply access the ScriptContainer itself from within
+ // python scripting code.
+ Py::Dict moduledict = d->m_module->getDict();
+ moduledict["self"] = PythonExtension::toPyObject( m_scriptcontainer );
+ //moduledict["parent"] = PythonExtension::toPyObject( m_manager );
+
+/*
+ // Prepare the local context.
+ QString s =
+ //"import sys\n"
+ "if self.has(\"stdout\"):\n"
+ " self.stdout = Redirect( self.get(\"stdout\") )\n"
+ "if self.has(\"stderr\"):\n"
+ " self.stderr = Redirect( self.get(\"stderr\") )\n"
+ ;
+ Py::Dict mainmoduledict = ((PythonInterpreter*)m_interpreter)->mainModule()->getDict();
+ PyObject* pyrun = PyRun_StringFlags((char*)s.latin1(), Py_file_input, mainmoduledict.ptr(), moduledict.ptr());
+ if(! pyrun)
+ throw Py::Exception(); // throw exception
+ Py_XDECREF(pyrun); // free the reference.
+*/
+
+ // Compile the python script code. It will be later on request
+ // executed. That way we cache the compiled code.
+ PyObject* code = 0;
+ bool restricted = m_scriptcontainer->getOption("restricted", QVariant(false,0), true).toBool();
+
+ krossdebug( QString("PythonScript::initialize() name=%1 restricted=%2").arg(m_scriptcontainer->getName()).arg(restricted) );
+ if(restricted) {
+
+ // Use the RestrictedPython module wrapped by the PythonSecurity class.
+ code = dynamic_cast<PythonInterpreter*>(m_interpreter)->securityModule()->compile_restricted(
+ m_scriptcontainer->getCode(),
+ m_scriptcontainer->getName(),
+ "exec"
+ );
+
+ }
+ else {
+ //PyCompilerFlags* cf = new PyCompilerFlags;
+ //cf->cf_flags |= PyCF_SOURCE_IS_UTF8;
+
+ // Just compile the code without any restrictions.
+ code = Py_CompileString(
+ (char*) m_scriptcontainer->getCode().latin1(),
+ (char*) m_scriptcontainer->getName().latin1(),
+ Py_file_input
+ );
+ }
+
+ if(! code)
+ throw Py::Exception();
+ d->m_code = new Py::Object(code, true);
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ Kross::Api::Exception::Ptr exception = toException( QString("Failed to compile python code: %1").arg(err) );
+ e.clear(); // exception is handled. clear it now.
+ throw exception;
+ }
+}
+
+void PythonScript::finalize()
+{
+#ifdef KROSS_PYTHON_SCRIPT_FINALIZE_DEBUG
+ if(d->m_module)
+ krossdebug( QString("PythonScript::finalize() module='%1' refcount='%2'").arg(d->m_module->as_string().c_str()).arg(d->m_module->reference_count()) );
+#endif
+
+ delete d->m_module; d->m_module = 0;
+ delete d->m_code; d->m_code = 0;
+ d->m_functions.clear();
+ d->m_classes.clear();
+}
+
+Kross::Api::Exception::Ptr PythonScript::toException(const QString& error)
+{
+ long lineno = -1;
+ QStringList errorlist;
+
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+ Py_FlushLine();
+ PyErr_NormalizeException(&type, &value, &traceback);
+
+ if(traceback) {
+ Py::List tblist;
+ try {
+ Py::Module tbmodule( PyImport_Import(Py::String("traceback").ptr()), true );
+ Py::Dict tbdict = tbmodule.getDict();
+ Py::Callable tbfunc(tbdict.getItem("format_tb"));
+ Py::Tuple args(1);
+ args.setItem(0, Py::Object(traceback));
+ tblist = tbfunc.apply(args);
+ uint length = tblist.length();
+ for(Py::List::size_type i = 0; i < length; ++i)
+ errorlist.append( Py::Object(tblist[i]).as_string().c_str() );
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ e.clear(); // exception is handled. clear it now.
+ krosswarning( QString("Kross::Python::PythonScript::toException() Failed to fetch a traceback: %1").arg(err) );
+ }
+
+ PyObject *next;
+ while (traceback && traceback != Py_None) {
+ PyFrameObject *frame = (PyFrameObject*)PyObject_GetAttrString(traceback, "tb_frame");
+ Py_DECREF(frame);
+ {
+ PyObject *getobj = PyObject_GetAttrString(traceback, "tb_lineno");
+ lineno = PyInt_AsLong(getobj);
+ Py_DECREF(getobj);
+ }
+ if(Py_OptimizeFlag) {
+ PyObject *getobj = PyObject_GetAttrString(traceback, "tb_lasti");
+ int lasti = PyInt_AsLong(getobj);
+ Py_DECREF(getobj);
+ lineno = PyCode_Addr2Line(frame->f_code, lasti);
+ }
+
+ //const char* filename = PyString_AsString(frame->f_code->co_filename);
+ //const char* name = PyString_AsString(frame->f_code->co_name);
+ //errorlist.append( QString("%1#%2: \"%3\"").arg(filename).arg(lineno).arg(name) );
+
+ next = PyObject_GetAttrString(traceback, "tb_next");
+ Py_DECREF(traceback);
+ traceback = next;
+ }
+ }
+
+ if(lineno < 0) {
+ if(value) {
+ PyObject *getobj = PyObject_GetAttrString(value, "lineno");
+ if(getobj) {
+ lineno = PyInt_AsLong(getobj);
+ Py_DECREF(getobj);
+ }
+ }
+ if(lineno < 0)
+ lineno = 0;
+ }
+
+ //PyErr_Restore(type, value, traceback);
+
+ Kross::Api::Exception::Ptr exception = new Kross::Api::Exception(error, lineno - 1);
+ if(errorlist.count() > 0)
+ exception->setTrace( errorlist.join("\n") );
+ return exception;
+}
+
+const QStringList& PythonScript::getFunctionNames()
+{
+ if(! d->m_module)
+ initialize(); //TODO catch exception
+ return d->m_functions;
+ /*
+ QStringList list;
+ Py::List l = d->m_module->getDict().keys();
+ int length = l.length();
+ for(Py::List::size_type i = 0; i < length; ++i)
+ list.append( l[i].str().as_string().c_str() );
+ return list;
+ */
+}
+
+Kross::Api::Object::Ptr PythonScript::execute()
+{
+#ifdef KROSS_PYTHON_SCRIPT_EXEC_DEBUG
+ krossdebug( QString("PythonScript::execute()") );
+#endif
+
+ try {
+ if(! d->m_module)
+ initialize();
+
+ // the main module dictonary.
+ Py::Dict mainmoduledict = ((PythonInterpreter*)m_interpreter)->mainModule()->getDict();
+ // the local context dictonary.
+ Py::Dict moduledict( d->m_module->getDict().ptr() );
+
+ // Initialize context before execution.
+ QString s =
+ "import sys\n"
+ //"if self.has(\"stdout\"):\n"
+ //" sys.stdout = Redirect( self.get(\"stdout\") )\n"
+ //"if self.has(\"stderr\"):\n"
+ //" sys.stderr = Redirect( self.get(\"stderr\") )\n"
+ ;
+
+ PyObject* pyrun = PyRun_String(s.latin1(), Py_file_input, mainmoduledict.ptr(), moduledict.ptr());
+ if(! pyrun)
+ throw Py::Exception(); // throw exception
+ Py_XDECREF(pyrun); // free the reference.
+
+ // Acquire interpreter lock*/
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ // Evaluate the already compiled code.
+ PyObject* pyresult = PyEval_EvalCode(
+ (PyCodeObject*)d->m_code->ptr(),
+ mainmoduledict.ptr(),
+ moduledict.ptr()
+ );
+
+ // Free interpreter lock
+ PyGILState_Release(gilstate);
+
+ if(! pyresult || PyErr_Occurred()) {
+ krosswarning("Kross::Python::PythonScript::execute(): Failed to PyEval_EvalCode");
+ throw Py::Exception();
+ }
+ Py::Object result(pyresult, true);
+
+#ifdef KROSS_PYTHON_SCRIPT_EXEC_DEBUG
+ krossdebug( QString("PythonScript::execute() result=%1").arg(result.as_string().c_str()) );
+#endif
+
+ for(Py::Dict::iterator it = moduledict.begin(); it != moduledict.end(); ++it) {
+ Py::Dict::value_type vt(*it);
+ if(PyClass_Check( vt.second.ptr() )) {
+#ifdef KROSS_PYTHON_SCRIPT_EXEC_DEBUG
+ krossdebug( QString("PythonScript::execute() class '%1' added.").arg(vt.first.as_string().c_str()) );
+#endif
+ d->m_classes.append( vt.first.as_string().c_str() );
+ }
+ else if(vt.second.isCallable()) {
+#ifdef KROSS_PYTHON_SCRIPT_EXEC_DEBUG
+ krossdebug( QString("PythonScript::execute() function '%1' added.").arg(vt.first.as_string().c_str()) );
+#endif
+ d->m_functions.append( vt.first.as_string().c_str() );
+ }
+ }
+
+ Kross::Api::Object::Ptr r = PythonExtension::toObject(result);
+ return r;
+ }
+ catch(Py::Exception& e) {
+ try {
+ Py::Object errobj = Py::value(e);
+ if(errobj.ptr() == Py_None) // at least string-exceptions have there errormessage in the type-object
+ errobj = Py::type(e);
+ QString err = errobj.as_string().c_str();
+
+ Kross::Api::Exception::Ptr exception = toException( QString("Failed to execute python code: %1").arg(err) );
+ e.clear(); // exception is handled. clear it now.
+ setException( exception );
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ Kross::Api::Exception::Ptr exception = toException( QString("Failed to execute python code: %1").arg(err) );
+ e.clear(); // exception is handled. clear it now.
+ setException( exception );
+ }
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ setException(e);
+ }
+
+ return 0; // return nothing if exception got thrown.
+}
+
+Kross::Api::Object::Ptr PythonScript::callFunction(const QString& name, Kross::Api::List::Ptr args)
+{
+#ifdef KROSS_PYTHON_SCRIPT_CALLFUNC_DEBUG
+ krossdebug( QString("PythonScript::callFunction(%1, %2)")
+ .arg(name)
+ .arg(args ? QString::number(args->count()) : QString("NULL")) );
+#endif
+
+ if(hadException()) return 0; // abort if we had an unresolved exception.
+
+ if(! d->m_module) {
+ setException( new Kross::Api::Exception(QString("Script not initialized.")) );
+ return 0;
+ }
+
+ try {
+ Py::Dict moduledict = d->m_module->getDict();
+
+ // Try to determinate the function we like to execute.
+ PyObject* func = PyDict_GetItemString(moduledict.ptr(), name.latin1());
+
+ if( (! d->m_functions.contains(name)) || (! func) )
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("No such function '%1'.").arg(name)) );
+
+ Py::Callable funcobject(func, true); // the funcobject takes care of freeing our func pyobject.
+
+ // Check if the object is really a function and therefore callable.
+ if(! funcobject.isCallable())
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Function is not callable.")) );
+
+ // Call the function.
+ Py::Object result = funcobject.apply(PythonExtension::toPyTuple(args));
+ return PythonExtension::toObject(result);
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ e.clear(); // exception is handled. clear it now.
+ setException( new Kross::Api::Exception(QString("Python Exception: %1").arg(err)) );
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ setException(e);
+ }
+
+ return 0; // return nothing if exception got thrown.
+}
+
+const QStringList& PythonScript::getClassNames()
+{
+ if(! d->m_module)
+ initialize(); //TODO catch exception
+ return d->m_classes;
+}
+
+Kross::Api::Object::Ptr PythonScript::classInstance(const QString& name)
+{
+ if(hadException()) return 0; // abort if we had an unresolved exception.
+
+ if(! d->m_module) {
+ setException( new Kross::Api::Exception(QString("Script not initialized.")) );
+ return 0;
+ }
+
+ try {
+ Py::Dict moduledict = d->m_module->getDict();
+
+ // Try to determinate the class.
+ PyObject* pyclass = PyDict_GetItemString(moduledict.ptr(), name.latin1());
+ if( (! d->m_classes.contains(name)) || (! pyclass) )
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("No such class '%1'.").arg(name)) );
+
+ PyObject *pyobj = PyInstance_New(pyclass, 0, 0);//aclarg, 0);
+ if(! pyobj)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to create instance of class '%1'.").arg(name)) );
+
+ Py::Object classobject(pyobj, true);
+
+#ifdef KROSS_PYTHON_SCRIPT_CLASSINSTANCE_DEBUG
+ krossdebug( QString("PythonScript::classInstance() inst='%1'").arg(classobject.as_string().c_str()) );
+#endif
+ return PythonExtension::toObject(classobject);
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ e.clear(); // exception is handled. clear it now.
+ setException( Kross::Api::Exception::Ptr( new Kross::Api::Exception(err) ) );
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ setException(e);
+ }
+
+ return 0; // return nothing if exception got thrown.
+}
+
diff --git a/lib/kross/python/pythonscript.h b/lib/kross/python/pythonscript.h
new file mode 100644
index 00000000..6cbef625
--- /dev/null
+++ b/lib/kross/python/pythonscript.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * pythonscript.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_PYTHONSCRIPT_H
+#define KROSS_PYTHON_PYTHONSCRIPT_H
+
+#include "pythonconfig.h"
+#include "../api/script.h"
+
+namespace Kross { namespace Python {
+
+ // Forward declarations.
+ class PythonScriptPrivate;
+ class PythonModuleManager;
+
+ /**
+ * Handle python scripts. This class implements
+ * \a Kross::Api::Script for python.
+ */
+ class PythonScript : public Kross::Api::Script
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param interpreter The \a Kross::Python::PythonInterpreter used
+ * to create this PythonScript instance.
+ * \param scriptcontainer The with this PythonScript associated
+ * \a Kross::Api::ScriptContainer instance that spends us
+ * e.g. the python scripting code.
+ */
+ explicit PythonScript(Kross::Api::Interpreter* interpreter, Kross::Api::ScriptContainer* scriptcontainer);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PythonScript();
+
+ /**
+ * Return a list of callable functionnames this
+ * script spends.
+ */
+ virtual const QStringList& getFunctionNames();
+
+ /**
+ * Execute the script.
+ */
+ virtual Kross::Api::Object::Ptr execute();
+
+ /**
+ * Call a function.
+ */
+ virtual Kross::Api::Object::Ptr callFunction(const QString& name, Kross::Api::List::Ptr args);
+
+ /**
+ * Return a list of class types this script supports.
+ */
+ virtual const QStringList& getClassNames();
+
+ /**
+ * Create and return a new class instance.
+ */
+ virtual Kross::Api::Object::Ptr classInstance(const QString& name);
+
+ private:
+ /// Private d-pointer class.
+ PythonScriptPrivate* d;
+
+ /// Initialize the script.
+ void initialize();
+ /// Finalize and cleanup the script.
+ void finalize();
+
+ /// \return a \a Kross::Api::Exception instance.
+ Kross::Api::Exception::Ptr toException(const QString& error);
+ };
+
+}}
+
+#endif
+
diff --git a/lib/kross/python/pythonsecurity.cpp b/lib/kross/python/pythonsecurity.cpp
new file mode 100644
index 00000000..86be0092
--- /dev/null
+++ b/lib/kross/python/pythonsecurity.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * pythonsecurity.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "pythonsecurity.h"
+#include "pythoninterpreter.h"
+#include "pythonmodule.h"
+
+using namespace Kross::Python;
+
+PythonSecurity::PythonSecurity(PythonInterpreter* interpreter)
+ : Py::ExtensionModule<PythonSecurity>("PythonSecurity")
+ , m_interpreter(interpreter)
+ , m_pymodule(0)
+{
+ add_varargs_method("_getattr_", &PythonSecurity::_getattr_, "Secure wapper around the getattr method.");
+ initialize("The PythonSecurity module used to wrap the RestrictedPython functionality.");
+
+ /* TESTCASE
+ initRestrictedPython();
+ compile_restricted(
+ "a = 2 + 5\n"
+ "import os\n"
+ "import sys\n"
+ "b = sys.path\n"
+ "print \"######### >>>testcase<<< #########\" \n"
+ ,
+ "mytestcase", // filename
+ "exec" // 'exec' or 'eval' or 'single'
+ );
+ */
+
+}
+
+PythonSecurity::~PythonSecurity()
+{
+ delete m_pymodule;
+}
+
+void PythonSecurity::initRestrictedPython()
+{
+ try {
+ Py::Dict mainmoduledict = ((PythonInterpreter*)m_interpreter)->mainModule()->getDict();
+ PyObject* pymodule = PyImport_ImportModuleEx(
+ "RestrictedPython", // name of the module being imported (may be a dotted name)
+ mainmoduledict.ptr(), // reference to the current global namespace
+ mainmoduledict.ptr(), // reference to the local namespace
+ 0 // PyObject *fromlist
+ );
+ if(! pymodule)
+ throw Py::Exception();
+ m_pymodule = new Py::Module(pymodule, true);
+
+ PyObject* pyrun = PyRun_String(
+ //"import os\n"
+ //"import sys\n"
+ "import __main__\n"
+ "import PythonSecurity\n"
+ "from RestrictedPython import compile_restricted, PrintCollector\n"
+ "from RestrictedPython.Eval import RestrictionCapableEval\n"
+ "from RestrictedPython.RCompile import RModule\n"
+
+ "setattr(__main__, '_getattr_', PythonSecurity._getattr_)\n"
+ "setattr(__main__, '_print_', PrintCollector)\n"
+ ,
+ Py_file_input,
+ m_pymodule->getDict().ptr(),
+ m_pymodule->getDict().ptr()
+ );
+ if(! pyrun)
+ throw Py::Exception();
+
+ krossdebug("PythonSecurity::PythonSecurity SUCCESSFULLY LOADED");
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ e.clear();
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to initialize PythonSecurity module: %1").arg(err) ) );
+ }
+}
+
+Py::Object PythonSecurity::_getattr_(const Py::Tuple& args)
+{
+ krossdebug("PythonSecurity::_getattr_");
+ for(uint i = 0; i < args.size(); i++) {
+ Py::Object o = args[i];
+ krossdebug( o.as_string().c_str() );
+ }
+ return Py::None();
+}
+
+PyObject* PythonSecurity::compile_restricted(const QString& source, const QString& filename, const QString& mode)
+{
+ krossdebug("PythonSecurity::compile_restricted");
+ if(! m_pymodule)
+ initRestrictedPython(); // throws exception if failed
+
+ try {
+ Py::Dict mainmoduledict = ((PythonInterpreter*)m_interpreter)->mainModule()->getDict();
+
+ PyObject* func = PyDict_GetItemString(m_pymodule->getDict().ptr(), "compile_restricted");
+ if(! func)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("No such function '%1'.").arg("compile_restricted")) );
+
+ Py::Callable funcobject(func, true); // the funcobject takes care of freeing our func pyobject.
+
+ if(! funcobject.isCallable())
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Function '%1' is not callable.").arg("compile_restricted")) );
+
+ Py::Tuple args(3);
+ args[0] = Py::String(source.utf8());
+ args[1] = Py::String(filename.utf8());
+ args[2] = Py::String(mode.utf8());
+
+ Py::Object result = funcobject.apply(args);
+
+ PyObject* pycode = PyEval_EvalCode(
+ (PyCodeObject*)result.ptr(),
+ mainmoduledict.ptr(),
+ mainmoduledict.ptr()
+ );
+ if(! pycode)
+ throw Py::Exception();
+
+ /*
+ Py::List ml = mainmoduledict;
+ for(Py::List::size_type mi = 0; mi < ml.length(); ++mi) {
+ krossdebug( QString("dir() = %1").arg( ml[mi].str().as_string().c_str() ) );
+ //krossdebug( QString("dir().dir() = %1").arg( Py::Object(ml[mi]).dir().as_string().c_str() ) );
+ }
+ */
+
+ Py::Object code(pycode);
+ krossdebug( QString("%1 callable=%2").arg(code.as_string().c_str()).arg(PyCallable_Check(code.ptr())) );
+ Py::List l = code.dir();
+ for(Py::List::size_type i = 0; i < l.length(); ++i) {
+ krossdebug( QString("dir() = %1").arg( l[i].str().as_string().c_str() ) );
+ //krossdebug( QString("dir().dir() = %1").arg( Py::Object(l[i]).dir().as_string().c_str() ) );
+ }
+
+ return pycode;
+ }
+ catch(Py::Exception& e) {
+ QString err = Py::value(e).as_string().c_str();
+ e.clear();
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Function '%1' failed with python exception: %2").arg("compile_restricted").arg(err) ) );
+ }
+}
+
+#if 0
+void PythonSecurity::compile_restricted_function(const Py::Tuple& /*args*/, const QString& /*body*/, const QString& /*name*/, const QString& /*filename*/, const Py::Object& /*globalize*/)
+{
+ //TODO
+}
+
+void PythonSecurity::compile_restricted_exec(const QString& /*source*/, const QString& /*filename*/)
+{
+ //TODO
+}
+
+void PythonSecurity::compile_restricted_eval(const QString& /*source*/, const QString& /*filename*/)
+{
+ //TODO
+}
+#endif
+
diff --git a/lib/kross/python/pythonsecurity.h b/lib/kross/python/pythonsecurity.h
new file mode 100644
index 00000000..7ffbcfff
--- /dev/null
+++ b/lib/kross/python/pythonsecurity.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * pythonsecurity.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_PYTHON_SECURITY_H
+#define KROSS_PYTHON_SECURITY_H
+
+#include "pythonconfig.h"
+
+#include <qstring.h>
+
+namespace Kross { namespace Python {
+
+ // Forward declaration.
+ class PythonInterpreter;
+
+ /**
+ * This class handles the used Zope3 RestrictedPython
+ * package to spend a restricted sandbox for scripting
+ * code.
+ *
+ * The RestrictedPython code is avaible as Python files.
+ * So, this class takes care of loading them and spending
+ * the functions we need to access the functionality
+ * from within Kross. That way it's easy to update the
+ * module with a newer version if some security issues
+ * show up.
+ *
+ * What the RestrictedPython code does is to compile
+ * the plain python code (py) into compiled python code (pyc)
+ * and manipulate those compiled code by replacing unsafe
+ * code with own wrapped code.
+ * As example a simple "x = y.z" would be transfered to
+ * "x = _getattr_(y, 'z')". The _getattr_ is defined in
+ * the RestrictedPython module and will take care of
+ * applied restrictions.
+ *
+ * \see http://www.zope.org
+ * \see http://svn.zope.org/Zope3/trunk/src/RestrictedPython/
+ */
+ class PythonSecurity : public Py::ExtensionModule<PythonSecurity>
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param interpreter The \a PythonInterpreter instance
+ * used to create this Module.
+ */
+ explicit PythonSecurity(PythonInterpreter* interpreter);
+
+ /**
+ * Destructor.
+ */
+ virtual ~PythonSecurity();
+
+ /**
+ * Compile python scripting code and return a restricted
+ * code object.
+ *
+ * \param source The python scripting code.
+ * \param filename The filename used on errormessages.
+ * \param mode Compilemode, could be 'exec' or 'eval' or 'single'.
+ * \return The compiled python code object on success else
+ * NULL. The caller owns the resulting object and needs
+ * to take care to decrease the ref-counter it not needed
+ * any longer.
+ */
+ PyObject* compile_restricted(const QString& source, const QString& filename, const QString& mode);
+
+#if 0
+ //TODO
+ void compile_restricted_function(const Py::Tuple& args, const QString& body, const QString& name, const QString& filename, const Py::Object& globalize = Py::None());
+ void compile_restricted_exec(const QString& source, const QString& filename = "<string>");
+ void compile_restricted_eval(const QString& source, const QString& filename = "<string>");
+#endif
+
+ private:
+ /// We keep a pointer to the used \a PythonInterpreter.
+ PythonInterpreter* m_interpreter;
+ /// The imported external RestrictedPython module.
+ Py::Module* m_pymodule;
+
+ /// Initialize the restricted python module.
+ inline void initRestrictedPython();
+
+ /// Secure wrapper around the getattr method.
+ Py::Object _getattr_(const Py::Tuple&);
+ };
+
+}}
+
+#endif
diff --git a/lib/kross/python/scripts/Makefile.am b/lib/kross/python/scripts/Makefile.am
new file mode 100644
index 00000000..c3b720ce
--- /dev/null
+++ b/lib/kross/python/scripts/Makefile.am
@@ -0,0 +1,4 @@
+modulesdir = $(kde_datadir)/kross/python
+modules_SCRIPTS = gui.py
+
+SUBDIRS = RestrictedPython
diff --git a/lib/kross/python/scripts/RestrictedPython/Eval.py b/lib/kross/python/scripts/RestrictedPython/Eval.py
new file mode 100644
index 00000000..841067a1
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/Eval.py
@@ -0,0 +1,118 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Restricted Python Expressions
+
+$Id: Eval.py 24763 2004-05-17 05:59:28Z philikon $
+"""
+
+__version__='$Revision: 1.6 $'[11:-2]
+
+from RestrictedPython import compile_restricted_eval
+
+from string import translate, strip
+import string
+
+nltosp = string.maketrans('\r\n',' ')
+
+default_guarded_getattr = getattr # No restrictions.
+
+def default_guarded_getitem(ob, index):
+ # No restrictions.
+ return ob[index]
+
+PROFILE = 0
+
+class RestrictionCapableEval:
+ """A base class for restricted code."""
+
+ globals = {'__builtins__': None}
+ rcode = None # restricted
+ ucode = None # unrestricted
+ used = None
+
+ def __init__(self, expr):
+ """Create a restricted expression
+
+ where:
+
+ expr -- a string containing the expression to be evaluated.
+ """
+ expr = strip(expr)
+ self.__name__ = expr
+ expr = translate(expr, nltosp)
+ self.expr = expr
+ self.prepUnrestrictedCode() # Catch syntax errors.
+
+ def prepRestrictedCode(self):
+ if self.rcode is None:
+ if PROFILE:
+ from time import clock
+ start = clock()
+ co, err, warn, used = compile_restricted_eval(
+ self.expr, '<string>')
+ if PROFILE:
+ end = clock()
+ print 'prepRestrictedCode: %d ms for %s' % (
+ (end - start) * 1000, `self.expr`)
+ if err:
+ raise SyntaxError, err[0]
+ self.used = tuple(used.keys())
+ self.rcode = co
+
+ def prepUnrestrictedCode(self):
+ if self.ucode is None:
+ # Use the standard compiler.
+ co = compile(self.expr, '<string>', 'eval')
+ if self.used is None:
+ # Examine the code object, discovering which names
+ # the expression needs.
+ names=list(co.co_names)
+ used={}
+ i=0
+ code=co.co_code
+ l=len(code)
+ LOAD_NAME=101
+ HAVE_ARGUMENT=90
+ while(i < l):
+ c=ord(code[i])
+ if c==LOAD_NAME:
+ name=names[ord(code[i+1])+256*ord(code[i+2])]
+ used[name]=1
+ i=i+3
+ elif c >= HAVE_ARGUMENT: i=i+3
+ else: i=i+1
+ self.used=tuple(used.keys())
+ self.ucode=co
+
+ def eval(self, mapping):
+ # This default implementation is probably not very useful. :-(
+ # This is meant to be overridden.
+ self.prepRestrictedCode()
+ code = self.rcode
+ d = {'_getattr_': default_guarded_getattr,
+ '_getitem_': default_guarded_getitem}
+ d.update(self.globals)
+ has_key = d.has_key
+ for name in self.used:
+ try:
+ if not has_key(name):
+ d[name] = mapping[name]
+ except KeyError:
+ # Swallow KeyErrors since the expression
+ # might not actually need the name. If it
+ # does need the name, a NameError will occur.
+ pass
+ return eval(code, d)
+
+ def __call__(self, **kw):
+ return self.eval(kw)
diff --git a/lib/kross/python/scripts/RestrictedPython/Guards.py b/lib/kross/python/scripts/RestrictedPython/Guards.py
new file mode 100644
index 00000000..4fbdcad1
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/Guards.py
@@ -0,0 +1,136 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+__version__ = '$Revision: 1.14 $'[11:-2]
+
+import exceptions
+
+# This tiny set of safe builtins is extended by users of the module.
+# AccessControl.ZopeGuards contains a large set of wrappers for builtins.
+# DocumentTemplate.DT_UTil contains a few.
+
+safe_builtins = {}
+
+for name in ['False', 'None', 'True', 'abs', 'basestring', 'bool', 'callable',
+ 'chr', 'cmp', 'complex', 'divmod', 'float', 'hash',
+ 'hex', 'id', 'int', 'isinstance', 'issubclass', 'len',
+ 'long', 'oct', 'ord', 'pow', 'range', 'repr', 'round',
+ 'str', 'tuple', 'unichr', 'unicode', 'xrange', 'zip']:
+
+ safe_builtins[name] = __builtins__[name]
+
+# Wrappers provided by this module:
+# delattr
+# setattr
+
+# Wrappers provided by ZopeGuards:
+# __import__
+# apply
+# dict
+# enumerate
+# filter
+# getattr
+# hasattr
+# iter
+# list
+# map
+# max
+# min
+# sum
+
+# Builtins that are intentionally disabled
+# compile - don't let them produce new code
+# dir - a general purpose introspector, probably hard to wrap
+# execfile - no direct I/O
+# file - no direct I/O
+# globals - uncontrolled namespace access
+# input - no direct I/O
+# locals - uncontrolled namespace access
+# open - no direct I/O
+# raw_input - no direct I/O
+# vars - uncontrolled namespace access
+
+# There are several strings that describe Python. I think there's no
+# point to including these, although they are obviously safe:
+# copyright, credits, exit, help, license, quit
+
+# Not provided anywhere. Do something about these? Several are
+# related to new-style classes, which we are too scared of to support
+# <0.3 wink>. coerce, buffer, and reload are esoteric enough that no
+# one should care.
+
+# buffer
+# classmethod
+# coerce
+# eval
+# intern
+# object
+# property
+# reload
+# slice
+# staticmethod
+# super
+# type
+
+for name in dir(exceptions):
+ if name[0] != "_":
+ safe_builtins[name] = getattr(exceptions, name)
+
+def _write_wrapper():
+ # Construct the write wrapper class
+ def _handler(secattr, error_msg):
+ # Make a class method.
+ def handler(self, *args):
+ try:
+ f = getattr(self.ob, secattr)
+ except AttributeError:
+ raise TypeError, error_msg
+ f(*args)
+ return handler
+ class Wrapper:
+ def __len__(self):
+ # Required for slices with negative bounds.
+ return len(self.ob)
+ def __init__(self, ob):
+ self.__dict__['ob'] = ob
+ __setitem__ = _handler('__guarded_setitem__',
+ 'object does not support item or slice assignment')
+ __delitem__ = _handler('__guarded_delitem__',
+ 'object does not support item or slice assignment')
+ __setattr__ = _handler('__guarded_setattr__',
+ 'attribute-less object (assign or del)')
+ __delattr__ = _handler('__guarded_delattr__',
+ 'attribute-less object (assign or del)')
+ return Wrapper
+
+def _full_write_guard():
+ # Nested scope abuse!
+ # safetype and Wrapper variables are used by guard()
+ safetype = {dict: True, list: True}.has_key
+ Wrapper = _write_wrapper()
+ def guard(ob):
+ # Don't bother wrapping simple types, or objects that claim to
+ # handle their own write security.
+ if safetype(type(ob)) or hasattr(ob, '_guarded_writes'):
+ return ob
+ # Hand the object to the Wrapper instance, then return the instance.
+ return Wrapper(ob)
+ return guard
+full_write_guard = _full_write_guard()
+
+def guarded_setattr(object, name, value):
+ setattr(full_write_guard(object), name, value)
+safe_builtins['setattr'] = guarded_setattr
+
+def guarded_delattr(object, name):
+ delattr(full_write_guard(object), name)
+safe_builtins['delattr'] = guarded_delattr
diff --git a/lib/kross/python/scripts/RestrictedPython/Limits.py b/lib/kross/python/scripts/RestrictedPython/Limits.py
new file mode 100644
index 00000000..3b782e65
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/Limits.py
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+__version__='$Revision: 1.5 $'[11:-2]
+
+limited_builtins = {}
+
+def limited_range(iFirst, *args):
+ # limited range function from Martijn Pieters
+ RANGELIMIT = 1000
+ if not len(args):
+ iStart, iEnd, iStep = 0, iFirst, 1
+ elif len(args) == 1:
+ iStart, iEnd, iStep = iFirst, args[0], 1
+ elif len(args) == 2:
+ iStart, iEnd, iStep = iFirst, args[0], args[1]
+ else:
+ raise AttributeError, 'range() requires 1-3 int arguments'
+ if iStep == 0: raise ValueError, 'zero step for range()'
+ iLen = int((iEnd - iStart) / iStep)
+ if iLen < 0: iLen = 0
+ if iLen >= RANGELIMIT: raise ValueError, 'range() too large'
+ return range(iStart, iEnd, iStep)
+limited_builtins['range'] = limited_range
+
+def limited_list(seq):
+ if isinstance(seq, str):
+ raise TypeError, 'cannot convert string to list'
+ return list(seq)
+limited_builtins['list'] = limited_list
+
+def limited_tuple(seq):
+ if isinstance(seq, str):
+ raise TypeError, 'cannot convert string to tuple'
+ return tuple(seq)
+limited_builtins['tuple'] = limited_tuple
diff --git a/lib/kross/python/scripts/RestrictedPython/Makefile.am b/lib/kross/python/scripts/RestrictedPython/Makefile.am
new file mode 100644
index 00000000..3d5b3c73
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/Makefile.am
@@ -0,0 +1,4 @@
+restrictedpythondir = $(kde_datadir)/kross/python/RestrictedPython
+restrictedpython_SCRIPTS = __init__.py Eval.py Guards.py Limits.py \
+ MutatingWalker.py PrintCollector.py RCompile.py RestrictionMutator.py \
+ SelectCompiler.py Utilities.py
diff --git a/lib/kross/python/scripts/RestrictedPython/MutatingWalker.py b/lib/kross/python/scripts/RestrictedPython/MutatingWalker.py
new file mode 100644
index 00000000..b0b8c9ce
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/MutatingWalker.py
@@ -0,0 +1,74 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+__version__='$Revision: 1.6 $'[11:-2]
+
+from SelectCompiler import ast
+
+ListType = type([])
+TupleType = type(())
+SequenceTypes = (ListType, TupleType)
+
+class MutatingWalker:
+
+ def __init__(self, visitor):
+ self.visitor = visitor
+ self._cache = {}
+
+ def defaultVisitNode(self, node, walker=None, exclude=None):
+ for name, child in node.__dict__.items():
+ if exclude is not None and name in exclude:
+ continue
+ v = self.dispatchObject(child)
+ if v is not child:
+ # Replace the node.
+ node.__dict__[name] = v
+ return node
+
+ def visitSequence(self, seq):
+ res = seq
+ for idx in range(len(seq)):
+ child = seq[idx]
+ v = self.dispatchObject(child)
+ if v is not child:
+ # Change the sequence.
+ if type(res) is ListType:
+ res[idx : idx + 1] = [v]
+ else:
+ res = res[:idx] + (v,) + res[idx + 1:]
+ return res
+
+ def dispatchObject(self, ob):
+ '''
+ Expected to return either ob or something that will take
+ its place.
+ '''
+ if isinstance(ob, ast.Node):
+ return self.dispatchNode(ob)
+ elif type(ob) in SequenceTypes:
+ return self.visitSequence(ob)
+ else:
+ return ob
+
+ def dispatchNode(self, node):
+ klass = node.__class__
+ meth = self._cache.get(klass, None)
+ if meth is None:
+ className = klass.__name__
+ meth = getattr(self.visitor, 'visit' + className,
+ self.defaultVisitNode)
+ self._cache[klass] = meth
+ return meth(node, self)
+
+def walk(tree, visitor):
+ return MutatingWalker(visitor).dispatchNode(tree)
diff --git a/lib/kross/python/scripts/RestrictedPython/PrintCollector.py b/lib/kross/python/scripts/RestrictedPython/PrintCollector.py
new file mode 100644
index 00000000..15a1c180
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/PrintCollector.py
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+__version__='$Revision: 1.4 $'[11:-2]
+
+class PrintCollector:
+ '''Collect written text, and return it when called.'''
+ def __init__(self):
+ self.txt = []
+ def write(self, text):
+ self.txt.append(text)
+ def __call__(self):
+ return ''.join(self.txt)
diff --git a/lib/kross/python/scripts/RestrictedPython/RCompile.py b/lib/kross/python/scripts/RestrictedPython/RCompile.py
new file mode 100644
index 00000000..0a538657
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/RCompile.py
@@ -0,0 +1,235 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Compiles restricted code using the compiler module from the
+Python standard library.
+"""
+
+__version__='$Revision: 1.6 $'[11:-2]
+
+from compiler import ast, parse, misc, syntax, pycodegen
+from compiler.pycodegen import AbstractCompileMode, Expression, \
+ Interactive, Module, ModuleCodeGenerator, FunctionCodeGenerator, findOp
+
+import MutatingWalker
+from RestrictionMutator import RestrictionMutator
+
+
+def niceParse(source, filename, mode):
+ try:
+ return parse(source, mode)
+ except:
+ # Try to make a clean error message using
+ # the builtin Python compiler.
+ try:
+ compile(source, filename, mode)
+ except SyntaxError:
+ raise
+ # Some other error occurred.
+ raise
+
+class RestrictedCompileMode(AbstractCompileMode):
+ """Abstract base class for hooking up custom CodeGenerator."""
+ # See concrete subclasses below.
+
+ def __init__(self, source, filename):
+ self.rm = RestrictionMutator()
+ AbstractCompileMode.__init__(self, source, filename)
+
+ def parse(self):
+ return niceParse(self.source, self.filename, self.mode)
+
+ def _get_tree(self):
+ tree = self.parse()
+ MutatingWalker.walk(tree, self.rm)
+ if self.rm.errors:
+ raise SyntaxError, self.rm.errors[0]
+ misc.set_filename(self.filename, tree)
+ syntax.check(tree)
+ return tree
+
+ def compile(self):
+ tree = self._get_tree()
+ gen = self.CodeGeneratorClass(tree)
+ self.code = gen.getCode()
+
+
+def compileAndTuplize(gen):
+ try:
+ gen.compile()
+ except SyntaxError, v:
+ return None, (str(v),), gen.rm.warnings, gen.rm.used_names
+ return gen.getCode(), (), gen.rm.warnings, gen.rm.used_names
+
+def compile_restricted_function(p, body, name, filename, globalize=None):
+ """Compiles a restricted code object for a function.
+
+ The function can be reconstituted using the 'new' module:
+
+ new.function(<code>, <globals>)
+
+ The globalize argument, if specified, is a list of variable names to be
+ treated as globals (code is generated as if each name in the list
+ appeared in a global statement at the top of the function).
+ """
+ gen = RFunction(p, body, name, filename, globalize)
+ return compileAndTuplize(gen)
+
+def compile_restricted_exec(s, filename='<string>'):
+ """Compiles a restricted code suite."""
+ gen = RModule(s, filename)
+ return compileAndTuplize(gen)
+
+def compile_restricted_eval(s, filename='<string>'):
+ """Compiles a restricted expression."""
+ gen = RExpression(s, filename)
+ return compileAndTuplize(gen)
+
+def compile_restricted(source, filename, mode):
+ """Replacement for the builtin compile() function."""
+ if mode == "single":
+ gen = RInteractive(source, filename)
+ elif mode == "exec":
+ gen = RModule(source, filename)
+ elif mode == "eval":
+ gen = RExpression(source, filename)
+ else:
+ raise ValueError("compile_restricted() 3rd arg must be 'exec' or "
+ "'eval' or 'single'")
+ gen.compile()
+ return gen.getCode()
+
+class RestrictedCodeGenerator:
+ """Mixin for CodeGenerator to replace UNPACK_SEQUENCE bytecodes.
+
+ The UNPACK_SEQUENCE opcode is not safe because it extracts
+ elements from a sequence without using a safe iterator or
+ making __getitem__ checks.
+
+ This code generator replaces use of UNPACK_SEQUENCE with calls to
+ a function that unpacks the sequence, performes the appropriate
+ security checks, and returns a simple list.
+ """
+
+ # Replace the standard code generator for assignments to tuples
+ # and lists.
+
+ def _gen_safe_unpack_sequence(self, num):
+ # We're at a place where UNPACK_SEQUENCE should be generated, to
+ # unpack num items. That's a security hole, since it exposes
+ # individual items from an arbitrary iterable. We don't remove
+ # the UNPACK_SEQUENCE, but instead insert a call to our _getiter_()
+ # wrapper first. That applies security checks to each item as
+ # it's delivered. codegen is (just) a bit messy because the
+ # iterable is already on the stack, so we have to do a stack swap
+ # to get things in the right order.
+ self.emit('LOAD_GLOBAL', '_getiter_')
+ self.emit('ROT_TWO')
+ self.emit('CALL_FUNCTION', 1)
+ self.emit('UNPACK_SEQUENCE', num)
+
+ def _visitAssSequence(self, node):
+ if findOp(node) != 'OP_DELETE':
+ self._gen_safe_unpack_sequence(len(node.nodes))
+ for child in node.nodes:
+ self.visit(child)
+
+ visitAssTuple = _visitAssSequence
+ visitAssList = _visitAssSequence
+
+ # Call to generate code for unpacking nested tuple arguments
+ # in function calls.
+
+ def unpackSequence(self, tup):
+ self._gen_safe_unpack_sequence(len(tup))
+ for elt in tup:
+ if isinstance(elt, tuple):
+ self.unpackSequence(elt)
+ else:
+ self._nameOp('STORE', elt)
+
+# A collection of code generators that adds the restricted mixin to
+# handle unpacking for all the different compilation modes. They
+# are defined here (at the end) so that can refer to RestrictedCodeGenerator.
+
+class RestrictedFunctionCodeGenerator(RestrictedCodeGenerator,
+ pycodegen.FunctionCodeGenerator):
+ pass
+
+class RestrictedExpressionCodeGenerator(RestrictedCodeGenerator,
+ pycodegen.ExpressionCodeGenerator):
+ pass
+
+class RestrictedInteractiveCodeGenerator(RestrictedCodeGenerator,
+ pycodegen.InteractiveCodeGenerator):
+ pass
+
+class RestrictedModuleCodeGenerator(RestrictedCodeGenerator,
+ pycodegen.ModuleCodeGenerator):
+
+ def initClass(self):
+ ModuleCodeGenerator.initClass(self)
+ self.__class__.FunctionGen = RestrictedFunctionCodeGenerator
+
+
+# These subclasses work around the definition of stub compile and mode
+# attributes in the common base class AbstractCompileMode. If it
+# didn't define new attributes, then the stub code inherited via
+# RestrictedCompileMode would override the real definitions in
+# Expression.
+
+class RExpression(RestrictedCompileMode, Expression):
+ mode = "eval"
+ CodeGeneratorClass = RestrictedExpressionCodeGenerator
+
+class RInteractive(RestrictedCompileMode, Interactive):
+ mode = "single"
+ CodeGeneratorClass = RestrictedInteractiveCodeGenerator
+
+class RModule(RestrictedCompileMode, Module):
+ mode = "exec"
+ CodeGeneratorClass = RestrictedModuleCodeGenerator
+
+class RFunction(RModule):
+ """A restricted Python function built from parts."""
+
+ CodeGeneratorClass = RestrictedModuleCodeGenerator
+
+ def __init__(self, p, body, name, filename, globals):
+ self.params = p
+ self.body = body
+ self.name = name
+ self.globals = globals or []
+ RModule.__init__(self, None, filename)
+
+ def parse(self):
+ # Parse the parameters and body, then combine them.
+ firstline = 'def f(%s): pass' % self.params
+ tree = niceParse(firstline, '<function parameters>', 'exec')
+ f = tree.node.nodes[0]
+ body_code = niceParse(self.body, self.filename, 'exec')
+ # Stitch the body code into the function.
+ f.code.nodes = body_code.node.nodes
+ f.name = self.name
+ # Look for a docstring.
+ stmt1 = f.code.nodes[0]
+ if (isinstance(stmt1, ast.Discard) and
+ isinstance(stmt1.expr, ast.Const) and
+ isinstance(stmt1.expr.value, str)):
+ f.doc = stmt1.expr.value
+ # The caller may specify that certain variables are globals
+ # so that they can be referenced before a local assignment.
+ # The only known example is the variables context, container,
+ # script, traverse_subpath in PythonScripts.
+ if self.globals:
+ f.code.nodes.insert(0, ast.Global(self.globals))
+ return tree
diff --git a/lib/kross/python/scripts/RestrictedPython/RestrictionMutator.py b/lib/kross/python/scripts/RestrictedPython/RestrictionMutator.py
new file mode 100644
index 00000000..a8b3850e
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/RestrictionMutator.py
@@ -0,0 +1,372 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Modify AST to include security checks.
+
+RestrictionMutator modifies a tree produced by
+compiler.transformer.Transformer, restricting and enhancing the
+code in various ways before sending it to pycodegen.
+
+$Revision: 1.13 $
+"""
+
+from SelectCompiler import ast, parse, OP_ASSIGN, OP_DELETE, OP_APPLY
+
+# These utility functions allow us to generate AST subtrees without
+# line number attributes. These trees can then be inserted into other
+# trees without affecting line numbers shown in tracebacks, etc.
+def rmLineno(node):
+ """Strip lineno attributes from a code tree."""
+ if node.__dict__.has_key('lineno'):
+ del node.lineno
+ for child in node.getChildren():
+ if isinstance(child, ast.Node):
+ rmLineno(child)
+
+def stmtNode(txt):
+ """Make a "clean" statement node."""
+ node = parse(txt).node.nodes[0]
+ rmLineno(node)
+ return node
+
+# The security checks are performed by a set of six functions that
+# must be provided by the restricted environment.
+
+_apply_name = ast.Name("_apply_")
+_getattr_name = ast.Name("_getattr_")
+_getitem_name = ast.Name("_getitem_")
+_getiter_name = ast.Name("_getiter_")
+_print_target_name = ast.Name("_print")
+_write_name = ast.Name("_write_")
+
+# Constants.
+_None_const = ast.Const(None)
+_write_const = ast.Const("write")
+
+_printed_expr = stmtNode("_print()").expr
+_print_target_node = stmtNode("_print = _print_()")
+
+class FuncInfo:
+ print_used = False
+ printed_used = False
+
+class RestrictionMutator:
+
+ def __init__(self):
+ self.warnings = []
+ self.errors = []
+ self.used_names = {}
+ self.funcinfo = FuncInfo()
+
+ def error(self, node, info):
+ """Records a security error discovered during compilation."""
+ lineno = getattr(node, 'lineno', None)
+ if lineno is not None and lineno > 0:
+ self.errors.append('Line %d: %s' % (lineno, info))
+ else:
+ self.errors.append(info)
+
+ def checkName(self, node, name):
+ """Verifies that a name being assigned is safe.
+
+ This is to prevent people from doing things like:
+
+ __metatype__ = mytype (opens up metaclasses, a big unknown
+ in terms of security)
+ __path__ = foo (could this confuse the import machinery?)
+ _getattr = somefunc (not very useful, but could open a hole)
+
+ Note that assigning a variable is not the only way to assign
+ a name. def _badname, class _badname, import foo as _badname,
+ and perhaps other statements assign names. Special case:
+ '_' is allowed.
+ """
+ if name.startswith("_") and name != "_":
+ # Note: "_" *is* allowed.
+ self.error(node, '"%s" is an invalid variable name because'
+ ' it starts with "_"' % name)
+ if name == "printed":
+ self.error(node, '"printed" is a reserved name.')
+
+ def checkAttrName(self, node):
+ """Verifies that an attribute name does not start with _.
+
+ As long as guards (security proxies) have underscored names,
+ this underscore protection is important regardless of the
+ security policy. Special case: '_' is allowed.
+ """
+ name = node.attrname
+ if name.startswith("_") and name != "_":
+ # Note: "_" *is* allowed.
+ self.error(node, '"%s" is an invalid attribute name '
+ 'because it starts with "_".' % name)
+
+ def prepBody(self, body):
+ """Insert code for print at the beginning of the code suite."""
+
+ if self.funcinfo.print_used or self.funcinfo.printed_used:
+ # Add code at top for creating _print_target
+ body.insert(0, _print_target_node)
+ if not self.funcinfo.printed_used:
+ self.warnings.append(
+ "Prints, but never reads 'printed' variable.")
+ elif not self.funcinfo.print_used:
+ self.warnings.append(
+ "Doesn't print, but reads 'printed' variable.")
+
+ def visitFunction(self, node, walker):
+ """Checks and mutates a function definition.
+
+ Checks the name of the function and the argument names using
+ checkName(). It also calls prepBody() to prepend code to the
+ beginning of the code suite.
+ """
+ self.checkName(node, node.name)
+ for argname in node.argnames:
+ if isinstance(argname, str):
+ self.checkName(node, argname)
+ else:
+ for name in argname:
+ self.checkName(node, name)
+ walker.visitSequence(node.defaults)
+
+ former_funcinfo = self.funcinfo
+ self.funcinfo = FuncInfo()
+ node = walker.defaultVisitNode(node, exclude=('defaults',))
+ self.prepBody(node.code.nodes)
+ self.funcinfo = former_funcinfo
+ return node
+
+ def visitLambda(self, node, walker):
+ """Checks and mutates an anonymous function definition.
+
+ Checks the argument names using checkName(). It also calls
+ prepBody() to prepend code to the beginning of the code suite.
+ """
+ for argname in node.argnames:
+ self.checkName(node, argname)
+ return walker.defaultVisitNode(node)
+
+ def visitPrint(self, node, walker):
+ """Checks and mutates a print statement.
+
+ Adds a target to all print statements. 'print foo' becomes
+ 'print >> _print, foo', where _print is the default print
+ target defined for this scope.
+
+ Alternatively, if the untrusted code provides its own target,
+ we have to check the 'write' method of the target.
+ 'print >> ob, foo' becomes
+ 'print >> (_getattr(ob, 'write') and ob), foo'.
+ Otherwise, it would be possible to call the write method of
+ templates and scripts; 'write' happens to be the name of the
+ method that changes them.
+ """
+ node = walker.defaultVisitNode(node)
+ self.funcinfo.print_used = True
+ if node.dest is None:
+ node.dest = _print_target_name
+ else:
+ # Pre-validate access to the "write" attribute.
+ # "print >> ob, x" becomes
+ # "print >> (_getattr(ob, 'write') and ob), x"
+ node.dest = ast.And([
+ ast.CallFunc(_getattr_name, [node.dest, _write_const]),
+ node.dest])
+ return node
+
+ visitPrintnl = visitPrint
+
+ def visitName(self, node, walker):
+ """Prevents access to protected names as defined by checkName().
+
+ Also converts use of the name 'printed' to an expression.
+ """
+ if node.name == 'printed':
+ # Replace name lookup with an expression.
+ self.funcinfo.printed_used = True
+ return _printed_expr
+ self.checkName(node, node.name)
+ self.used_names[node.name] = True
+ return node
+
+ def visitCallFunc(self, node, walker):
+ """Checks calls with *-args and **-args.
+
+ That's a way of spelling apply(), and needs to use our safe
+ _apply_ instead.
+ """
+ walked = walker.defaultVisitNode(node)
+ if node.star_args is None and node.dstar_args is None:
+ # This is not an extended function call
+ return walked
+ # Otherwise transform foo(a, b, c, d=e, f=g, *args, **kws) into a call
+ # of _apply_(foo, a, b, c, d=e, f=g, *args, **kws). The interesting
+ # thing here is that _apply_() is defined with just *args and **kws,
+ # so it gets Python to collapse all the myriad ways to call functions
+ # into one manageable form.
+ #
+ # From there, _apply_() digs out the first argument of *args (it's the
+ # function to call), wraps args and kws in guarded accessors, then
+ # calls the function, returning the value.
+ # Transform foo(...) to _apply(foo, ...)
+ walked.args.insert(0, walked.node)
+ walked.node = _apply_name
+ return walked
+
+ def visitAssName(self, node, walker):
+ """Checks a name assignment using checkName()."""
+ self.checkName(node, node.name)
+ return node
+
+ def visitFor(self, node, walker):
+ # convert
+ # for x in expr:
+ # to
+ # for x in _getiter(expr):
+ #
+ # Note that visitListCompFor is the same thing. Exactly the same
+ # transformation is needed to convert
+ # [... for x in expr ...]
+ # to
+ # [... for x in _getiter(expr) ...]
+ node = walker.defaultVisitNode(node)
+ node.list = ast.CallFunc(_getiter_name, [node.list])
+ return node
+
+ visitListCompFor = visitFor
+
+ def visitGetattr(self, node, walker):
+ """Converts attribute access to a function call.
+
+ 'foo.bar' becomes '_getattr(foo, "bar")'.
+
+ Also prevents augmented assignment of attributes, which would
+ be difficult to support correctly.
+ """
+ self.checkAttrName(node)
+ node = walker.defaultVisitNode(node)
+ if getattr(node, 'in_aug_assign', False):
+ # We're in an augmented assignment
+ # We might support this later...
+ self.error(node, 'Augmented assignment of '
+ 'attributes is not allowed.')
+ return ast.CallFunc(_getattr_name,
+ [node.expr, ast.Const(node.attrname)])
+
+ def visitSubscript(self, node, walker):
+ """Checks all kinds of subscripts.
+
+ 'foo[bar] += baz' is disallowed.
+ 'a = foo[bar, baz]' becomes 'a = _getitem(foo, (bar, baz))'.
+ 'a = foo[bar]' becomes 'a = _getitem(foo, bar)'.
+ 'a = foo[bar:baz]' becomes 'a = _getitem(foo, slice(bar, baz))'.
+ 'a = foo[:baz]' becomes 'a = _getitem(foo, slice(None, baz))'.
+ 'a = foo[bar:]' becomes 'a = _getitem(foo, slice(bar, None))'.
+ 'del foo[bar]' becomes 'del _write(foo)[bar]'.
+ 'foo[bar] = a' becomes '_write(foo)[bar] = a'.
+
+ The _write function returns a security proxy.
+ """
+ node = walker.defaultVisitNode(node)
+ if node.flags == OP_APPLY:
+ # Set 'subs' to the node that represents the subscript or slice.
+ if getattr(node, 'in_aug_assign', False):
+ # We're in an augmented assignment
+ # We might support this later...
+ self.error(node, 'Augmented assignment of '
+ 'object items and slices is not allowed.')
+ if hasattr(node, 'subs'):
+ # Subscript.
+ subs = node.subs
+ if len(subs) > 1:
+ # example: ob[1,2]
+ subs = ast.Tuple(subs)
+ else:
+ # example: ob[1]
+ subs = subs[0]
+ else:
+ # Slice.
+ # example: obj[0:2]
+ lower = node.lower
+ if lower is None:
+ lower = _None_const
+ upper = node.upper
+ if upper is None:
+ upper = _None_const
+ subs = ast.Sliceobj([lower, upper])
+ return ast.CallFunc(_getitem_name, [node.expr, subs])
+ elif node.flags in (OP_DELETE, OP_ASSIGN):
+ # set or remove subscript or slice
+ node.expr = ast.CallFunc(_write_name, [node.expr])
+ return node
+
+ visitSlice = visitSubscript
+
+ def visitAssAttr(self, node, walker):
+ """Checks and mutates attribute assignment.
+
+ 'a.b = c' becomes '_write(a).b = c'.
+ The _write function returns a security proxy.
+ """
+ self.checkAttrName(node)
+ node = walker.defaultVisitNode(node)
+ node.expr = ast.CallFunc(_write_name, [node.expr])
+ return node
+
+ def visitExec(self, node, walker):
+ self.error(node, 'Exec statements are not allowed.')
+
+ def visitYield(self, node, walker):
+ self.error(node, 'Yield statements are not allowed.')
+
+ def visitClass(self, node, walker):
+ """Checks the name of a class using checkName().
+
+ Should classes be allowed at all? They don't cause security
+ issues, but they aren't very useful either since untrusted
+ code can't assign instance attributes.
+ """
+ self.checkName(node, node.name)
+ return walker.defaultVisitNode(node)
+
+ def visitModule(self, node, walker):
+ """Adds prep code at module scope.
+
+ Zope doesn't make use of this. The body of Python scripts is
+ always at function scope.
+ """
+ node = walker.defaultVisitNode(node)
+ self.prepBody(node.node.nodes)
+ return node
+
+ def visitAugAssign(self, node, walker):
+ """Makes a note that augmented assignment is in use.
+
+ Note that although augmented assignment of attributes and
+ subscripts is disallowed, augmented assignment of names (such
+ as 'n += 1') is allowed.
+
+ This could be a problem if untrusted code got access to a
+ mutable database object that supports augmented assignment.
+ """
+ node.node.in_aug_assign = True
+ return walker.defaultVisitNode(node)
+
+ def visitImport(self, node, walker):
+ """Checks names imported using checkName()."""
+ for name, asname in node.names:
+ self.checkName(node, name)
+ if asname:
+ self.checkName(node, asname)
+ return node
+
diff --git a/lib/kross/python/scripts/RestrictedPython/SelectCompiler.py b/lib/kross/python/scripts/RestrictedPython/SelectCompiler.py
new file mode 100644
index 00000000..5f9da698
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/SelectCompiler.py
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Compiler selector.
+
+$Id: SelectCompiler.py 24763 2004-05-17 05:59:28Z philikon $
+"""
+
+# Use the compiler from the standard library.
+import compiler
+from compiler import ast
+from compiler.transformer import parse
+from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
+
+from RCompile import \
+ compile_restricted, \
+ compile_restricted_function, \
+ compile_restricted_exec, \
+ compile_restricted_eval
diff --git a/lib/kross/python/scripts/RestrictedPython/Utilities.py b/lib/kross/python/scripts/RestrictedPython/Utilities.py
new file mode 100644
index 00000000..87eef69b
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/Utilities.py
@@ -0,0 +1,77 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+__version__='$Revision: 1.7 $'[11:-2]
+
+import string, math, random
+import DocumentTemplate.sequence
+
+utility_builtins = {}
+
+utility_builtins['string'] = string
+utility_builtins['math'] = math
+utility_builtins['random'] = random
+utility_builtins['whrandom'] = random
+utility_builtins['sequence'] = DocumentTemplate.sequence
+
+try:
+ import DateTime
+ utility_builtins['DateTime']= DateTime.DateTime
+except: pass
+
+def same_type(arg1, *args):
+ '''Compares the class or type of two or more objects.'''
+ t = getattr(arg1, '__class__', type(arg1))
+ for arg in args:
+ if getattr(arg, '__class__', type(arg)) is not t:
+ return 0
+ return 1
+utility_builtins['same_type'] = same_type
+
+def test(*args):
+ l=len(args)
+ for i in range(1, l, 2):
+ if args[i-1]: return args[i]
+
+ if l%2: return args[-1]
+utility_builtins['test'] = test
+
+def reorder(s, with=None, without=()):
+ # s, with, and without are sequences treated as sets.
+ # The result is subtract(intersect(s, with), without),
+ # unless with is None, in which case it is subtract(s, without).
+ if with is None: with=s
+ d={}
+ tt=type(())
+ for i in s:
+ if type(i) is tt and len(i)==2: k, v = i
+ else: k= v = i
+ d[k]=v
+ r=[]
+ a=r.append
+ h=d.has_key
+
+ for i in without:
+ if type(i) is tt and len(i)==2: k, v = i
+ else: k= v = i
+ if h(k): del d[k]
+
+ for i in with:
+ if type(i) is tt and len(i)==2: k, v = i
+ else: k= v = i
+ if h(k):
+ a((k,d[k]))
+ del d[k]
+
+ return r
+utility_builtins['reorder'] = reorder
diff --git a/lib/kross/python/scripts/RestrictedPython/__init__.py b/lib/kross/python/scripts/RestrictedPython/__init__.py
new file mode 100644
index 00000000..0c70947e
--- /dev/null
+++ b/lib/kross/python/scripts/RestrictedPython/__init__.py
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+'''
+RestrictedPython package.
+$Id: __init__.py 24763 2004-05-17 05:59:28Z philikon $
+'''
+
+from SelectCompiler import *
+from PrintCollector import PrintCollector
diff --git a/lib/kross/python/scripts/gui.py b/lib/kross/python/scripts/gui.py
new file mode 100755
index 00000000..8891714a
--- /dev/null
+++ b/lib/kross/python/scripts/gui.py
@@ -0,0 +1,396 @@
+"""
+Python script for a GUI-dialog.
+
+Description:
+Python script to provide an abstract GUI for other python scripts. That
+way we've all the GUI-related code within one single file and are
+able to easily modify GUI-stuff in a central place.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+Published as-is without any warranties.
+"""
+
+def getHome():
+ """ Return the homedirectory. """
+ import os
+ try:
+ home = os.getenv("HOME")
+ if not home:
+ import pwd
+ user = os.getenv("USER") or os.getenv("LOGNAME")
+ if not user:
+ pwent = pwd.getpwuid(os.getuid())
+ else:
+ pwent = pwd.getpwnam(user)
+ home = pwent[6]
+ return home
+ except (KeyError, ImportError):
+ return os.curdir
+
+class TkDialog:
+ """ This class is used to wrap Tkinter into a more abstract interface."""
+
+ def __init__(self, title):
+ import Tkinter
+ self.root = Tkinter.Tk()
+ self.root.title(title)
+ self.root.deiconify()
+
+ mainframe = self.Frame(self, self.root)
+ self.widget = mainframe.widget
+
+ class Widget:
+ def __init__(self, dialog, parent):
+ self.dialog = dialog
+ self.parent = parent
+ #def setVisible(self, visibled): pass
+ #def setEnabled(self, enabled): pass
+
+ class Frame(Widget):
+ def __init__(self, dialog, parent):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ import Tkinter
+ self.widget = Tkinter.Frame(parent)
+ self.widget.pack()
+
+ class Label(Widget):
+ def __init__(self, dialog, parent, caption):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ import Tkinter
+ self.widget = Tkinter.Label(parent, text=caption)
+ self.widget.pack(side=Tkinter.TOP)
+
+ class CheckBox(Widget):
+ def __init__(self, dialog, parent, caption, checked = True):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ import Tkinter
+ self.checkstate = Tkinter.IntVar()
+ self.checkstate.set(checked)
+ self.widget = Tkinter.Checkbutton(parent, text=caption, variable=self.checkstate)
+ self.widget.pack(side=Tkinter.TOP)
+ def isChecked(self):
+ return self.checkstate.get()
+
+ class List(Widget):
+ def __init__(self, dialog, parent, caption, items):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ import Tkinter
+
+ listframe = Tkinter.Frame(parent)
+ listframe.pack()
+
+ Tkinter.Label(listframe, text=caption).pack(side=Tkinter.LEFT)
+
+ self.items = items
+ self.variable = Tkinter.StringVar()
+ itemlist = apply(Tkinter.OptionMenu, (listframe, self.variable) + tuple( items ))
+ itemlist.pack(side=Tkinter.LEFT)
+ def get(self):
+ return self.variable.get()
+ def set(self, index):
+ self.variable.set( self.items[index] )
+
+ class Button(Widget):
+ def __init__(self, dialog, parent, caption, commandmethod):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ import Tkinter
+ self.widget = Tkinter.Button(parent, text=caption, command=self.doCommand)
+ self.commandmethod = commandmethod
+ self.widget.pack(side=Tkinter.LEFT)
+ def doCommand(self):
+ try:
+ self.commandmethod()
+ except:
+ #TODO why the heck we arn't able to redirect exceptions?
+ import traceback
+ import StringIO
+ fp = StringIO.StringIO()
+ traceback.print_exc(file=fp)
+ import tkMessageBox
+ tkMessageBox.showerror("Exception", fp.getvalue())
+ #self.dialog.root.destroy()
+
+ class Edit(Widget):
+ def __init__(self, dialog, parent, caption, text):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ import Tkinter
+ self.widget = Tkinter.Frame(parent)
+ self.widget.pack()
+ label = Tkinter.Label(self.widget, text=caption)
+ label.pack(side=Tkinter.LEFT)
+ self.entrytext = Tkinter.StringVar()
+ self.entrytext.set(text)
+ self.entry = Tkinter.Entry(self.widget, width=36, textvariable=self.entrytext)
+ self.entry.pack(side=Tkinter.LEFT)
+ def get(self):
+ return self.entrytext.get()
+
+ class FileChooser(Edit):
+ def __init__(self, dialog, parent, caption, initialfile = None, filetypes = None):
+ TkDialog.Edit.__init__(self, dialog, parent, caption, initialfile)
+ import Tkinter
+
+ self.initialfile = initialfile
+ self.entrytext.set(initialfile)
+
+ btn = Tkinter.Button(self.widget, text="...", command=self.browse)
+ btn.pack(side=Tkinter.LEFT)
+
+ if filetypes:
+ self.filetypes = filetypes
+ else:
+ self.filetypes = (('All files', '*'),)
+
+ def browse(self):
+ import os
+ text = self.entrytext.get()
+ d = os.path.dirname(text) or os.path.dirname(self.initialfile)
+ f = os.path.basename(text) or os.path.basename(self.initialfile)
+
+ import tkFileDialog
+ file = tkFileDialog.asksaveasfilename(
+ initialdir=d,
+ initialfile=f,
+ #defaultextension='.html',
+ filetypes=self.filetypes
+ )
+ if file:
+ self.entrytext.set( file )
+
+ class MessageBox:
+ def __init__(self, dialog, typename, caption, message):
+ self.widget = dialog.widget
+ self.typename = typename
+ self.caption = str(caption)
+ self.message = str(message)
+ def show(self):
+ import tkMessageBox
+ if self.typename == "okcancel":
+ return tkMessageBox.askokcancel(self.caption, self.message,icon=tkmessageBox.QESTION)
+ else:
+ tkMessageBox.showinfo(self.caption, self.message)
+ return True
+
+ def show(self):
+ self.root.mainloop()
+
+ def close(self):
+ self.root.destroy()
+
+class QtDialog:
+ """ This class is used to wrap pyQt/pyKDE into a more abstract interface."""
+
+ def __init__(self, title):
+ import qt
+
+ class Dialog(qt.QDialog):
+ def __init__(self, parent = None, name = None, modal = 0, fl = 0):
+ qt.QDialog.__init__(self, parent, name, modal, fl)
+ qt.QDialog.accept = self.accept
+ self.layout = qt.QVBoxLayout(self)
+ self.layout.setSpacing(6)
+ self.layout.setMargin(11)
+
+ class Label(qt.QLabel):
+ def __init__(self, dialog, parent, caption):
+ qt.QLabel.__init__(self, parent)
+ self.setText("<qt>%s</qt>" % caption.replace("\n","<br>"))
+
+ class Frame(qt.QHBox):
+ def __init__(self, dialog, parent):
+ qt.QHBox.__init__(self, parent)
+ self.widget = self
+ self.setSpacing(6)
+
+ class Edit(qt.QHBox):
+ def __init__(self, dialog, parent, caption, text):
+ qt.QHBox.__init__(self, parent)
+ self.setSpacing(6)
+ label = qt.QLabel(caption, self)
+ self.edit = qt.QLineEdit(self)
+ self.edit.setText( str(text) )
+ self.setStretchFactor(self.edit, 1)
+ label.setBuddy(self.edit)
+ def get(self):
+ return self.edit.text()
+
+ class Button(qt.QPushButton):
+ #def __init__(self, *args):
+ def __init__(self, dialog, parent, caption, commandmethod):
+ #apply(qt.QPushButton.__init__, (self,) + args)
+ qt.QPushButton.__init__(self, parent)
+ self.commandmethod = commandmethod
+ self.setText(caption)
+ qt.QObject.connect(self, qt.SIGNAL("clicked()"), self.commandmethod)
+
+
+ class CheckBox(qt.QCheckBox):
+ def __init__(self, dialog, parent, caption, checked = True):
+ #TkDialog.Widget.__init__(self, dialog, parent)
+ qt.QCheckBox.__init__(self, parent)
+ self.setText(caption)
+ self.setChecked(checked)
+ #def isChecked(self):
+ # return self.isChecked()
+
+ class List(qt.QHBox):
+ def __init__(self, dialog, parent, caption, items):
+ qt.QHBox.__init__(self, parent)
+ self.setSpacing(6)
+ label = qt.QLabel(caption, self)
+ self.combo = qt.QComboBox(self)
+ self.setStretchFactor(self.combo, 1)
+ label.setBuddy(self.combo)
+ for item in items:
+ self.combo.insertItem( str(item) )
+ def get(self):
+ return self.combo.currentText()
+ def set(self, index):
+ self.combo.setCurrentItem(index)
+
+ class FileChooser(qt.QHBox):
+ def __init__(self, dialog, parent, caption, initialfile = None, filetypes = None):
+ #apply(qt.QHBox.__init__, (self,) + args)
+ qt.QHBox.__init__(self, parent)
+ self.setMinimumWidth(400)
+
+ self.initialfile = initialfile
+ self.filetypes = filetypes
+
+ self.setSpacing(6)
+ label = qt.QLabel(caption, self)
+ self.edit = qt.QLineEdit(self)
+ self.edit.setText(self.initialfile)
+ self.setStretchFactor(self.edit, 1)
+ label.setBuddy(self.edit)
+
+ browsebutton = Button(dialog, self, "...", self.browseButtonClicked)
+ #qt.QObject.connect(browsebutton, qt.SIGNAL("clicked()"), self.browseButtonClicked)
+
+ def get(self):
+ return self.edit.text()
+
+ def browseButtonClicked(self):
+ filtermask = ""
+ import types
+ if isinstance(self.filetypes, types.TupleType):
+ for ft in self.filetypes:
+ if len(ft) == 1:
+ filtermask += "%s\n" % (ft[0])
+ if len(ft) == 2:
+ filtermask += "%s|%s (%s)\n" % (ft[1],ft[0],ft[1])
+ if filtermask == "":
+ filtermask = "All files (*.*)"
+ else:
+ filtermask = filtermask[:-1]
+
+ filename = None
+ try:
+ print "QtDialog.FileChooser.browseButtonClicked() kfile.KFileDialog"
+ # try to use the kfile module included in pykde
+ import kfile
+ filename = kfile.KFileDialog.getOpenFileName(self.initialfile, filtermask, self, "Save to file")
+ except:
+ print "QtDialog.FileChooser.browseButtonClicked() qt.QFileDialog"
+ # fallback to Qt filedialog
+ filename = qt.QFileDialog.getOpenFileName(self.initialfile, filtermask, self, "Save to file")
+ if filename != None and filename != "":
+ self.edit.setText(filename)
+
+ class MessageBox:
+ def __init__(self, dialog, typename, caption, message):
+ self.widget = dialog.widget
+ self.typename = typename
+ self.caption = str(caption)
+ self.message = str(message)
+ def show(self):
+ result = 1
+ if self.typename == "okcancel":
+ result = qt.QMessageBox.question(self.widget, self.caption, self.message, "&Ok", "&Cancel", "", 1)
+ else:
+ qt.QMessageBox.information(self.widget, self.caption, self.message, "&Ok")
+ result = 0
+ if result == 0:
+ return True
+ return False
+
+ self.app = qt.qApp
+ self.dialog = Dialog(self.app.mainWidget(), "Dialog", 1, qt.Qt.WDestructiveClose)
+ self.dialog.setCaption(title)
+
+ self.widget = qt.QVBox(self.dialog)
+ self.widget.setSpacing(6)
+ self.dialog.layout.addWidget(self.widget)
+
+ self.Frame = Frame
+ self.Label = Label
+ self.Edit = Edit
+ self.Button = Button
+ self.CheckBox = CheckBox
+ self.List = List
+ self.FileChooser = FileChooser
+ self.MessageBox = MessageBox
+
+ def show(self):
+ import qt
+ qt.QApplication.setOverrideCursor(qt.Qt.arrowCursor)
+ self.dialog.exec_loop()
+ qt.QApplication.restoreOverrideCursor()
+
+ def close(self):
+ print "QtDialog.close()"
+ self.dialog.close()
+ #self.dialog.deleteLater()
+
+class Dialog:
+ """ Central class that provides abstract GUI-access to the outer world. """
+
+ def __init__(self, title):
+ self.dialog = None
+
+ try:
+ print "Trying to import PyQt..."
+ self.dialog = QtDialog(title)
+ print "PyQt is our toolkit!"
+ except:
+ try:
+ print "Failed to import PyQt. Trying to import TkInter..."
+ self.dialog = TkDialog(title)
+ print "Falling back to TkInter as our toolkit!"
+ except:
+ raise "Failed to import GUI-toolkit. Please install the PyQt or the Tkinter python module."
+
+ self.widget = self.dialog.widget
+
+ def show(self):
+ self.dialog.show()
+
+ def close(self):
+ self.dialog.close()
+
+ def addFrame(self, parentwidget):
+ return self.dialog.Frame(self.dialog, parentwidget.widget)
+
+ def addLabel(self, parentwidget, caption):
+ return self.dialog.Label(self.dialog, parentwidget.widget, caption)
+
+ def addCheckBox(self, parentwidget, caption, checked = True):
+ return self.dialog.CheckBox(self.dialog, parentwidget.widget, caption, checked)
+
+ def addButton(self, parentwidget, caption, commandmethod):
+ return self.dialog.Button(self.dialog, parentwidget.widget, caption, commandmethod)
+
+ def addEdit(self, parentwidget, caption, text):
+ return self.dialog.Edit(self.dialog, parentwidget.widget, caption, text)
+
+ def addFileChooser(self, parentwidget, caption, initialfile = None, filetypes = None):
+ return self.dialog.FileChooser(self.dialog, parentwidget.widget, caption, initialfile, filetypes)
+
+ def addList(self, parentwidget, caption, items):
+ return self.dialog.List(self.dialog, parentwidget.widget, caption, items)
+
+ def showMessageBox(self, typename, caption, message):
+ return self.dialog.MessageBox(self.dialog, typename, caption, message)
diff --git a/lib/kross/readme.dox b/lib/kross/readme.dox
new file mode 100644
index 00000000..4fb7c4b4
--- /dev/null
+++ b/lib/kross/readme.dox
@@ -0,0 +1,28 @@
+/** @mainpage Kross
+ *
+ * Kross is a scripting bridge to embed scripting functionality
+ * into an application. Kross provides an abstract API to access
+ * the scripting functionality in a interpreter-independend
+ * way. The application that uses Kross should not need to know
+ * anything about the used interpreter-language.
+ *
+ * @see http://kross.dipe.org
+ * @see http://www.kexi-project.org/wiki/wikiview/index.php?Scripting
+ *
+ * @section Legal
+ *
+ * @li copyright (C) 2004-2006 by Sebastian Sauer (mail AT dipe DOT org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
diff --git a/lib/kross/ruby/Makefile.am b/lib/kross/ruby/Makefile.am
new file mode 100644
index 00000000..fb8ddfac
--- /dev/null
+++ b/lib/kross/ruby/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/lib/kross/Makefile.global
+
+INCLUDES = -I$(top_srcdir)/lib/kross -I$(RUBY_INCLUDEDIR) $(all_includes)
+METASOURCES = AUTO
+kde_module_LTLIBRARIES = krossruby.la
+
+krossruby_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries) $(RUBY_LIBRUBYARG) -module $(VER_INFO)
+
+krossruby_la_LIBADD = \
+ $(LIB_QT) \
+ $(LIB_KDECORE) \
+ ../api/libkrossapi.la \
+ ../main/libkrossmain.la
+
+noinst_HEADERS = rubyinterpreter.h rubyextension.h rubyscript.h rubyconfig.h
+krossruby_la_SOURCES = rubyinterpreter.cpp rubyextension.cpp rubyscript.cpp rubymodule.cpp
diff --git a/lib/kross/ruby/rubyconfig.h b/lib/kross/ruby/rubyconfig.h
new file mode 100644
index 00000000..81a74c55
--- /dev/null
+++ b/lib/kross/ruby/rubyconfig.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * pythonconfig.h
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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_RUBY_CONFIG_H
+#define KROSS_RUBY_CONFIG_H
+
+#include "../main/krossconfig.h"
+
+namespace Kross {
+
+/**
+ * The Ruby plugin for the \a Kross scripting framework.
+ *
+ * @author Cyrille Berger
+ * @sa http://www.ruby-lang.org
+ */
+namespace Ruby {
+// #define KROSS_RUBY_SCRIPT_DEBUG
+// #define KROSS_RUBY_INTERPRETER_DEBUG
+// #define KROSS_RUBY_EXTENSION_DEBUG
+// #define KROSS_RUBY_MODULE_DEBUG
+}
+}
+
+#endif
+
diff --git a/lib/kross/ruby/rubyextension.cpp b/lib/kross/ruby/rubyextension.cpp
new file mode 100644
index 00000000..2c022cee
--- /dev/null
+++ b/lib/kross/ruby/rubyextension.cpp
@@ -0,0 +1,378 @@
+/***************************************************************************
+ * rubyinterpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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 "rubyextension.h"
+
+#include <st.h>
+
+#include <qmap.h>
+#include <qstring.h>
+
+#include "api/list.h"
+
+#include "rubyconfig.h"
+
+namespace Kross {
+
+namespace Ruby {
+
+
+class RubyExtensionPrivate {
+ friend class RubyExtension;
+ /// The \a Kross::Api::Object this RubyExtension wraps.
+ Kross::Api::Object::Ptr m_object;
+ ///
+ static VALUE s_krossObject;
+ static VALUE s_krossException;
+};
+
+VALUE RubyExtensionPrivate::s_krossObject = 0;
+VALUE RubyExtensionPrivate::s_krossException = 0;
+
+VALUE RubyExtension::method_missing(int argc, VALUE *argv, VALUE self)
+{
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug("method_missing(argc, argv, self)");
+#endif
+ if(argc < 1)
+ {
+ return 0;
+ }
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug("Converting self to Kross::Api::Object");
+#endif
+
+ Kross::Api::Object::Ptr object = toObject( self );
+ return RubyExtension::call_method(object, argc, argv);
+}
+
+VALUE RubyExtension::call_method( Kross::Api::Object::Ptr object, int argc, VALUE *argv)
+{
+ QString funcname = rb_id2name(SYM2ID(argv[0]));
+ QValueList<Api::Object::Ptr> argsList;
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug(QString("Building arguments list for function: %1 there are %2 arguments.").arg(funcname).arg(argc-1));
+#endif
+ for(int i = 1; i < argc; i++)
+ {
+ Kross::Api::Object::Ptr obj = toObject(argv[i]);
+ if(obj) argsList.append(obj);
+ }
+ Kross::Api::Object::Ptr result;
+ try { // We need a double try/catch because, the cleaning is only done at the end of the catch, so if we had only one try/catch, kross would crash after the call to rb_exc_raise
+ try { // We can't let a C++ exceptions propagate in the C mechanism
+ Kross::Api::Callable* callable = dynamic_cast<Kross::Api::Callable*>(object.data());
+ if(callable && callable->hasChild(funcname)) {
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug( QString("Kross::Ruby::RubyExtension::method_missing name='%1' is a child object of '%2'.").arg(funcname).arg(object->getName()) );
+#endif
+ result = callable->getChild(funcname)->call(QString::null, new Api::List(argsList));
+ }
+ else {
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug( QString("Kross::Ruby::RubyExtension::method_missing try to call function with name '%1' in object '%2'.").arg(funcname).arg(object->getName()) );
+#endif
+ result = object->call(funcname, new Api::List(argsList));
+ }
+ } catch(Kross::Api::Exception::Ptr exception)
+ {
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug("c++ exception catched, raise a ruby error");
+#endif
+ throw convertFromException(exception);
+ } catch(...)
+ {
+ throw convertFromException(new Kross::Api::Exception( "Unknow error" )); // TODO: fix //i18n
+ }
+ } catch(VALUE v) {
+ rb_exc_raise(v );
+ }
+ return toVALUE(result);
+}
+
+void RubyExtension::delete_object(void* object)
+{
+ krossdebug("delete_object");
+ RubyExtension* obj = static_cast<RubyExtension*>(object);
+ if(obj)
+ delete obj;
+}
+
+void RubyExtension::delete_exception(void* object)
+{
+ Kross::Api::Exception* exc = static_cast<Kross::Api::Exception*>(object);
+ exc->_KShared_unref();
+}
+
+
+RubyExtension::RubyExtension(Kross::Api::Object::Ptr object) : d(new RubyExtensionPrivate())
+{
+ d->m_object = object;
+}
+
+
+RubyExtension::~RubyExtension()
+{
+ krossdebug("Delete RubyExtension");
+ delete d;
+}
+
+typedef QMap<QString, Kross::Api::Object::Ptr> mStrObj;
+
+int RubyExtension::convertHash_i(VALUE key, VALUE value, VALUE vmap)
+{
+ QMap<QString, Kross::Api::Object::Ptr>* map;
+ Data_Get_Struct(vmap, mStrObj, map);
+ if (key != Qundef)
+ {
+ Kross::Api::Object::Ptr o = RubyExtension::toObject( value );
+ if(o) map->replace(STR2CSTR(key), o);
+ }
+ return ST_CONTINUE;
+}
+
+bool RubyExtension::isOfExceptionType(VALUE value)
+{
+ VALUE result = rb_funcall(value, rb_intern("kind_of?"), 1, RubyExtensionPrivate::s_krossException );
+ return (TYPE(result) == T_TRUE);
+}
+
+bool RubyExtension::isOfObjectType(VALUE value)
+{
+ VALUE result = rb_funcall(value, rb_intern("kind_of?"), 1, RubyExtensionPrivate::s_krossObject );
+ return (TYPE(result) == T_TRUE);
+}
+
+
+Kross::Api::Exception::Ptr RubyExtension::convertToException(VALUE value)
+{
+ if( isOfExceptionType(value) )
+ {
+ Kross::Api::Exception* exception;
+ Data_Get_Struct(value, Kross::Api::Exception, exception);
+ return exception;
+ }
+ return 0;
+}
+
+VALUE RubyExtension::convertFromException(Kross::Api::Exception::Ptr exc)
+{
+ if(RubyExtensionPrivate::s_krossException == 0)
+ {
+ RubyExtensionPrivate::s_krossException = rb_define_class("KrossException", rb_eRuntimeError);
+ }
+ exc->_KShared_ref();
+ return Data_Wrap_Struct(RubyExtensionPrivate::s_krossException, 0, RubyExtension::delete_exception, exc.data() );
+}
+
+
+Kross::Api::Object::Ptr RubyExtension::toObject(VALUE value)
+{
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug(QString("RubyExtension::toObject of type %1").arg(TYPE(value)));
+#endif
+ switch( TYPE( value ) )
+ {
+ case T_DATA:
+ {
+#ifdef KROSS_RUBY_EXTENSION_DEBUG
+ krossdebug("Object is a Kross Object");
+#endif
+ if( isOfObjectType(value) )
+ {
+ RubyExtension* objectExtension;
+ Data_Get_Struct(value, RubyExtension, objectExtension);
+ Kross::Api::Object::Ptr object = objectExtension->d->m_object;
+ return object;
+ } else {
+ krosswarning("Cannot yet convert standard ruby type to kross object");
+ return 0;
+ }
+ }
+ case T_FLOAT:
+ return new Kross::Api::Variant(NUM2DBL(value));
+ case T_STRING:
+ return new Kross::Api::Variant(QString(STR2CSTR(value)));
+ case T_ARRAY:
+ {
+ QValueList<Kross::Api::Object::Ptr> l;
+ for(int i = 0; i < RARRAY(value)->len; i++)
+ {
+ Kross::Api::Object::Ptr o = toObject( rb_ary_entry( value , i ) );
+ if(o) l.append(o);
+ }
+ return new Kross::Api::List(l);
+ }
+ case T_FIXNUM:
+ return new Kross::Api::Variant((Q_LLONG)FIX2INT(value));
+ case T_HASH:
+ {
+ QMap<QString, Kross::Api::Object::Ptr> map;
+ VALUE vmap = Data_Wrap_Struct(rb_cObject, 0,0, &map);
+ rb_hash_foreach(value, (int (*)(...))convertHash_i, vmap);
+ return new Kross::Api::Dict(map);
+ }
+ case T_BIGNUM:
+ {
+ return new Kross::Api::Variant((Q_LLONG)NUM2LONG(value));
+ }
+ case T_TRUE:
+ {
+ return new Kross::Api::Variant(true);
+ }
+ case T_FALSE:
+ {
+ return new Kross::Api::Variant(false);
+ }
+ case T_SYMBOL:
+ {
+ return new Kross::Api::Variant(QString(rb_id2name(SYM2ID(value))));
+ }
+ case T_MATCH:
+ case T_OBJECT:
+ case T_FILE:
+ case T_STRUCT:
+ case T_REGEXP:
+ case T_MODULE:
+ case T_ICLASS:
+ case T_CLASS:
+ krosswarning(QString("This ruby type '%1' cannot be converted to a Kross::Api::Object").arg(TYPE(value)));
+ default:
+ case T_NIL:
+ return 0;
+ }
+}
+
+VALUE RubyExtension::toVALUE(const QString& s)
+{
+ return s.isNull() ? rb_str_new2("") : rb_str_new2(s.latin1());
+}
+
+VALUE RubyExtension::toVALUE(QStringList list)
+{
+ VALUE l = rb_ary_new();
+ for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
+ rb_ary_push(l, toVALUE(*it));
+ return l;
+}
+
+
+VALUE RubyExtension::toVALUE(QMap<QString, QVariant> map)
+{
+ VALUE h = rb_hash_new();
+ for(QMap<QString, QVariant>::Iterator it = map.begin(); it != map.end(); ++it)
+ rb_hash_aset(h, toVALUE(it.key()), toVALUE(it.data()) );
+ return h;
+
+}
+
+VALUE RubyExtension::toVALUE(QValueList<QVariant> list)
+{
+ VALUE l = rb_ary_new();
+ for(QValueList<QVariant>::Iterator it = list.begin(); it != list.end(); ++it)
+ rb_ary_push(l, toVALUE(*it));
+ return l;
+}
+
+
+VALUE RubyExtension::toVALUE(const QVariant& variant)
+{
+
+ switch(variant.type()) {
+ case QVariant::Invalid:
+ return Qnil;
+ case QVariant::Bool:
+ return (variant.toBool()) ? Qtrue : Qfalse;
+ case QVariant::Int:
+ return INT2FIX(variant.toInt());
+ case QVariant::UInt:
+ return UINT2NUM(variant.toUInt());
+ case QVariant::Double:
+ return rb_float_new(variant.toDouble());
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ case QVariant::ByteArray:
+ case QVariant::BitArray:
+ case QVariant::CString:
+ case QVariant::String:
+ return toVALUE(variant.toString());
+ case QVariant::StringList:
+ return toVALUE(variant.toStringList());
+ case QVariant::Map:
+ return toVALUE(variant.toMap());
+ case QVariant::List:
+ return toVALUE(variant.toList());
+
+ // To handle following both cases is a bit difficult
+ // cause Python doesn't spend an easy possibility
+ // for such large numbers (TODO maybe BigInt?). So,
+ // we risk overflows here, but well...
+ case QVariant::LongLong: {
+ return INT2NUM((long)variant.toLongLong());
+ }
+ case QVariant::ULongLong:
+ return UINT2NUM((unsigned long)variant.toULongLong());
+ default: {
+ krosswarning( QString("Kross::Ruby::RubyExtension::toVALUE(QVariant) Not possible to convert the QVariant type '%1' to a VALUE.").arg(variant.typeName()) );
+ return Qundef;
+ }
+ }
+}
+
+VALUE RubyExtension::toVALUE(Kross::Api::Object::Ptr object)
+{
+ if(! object.data()) {
+ return 0;
+ }
+ if(object->getClassName() == "Kross::Api::Variant") {
+ QVariant v = static_cast<Kross::Api::Variant*>( object.data() )->getValue();
+ return toVALUE(v);
+ }
+
+ if(object->getClassName() == "Kross::Api::List") {
+ Kross::Api::List* list = static_cast<Kross::Api::List*>( object.data() );
+ return toVALUE((Kross::Api::List::Ptr)list);
+ }
+
+ if(object->getClassName() == "Kross::Api::Dict") {
+ Kross::Api::Dict* dict = static_cast<Kross::Api::Dict*>( object.data() );
+ return toVALUE((Kross::Api::Dict::Ptr)dict);
+ }
+
+ if(RubyExtensionPrivate::s_krossObject == 0)
+ {
+ RubyExtensionPrivate::s_krossObject = rb_define_class("KrossObject", rb_cObject);
+ rb_define_method(RubyExtensionPrivate::s_krossObject, "method_missing", (VALUE (*)(...))RubyExtension::method_missing, -1);
+ }
+ return Data_Wrap_Struct(RubyExtensionPrivate::s_krossObject, 0, RubyExtension::delete_object, new RubyExtension(object) );
+}
+
+VALUE RubyExtension::toVALUE(Kross::Api::List::Ptr list)
+{
+ VALUE l = rb_ary_new();
+ uint count = list ? list->count() : 0;
+ for(uint i = 0; i < count; i++)
+ rb_ary_push(l, toVALUE(list->item(i)));
+ return l;
+
+}
+
+}
+
+}
diff --git a/lib/kross/ruby/rubyextension.h b/lib/kross/ruby/rubyextension.h
new file mode 100644
index 00000000..74041048
--- /dev/null
+++ b/lib/kross/ruby/rubyextension.h
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * rubyinterpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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_RUBYRUBYEXTENSION_H
+#define KROSS_RUBYRUBYEXTENSION_H
+
+#include <ruby.h>
+
+#include <api/class.h>
+#include <api/dict.h>
+#include <api/list.h>
+#include <api/object.h>
+
+namespace Kross {
+
+namespace Ruby {
+
+class RubyExtensionPrivate;
+
+/**
+ * This class wraps a \a Kross::Api::Object into the world of ruby.
+ * @author Cyrille Berger
+ */
+class RubyExtension{
+ friend class RubyInterpreter;
+ friend class RubyModule;
+ friend class RubyScript;
+ public:
+ /**
+ * Constructor.
+ *
+ * @param object The \a Kross::Api::Object instance this
+ * extension provides access to.
+ */
+ RubyExtension(Kross::Api::Object::Ptr object);
+ /**
+ * Destructor.
+ */
+ ~RubyExtension();
+ private:
+ /**
+ * This function will catch functions that are undefined.
+ */
+ static VALUE method_missing(int argc, VALUE *argv, VALUE self);
+ /**
+ * This function will call a function in a Kross object
+ * @param obj kross object which contains the function
+ * @param argc the number of argument
+ * @param argv the lists of arguments (the first argument is the Ruby ID of the function)
+ */
+ static VALUE call_method( Kross::Api::Object::Ptr obj, int argc, VALUE *argv);
+ /**
+ * This function is called by ruby to delete a RubyExtension object
+ */
+ static void delete_object(void* object);
+ /**
+ * This function is called by ruby to delete a RubyExtension object
+ */
+ static void delete_exception(void* object);
+ private: // Tests
+ /**
+ * Test if the ruby object is an exception.
+ */
+ static bool isOfExceptionType(VALUE obj);
+ /**
+ * Test if the ruby object is an object
+ */
+ static bool isOfObjectType(VALUE obj);
+ private: //Converting functions
+ /**
+ * Convert a ruby object to the exception type.
+ * @return 0 if the object wasn't an exception.
+ */
+ static Kross::Api::Exception::Ptr convertToException(VALUE obj);
+ /**
+ * Wrap an exception in a ruby object.
+ */
+ static VALUE convertFromException(Kross::Api::Exception::Ptr exc);
+ /**
+ * This function iterats through a ruby hash
+ */
+ static int convertHash_i(VALUE key, VALUE value, VALUE vmap);
+ /**
+ * Converts a \a VALUE into a \a Kross::Api::Object.
+ * \param object The ruby VALUE to convert.
+ * \return The to a Kross::Api::Object converted Py::Object.
+ */
+ static Kross::Api::Object::Ptr toObject(VALUE value);
+ /**
+ * Converts a QString to a VALUE. If
+ * the QString isNull() then a "" will
+ * be returned.
+ * \param s The QString to convert.
+ * \return The converted QString.
+ */
+ static VALUE toVALUE(const QString& s);
+
+ /**
+ * Converts a QStringList to a VALUE.
+ * \param list The QStringList to convert.
+ * \return The converted QStringList.
+ */
+ static VALUE toVALUE(QStringList list);
+
+ /**
+ * Converts a QMap to a VALUE.
+ * \param map The QMap to convert.
+ * \return The converted QMap.
+ */
+ static VALUE toVALUE(QMap<QString, QVariant> map);
+
+ /**
+ * Converts a QValueList to a VALUE.
+ * \param list The QValueList to convert.
+ * \return The converted QValueList.
+ */
+ static VALUE toVALUE(QValueList<QVariant> list);
+ /**
+ * Converts a QVariant to a VALUE.
+ * \param variant The QVariant to convert.
+ * \return The converted QVariant.
+ */
+ static VALUE toVALUE(const QVariant& variant);
+
+ /**
+ * Converts a \a Kross::Api::Object to a VALUE.
+ * \param object The Kross::Api::Object to convert.
+ * \return The converted Kross::Api::Object.
+ */
+ static VALUE toVALUE(Kross::Api::Object::Ptr object);
+
+ /**
+ * Converts a \a Kross::Api::List into a VALUE.
+ * \param list The Kross::Api::List to convert.
+ * \return The converted Kross::Api::List.
+ */
+ static VALUE toVALUE(Kross::Api::List::Ptr list);
+ private:
+ /// Private d-pointer.
+ RubyExtensionPrivate* d;
+ };
+
+}
+
+}
+
+#endif
diff --git a/lib/kross/ruby/rubyinterpreter.cpp b/lib/kross/ruby/rubyinterpreter.cpp
new file mode 100644
index 00000000..805ae722
--- /dev/null
+++ b/lib/kross/ruby/rubyinterpreter.cpp
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * rubyinterpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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 "rubyinterpreter.h"
+
+#include <map>
+
+#include <qregexp.h>
+#include <ksharedptr.h>
+
+#include <api/exception.h>
+#include <api/module.h>
+#include <main/manager.h>
+
+#include "rubyconfig.h"
+#include "rubyextension.h"
+#include "rubymodule.h"
+#include "rubyscript.h"
+
+extern "C"
+{
+ /**
+ * Exported and loadable function as entry point to use
+ * the \a RubyInterpreter.
+ * The krossruby library will be loaded dynamicly at runtime from e.g.
+ * \a Kross::Api::Manager::getInterpreter and this exported
+ * function will be used to return an instance of the
+ * \a RubyInterpreter implementation.
+ */
+ void* krossinterpreter(Kross::Api::InterpreterInfo* info)
+ {
+#ifdef KROSS_RUBY_INTERPRETER_DEBUG
+ krossdebug("krossinterpreter(info)");
+#endif
+ try {
+ return new Kross::Ruby::RubyInterpreter(info);
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ Kross::krosswarning("krossinterpreter(Kross::Api::InterpreterInfo* info): Unhandled exception.");
+ }
+ return 0;
+ }
+};
+
+
+namespace Kross {
+
+namespace Ruby {
+typedef std::map<QString, VALUE> mStrVALUE;
+typedef mStrVALUE::iterator mStrVALUE_it;
+typedef mStrVALUE::const_iterator mStrVALUE_cit;
+class RubyInterpreterPrivate {
+ friend class RubyInterpreter;
+};
+
+RubyInterpreterPrivate* RubyInterpreter::d = 0;
+
+RubyInterpreter::RubyInterpreter(Kross::Api::InterpreterInfo* info): Kross::Api::Interpreter(info)
+{
+#ifdef KROSS_RUBY_INTERPRETER_DEBUG
+ krossdebug("RubyInterpreter::RubyInterpreter(info)");
+#endif
+ if(d == 0)
+ {
+ initRuby();
+ }
+ if(info->hasOption("safelevel") )
+ {
+ rb_set_safe_level( info->getOption("safelevel")->value.toInt() );
+ } else {
+ rb_set_safe_level(4); // if the safelevel option is undefined, set it to maximum level
+ }
+}
+
+
+RubyInterpreter::~RubyInterpreter()
+{
+ finalizeRuby();
+}
+
+
+Kross::Api::Script* RubyInterpreter::createScript(Kross::Api::ScriptContainer* scriptcontainer)
+{
+ return new RubyScript(this, scriptcontainer);
+}
+
+void RubyInterpreter::initRuby()
+{
+ d = new RubyInterpreterPrivate();
+ ruby_init();
+ ruby_init_loadpath();
+ rb_define_global_function("require", (VALUE (*)(...))RubyInterpreter::require, 1);
+}
+
+void RubyInterpreter::finalizeRuby()
+{
+ delete d;
+ d = 0;
+ ruby_finalize();
+}
+
+VALUE RubyInterpreter::require (VALUE obj, VALUE name)
+{
+#ifdef KROSS_RUBY_INTERPRETER_DEBUG
+ krossdebug("RubyInterpreter::require(obj,name)");
+#endif
+ QString modname = StringValuePtr(name);
+ if(modname.startsWith("kross")) {
+ krossdebug( QString("RubyInterpreter::require() module=%1").arg(modname) );
+ if( modname.find( QRegExp("[^a-zA-Z0-9\\_\\-]") ) >= 0 ) {
+ krosswarning( QString("Denied import of Kross module '%1' cause of untrusted chars.").arg(modname) );
+ }
+ else {
+ Kross::Api::Module::Ptr module = Kross::Api::Manager::scriptManager()->loadModule(modname);
+ if(module)
+ {
+ new RubyModule(module, modname);
+// VALUE rmodule = rb_define_module(modname.ascii());
+// rb_define_module_function();
+// VALUE rm = RubyExtension::toVALUE(module);
+// rb_define_variable( ("$" + modname).ascii(), & RubyInterpreter::d->m_modules.insert( mStrVALUE::value_type( modname, rm) ).first->second );
+ return Qtrue;
+ }
+ krosswarning( QString("Loading of Kross module '%1' failed.").arg(modname) );
+ }
+ } else {
+ return rb_f_require(obj, name);
+ }
+ return Qfalse;
+}
+
+}
+
+}
diff --git a/lib/kross/ruby/rubyinterpreter.h b/lib/kross/ruby/rubyinterpreter.h
new file mode 100644
index 00000000..f16f2b3d
--- /dev/null
+++ b/lib/kross/ruby/rubyinterpreter.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * rubyinterpreter.h
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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_RUBYRUBYINTERPRETER_H
+#define KROSS_RUBYRUBYINTERPRETER_H
+
+#include <ruby.h>
+
+#include <api/interpreter.h>
+
+namespace Kross {
+
+namespace Ruby {
+
+class RubyInterpreterPrivate;
+/**
+ * This class is the bridget between Kross and Ruby.
+ * @author Cyrille Berger
+ */
+class RubyInterpreter : public Kross::Api::Interpreter
+{
+ public:
+
+ /**
+ * Constructor
+ *
+ * @param info The \a Kross::Api::InterpreterInfo instance
+ * that describes this \a RubyInterpreter .
+ */
+ RubyInterpreter(Kross::Api::InterpreterInfo* info);
+
+ /**
+ * Destructor.
+ */
+ virtual ~RubyInterpreter();
+
+ /**
+ * Factory method to create and return a new \a RubyScript instance.
+ */
+ virtual Kross::Api::Script* createScript(Kross::Api::ScriptContainer* scriptcontainer);
+
+ private:
+ /// Initialize the ruby interpreter.
+ void initRuby();
+ /// Finalize the ruby interpreter.
+ void finalizeRuby();
+ /// Load an external plugin / module.
+ static VALUE require (VALUE, VALUE);
+ private:
+ /// Private d-pointer.
+ static RubyInterpreterPrivate* d;
+};
+
+}
+
+}
+
+#endif
diff --git a/lib/kross/ruby/rubymodule.cpp b/lib/kross/ruby/rubymodule.cpp
new file mode 100644
index 00000000..b002f24c
--- /dev/null
+++ b/lib/kross/ruby/rubymodule.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * rubyinterpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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 "rubymodule.h"
+
+#include "rubyconfig.h"
+#include "rubyextension.h"
+
+namespace Kross {
+
+namespace Ruby {
+
+class RubyModulePrivate {
+ friend class RubyModule;
+ /// The \a Kross::Api::Module this RubyExtension wraps.
+ Kross::Api::Module::Ptr m_module;
+
+};
+
+RubyModule::RubyModule(Kross::Api::Module::Ptr mod, QString modname) : d(new RubyModulePrivate)
+{
+ d->m_module = mod;
+ modname = modname.left(1).upper() + modname.right(modname.length() - 1 );
+ krossdebug(QString("Module: %1").arg(modname));
+ VALUE rmodule = rb_define_module(modname.ascii());
+ rb_define_module_function(rmodule,"method_missing", (VALUE (*)(...))RubyModule::method_missing, -1);
+ VALUE rm = RubyExtension::toVALUE( mod.data() );
+ rb_define_const(rmodule, "MODULEOBJ", rm);
+}
+
+RubyModule::~RubyModule()
+{
+}
+
+VALUE RubyModule::method_missing(int argc, VALUE *argv, VALUE self)
+{
+#ifdef KROSS_RUBY_MODULE_DEBUG
+ QString funcname = rb_id2name(SYM2ID(argv[0]));
+ krossdebug(QString("Function %1 missing in a module").arg(funcname));
+#endif
+
+ VALUE rubyObjectModule = rb_funcall( self, rb_intern("const_get"), 1, ID2SYM(rb_intern("MODULEOBJ")) );
+ RubyModule* objectModule;
+ Data_Get_Struct(rubyObjectModule, RubyModule, objectModule);
+ Kross::Api::Object::Ptr object = (Kross::Api::Object*)objectModule->d->m_module;
+
+ return RubyExtension::call_method(object, argc, argv);
+}
+
+}
+
+}
diff --git a/lib/kross/ruby/rubymodule.h b/lib/kross/ruby/rubymodule.h
new file mode 100644
index 00000000..0e4c278c
--- /dev/null
+++ b/lib/kross/ruby/rubymodule.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * rubyinterpreter.cpp
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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_RUBYRUBYMODULE_H
+#define KROSS_RUBYRUBYMODULE_H
+
+#include <ruby.h>
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/module.h>
+
+namespace Kross {
+
+namespace Ruby {
+
+class RubyModulePrivate;
+
+/**
+ * A ruby module.
+ * @author Cyrille Berger
+ */
+class RubyModule {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * @param mod The \a Kross::Api::Module this RubyExtension
+ * wraps.
+ * @param modname The name the module will be published as.
+ */
+ RubyModule(Kross::Api::Module::Ptr mod, QString modname);
+
+ /**
+ * Destructor.
+ */
+ ~RubyModule();
+
+ private:
+
+ /**
+ * This function will catch functions that are undefined.
+ */
+ static VALUE method_missing(int argc, VALUE *argv, VALUE self);
+
+ private:
+ /// Private d-pointer.
+ RubyModulePrivate* d;
+};
+
+}
+
+}
+
+#endif
diff --git a/lib/kross/ruby/rubyscript.cpp b/lib/kross/ruby/rubyscript.cpp
new file mode 100644
index 00000000..fa0ee1d0
--- /dev/null
+++ b/lib/kross/ruby/rubyscript.cpp
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * rubyscript.h
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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 "rubyscript.h"
+
+#include <ruby.h>
+#include <env.h>
+#include <rubysig.h>
+#include <node.h>
+
+#include <main/scriptcontainer.h>
+
+#include "rubyconfig.h"
+#include "rubyextension.h"
+#include "rubyinterpreter.h"
+
+extern NODE *ruby_eval_tree;
+
+namespace Kross {
+
+namespace Ruby {
+
+class RubyScriptPrivate {
+ friend class RubyScript;
+ RubyScriptPrivate() : m_compile(0) { }
+ RNode* m_compile;
+ /// A list of functionnames.
+ QStringList m_functions;
+
+ /// A list of classnames.
+ QStringList m_classes;
+};
+
+RubyScript::RubyScript(Kross::Api::Interpreter* interpreter, Kross::Api::ScriptContainer* scriptcontainer)
+ : Kross::Api::Script(interpreter, scriptcontainer), d(new RubyScriptPrivate())
+{
+}
+
+
+RubyScript::~RubyScript()
+{
+}
+
+#define selectScript() \
+ NODE* old_tree = ruby_eval_tree; \
+ ruby_eval_tree = d->m_compile;
+#define unselectScript() \
+ d->m_compile = 0; \
+ ruby_eval_tree = old_tree;
+
+void RubyScript::compile()
+{
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("RubyScript::compile()");
+#endif
+ int critical;
+
+ ruby_nerrs = 0;
+ ruby_errinfo = Qnil;
+ VALUE src = RubyExtension::toVALUE( m_scriptcontainer->getCode() );
+ StringValue(src);
+ critical = rb_thread_critical;
+ rb_thread_critical = Qtrue;
+ ruby_in_eval++;
+ d->m_compile = rb_compile_string((char*) m_scriptcontainer->getName().latin1(), src, 0);
+ ruby_in_eval--;
+ rb_thread_critical = critical;
+
+ if (ruby_nerrs != 0)
+ {
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("Compilation has failed");
+#endif
+ setException( new Kross::Api::Exception(QString("Failed to compile ruby code: %1").arg(STR2CSTR( rb_obj_as_string(ruby_errinfo) )), 0) ); // TODO: get the error
+ d->m_compile = 0;
+ }
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("Compilation was successfull");
+#endif
+}
+
+const QStringList& RubyScript::getFunctionNames()
+{
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("RubyScript::getFunctionNames()");
+#endif
+ if(d->m_compile == 0)
+ {
+ compile();
+ }
+ return d->m_functions;
+}
+
+Kross::Api::Object::Ptr RubyScript::execute()
+{
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("RubyScript::execute()");
+#endif
+ if(d->m_compile == 0)
+ {
+ compile();
+ }
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("Start execution");
+#endif
+ selectScript();
+ int result = ruby_exec();
+ if (result != 0)
+ {
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("Execution has failed");
+#endif
+ if( TYPE( ruby_errinfo ) == T_DATA && RubyExtension::isOfExceptionType( ruby_errinfo ) )
+ {
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("Kross exception");
+#endif
+ setException( RubyExtension::convertToException( ruby_errinfo ) );
+ } else {
+ setException( new Kross::Api::Exception(QString("Failed to execute ruby code: %1").arg(STR2CSTR( rb_obj_as_string(ruby_errinfo) )), 0) ); // TODO: get the error
+ }
+ }
+
+ unselectScript();
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("Execution is finished");
+#endif
+ return 0;
+}
+
+Kross::Api::Object::Ptr RubyScript::callFunction(const QString& name, Kross::Api::List::Ptr args)
+{
+ Q_UNUSED(name)
+ Q_UNUSED(args)
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("RubyScript::callFunction()");
+#endif
+ if(d->m_compile == 0)
+ {
+ compile();
+ }
+ selectScript();
+ unselectScript();
+ return 0;
+}
+
+const QStringList& RubyScript::getClassNames()
+{
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("RubyScript::getClassNames()");
+#endif
+ if(d->m_compile == 0)
+ {
+ compile();
+ }
+ return d->m_classes;
+}
+
+Kross::Api::Object::Ptr RubyScript::classInstance(const QString& name)
+{
+ Q_UNUSED(name)
+#ifdef KROSS_RUBY_SCRIPT_DEBUG
+ krossdebug("RubyScript::classInstance()");
+#endif
+ if(d->m_compile == 0)
+ {
+ compile();
+ }
+ selectScript();
+ unselectScript();
+ return 0;
+}
+
+
+}
+
+}
diff --git a/lib/kross/ruby/rubyscript.h b/lib/kross/ruby/rubyscript.h
new file mode 100644
index 00000000..cc6eda43
--- /dev/null
+++ b/lib/kross/ruby/rubyscript.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * rubyscript.h
+ * This file is part of the KDE project
+ * copyright (C)2005 by Cyrille Berger (cberger@cberger.net)
+ *
+ * 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_RUBYRUBYSCRIPT_H
+#define KROSS_RUBYRUBYSCRIPT_H
+
+#include <api/script.h>
+
+namespace Kross {
+
+namespace Ruby {
+
+class RubyScriptPrivate;
+
+/**
+ * Handle ruby scripts. This class implements
+ * \a Kross::Api::Script for ruby.
+ * @author Cyrille Berger
+ */
+class RubyScript : public Kross::Api::Script
+{
+ public:
+
+ /**
+ * Constructor.
+ *
+ * @param interpreter The @a RubyInterpreter instance used to
+ * create this script.
+ * @param scriptcontainer The @a Kross::Api::ScriptContainer
+ * instance this @a RubyScript does handle the
+ * backend-work for.
+ */
+ RubyScript(Kross::Api::Interpreter* interpreter, Kross::Api::ScriptContainer* scriptcontainer);
+
+ /**
+ * Destructor.
+ */
+ ~RubyScript();
+
+ /**
+ * Return a list of callable functionnames this
+ * script spends.
+ */
+ virtual const QStringList& getFunctionNames();
+
+ /**
+ * Execute the script.
+ */
+ virtual Kross::Api::Object::Ptr execute();
+
+ /**
+ * Call a function.
+ */
+ virtual Kross::Api::Object::Ptr callFunction(const QString& name, Kross::Api::List::Ptr args);
+
+ /**
+ * Return a list of class types this script supports.
+ */
+ virtual const QStringList& getClassNames();
+
+ /**
+ * Create and return a new class instance.
+ */
+ virtual Kross::Api::Object::Ptr classInstance(const QString& name);
+
+ private:
+
+ /**
+ * Compile the script.
+ */
+ void compile();
+
+ private:
+ /// Private d-pointer.
+ RubyScriptPrivate* d;
+};
+
+}
+
+}
+
+#endif
diff --git a/lib/kross/runner/Makefile.am b/lib/kross/runner/Makefile.am
new file mode 100644
index 00000000..8c62b884
--- /dev/null
+++ b/lib/kross/runner/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/lib/kross/Makefile.global
+
+#noinst_PROGRAMS = krossrunner
+bin_PROGRAMS = krossrunner
+
+krossrunner_SOURCES = main.cpp
+krossrunner_LDADD = $(LIB_QT) $(LIB_KDECORE) ../api/libkrossapi.la ../main/libkrossmain.la
+INCLUDES = $(KROSS_INCLUDES) $(all_includes)
+krossrunner_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+SUBDIRS = .
+METASOURCES = AUTO
diff --git a/lib/kross/runner/main.cpp b/lib/kross/runner/main.cpp
new file mode 100644
index 00000000..89a35278
--- /dev/null
+++ b/lib/kross/runner/main.cpp
@@ -0,0 +1,144 @@
+/***************************************************************************
+ * main.cpp
+ * This file is part of the KDE project
+ * copyright (C)2006 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+// for std namespace
+#include <string>
+#include <iostream>
+
+// Qt
+#include <qstring.h>
+#include <qfile.h>
+
+// KDE
+#include <kinstance.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <ksharedptr.h>
+
+// Kross
+#include "../main/manager.h"
+#include "../main/scriptcontainer.h"
+#include "../api/interpreter.h"
+
+#define ERROR_OK 0
+#define ERROR_HELP -1
+#define ERROR_NOSUCHFILE -2
+#define ERROR_OPENFAILED -3
+#define ERROR_NOINTERPRETER -4
+#define ERROR_UNHALDEDEXCEPTION -5
+#define ERROR_EXCEPTION -6
+
+KApplication* app = 0;
+
+int runScriptFile(const QString& scriptfile)
+{
+ // Read the scriptfile
+ QFile f(QFile::encodeName(scriptfile));
+ if(! f.exists()) {
+ std::cerr << "No such scriptfile: " << scriptfile.latin1() << std::endl;
+ return ERROR_NOSUCHFILE;
+ }
+ if(! f.open(IO_ReadOnly)) {
+ std::cerr << "Failed to open scriptfile: " << scriptfile.latin1() << std::endl;
+ return ERROR_OPENFAILED;
+ }
+ QString scriptcode = f.readAll();
+ f.close();
+
+ // Determinate the matching interpreter
+ Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
+ Kross::Api::InterpreterInfo* interpreterinfo = manager->getInterpreterInfo( manager->getInterpreternameForFile(scriptfile) );
+ if(! interpreterinfo) {
+ std::cerr << "No interpreter for file: " << scriptfile.latin1() << std::endl;
+ return ERROR_NOINTERPRETER;
+ }
+
+ // Run the script.
+ try {
+ // First we need a scriptcontainer and fill it.
+ Kross::Api::ScriptContainer::Ptr scriptcontainer = manager->getScriptContainer(scriptfile);
+ scriptcontainer->setInterpreterName( interpreterinfo->getInterpretername() );
+ scriptcontainer->setCode(scriptcode);
+ // Now execute the scriptcontainer.
+ scriptcontainer->execute();
+ if(scriptcontainer->hadException()) {
+ // We had an exception.
+ QString errormessage = scriptcontainer->getException()->getError();
+ QString tracedetails = scriptcontainer->getException()->getTrace();
+ std::cerr << QString("%2\n%1").arg(tracedetails).arg(errormessage).latin1() << std::endl;
+ return ERROR_EXCEPTION;
+ }
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ // Normaly that shouldn't be the case...
+ std::cerr << QString("EXCEPTION %1").arg(e->toString()).latin1() << std::endl;
+ return ERROR_UNHALDEDEXCEPTION;
+ }
+ return ERROR_OK;
+}
+
+int main(int argc, char **argv)
+{
+ int result = ERROR_OK;
+
+ KAboutData about("krossrunner",
+ "krossrunner",
+ "0.1",
+ "KDE application to run Kross scripts.",
+ KAboutData::License_LGPL,
+ "(C) 2006 Sebastian Sauer",
+ "Run Kross scripts.",
+ "http://www.dipe.org/kross",
+ "kross@dipe.org");
+ about.addAuthor("Sebastian Sauer", "Author", "mail@dipe.org");
+
+ // Initialize command line args
+ KCmdLineArgs::init(argc, argv, &about);
+ // Tell which options are supported and parse them.
+ static KCmdLineOptions options[] = {
+ { "+file", I18N_NOOP("Scriptfile"), 0 },
+ KCmdLineLastOption
+ };
+ KCmdLineArgs::addCmdLineOptions(options);
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ // If no options are defined.
+ if(args->count() < 1) {
+ std::cout << "Syntax: " << KCmdLineArgs::appName() << " scriptfile1 [scriptfile2] [scriptfile3] ..." << std::endl;
+ return ERROR_HELP;
+ }
+
+ // Create KApplication instance.
+ app = new KApplication( /* allowStyles */ true, /* GUIenabled */ true );
+
+ //QString interpretername = args->getOption("interpreter");
+ //QString scriptfilename = args->getOption("scriptfile");
+
+ // Each argument is a scriptfile to open
+ for(int i = 0; i < args->count(); i++) {
+ result = runScriptFile(QFile::decodeName(args->arg(i)));
+ if(result != ERROR_OK)
+ break;
+ }
+
+ // Free the KApplication instance and exit the program.
+ delete app;
+ return result;
+}
diff --git a/lib/kross/test/Makefile.am b/lib/kross/test/Makefile.am
new file mode 100644
index 00000000..ddf235c3
--- /dev/null
+++ b/lib/kross/test/Makefile.am
@@ -0,0 +1,17 @@
+include $(top_srcdir)/lib/kross/Makefile.global
+
+noinst_PROGRAMS = krosstest
+
+krosstest_SOURCES = testobject.cpp testaction.cpp testplugin.cpp testwindow.cpp main.cpp
+
+krosstest_LDADD = \
+ $(LIB_QT) \
+ $(LIB_KDECORE) \
+ $(LIB_KDEUI) \
+ ../api/libkrossapi.la \
+ ../main/libkrossmain.la
+
+INCLUDES = $(KROSS_INCLUDES) $(all_includes)
+krosstest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+SUBDIRS = .
+METASOURCES = AUTO
diff --git a/lib/kross/test/main.cpp b/lib/kross/test/main.cpp
new file mode 100644
index 00000000..31b4f579
--- /dev/null
+++ b/lib/kross/test/main.cpp
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * main.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "../main/manager.h"
+
+#include "../api/object.h"
+#include "../api/class.h"
+#include "../api/module.h"
+//#include "../api/script.h"
+#include "../api/interpreter.h"
+
+#include "../main/scriptcontainer.h"
+
+//#include "../kexidb/kexidbmodule.h"
+
+#include "testobject.h"
+#include "testaction.h"
+#include "testwindow.h"
+#include "testplugin.h"
+
+// Qt
+#include <qstring.h>
+#include <qfile.h>
+
+// KDE
+#include <kinstance.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <ksharedptr.h>
+
+// for std namespace
+#include <string>
+#include <iostream>
+
+KApplication *app = 0;
+
+
+
+static KCmdLineOptions options[] =
+{
+ { "interpreter <interpretername>", I18N_NOOP("Name of the interpreter being used"), "python" },
+ { "scriptfile <filename>", I18N_NOOP("Script file to execute with the defined interpreter"), "testcase.py" },
+ { "gui", I18N_NOOP("Start the GUI; otherwise the command line application is used."), 0 },
+
+ //{ "functionname <functioname>", I18N_NOOP("Execute the function in the defined script file."), "" },
+ //{ "functionargs <functioarguments>", I18N_NOOP("List of arguments to pass to the function on execution."), "" },
+ { 0, 0, 0 }
+};
+
+void runInterpreter(const QString& interpretername, const QString& scriptcode)
+{
+ try {
+
+ // Return the scriptingmanager instance. The manager is used as main
+ // entry point to work with Kross.
+ Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
+
+ // Add modules that should be accessible by scripting. Those
+ // modules are wrappers around functionality you want to be
+ // able to access from within scripts. You don't need to take
+ // care of freeing them cause that will be done by Kross.
+ // Modules are shared between the ScriptContainer instances.
+ manager->addModule( new TestPluginModule("krosstestpluginmodule") );
+
+ // To represent a script that should be executed Kross uses
+ // the Script container class. You are able to fill them with
+ // what is needed and just execute them.
+ Kross::Api::ScriptContainer::Ptr scriptcontainer = manager->getScriptContainer("MyScriptName");
+
+ //scriptcontainer->enableModule("KexiDB");
+
+ scriptcontainer->setInterpreterName(interpretername);
+ scriptcontainer->setCode(scriptcode);
+
+ //TESTCASE
+ TestObject* testobject = new TestObject(app, scriptcontainer);
+ manager->addQObject( testobject );
+
+ /*TestAction* testaction =*/ new TestAction(scriptcontainer);
+ //manager->addQObject( testaction );
+
+ /*Kross::Api::Object* o =*/ scriptcontainer->execute();
+
+ // Call a function.
+ //scriptcontainer->callFunction("testobjectCallback" /*, Kross::Api::List* functionarguments */);
+
+ // Call a class.
+ /*
+ Kross::Api::Object* testclassinstance = scriptcontainer->classInstance("testClass");
+ if(testclassinstance) {
+ QValueList<Kross::Api::Object*> ll;
+ Kross::Api::Object* instancecallresult = testclassinstance->call("testClassFunction1", Kross::Api::List::create(ll));
+ //krossdebug( QString("testClass.testClassFunction1 returnvalue => '%1'").arg( instancecallresult.toString() ) );
+ }
+ */
+
+
+/*
+ // Connect QObject signal with scriptfunction.
+ scriptcontainer->connect(testobject, SIGNAL(testSignal()), "testobjectCallback");
+ scriptcontainer->connect(testobject, SIGNAL(testSignalString(const QString&)), "testobjectCallbackWithParams");
+ // Call the testSlot to emit the testSignal.
+ testobject->testSlot();
+*/
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ std::cout << QString("EXCEPTION %1").arg(e->toString()).latin1() << std::endl;
+ }
+
+/*TESTCASE
+ Kross::Api::ScriptContainer* sc2 = manager->getScriptContainer("MyScriptName222");
+ sc2->setInterpreterName(interpretername);
+ sc2->setCode(scriptcode);
+ try {
+ sc2->execute();
+ }
+ catch(Kross::Api::Exception& e) {
+ krossdebug( QString("EXCEPTION type='%1' description='%2'").arg(e.type()).arg(e.description()) );
+ }
+ //delete sc2;
+*/
+
+ std::string s; std::cin >> s; // just wait.
+}
+
+int main(int argc, char **argv)
+{
+ int result = 0;
+
+ KAboutData about("krosstest",
+ "KrossTest",
+ "0.1",
+ "KDE application to test the Kross framework.",
+ KAboutData::License_LGPL,
+ "(C) 2005 Sebastian Sauer",
+ "Test the Kross framework!",
+ "http://www.dipe.org/kross",
+ "kross@dipe.org");
+ about.addAuthor("Sebastian Sauer", "Author", "mail@dipe.org");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ QString interpretername = args->getOption("interpreter");
+ QString scriptfilename = args->getOption("scriptfile");
+
+ QFile f(QFile::encodeName(scriptfilename));
+ if(f.exists() && f.open(IO_ReadOnly)) {
+ QString scriptcode = f.readAll();
+ f.close();
+
+ if( args->isSet("gui") ) {
+ app = new KApplication();
+ TestWindow *mainWin = new TestWindow(interpretername, scriptcode);
+ app->setMainWidget(mainWin);
+ mainWin->show();
+ args->clear();
+ result = app->exec();
+ }
+ else {
+ app = new KApplication(true, true);
+ runInterpreter(interpretername, scriptcode);
+ }
+ }
+ else {
+ Kross::krosswarning( QString("Failed to load scriptfile: %1").arg(scriptfilename) );
+ result = -1;
+ }
+
+ delete app;
+ return result;
+}
diff --git a/lib/kross/test/testaction.cpp b/lib/kross/test/testaction.cpp
new file mode 100644
index 00000000..93c32090
--- /dev/null
+++ b/lib/kross/test/testaction.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * testaction.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "testaction.h"
+
+TestAction::TestAction(Kross::Api::ScriptContainer::Ptr scriptcontainer)
+ : QWidget()
+{
+ m_actioncollection = new KActionCollection(this, this);
+
+ m_action1 = new KAction("Action1_Text", 0, this, SLOT(activatedAction1()), m_actioncollection, "Action1");
+ m_actionlist.append(m_action1);
+ scriptcontainer->addKAction(m_action1);
+
+ m_action2 = new KAction("Action2_Text", 0, this, SLOT(activatedAction2()), m_actioncollection, "Action2");
+ m_actionlist.append(m_action2);
+ scriptcontainer->addKAction(m_action2);
+}
+
+TestAction::~TestAction()
+{
+}
+
+void TestAction::activatedAction1()
+{
+ Kross::krossdebug("TestAction::activatedAction1()");
+}
+
+void TestAction::activatedAction2()
+{
+ Kross::krossdebug("TestAction::activatedAction2()");
+}
+
diff --git a/lib/kross/test/testaction.h b/lib/kross/test/testaction.h
new file mode 100644
index 00000000..03ea95fe
--- /dev/null
+++ b/lib/kross/test/testaction.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * testaction.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_TEST_TESTACTION_H
+#define KROSS_TEST_TESTACTION_H
+
+#include "../main/scriptcontainer.h"
+
+#include <qobject.h>
+#include <qwidget.h>
+#include <qstring.h>
+
+#include <kaction.h>
+#include <kactioncollection.h>
+
+class TestAction : public QWidget
+{
+ Q_OBJECT
+ public:
+ TestAction(Kross::Api::ScriptContainer::Ptr scriptcontainer);
+ ~TestAction();
+
+ private slots:
+ void activatedAction1();
+ void activatedAction2();
+
+ private:
+ KAction* m_action1;
+ KAction* m_action2;
+ KActionCollection* m_actioncollection;
+ KActionPtrList m_actionlist;
+};
+
+#endif
diff --git a/lib/kross/test/testcase.py b/lib/kross/test/testcase.py
new file mode 100644
index 00000000..d3f2ea7b
--- /dev/null
+++ b/lib/kross/test/testcase.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+
+"""
+ This Python script is used to test the Kross scripting framework.
+"""
+
+#def testobjectCallback():
+# print "function testobjectCallback() called !"
+# return "this is the __main__.testobjectCallback() returnvalue!"
+#def testobjectCallbackWithParams(argument):
+# print "testobjectCallbackWithParams() argument = %s" % str(argument)
+# return "this is the __main__.testobjectCallbackWithParams() returnvalue!"
+#def testQtObject(self):
+ ## Get the QtObject instance to access the QObject.
+ ##testobject = get("TestObject")
+ #testobject = self.get("TestObject")
+ #if testobject == None: raise "Object 'TestObject' undefined !!!"
+ #print "testobject = %s %s" % (str(testobject),dir(testobject))
+ ##print "propertyNames = %s" % testobject.propertyNames()
+ ##print "slotNames = %s" % testobject.slotNames()
+ ##print "signalNames = %s" % testobject.signalNames()
+ ## We could just call a slot or a signal.
+ #print testobject.call("testSlot2()");
+ #print testobject.call("testSignal()");
+ ##print testobject.call() #KrossTest: List::item index=0 is out of bounds. Raising TypeException.
+ ## Each slot a QObject spends is a object itself.
+ #myslot = testobject.get("testSlot()")
+ #print "myslotevent = %s" % str(myslot)
+ #print myslot.call()
+ #print "__name__ = %s" % __name__
+ #print "__dir__ = %s" % dir()
+ ##print "__builtin__ = %s" % __builtin__
+ #print "self = %s %s" % (str(self),dir(self))
+ ##print "TestCase = %s" % str(TestCase)
+ #print "self.list = %s" % self.list()
+ #print "self.dict = %s" % self.dict()
+ #testobject = self.get("TestObject")
+ #print "testobject = %s" % testobject
+ #if not testobject.connect("testSignal()",testobject,"testSlot2()"):
+ #raise "Failed to connect testSignal() with testSlot2() at object 'TestObject'."
+ #testobject.signal("testSignal()")
+ ##testobject.testSlot()
+ #testobject.slot("testSlot()")
+ #testobject.disconnect("testSignal()")
+#def testActionEvent(self):
+ ##action1 = get("Action1")
+ #action1 = self.get("Action1")
+ #if action1 == None:
+ #raise "Object 'Action1' undefined !!!"
+ #print "action1 = %s %s" % (str(action1),dir(action1))
+ ##action1.call()
+ #action1.activate()
+
+import unittest
+
+class TestPlugin(unittest.TestCase):
+ """ Testcase to test the Kross python functionality for regressions. """
+
+ def setUp(self):
+ import krosstestpluginmodule
+ self.pluginobject1 = krosstestpluginmodule.testpluginobject1()
+ self.assert_( self.pluginobject1 )
+
+ self.pluginobject2 = krosstestpluginmodule.testpluginobject2()
+ self.assert_( self.pluginobject2 )
+
+ self.testqobject1 = krosstestpluginmodule.testqobject1()
+ self.assert_( self.testqobject1 )
+
+ def testBasicDataTypes(self):
+ self.assert_( self.pluginobject1.uintfunc(177321) == 177321 )
+ self.assert_( self.pluginobject1.intfunc(93675) == 93675 )
+ self.assert_( self.pluginobject1.intfunc(-73673) == -73673 )
+ self.assert_( self.pluginobject1.boolfunc(True) == True )
+ self.assert_( self.pluginobject1.boolfunc(False) == False )
+ self.assert_( self.pluginobject1.doublefunc(4265.3723) == 4265.3723 )
+ self.assert_( self.pluginobject1.doublefunc(-4265.68) == -4265.68 )
+ self.assert_( self.pluginobject1.cstringfunc(" This is a Test! ") == " This is a Test! " )
+ self.assert_( self.pluginobject1.stringfunc(" Another \n\r Test! $%&\"") == " Another \n\r Test! $%&\"" )
+
+ #TODO
+ #self.assert_( self.pluginobject1.stringfunc( unicode(" Unicode test ") ) == " Unicode test " )
+ #self.assert_( self.pluginobject1.stringfunc(unicode(" Another Test! ")) == unicode(" Another Test! ") )
+
+ self.assert_( self.pluginobject1.stringstringfunc("MyString1", "MyString2") == "MyString1" )
+ self.assert_( self.pluginobject1.uintdoublestringfunc(8529,285.246,"String") == 8529 )
+ self.assert_( self.pluginobject1.stringlistbooluintdouble(["s1","s2"],True,6,7.0,"String") == ["s1","s2"] )
+
+ def testStringList(self):
+ self.assert_( self.pluginobject1.stringlistfunc( [] ) == [] )
+ self.assert_( self.pluginobject1.stringlistfunc( ["First Item"," Second Item "] ) == ["First Item"," Second Item "] )
+ self.assert_( self.pluginobject1.stringlistfunc( ("Theird Item"," Forth Item ","Fifth Item") ) == ["Theird Item"," Forth Item ","Fifth Item"] )
+
+ def testVariant(self):
+ self.assert_( self.pluginobject1.variantfunc(True) == True )
+ self.assert_( self.pluginobject1.variantfunc(False) == False )
+ self.assert_( self.pluginobject1.variantfunc(187937) == 187937 )
+ self.assert_( self.pluginobject1.variantfunc(-69825) == -69825 )
+ self.assert_( self.pluginobject1.variantfunc(8632.274) == 8632.274 )
+ self.assert_( self.pluginobject1.variantfunc(-8632.351) == -8632.351 )
+ self.assert_( self.pluginobject1.variantfunc(" Test \n\r This String $%&\"") == " Test \n\r This String $%&\"")
+
+ def testObjects(self):
+ print "-----------------1"
+ newobjref = self.pluginobject1.objectfunc(self.pluginobject2)
+ print "-----------------2"
+ print str(newobjref)
+
+ #self.assert_( newobjref.myuniqueid == self.pluginobject2.myuniqueid )
+ #print "===========> %s" % self.pluginobject2.myName()
+
+ print "testqobject1 properties=%s" % self.testqobject1.propertyNames()
+ print "testqobject1 slots=%s" % self.testqobject1.slotNames()
+ print "testqobject1 signals=%s" % self.testqobject1.signalNames()
+ print "-----------------3"
+ print "DIR=>%s" % dir(self.testqobject1)
+
+ print "===================> slotcall-result: %s" % self.testqobject1.slot("self()")
+
+ #testobject = newobjref.get("TestObject")
+ #print testobject
+ print "-----------------9"
+
+ def testDefaultArguments(self):
+ self.assert_( self.pluginobject1.uintfunc_defarg(98765) == 98765 )
+ self.assert_( self.pluginobject1.uintfunc_defarg() == 12345 )
+ self.assert_( self.pluginobject1.stringfunc_defarg("MyString") == "MyString" )
+ self.assert_( self.pluginobject1.stringfunc_defarg() == "MyDefaultString" )
+ self.assert_( self.pluginobject1.stringlistfunc_defarg(["s1","s2","s3"]) == ["s1","s2","s3"] )
+ self.assert_( self.pluginobject1.stringlistfunc_defarg() == ["Default1","Default2"] )
+ self.assert_( self.pluginobject1.variantfunc_defarg(822.75173) == 822.75173 )
+ self.assert_( self.pluginobject1.variantfunc_defarg() == "MyDefaultVariantString" )
+
+ #def testExpectedFailures(self):
+ # to less arguments
+ #self.assertRaises(ValueError, self.pluginobject1.uintfunc)
+ #self.assert_( self.pluginobject1.uintfunc() != 8465 )
+
+print "__name__ = %s" % __name__
+#print "self = %s" % self
+#print self.get("TestObject")
+
+suite = unittest.makeSuite(TestPlugin)
+unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/lib/kross/test/testcase.rb b/lib/kross/test/testcase.rb
new file mode 100644
index 00000000..71354ea2
--- /dev/null
+++ b/lib/kross/test/testcase.rb
@@ -0,0 +1,15 @@
+require 'test/unit'
+
+class TestKross < Test::Unit::TestCase
+ def setup:
+ require "krosstestpluginmodule"
+ testpluginobject1 = Krosstestpluginmodule::get("testpluginobject1")
+ #Krosskritacore::get("KritaDocument")
+ #testpluginobject1.func1()
+ #def test_primitive
+ # print "---------------- 1\n"
+
+ end
+end
+
+print "3----------------\n"
diff --git a/lib/kross/test/testgui.py b/lib/kross/test/testgui.py
new file mode 100644
index 00000000..f252184d
--- /dev/null
+++ b/lib/kross/test/testgui.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+
+"""
+ This Python script demonstrates the usage of the Kross
+ python-interface to access KexiDB functionality from
+ within Python.
+"""
+
+class TkTest:
+ def __init__(self):
+ import Tkinter
+ self.root = Tkinter.Tk()
+ self.root.title("TkTest")
+ self.root.deiconify()
+
+ self.mainframe = Tkinter.Frame(self.root)
+ self.mainframe.pack()
+
+ self.button1 = Tkinter.Button(self.mainframe, text="Button1", command=self.callback1)
+ self.button1.pack(side=Tkinter.LEFT)
+
+ self.button2 = Tkinter.Button(self.mainframe, text="Button2", command=self.callback2)
+ self.button2.pack(side=Tkinter.LEFT)
+
+ self.exitbutton = Tkinter.Button(self.mainframe, text="Exit", command=self.root.destroy)
+ self.exitbutton.pack(side=Tkinter.LEFT)
+
+ self.root.mainloop()
+
+ def callback1(self):
+ import tkMessageBox
+ tkMessageBox.showinfo("Callback1", "Callback1 called.")
+
+ def callback2(self):
+ import tkMessageBox
+ tkMessageBox.showinfo("Callback2", "Callback2 called.")
+
+class QtTest:
+ def __init__(self):
+ import qt
+
+ class Button(qt.QPushButton):
+ def __init__(self, *args):
+ apply(qt.QPushButton.__init__, (self,) + args)
+
+ class ComboBox(qt.QHBox):
+ def __init__(self, parent, caption, items = []):
+ qt.QHBox.__init__(self, parent)
+ self.setSpacing(6)
+ label = qt.QLabel(str(caption), self)
+ self.combobox = qt.QComboBox(self)
+ self.setStretchFactor(self.combobox, 1)
+ label.setBuddy(self.combobox)
+ for item in items:
+ self.combobox.insertItem( str(item) )
+
+ class FileChooser(qt.QHBox):
+ def __init__(self, *args):
+ apply(qt.QHBox.__init__, (self,) + args)
+ self.defaultfilename = "~/output.html"
+
+ self.setSpacing(6)
+ label = qt.QLabel("File:", self)
+ self.edit = qt.QLineEdit(self)
+ self.edit.setText(self.defaultfilename)
+ self.setStretchFactor(self.edit, 1)
+ label.setBuddy(self.edit)
+
+ browsebutton = Button("...", self)
+ qt.QObject.connect(browsebutton, qt.SIGNAL("clicked()"), self.browseButtonClicked)
+
+ def file(self):
+ return self.edit.text()
+
+ def browseButtonClicked(self):
+ filename = None
+ try:
+ # try to use the kfile module included in pykde
+ import kfile
+ filename = kfile.KFileDialog.getOpenFileName(self.defaultfilename, "*.html", self, "Save to file")
+ except:
+ # fallback to Qt filedialog
+ filename = qt.QFileDialog.getOpenFileName(self.defaultfilename, "*.html", self, "Save to file")
+ if filename != None and filename != "":
+ self.edit.setText(filename)
+
+ class Dialog(qt.QDialog):
+ def __init__(self, parent = None, name = None, modal = 0, fl = 0):
+ qt.QDialog.__init__(self, parent, name, modal, fl)
+ qt.QDialog.accept = self.accept
+ self.setCaption("Export to HTML")
+ #self.layout()
+
+ self.layout = qt.QVBoxLayout(self)
+ self.layout.setSpacing(6)
+ self.layout.setMargin(11)
+
+ infolabel = qt.QLabel("Export the data of a table or a query to a HTML-file.", self)
+ self.layout.addWidget(infolabel)
+
+ source = ComboBox(self, "Datasource:")
+ self.layout.addWidget(source)
+
+ self.exporttype = ComboBox(self, "Style:", ["Plain","Paper","Desert","Blues"])
+ self.layout.addWidget(self.exporttype)
+
+ self.filechooser = FileChooser(self)
+ self.layout.addWidget(self.filechooser)
+
+ buttonbox = qt.QHBox(self)
+ buttonbox.setSpacing(6)
+ self.layout.addWidget(buttonbox)
+
+ savebutton = Button("Save", buttonbox)
+ qt.QObject.connect(savebutton, qt.SIGNAL("clicked()"), self, qt.SLOT("accept()"))
+ #qt.QObject.connect(savebutton, qt.SIGNAL("clicked()"), self.exportButtonClicked)
+
+ cancelbutton = Button("Cancel", buttonbox)
+ qt.QObject.connect(cancelbutton, qt.SIGNAL("clicked()"), self, qt.SLOT("close()"))
+
+ def accept(self):
+ print "ACCEPTTTTTTTT !!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+
+ file = qt.QFile( self.filechooser.file() )
+ #if not file.exists():
+ # print "File '%s' does not exist." % self.filechooser.file()
+ #else:
+ # print "File '%s' does exist." % self.filechooser.file()
+
+ def exportButtonClicked(self):
+ print "Export to HTML !!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+
+ def __getattr__(self, attr):
+ print "=> Dialog.__getattr__(self,attr)"
+ #def closeEvent(self, ev): pass
+ def event(self, e):
+ print "=> Dialog.event %s" % e
+ #self.deleteLater()
+ #support.swapThreadState() # calls appropriate c-function
+ return qt.QDialog.event(self, e)
+
+ app = qt.qApp
+ dialog = Dialog(app.mainWidget(), "Dialog", 1)
+ dialog.show()
+
+print "################## BEGIN"
+#TkTest()
+QtTest()
+print "################## END"
diff --git a/lib/kross/test/testkexidb.py b/lib/kross/test/testkexidb.py
new file mode 100644
index 00000000..048b7e19
--- /dev/null
+++ b/lib/kross/test/testkexidb.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+
+"""
+ This Python script demonstrates the usage of the Kross
+ python-interface to access KexiDB functionality from
+ within Python.
+"""
+
+# Class to test the KexiDB functionality.
+class KexiDBClass:
+
+ # Constructor.
+ def __init__(self):
+ # The KexiDB module spends us access to the KexiDB functionality.
+ #import KexiDB
+ import krosskexidb
+ self.kexidbmodule = krosskexidb
+ print "KrossKexiDB version=%s" % self.kexidbmodule.version()
+
+ # Create and remember the drivermanager.
+ self.drivermanager = self.kexidbmodule.DriverManager()
+
+ # Print informations about the KexiDB module.
+ def printKexiDB(self):
+ print "KexiDB = %s %s" % (str(self.kexidbmodule),dir(self.kexidbmodule))
+ # Each object has __name__ and __doc__
+ #print "KexiDB.__name__ = %s" % self.kexidbmodule.__name__
+ #print "KexiDB.__doc__ = %s" % self.kexidbmodule.__doc__
+ # Print some infos about the drivermanager.
+ print "drivermanager = %s %s" % (self.drivermanager,dir(self.drivermanager))
+ # The drivermanager holds a list of drivers he supports.
+ print "drivermanager.driverNames() = %s" % self.driverNames()
+
+ # Print informations about a driver.
+ def printDriverManger(self, driver):
+ print "driver = %s %s" % (driver,dir(driver))
+ # Each driver has a version to be able to determinate with what release we are working.
+ print "driver.versionMajor() = %s" % driver.versionMajor()
+ print "driver.versionMinor() = %s" % driver.versionMinor()
+ # Show us what connections are opened right now.
+ print "driver.connectionsList() = %s" % str(driver.connectionsList())
+
+ # Print informations about a connection.
+ def printConnection(self, connection):
+ print "connection = %s %s" % (str(connection),dir(connection))
+ # Print a list of all avaible databasenames this connection has.
+ print "connection.databaseNames() = %s" % connection.databaseNames()
+
+ # Return a list of drivernames.
+ def driverNames(self):
+ return self.drivermanager.driverNames()
+
+ # Return the to drivername matching KexiDBDriver object.
+ def driver(self, drivername):
+ return self.drivermanager.driver(drivername)
+
+ # Return a new KexiDBConnectionData object.
+ def getConnectionData(self):
+ return self.drivermanager.createConnectionData()
+
+ # Open a connection to a filebased driver.
+ def connectWithFile(self, driver, filename):
+ # First we need a new connectiondata object.
+ connectiondata = self.getConnectionData()
+ # Fill the new connectiondata object with what we need to connect.
+ connectiondata.setCaption("myFileConnection")
+ connectiondata.setFileName(filename)
+ print "connectiondata.serverInfoString = %s" % connectiondata.serverInfoString()
+ # Create the connection now.
+ connection = driver.createConnection(connectiondata)
+ # Establish the connection.
+ if not connection.connect():
+ raise("ERROR in connectWithDatabase(): Failed to connect!")
+ # Open database for usage. The filebased driver uses the filename as databasename.
+ self.useDatabase(connection, filename)
+ return connection
+
+ # Open database for usage.
+ def useDatabase(self, connection, dbname):
+ if not connection.useDatabase(dbname):
+ raise("ERROR in connectWithDatabase(): Failed to use database!")
+
+ # Create a new database.
+ def createDatabase(self, connection, dbname):
+ #print "createDatabase dbname='%s' dbnames='%s'" % (dbname,connection.databaseNames())
+ connection.createDatabase(dbname)
+ #print "createDatabase databaseExists(%s) = %s" % (dbname,connection.databaseExists(dbname))
+ #print "createDatabase dbname='%s' dbnames='%s'" % (dbname,connection.databaseNames())
+
+ # Drop an existing database.
+ def dropDatabase(self, connection, dbname):
+ #print "dropDatabase dbname='%s' dbnames='%s'" % (dbname,connection.databaseNames())
+ myfileconnection.dropDatabase(dbname)
+ #print "dropDatabase databaseExists(%s) = %s" % (dbname,connection.databaseExists(dbname))
+ #print "dropDatabase dbname='%s' dbnames='%s'" % (dbname,connection.databaseNames())
+
+ # Test KexiDBParser used to parse SQL-statements.
+ def testParser(self, connection, sqlstatement):
+ parser = connection.parser()
+ if not parser:
+ raise "ERROR in testParser(): Failed to create parser!"
+ print "parser.parse = %s" % parser.parse(sqlstatement)
+ print "parser.statement = %s" % parser.statement()
+ print "parser.operation = %s" % parser.operation()
+ print "parser.table = %s" % parser.table()
+ print "parser.query = %s" % parser.query()
+ print "parser.connection = %s" % parser.connection()
+
+ # Execute the sql query statement and print the single string result.
+ def printQuerySingleString(self, connection, sqlstatement):
+ query = myfileconnection.querySingleString("SELECT * FROM table1", 0)
+ print "querySingleString = %s" % query
+
+ # Execute the sql query statement and print the single stringlist result.
+ def printQueryStringList(self, connection, sqlstatement):
+ query = myfileconnection.queryStringList("SELECT * FROM table1", 0)
+ print "queryStringList = %s" % query
+
+ # Walk through the KexiDBCursor and print all item values.
+ def printQueryCursor(self, cursor):
+ if cursor == None:
+ raise("ERROR: executeQuery failed!")
+ #print "printCursor() cursor = %s %s" % (str(cursor), dir(cursor))
+
+ # Go to the first item of the table.
+ if not cursor.moveFirst():
+ raise("ERROR in printCursor(): cursor.moveFirst() returned False!")
+
+ # Walk through all items in the table.
+ while(not cursor.eof()):
+ # Print for each item some infos about the fields and there content.
+ for i in range( cursor.fieldCount() ):
+ print "Item='%s' Field='%s' Value='%s'" % (cursor.at(), i, cursor.value(i))
+ # Move to the next item
+ cursor.moveNext()
+
+ # Similar to printQueryCursor
+ def printQuerySchema(self, connection, queryschema):
+ return self.printQueryCursor(connection.executeQuerySchema(queryschema))
+
+ # Similar to printQueryCursor
+ def printQueryString(self, connection, sqlstring):
+ return self.printQueryCursor(connection.executeQueryString(sqlstring))
+
+ # Add a field to the tableschema.
+ def addField(self, tableschema, name):
+ field = self.drivermanager.field()
+ field.setType("Text")
+ field.setName(name)
+ tableschema.fieldlist().addField(field)
+ print "tableschema.fieldlist().fieldCount() = %s" % tableschema.fieldlist().fieldCount()
+ return field
+
+ # Create a table.
+ def createTable(self, connection, tablename):
+ # First we need a new tableschema.
+ tableschema = self.drivermanager.tableSchema(tablename)
+ self.addField(tableschema, "myfield")
+ print "connection.createTable = %s" % connection.createTable(tableschema, True)
+ return tableschema
+
+ # Drop a table.
+ def dropTable(self, connection, tablename):
+ connection.dropTable(tablename)
+
+ # Alter the name of a table.
+ def alterTableName(self, connection, tablename, newtablename):
+ tableschema = connection.tableSchema(tablename)
+ print "alterTableName from=%s to=%s tableschema=%s" % (tablename, newtablename, tableschema)
+ connection.alterTableName(tableschema, newtablename)
+
+def testKexiDB():
+ global KexiDBClass
+ mykexidbclass = KexiDBClass()
+ mykexidbclass.printKexiDB()
+
+ mydriver = mykexidbclass.driver("SQLite3")
+ mykexidbclass.printDriverManger(mydriver)
+
+ myfileconnection = mykexidbclass.connectWithFile(mydriver, "/home/snoopy/test.kexi")
+ mykexidbclass.printConnection(myfileconnection)
+ #mykexidbclass.testParser(myfileconnection, "SELECT * from table1")
+
+ #mykexidbclass.printQuerySingleString(myfileconnection, "SELECT * FROM dept")
+ #mykexidbclass.printQueryStringList(myfileconnection, "SELECT * FROM dept")
+ mykexidbclass.printQueryString(myfileconnection, "SELECT * FROM dept")
+
+ #myqueryschema = mykexidbclass.drivermanager.querySchema()
+ #myqueryschema.setName("myqueryname")
+ #myqueryschema.setCaption("myquerycaption")
+ #myqueryschema.setStatement("SELECT * FROM table2")
+ #print "myqueryschema = %s" % myqueryschema.statement()
+ #mykexidbclass.printQuerySchema(myfileconnection, myqueryschema)
+
+ #mykexidbclass.createTable(myfileconnection, "mytable123")
+ #mykexidbclass.dropTable(myfileconnection, "mytable123")
+ #mykexidbclass.alterTableName(myfileconnection, "table1", "table111")
+
+ #TODO: new table isn't usuable!!!
+ #ts1 = myfileconnection.tableSchema("table2")
+ #ts2 = mykexidbclass.drivermanager.tableSchema("table4")
+ #mykexidbclass.addField(ts2, "MyField 111111111")
+ #print "myfileconnection.alterTable = %s" % myfileconnection.alterTable(ts1, ts2)
+ #TEST
+ #bool Connection::insertRecord(TableSchema &tableSchema, QValueList<QVariant>& values)
+ #myfileconnection.insertRecord(KexiDBField, ("field1", "field2"))
+ #del(mycursor)
+ #del(myfileconnection)
+ #del(mydriver)
+ #del(mykexidbclass)
+
+print "########## BEGIN TEST: KexiDB ##########"
+testKexiDB()
+print "########## END TEST: KexiDB ##########"
diff --git a/lib/kross/test/testobject.cpp b/lib/kross/test/testobject.cpp
new file mode 100644
index 00000000..893cccca
--- /dev/null
+++ b/lib/kross/test/testobject.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * testobject.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "testobject.h"
+
+#include <iostream> // for std::out
+
+TestObject::TestObject()
+ : QObject(0, "TestObject")
+{
+}
+
+TestObject::TestObject(QObject* parent, Kross::Api::ScriptContainer::Ptr scriptcontainer)
+ : QObject(parent, "TestObject")
+{
+ connect(this, SIGNAL(testSignal()), this, SLOT(testSignalSlot()));
+ connect(this, SIGNAL(stdoutSignal(const QString&)), this, SLOT(stdoutSlot(const QString&)));
+ connect(this, SIGNAL(stderrSignal(const QString&)), this, SLOT(stderrSlot(const QString&)));
+
+ scriptcontainer->addQObject(this);
+
+//scriptcontainer->addSignal("stdout", this, SIGNAL(stdoutSignal(const QString&)));
+//scriptcontainer->addSlot("stderr", this, SLOT(stderrSlot(const QString&)));
+
+ //scriptcontainer->addSignal("myTestSignal", this, SIGNAL(testSignal()));
+ //scriptcontainer->addSlot("myTestSlot", this, SLOT(testSlot()));
+}
+
+TestObject::~TestObject()
+{
+}
+
+uint TestObject::func1(uint i)
+{
+ Kross::krossdebug(QString("CALLED => TestObject::func1 i=%1").arg(i) );
+ return i;
+}
+
+void TestObject::func2(QString s, int i)
+{
+ Kross::krossdebug(QString("CALLED => TestObject::func2 s=%1 i=%2").arg(s).arg(i));
+}
+
+QString TestObject::func3(QString s, int i)
+{
+ Kross::krossdebug(QString("CALLED => TestObject::func3 s=%1 i=%2").arg(s).arg(i));
+ return s;
+}
+
+const QString& TestObject::func4(const QString& s, int i) const
+{
+ Kross::krossdebug(QString("CALLED => TestObject::func4 s=%1 i=%2").arg(s).arg(i));
+ return s;
+}
+
+void TestObject::testSlot()
+{
+ Kross::krossdebug("TestObject::testSlot called");
+ emit testSignal();
+ emit testSignalString("This is the emitted TestObject::testSignalString(const QString&)");
+}
+
+void TestObject::testSlot2()
+{
+ Kross::krossdebug("TestObject::testSlot2 called");
+}
+
+void TestObject::stdoutSlot(const QString& s)
+{
+ Kross::krossdebug(QString("stdout: %1").arg(s));
+ //std::cout << "<stdout> " << s.latin1() << std::endl;
+}
+
+void TestObject::stderrSlot(const QString& s)
+{
+ Kross::krossdebug(QString("stderr: %1").arg(s));
+ //std::cout << "<stderr> " << s.latin1() << std::endl;
+}
+
+//#include "testobject.moc"
diff --git a/lib/kross/test/testobject.h b/lib/kross/test/testobject.h
new file mode 100644
index 00000000..011b7e54
--- /dev/null
+++ b/lib/kross/test/testobject.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * testobject.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_TEST_TESTOBJECT_H
+#define KROSS_TEST_TESTOBJECT_H
+
+#include "../main/scriptcontainer.h"
+
+#include <qobject.h>
+#include <qstring.h>
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString testProperty READ testProperty WRITE setTestProperty)
+
+ public:
+ TestObject();
+ TestObject(QObject* parent, Kross::Api::ScriptContainer::Ptr scriptcontainer);
+ ~TestObject();
+
+ uint func1(uint);
+ void func2(QString, int);
+ QString func3(QString, int);
+ const QString& func4(const QString&, int) const;
+
+ QString testProperty() const { return m_prop; }
+ void setTestProperty(QString prop) { m_prop = prop; }
+
+ signals:
+ void testSignal();
+ void testSignalString(const QString&);
+ void stdoutSignal(const QString&);
+ void stderrSignal(const QString&);
+ public slots:
+ void testSlot();
+ void testSlot2();
+ void stdoutSlot(const QString&);
+ void stderrSlot(const QString&);
+
+ QObject* self() { return this; }
+
+ private:
+ QString m_prop;
+};
+
+#endif
diff --git a/lib/kross/test/testperformance.py b/lib/kross/test/testperformance.py
new file mode 100755
index 00000000..a76453ed
--- /dev/null
+++ b/lib/kross/test/testperformance.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+"""
+ This Python script is used as performance-tester and profiler
+ for the Kross scripting framework.
+"""
+
+def runner():
+ import krosstestpluginmodule
+ testobject1 = krosstestpluginmodule.testpluginobject1()
+
+ def testKexiDB(kexidbfile,drivername,sqlstring):
+ print "test kexidb"
+ import krosskexidb
+ drivermanager = krosskexidb.DriverManager()
+ connectiondata = drivermanager.createConnectionData()
+ connectiondata.setFileName(kexidbfile)
+ driver = drivermanager.driver(drivername)
+ connection = driver.createConnection(connectiondata)
+ if not connection.connect(): raise "Connect failed"
+ if not connection.useDatabase(kexidbfile): raise "Use database failed"
+ for i in range(20000):
+ cursor = connection.executeQueryString(sqlstring)
+ if not cursor: raise "Failed to create cursor"
+ cursor.moveFirst()
+ while(not cursor.eof()):
+ for i in range( cursor.fieldCount() ):
+ (item,field,value) = (cursor.at(), i, cursor.value(i))
+ cursor.moveNext()
+
+ def test1():
+ print "test1"
+ for i in range(100000):
+ testobject1.func1()
+ testobject1.func1()
+ testobject1.func1()
+
+ testobject1.func2("f2s1","f2s2")
+ testobject1.func2("f2s3","f2s4")
+ testobject1.func2("f2s5","f2s6")
+
+ testobject1.func3("f3s1","f3s2")
+ testobject1.func3("f3s3","f3s4")
+ testobject1.func3("f3s5","f3s6")
+
+ testobject1.func4("f4s1","f4s2")
+ testobject1.func4("f4s3","f4s4")
+ testobject1.func4("f4s5","f4s6")
+
+ testobject1.func5("f5s1","f5s2")
+ testobject1.func5("f5s3","f5s4")
+ testobject1.func5("f5s5","f5s6")
+
+ testobject1.func6( ("One1","Two2"), "haha" )
+ testobject1.func6( ("One3","Two4"), 123456789 )
+ testobject1.func6( ("One5","Two6"), 12345.67890 )
+
+ testobject1.func7("f5s1",123)
+ testobject1.func7("f5s3",456)
+ testobject1.func7("f5s5",789)
+
+ testobject1.func8(123,456)
+ testobject1.func8(12,34)
+ testobject1.func8(1,2)
+
+ testobject1.func9(2.0,1.0)
+ testobject1.func9(4.0,3.0)
+ testobject1.func9(6.0,5.0)
+
+ #test1()
+ testKexiDB("/home/snoopy/test.kexi", "SQLite3", "SELECT * FROM dept")
+
+import profile
+__main__.runner=runner
+profile.run("runner()")
diff --git a/lib/kross/test/testplugin.cpp b/lib/kross/test/testplugin.cpp
new file mode 100644
index 00000000..07fffc6a
--- /dev/null
+++ b/lib/kross/test/testplugin.cpp
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * testplugin.cpp
+ * This file is part of the KDE project
+ * copyright (C)2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "testplugin.h"
+#include "testobject.h"
+
+/************************************************************************
+ * TestPluginObject
+ */
+
+TestPluginObject::TestPluginObject(const QString& name)
+ : Kross::Api::Class<TestPluginObject>(name)
+{
+ // Functions to test the basic datatypes
+ this->addFunction1< void, Kross::Api::Variant >
+ ("voiduintfunc", this, &TestPluginObject::voiduintfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("uintfunc", this, &TestPluginObject::uintfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("intfunc", this, &TestPluginObject::intfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("boolfunc", this, &TestPluginObject::boolfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("doublefunc", this, &TestPluginObject::doublefunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("cstringfunc", this, &TestPluginObject::cstringfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("stringfunc", this, &TestPluginObject::stringfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("stringlistfunc", this, &TestPluginObject::stringlistfunc);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("variantfunc", this, &TestPluginObject::variantfunc);
+
+ // With 2 arguments
+ this->addFunction2< Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant >
+ ("stringstringfunc", this, &TestPluginObject::stringstringfunc);
+ // With 3 arguments
+ this->addFunction3< Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant >
+ ("uintdoublestringfunc", this, &TestPluginObject::uintdoublestringfunc);
+ // With 4 arguments
+ this->addFunction4< Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant >
+ ("stringlistbooluintdouble", this, &TestPluginObject::stringlistbooluintdouble);
+
+ // With default arguments
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("uintfunc_defarg", this, &TestPluginObject::uintfunc, new Kross::Api::Variant(12345) );
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("stringfunc_defarg", this, &TestPluginObject::stringfunc, new Kross::Api::Variant("MyDefaultString") );
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("stringlistfunc_defarg", this, &TestPluginObject::stringlistfunc, new Kross::Api::Variant(QVariant(QStringList() << "Default1" << "Default2")));
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >
+ ("variantfunc_defarg", this, &TestPluginObject::variantfunc, new Kross::Api::Variant("MyDefaultVariantString") );
+
+ // Test passing of objects
+ this->addFunction1<TestPluginObject, TestPluginObject>("objectfunc", this, &TestPluginObject::objectfunc, 0);
+}
+
+TestPluginObject::~TestPluginObject()
+{
+}
+
+const QString TestPluginObject::getClassName() const
+{
+ return "TestPluginObject";
+}
+
+uint TestPluginObject::uintfunc(uint i) { return i; }
+void TestPluginObject::voiduintfunc(uint) {}
+int TestPluginObject::intfunc(int i) { return i; }
+bool TestPluginObject::boolfunc(bool b) { return b; }
+double TestPluginObject::doublefunc(double d) { return d; }
+QCString TestPluginObject::cstringfunc(const QCString& s) { return s; }
+QString TestPluginObject::stringfunc(const QString& s) { return s; }
+QStringList TestPluginObject::stringlistfunc(const QStringList& sl) { return sl; }
+QVariant TestPluginObject::variantfunc(const QVariant& v) { return v; }
+TestPluginObject* TestPluginObject::objectfunc(TestPluginObject* obj) { return obj; }
+QString TestPluginObject::stringstringfunc(const QString& s, const QString&) { return s; }
+uint TestPluginObject::uintdoublestringfunc(uint i, double, const QString&) { return i; }
+QStringList TestPluginObject::stringlistbooluintdouble(const QStringList& sl, bool, uint, double) { return sl; }
+
+/************************************************************************
+ * TestPluginModule
+ */
+
+TestPluginModule::TestPluginModule(const QString& name)
+ : Kross::Api::Module(name)
+ , m_testobject( new TestObject() )
+
+{
+ addChild( new TestPluginObject("testpluginobject1") );
+
+ // Let's wrap a whole instance and it's methodfunctions.
+ Kross::Api::Event<TestObject> *testobjectclass =
+ new Kross::Api::Event<TestObject>("testpluginobject2");
+ addChild(testobjectclass);
+
+ // Wrap a whole QObject
+ addChild( new Kross::Api::QtObject( new TestObject() , "testqobject1" ) );
+}
+
+TestPluginModule::~TestPluginModule()
+{
+ delete m_testobject;
+}
+
+const QString TestPluginModule::getClassName() const
+{
+ return "TestPluginModule";
+}
+
diff --git a/lib/kross/test/testplugin.h b/lib/kross/test/testplugin.h
new file mode 100644
index 00000000..5253becf
--- /dev/null
+++ b/lib/kross/test/testplugin.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ * testplugin.h
+ * This file is part of the KDE project
+ * copyright (C)2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_TEST_TESTPLUGIN_H
+#define KROSS_TEST_TESTPLUGIN_H
+
+#include "../api/object.h"
+#include "../api/list.h"
+#include "../api/class.h"
+#include "../api/proxy.h"
+#include "../api/module.h"
+#include "../api/qtobject.h"
+
+#include <qobject.h>
+#include <qstring.h>
+
+class TestPluginObject : public Kross::Api::Class<TestPluginObject>
+{
+ public:
+ TestPluginObject(const QString& name);
+ virtual ~TestPluginObject();
+ virtual const QString getClassName() const;
+
+ private:
+ uint uintfunc(uint);
+ void voiduintfunc(uint);
+ int intfunc(int);
+ bool boolfunc(bool);
+ double doublefunc(double);
+ QCString cstringfunc(const QCString&);
+ QString stringfunc(const QString&);
+ QStringList stringlistfunc(const QStringList&);
+ QVariant variantfunc(const QVariant&);
+
+ TestPluginObject* objectfunc(TestPluginObject* obj);
+
+ QString stringstringfunc(const QString&, const QString&);
+ uint uintdoublestringfunc(uint, double, const QString&);
+ QStringList stringlistbooluintdouble(const QStringList&, bool, uint, double);
+};
+
+class TestObject;
+
+class TestPluginModule : public Kross::Api::Module
+{
+ public:
+ TestPluginModule(const QString& name);
+ virtual ~TestPluginModule();
+ virtual const QString getClassName() const;
+
+ virtual Kross::Api::Object::Ptr get(const QString& /*name*/, void* /*pointer*/ = 0)
+ {
+ return 0;
+ }
+ private:
+ TestObject* m_testobject;
+};
+
+#endif
diff --git a/lib/kross/test/testscripting.rc b/lib/kross/test/testscripting.rc
new file mode 100644
index 00000000..ee641d15
--- /dev/null
+++ b/lib/kross/test/testscripting.rc
@@ -0,0 +1,33 @@
+<KrossScripting>
+ <ScriptAction
+ name="sa1name"
+ text="ScriptAction1Text"
+ description="Some describing text"
+ interpreter="python"
+ icon="exec">
+print "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+print "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ </ScriptAction>
+
+ <ScriptAction
+ name="testcase"
+ text="TestCase"
+ description="Test some common functionality."
+ interpreter="python"
+ file="testcase.py" />
+
+ <ScriptAction
+ name="testgui"
+ text="TestGUI"
+ description="Test the GUI functionality."
+ interpreter="python"
+ file="testgui.py" />
+
+ <ScriptAction
+ name="testkexidb"
+ text="TestKexiDB"
+ description="Test the kexidb binding."
+ interpreter="python"
+ file="testkexidb.py" />
+
+</KrossScripting>
diff --git a/lib/kross/test/testwindow.cpp b/lib/kross/test/testwindow.cpp
new file mode 100644
index 00000000..f60119f0
--- /dev/null
+++ b/lib/kross/test/testwindow.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * testwindow.cpp
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "testwindow.h"
+#include "testplugin.h"
+
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qvgroupbox.h>
+//#include <qhgroupbox.h>
+#include <qcombobox.h>
+#include <qdir.h>
+#include <qpopupmenu.h>
+
+#include <ktextedit.h>
+#include <kpushbutton.h>
+#include <kpopupmenu.h>
+#include <kmenubar.h>
+#include <kstandarddirs.h>
+
+TestWindow::TestWindow(const QString& interpretername, const QString& scriptcode)
+ : KMainWindow()
+ , m_interpretername(interpretername)
+ , m_scriptcode(scriptcode)
+{
+ Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
+ manager->addModule( new TestPluginModule("krosstestpluginmodule") );
+ m_scriptcontainer = manager->getScriptContainer("test");
+
+ KPopupMenu *menuFile = new KPopupMenu( this );
+ menuBar()->insertItem( "&File", menuFile );
+
+ m_scriptextension = new Kross::Api::ScriptGUIClient(this, this);
+
+ QString file = KGlobal::dirs()->findResource("appdata", "testscripting.rc");
+ if(file.isNull())
+ file = QDir(QDir::currentDirPath()).filePath("testscripting.rc");
+ else Kross::krossdebug("-------------------------222222");
+
+ Kross::krossdebug(QString("XML-file: %1").arg(file));
+ m_scriptextension->setXMLFile(file);
+
+ //menuFile->insertSeparator();
+
+ KAction* execaction = m_scriptextension->action("executescriptfile");
+ if(execaction) execaction->plug(menuFile);
+
+ KAction* configaction = m_scriptextension->action("configurescripts");
+ if(configaction) configaction->plug(menuFile);
+
+ KAction* scriptsaction = m_scriptextension->action("installedscripts");
+ if(scriptsaction) scriptsaction->plug(menuFile);
+ //menuFile->insertItem( ( (KActionMenu*)m_scriptextension->action("scripts") )->popupMenu() );
+
+ QVBox* mainbox = new QVBox(this);
+
+ QVGroupBox* interpretergrpbox = new QVGroupBox("Interpreter", mainbox);
+ QStringList interpreters = Kross::Api::Manager::scriptManager()->getInterpreters();
+ m_interpretercombo = new QComboBox(interpretergrpbox);
+ m_interpretercombo->insertStringList(interpreters);
+ m_interpretercombo->setCurrentText(interpretername);
+
+ QVGroupBox* scriptgrpbox = new QVGroupBox("Scripting code", mainbox);
+ m_codeedit = new KTextEdit(m_scriptcode, QString::null, scriptgrpbox);
+ m_codeedit->setWordWrap(QTextEdit::NoWrap);
+ m_codeedit->setTextFormat(Qt::PlainText);
+
+ QHBox* btnbox = new QHBox(mainbox);
+ KPushButton* execbtn = new KPushButton("Execute", btnbox);
+ connect(execbtn, SIGNAL(clicked()), this, SLOT(execute()));
+
+ setCentralWidget(mainbox);
+ setMinimumSize(600,420);
+}
+
+TestWindow::~TestWindow()
+{
+}
+
+void TestWindow::execute()
+{
+ m_scriptcontainer->setInterpreterName( m_interpretercombo->currentText() );
+ m_scriptcontainer->setCode(m_codeedit->text());
+ Kross::Api::Object::Ptr result = m_scriptcontainer->execute();
+ if(m_scriptcontainer->hadException()) {
+ Kross::krossdebug( QString("EXCEPTION => %1").arg(m_scriptcontainer->getException()->toString()) );
+ }
+ else {
+ QString s = result ? result->toString() : QString::null;
+ Kross::krossdebug( QString("DONE => %1").arg(s) );
+ }
+}
+
+#include "testwindow.moc"
diff --git a/lib/kross/test/testwindow.h b/lib/kross/test/testwindow.h
new file mode 100644
index 00000000..dbb190b9
--- /dev/null
+++ b/lib/kross/test/testwindow.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * testwindow.h
+ * This file is part of the KDE project
+ * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef KROSS_TEST_TESTWINDOW_H
+#define KROSS_TEST_TESTWINDOW_H
+
+#include "../main/manager.h"
+#include "../main/scriptcontainer.h"
+#include "../main/scriptguiclient.h"
+#include "../api/object.h"
+
+//#include <qobject.h>
+#include <qstring.h>
+
+#include <kmainwindow.h>
+
+class QComboBox;
+class KTextEdit;
+
+class TestWindow : public KMainWindow
+{
+ Q_OBJECT
+ public:
+ TestWindow(const QString& interpretername, const QString& scriptcode);
+ virtual ~TestWindow();
+ private slots:
+ void execute();
+ private:
+ QString m_interpretername;
+ QString m_scriptcode;
+
+ Kross::Api::ScriptContainer::Ptr m_scriptcontainer;
+ Kross::Api::ScriptGUIClient* m_scriptextension;
+
+ QComboBox* m_interpretercombo;
+ KTextEdit* m_codeedit;
+};
+
+#endif