summaryrefslogtreecommitdiffstats
path: root/kexi/plugins/scripting
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/plugins/scripting
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/plugins/scripting')
-rw-r--r--kexi/plugins/scripting/Makefile.am1
-rw-r--r--kexi/plugins/scripting/README28
-rw-r--r--kexi/plugins/scripting/kexiapp/Makefile.am21
-rw-r--r--kexi/plugins/scripting/kexiapp/kexiappmainwindow.cpp106
-rw-r--r--kexi/plugins/scripting/kexiapp/kexiappmainwindow.h91
-rw-r--r--kexi/plugins/scripting/kexiapp/kexiappmodule.cpp97
-rw-r--r--kexi/plugins/scripting/kexiapp/kexiappmodule.h76
-rw-r--r--kexi/plugins/scripting/kexiapp/kexiapppart.cpp46
-rw-r--r--kexi/plugins/scripting/kexiapp/kexiapppart.h56
-rw-r--r--kexi/plugins/scripting/kexidb.doxyfile324
-rw-r--r--kexi/plugins/scripting/kexidb/Makefile.am30
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbconnection.cpp221
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbconnection.h194
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbconnectiondata.cpp112
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbconnectiondata.h126
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbcursor.cpp139
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbcursor.h159
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbdriver.cpp70
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbdriver.h114
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbdrivermanager.cpp178
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbdrivermanager.h105
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbfield.cpp147
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbfield.h148
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbfieldlist.cpp100
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbfieldlist.h104
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbmodule.cpp74
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbmodule.h69
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbparser.cpp77
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbparser.h95
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbschema.cpp197
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbschema.h134
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbtransaction.cpp52
-rw-r--r--kexi/plugins/scripting/kexidb/kexidbtransaction.h62
-rw-r--r--kexi/plugins/scripting/kexidb/readme.dox32
-rw-r--r--kexi/plugins/scripting/kexiscripting/Makefile.am37
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp337
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.h124
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscripteditor.cpp104
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscripteditor.h77
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscripthandler.desktop105
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscriptpart.cpp201
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscriptpart.h100
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscriptpartinstui.rc10
-rw-r--r--kexi/plugins/scripting/kexiscripting/kexiscriptpartui.rc10
-rw-r--r--kexi/plugins/scripting/scripts/Makefile.am1
-rw-r--r--kexi/plugins/scripting/scripts/copycenter/CopyCenter.py644
-rw-r--r--kexi/plugins/scripting/scripts/copycenter/CopyCenter.rc10
-rw-r--r--kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginKexiDB.py646
-rw-r--r--kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginQtSQL.py495
-rw-r--r--kexi/plugins/scripting/scripts/copycenter/Makefile.am4
-rw-r--r--kexi/plugins/scripting/scripts/copycenter/readme.html20
-rw-r--r--kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.py196
-rw-r--r--kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.rc8
-rw-r--r--kexi/plugins/scripting/scripts/exportxhtml/Makefile.am4
-rwxr-xr-xkexi/plugins/scripting/scripts/importxhtml/ImportXHTML.py434
-rw-r--r--kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.rc8
-rw-r--r--kexi/plugins/scripting/scripts/importxhtml/Makefile.am4
-rw-r--r--kexi/plugins/scripting/scripts/projectdocumentor/Makefile.am4
-rwxr-xr-xkexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.py186
-rw-r--r--kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.rc8
-rw-r--r--kexi/plugins/scripting/scripts/python/Makefile.am2
-rw-r--r--kexi/plugins/scripting/scripts/python/kexiapp/Makefile.am2
-rwxr-xr-xkexi/plugins/scripting/scripts/python/kexiapp/__init__.py25
63 files changed, 7391 insertions, 0 deletions
diff --git a/kexi/plugins/scripting/Makefile.am b/kexi/plugins/scripting/Makefile.am
new file mode 100644
index 00000000..ccd1bd64
--- /dev/null
+++ b/kexi/plugins/scripting/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kexiscripting kexiapp kexidb scripts
diff --git a/kexi/plugins/scripting/README b/kexi/plugins/scripting/README
new file mode 100644
index 00000000..e754b9cd
--- /dev/null
+++ b/kexi/plugins/scripting/README
@@ -0,0 +1,28 @@
+Kexi Scripting README
+---------------------
+
+The code in this directory implements a scripting plugin for
+Kexi. The Kross Scripting Framework located at koffice/libs/kross
+is used to embed scripting interpreters and access Kexi
+functionality from within those interpreters.
+
+See also http://www.kexi-project.org/wiki/wikiview/index.php?Scripting
+
+/kexiscripting/
+The scripting-plugin which will be loaded by Kexi at startup to
+embed Kross into Kexi.
+
+/kexiapp/
+Access to a running Kexi application. Kexi itself takes care of
+publishing it's KexiMainWindowImpl instance and the kexiapp-plugin
+provides access to some of the applications functionality at runtime.
+
+/kexidb/
+Kross-plugin to provide nearly the whole KexiDB-framework to scripting
+interpreters. That way we are able to read/write from/to all by KexiDB
+supported databases.
+
+/scripts/
+Kexi-dependend scripts. This directory holds our in python or ruby
+written scripting extensions. Those extensions are just plugins for
+Kexi to extend it's functionality.
diff --git a/kexi/plugins/scripting/kexiapp/Makefile.am b/kexi/plugins/scripting/kexiapp/Makefile.am
new file mode 100644
index 00000000..a2702a26
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/Makefile.am
@@ -0,0 +1,21 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+INCLUDES = -I$(top_srcdir)/kexi $(KROSS_INCLUDES) $(all_includes)
+
+kde_module_LTLIBRARIES = krosskexiapp.la
+
+krosskexiapp_la_SOURCES = \
+ kexiapppart.cpp \
+ kexiappmainwindow.cpp \
+ kexiappmodule.cpp
+
+krosskexiapp_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module
+krosskexiapp_la_LIBADD = \
+ $(LIB_QT) \
+ $(LIB_KDECORE) \
+ $(LIB_KROSS_API) \
+ $(LIB_KROSS_MAIN) \
+ $(top_builddir)/kexi/core/libkexicore.la
+
+METASOURCES = AUTO
+SUBDIRS = .
diff --git a/kexi/plugins/scripting/kexiapp/kexiappmainwindow.cpp b/kexi/plugins/scripting/kexiapp/kexiappmainwindow.cpp
new file mode 100644
index 00000000..4d82bc5d
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/kexiappmainwindow.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * kexiappmainwindow.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 "kexiappmainwindow.h"
+#include "kexiapppart.h"
+
+#include "core/keximainwindow.h"
+#include "core/kexiproject.h"
+#include "core/kexi.h"
+#include "kexidb/connection.h"
+
+#include "main/manager.h"
+
+//#include <kdebug.h>
+
+namespace Kross { namespace KexiApp {
+
+ /// \internal
+ class KexiAppMainWindowPrivate
+ {
+ public:
+ KexiMainWindow* mainwindow;
+
+ KexiProject* project() {
+ KexiProject* project = mainwindow->project();
+ if(! project)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("No project loaded.") );
+ return project;
+ }
+ };
+
+}}
+
+using namespace Kross::KexiApp;
+
+KexiAppMainWindow::KexiAppMainWindow(KexiMainWindow* mainwindow)
+ : Kross::Api::Class<KexiAppMainWindow>("KexiAppMainWindow")
+ , d(new KexiAppMainWindowPrivate())
+{
+ d->mainwindow = mainwindow;
+
+ this->addFunction0<Kross::Api::Variant>("isConnected", this, &KexiAppMainWindow::isConnected);
+ this->addFunction0<Kross::Api::Object>("getConnection", this, &KexiAppMainWindow::getConnection);
+
+ this->addFunction1<Kross::Api::List, Kross::Api::Variant>("getPartItems", this, &KexiAppMainWindow::getPartItems);
+ this->addFunction1<Kross::Api::Variant, KexiAppPartItem>("openPartItem", this, &KexiAppMainWindow::openPartItem);
+}
+
+KexiAppMainWindow::~KexiAppMainWindow()
+{
+ delete d;
+}
+
+const QString KexiAppMainWindow::getClassName() const
+{
+ return "Kross::KexiApp::KexiAppMainWindow";
+}
+
+bool KexiAppMainWindow::isConnected()
+{
+ return d->project()->isConnected();
+}
+
+Kross::Api::Object::Ptr KexiAppMainWindow::getConnection()
+{
+ ::KexiDB::Connection* connection = d->project()->dbConnection();
+ if(! connection)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("No connection established.") );
+ Kross::Api::Module::Ptr module = Kross::Api::Manager::scriptManager()->loadModule("krosskexidb");
+ if(! module)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("Could not load \"krosskexidb\" module.") );
+ return module->get("KexiDBConnection", connection);
+}
+
+Kross::Api::List* KexiAppMainWindow::getPartItems(const QString& mimetype)
+{
+ if(mimetype.isNull()) return 0; // just to be sure...
+ KexiPart::ItemDict* items = d->project()->itemsForMimeType( mimetype.latin1() );
+ if(! items) return 0;
+ return new Kross::Api::ListT<KexiAppPartItem>( *items );
+}
+
+bool KexiAppMainWindow::openPartItem(KexiAppPartItem* partitem)
+{
+ bool openingCancelled;
+ KexiDialogBase* dialog = partitem
+ ? d->mainwindow->openObject(partitem->item(), Kexi::DataViewMode, openingCancelled)
+ : 0;
+ return (dialog != 0 && ! openingCancelled);
+}
diff --git a/kexi/plugins/scripting/kexiapp/kexiappmainwindow.h b/kexi/plugins/scripting/kexiapp/kexiappmainwindow.h
new file mode 100644
index 00000000..fd02c193
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/kexiappmainwindow.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * kexiappmainwindow.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_KEXIAPP_KEXIAPPMAINWINDOW_H
+#define KROSS_KEXIAPP_KEXIAPPMAINWINDOW_H
+
+#include <qstring.h>
+#include <qvariant.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/list.h>
+#include <api/class.h>
+
+// Forward declarations.
+class KexiMainWindow;
+
+namespace Kross { namespace KexiApp {
+
+ // Forward declarations.
+ class KexiAppPartItem;
+ class KexiAppMainWindowPrivate;
+
+ /**
+ * Class to handle Kexi's mainwindow instance.
+ */
+ class KexiAppMainWindow : public Kross::Api::Class<KexiAppMainWindow>
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param mainwindow The \a KexiMainWindow instance
+ * this class provides access to.
+ */
+ KexiAppMainWindow(KexiMainWindow* mainwindow);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KexiAppMainWindow();
+
+ /// \see Kross::Api::Object::getClassName
+ virtual const QString getClassName() const;
+
+ /** \return true if Kexi is connected with a project else
+ false is returned. */
+ bool isConnected();
+
+ /** \return the \a Kross::KexiDB::KexiDBConnection object that
+ belongs to the opened project or throw an exception if there
+ was no project opened (no connection established). Cause the
+ KexiApp-module doesn't know anything about the KexiDB-module
+ we have to use the base-class \a Kross::Api::Object to pass
+ the \a Kross::KexiDB::KexiDBConnection object around. */
+ Kross::Api::Object::Ptr getConnection();
+
+ /** \return a list of \a KexiAppPartItem objects for the defined
+ \p mimetype string. */
+ Kross::Api::List* getPartItems(const QString& mimetype);
+
+ /** Try to open the defined \a KexiAppPartItem and \return true
+ on success else false. */
+ bool openPartItem(KexiAppPartItem* partitem);
+
+ private:
+ /// Private d-pointer class.
+ KexiAppMainWindowPrivate* d;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexiapp/kexiappmodule.cpp b/kexi/plugins/scripting/kexiapp/kexiappmodule.cpp
new file mode 100644
index 00000000..cb664496
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/kexiappmodule.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * kexiappmodule.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 "kexiappmodule.h"
+#include "kexiappmainwindow.h"
+
+#include "core/keximainwindow.h"
+
+#include <api/object.h>
+#include <api/qtobject.h>
+#include <main/manager.h>
+
+#include <kdebug.h>
+
+// The as version() published versionnumber of this kross-module.
+#define KROSS_KEXIAPP_VERSION 1
+
+extern "C"
+{
+ /**
+ * Exported an loadable function as entry point to use
+ * the \a KexiAppModule.
+ */
+ Kross::Api::Object* KDE_EXPORT init_module(Kross::Api::Manager* manager)
+ {
+ return new Kross::KexiApp::KexiAppModule(manager);
+ }
+}
+
+namespace Kross { namespace KexiApp {
+
+ /// \internal
+ class KexiAppModulePrivate
+ {
+ public:
+ Kross::Api::Manager* manager;
+ };
+
+}}
+
+using namespace Kross::KexiApp;
+
+KexiAppModule::KexiAppModule(Kross::Api::Manager* manager)
+ : Kross::Api::Module("KexiApp")
+ , d(new KexiAppModulePrivate())
+{
+ kdDebug() << "Kross::KexiApp::KexiAppModule Ctor" << endl;
+
+ d->manager = manager;
+
+ Kross::Api::Object::Ptr mainwinobject = manager->getChild("KexiMainWindow");
+ if(mainwinobject) {
+ Kross::Api::QtObject* mainwinqtobject = dynamic_cast< Kross::Api::QtObject* >( mainwinobject.data() );
+ if(mainwinqtobject) {
+ ::KexiMainWindow* mainwin = dynamic_cast< ::KexiMainWindow* >( mainwinqtobject->getObject() );
+ if(mainwin) {
+ addChild( "version", new Kross::Api::Variant(KROSS_KEXIAPP_VERSION) );
+ addChild( new KexiAppMainWindow(mainwin) );
+ return;
+ }
+ else kdDebug()<<"Kross::KexiApp::KexiAppModule: Failed to determinate KexiMainWindow instance"<<endl;
+ }
+ else kdDebug()<<"Kross::KexiApp::KexiAppModule: Failed to cast 'KexiMainWindow' to a QtObject"<<endl;
+ }
+ else kdDebug()<<"Kross::KexiApp::KexiAppModule: No such object 'KexiMainWindow'"<<endl;
+
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("There was no 'KexiMainWindow' published.") );
+}
+
+KexiAppModule::~KexiAppModule()
+{
+ kdDebug() << "Kross::KexiApp::KexiAppModule Dtor" << endl;
+ delete d;
+}
+
+
+const QString KexiAppModule::getClassName() const
+{
+ return "Kross::KexiApp::KexiAppModule";
+}
+
diff --git a/kexi/plugins/scripting/kexiapp/kexiappmodule.h b/kexi/plugins/scripting/kexiapp/kexiappmodule.h
new file mode 100644
index 00000000..08ed71f0
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/kexiappmodule.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * kexiappmodule.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_KEXIAPP_KEXIAPPMODULE_H
+#define KROSS_KEXIAPP_KEXIAPPMODULE_H
+
+#include <qstring.h>
+#include <qvariant.h>
+
+#include <api/module.h>
+
+namespace Kross { namespace Api {
+ class Manager;
+}}
+
+namespace Kross {
+
+/**
+ * Wrapper around the Kexi-application to access runtime
+ * information a running Kexi-application likes to
+ * provide.
+ */
+namespace KexiApp {
+
+ class KexiAppModulePrivate;
+
+ /**
+ * The Kexi-application module which provides us the
+ * main entrypoint to communicate with a running
+ * Kexi-application.
+ */
+ class KexiAppModule : public Kross::Api::Module
+ {
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param manager The \a Kross::Api::Manager singleton
+ * instance used to access this module.
+ */
+ KexiAppModule(Kross::Api::Manager* manager);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KexiAppModule();
+
+ /// \see Kross::Api::Object::getClassName
+ virtual const QString getClassName() const;
+
+ private:
+ /// Private d-pointer class.
+ KexiAppModulePrivate* d;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexiapp/kexiapppart.cpp b/kexi/plugins/scripting/kexiapp/kexiapppart.cpp
new file mode 100644
index 00000000..23d6c2f5
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/kexiapppart.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * kexiapppart.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.
+ ***************************************************************************/
+
+#include "kexiapppart.h"
+
+#include "core/kexipart.h"
+#include "core/kexipartitem.h"
+//#include "core/kexiproject.h"
+
+using namespace Kross::KexiApp;
+
+KexiAppPartItem::KexiAppPartItem(KexiPart::Item* item)
+ : Kross::Api::Class<KexiAppPartItem>("KexiAppPartItem")
+{
+ this->addFunction0<Kross::Api::Variant>("identifier", item, &::KexiPart::Item::identifier );
+
+ this->addFunction1<void, Kross::Api::Variant>("setIdentifier", item, &::KexiPart::Item::setIdentifier );
+
+ this->addFunction0<Kross::Api::Variant>("mimeType", item, &::KexiPart::Item::mimeType );
+ this->addFunction1<void, Kross::Api::Variant>("setMimeType", item, &::KexiPart::Item::setMimeType );
+
+ this->addFunction0<Kross::Api::Variant>("name", item, &::KexiPart::Item::name );
+ this->addFunction1<void, Kross::Api::Variant>("setName", item, &::KexiPart::Item::setName );
+
+ this->addFunction0<Kross::Api::Variant>("caption", item, &::KexiPart::Item::caption );
+ this->addFunction1<void, Kross::Api::Variant>("setCaption", item, &::KexiPart::Item::setCaption );
+
+ this->addFunction0<Kross::Api::Variant>("description", item, &::KexiPart::Item::description );
+ this->addFunction1<void, Kross::Api::Variant>("setDescription", item, &::KexiPart::Item::setDescription );
+}
diff --git a/kexi/plugins/scripting/kexiapp/kexiapppart.h b/kexi/plugins/scripting/kexiapp/kexiapppart.h
new file mode 100644
index 00000000..5f55d6bf
--- /dev/null
+++ b/kexi/plugins/scripting/kexiapp/kexiapppart.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * kexiapppart.h
+ * 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.
+ ***************************************************************************/
+
+#ifndef KROSS_KEXIAPP_KEXIAPPPART_H
+#define KROSS_KEXIAPP_KEXIAPPPART_H
+
+#include <qstring.h>
+#include <qvariant.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/class.h>
+
+// Forward declarations.
+namespace KexiPart {
+ class Item;
+ class Part;
+}
+
+namespace Kross { namespace KexiApp {
+
+ /**
+ * Class to handle Kexi Part::Item instance.
+ */
+ class KexiAppPartItem : public Kross::Api::Class<KexiAppPartItem>
+ {
+ public:
+ KexiAppPartItem(KexiPart::Item*);
+ virtual ~KexiAppPartItem() {}
+ virtual const QString getClassName() const { return "Kross::KexiApp::KexiAppPartItem"; }
+
+ KexiPart::Item* item() { return m_item; }
+ private:
+ KexiPart::Item* m_item;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb.doxyfile b/kexi/plugins/scripting/kexidb.doxyfile
new file mode 100644
index 00000000..e40a378e
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb.doxyfile
@@ -0,0 +1,324 @@
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+PROJECT_NAME = KrossKexiDB
+PROJECT_NUMBER = 1.0.
+OUTPUT_DIRECTORY = kexidbdocs
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+INLINE_INHERITED_MEMB = NO
+##INLINE_INHERITED_MEMB = YES
+
+FULL_PATH_NAMES = NO
+#STRIP_FROM_PATH = /home/snoopy/
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = YES
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+INHERIT_DOCS = YES
+
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = NO
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = YES
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = YES
+HIDE_IN_BODY_DOCS = YES
+INTERNAL_DOCS = NO
+
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = YES
+SHOW_INCLUDE_FILES = NO
+INLINE_INFO = NO
+SORT_MEMBER_DOCS = NO
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = NO
+GENERATE_TESTLIST = NO
+GENERATE_BUGLIST = NO
+GENERATE_DEPRECATEDLIST= NO
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+INPUT = ../kexidb/
+IMAGE_PATH =
+FILE_PATTERNS = *.cpp *.h *.dox
+RECURSIVE = YES
+
+EXCLUDE =
+EXCLUDE_SYMLINKS = YES
+EXCLUDE_PATTERNS = config.h *.moc.cpp
+
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+STRIP_CODE_COMMENTS = YES
+
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 4
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+COMPACT_LATEX = YES
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+##PDF_HYPERLINKS = NO
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+##LATEX_BATCHMODE = NO
+LATEX_BATCHMODE = YES
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+TAGFILES =
+GENERATE_TAGFILE = krosskexidb.tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = NO
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+HAVE_DOT = NO
+
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = NO
+CLASS_GRAPH = NO
+COLLABORATION_GRAPH = NO
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similiar to the OMG's Unified Modeling
+# Language.
+UML_LOOK = NO
+
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+##CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = NO
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = NO
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+SEARCHENGINE = NO
diff --git a/kexi/plugins/scripting/kexidb/Makefile.am b/kexi/plugins/scripting/kexidb/Makefile.am
new file mode 100644
index 00000000..12f82501
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/Makefile.am
@@ -0,0 +1,30 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+INCLUDES = -I$(top_srcdir)/kexi $(KROSS_INCLUDES) $(all_includes)
+
+kde_module_LTLIBRARIES = krosskexidb.la
+
+krosskexidb_la_SOURCES = \
+ kexidbfield.cpp \
+ kexidbfieldlist.cpp \
+ kexidbschema.cpp \
+ kexidbparser.cpp \
+ kexidbcursor.cpp \
+ kexidbtransaction.cpp \
+ kexidbconnectiondata.cpp \
+ kexidbconnection.cpp \
+ kexidbdriver.cpp \
+ kexidbdrivermanager.cpp \
+ kexidbmodule.cpp
+
+krosskexidb_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module
+krosskexidb_la_LIBADD = \
+ $(LIB_QT) \
+ $(LIB_KDECORE) \
+ $(LIB_KROSS_API) \
+ $(LIB_KROSS_MAIN) \
+ $(top_builddir)/kexi/kexidb/libkexidb.la \
+ $(top_builddir)/kexi/kexidb/parser/libkexidbparser.la
+
+METASOURCES = AUTO
+SUBDIRS = .
diff --git a/kexi/plugins/scripting/kexidb/kexidbconnection.cpp b/kexi/plugins/scripting/kexidb/kexidbconnection.cpp
new file mode 100644
index 00000000..d3b7cc76
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbconnection.cpp
@@ -0,0 +1,221 @@
+/***************************************************************************
+ * kexidbconnection.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 "kexidbconnection.h"
+#include "kexidbconnectiondata.h"
+#include "kexidbdrivermanager.h"
+#include "kexidbdriver.h"
+#include "kexidbcursor.h"
+#include "kexidbfieldlist.h"
+#include "kexidbschema.h"
+#include "kexidbtransaction.h"
+#include "kexidbparser.h"
+
+#include <api/exception.h>
+
+#include <kdebug.h>
+
+#include <kexidb/transaction.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBConnection::KexiDBConnection(::KexiDB::Connection* connection, KexiDBDriver* driver, KexiDBConnectionData* connectiondata)
+ : Kross::Api::Class<KexiDBConnection>("KexiDBConnection")
+ , m_connection(connection)
+ , m_connectiondata(connectiondata ? connectiondata : new KexiDBConnectionData(connection->data()))
+ , m_driver(driver ? driver : new KexiDBDriver(connection->driver()))
+{
+ this->addFunction0< Kross::Api::Variant >("hadError", this, &KexiDBConnection::hadError);
+ this->addFunction0< Kross::Api::Variant >("lastError", this, &KexiDBConnection::lastError);
+
+ this->addFunction0< KexiDBConnectionData >("data", this, &KexiDBConnection::data);
+ this->addFunction0< KexiDBDriver >("driver", this, &KexiDBConnection::driver);
+
+ this->addFunction0< Kross::Api::Variant >("connect", this, &KexiDBConnection::connect);
+ this->addFunction0< Kross::Api::Variant >("isConnected", this, &KexiDBConnection::isConnected);
+ this->addFunction0< Kross::Api::Variant >("disconnect", this, &KexiDBConnection::disconnect);
+
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("databaseExists", this, &KexiDBConnection::databaseExists);
+ this->addFunction0< Kross::Api::Variant >("currentDatabase", this, &KexiDBConnection::currentDatabase);
+ this->addFunction0< Kross::Api::Variant >("databaseNames", this, &KexiDBConnection::databaseNames);
+ this->addFunction0< Kross::Api::Variant >("isDatabaseUsed", this, &KexiDBConnection::isDatabaseUsed);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("useDatabase", this, &KexiDBConnection::useDatabase);
+ this->addFunction0< Kross::Api::Variant >("closeDatabase", this, &KexiDBConnection::closeDatabase);
+
+ this->addFunction0< Kross::Api::Variant >("tableNames", this, &KexiDBConnection::tableNames);
+ this->addFunction0< Kross::Api::Variant >("queryNames", this, &KexiDBConnection::queryNames);
+
+ this->addFunction1< KexiDBCursor, Kross::Api::Variant >("executeQueryString", this, &KexiDBConnection::executeQueryString);
+ this->addFunction1< KexiDBCursor, KexiDBQuerySchema >("executeQuerySchema", this, &KexiDBConnection::executeQuerySchema);
+
+ addFunction("insertRecord", &KexiDBConnection::insertRecord);
+
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("createDatabase", this, &KexiDBConnection::createDatabase);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("dropDatabase", this, &KexiDBConnection::dropDatabase);
+
+ this->addFunction1< Kross::Api::Variant, KexiDBTableSchema >("createTable", this, &KexiDBConnection::createTable);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("dropTable", this, &KexiDBConnection::dropTable);
+ this->addFunction2< Kross::Api::Variant, KexiDBTableSchema, KexiDBTableSchema >("alterTable", this, &KexiDBConnection::alterTable);
+ this->addFunction2< Kross::Api::Variant, KexiDBTableSchema, Kross::Api::Variant >("alterTableName", this, &KexiDBConnection::alterTableName);
+
+ this->addFunction1< KexiDBTableSchema, Kross::Api::Variant >("tableSchema", this, &KexiDBConnection::tableSchema);
+ this->addFunction1< Kross::Api::Variant, KexiDBTableSchema >("isEmptyTable", this, &KexiDBConnection::isEmptyTable);
+ this->addFunction1< KexiDBQuerySchema, Kross::Api::Variant >("querySchema", this, &KexiDBConnection::querySchema);
+
+ this->addFunction0< Kross::Api::Variant >("autoCommit", this, &KexiDBConnection::autoCommit);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("setAutoCommit", this, &KexiDBConnection::setAutoCommit);
+
+ this->addFunction0< KexiDBTransaction >("beginTransaction", this, &KexiDBConnection::beginTransaction);
+ this->addFunction1< Kross::Api::Variant, KexiDBTransaction >("commitTransaction", this, &KexiDBConnection::commitTransaction);
+ this->addFunction1< Kross::Api::Variant, KexiDBTransaction >("rollbackTransaction", this, &KexiDBConnection::rollbackTransaction);
+ this->addFunction0< KexiDBTransaction >("defaultTransaction", this, &KexiDBConnection::defaultTransaction);
+ this->addFunction1< void, KexiDBTransaction >("setDefaultTransaction", this, &KexiDBConnection::setDefaultTransaction);
+ this->addFunction0<Kross::Api::List>("transactions", this, &KexiDBConnection::transactions);
+
+ this->addFunction0< KexiDBParser >("parser", this, &KexiDBConnection::parser);
+}
+
+KexiDBConnection::~KexiDBConnection() {
+}
+
+const QString KexiDBConnection::getClassName() const {
+ return "Kross::KexiDB::KexiDBConnection";
+}
+
+::KexiDB::Connection* KexiDBConnection::connection() const {
+ if(! m_connection)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("KexiDB::Connection is NULL.")) );
+ //if(m_connection->error())
+ // throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("KexiDB::Connection error: %1").arg(m_connection->errorMsg())) );
+ return m_connection;
+}
+
+bool KexiDBConnection::hadError() const { return connection()->error(); }
+const QString KexiDBConnection::lastError() const { return connection()->errorMsg(); }
+
+KexiDBConnectionData* KexiDBConnection::data() { return m_connectiondata.data(); }
+KexiDBDriver* KexiDBConnection::driver() { return m_driver.data(); }
+
+bool KexiDBConnection::connect() { return connection()->connect(); }
+bool KexiDBConnection::isConnected() { return connection()->isConnected(); }
+bool KexiDBConnection::disconnect() { return connection()->disconnect(); }
+
+bool KexiDBConnection::isReadOnly() const { return connection()->isReadOnly(); }
+
+bool KexiDBConnection::databaseExists(const QString& dbname) { return connection()->databaseExists(dbname); }
+const QString KexiDBConnection::currentDatabase() const { return connection()->currentDatabase(); }
+const QStringList KexiDBConnection::databaseNames() const { return connection()->databaseNames(); }
+bool KexiDBConnection::isDatabaseUsed() const { return connection()->isDatabaseUsed(); }
+bool KexiDBConnection::useDatabase(const QString& dbname) { return connection()->databaseExists(dbname) && m_connection->useDatabase(dbname); }
+bool KexiDBConnection::closeDatabase() { return connection()->closeDatabase(); }
+
+const QStringList KexiDBConnection::allTableNames() const { return connection()->tableNames(true); }
+const QStringList KexiDBConnection::tableNames() const { return connection()->tableNames(false); }
+
+const QStringList KexiDBConnection::queryNames() const {
+ bool ok = true;
+ QStringList queries = connection()->objectNames(::KexiDB::QueryObjectType, &ok);
+ if(! ok) throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to determinate querynames.")) );
+ return queries;
+}
+
+KexiDBCursor* KexiDBConnection::executeQueryString(const QString& sqlquery) {
+ // The ::KexiDB::Connection::executeQuery() method does not check if we pass a valid SELECT-statement
+ // or e.g. a DROP TABLE operation. So, let's check for such dangerous operations right now.
+ ::KexiDB::Parser parser( connection() );
+ if(! parser.parse(sqlquery))
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to parse query: %1 %2").arg(parser.error().type()).arg(parser.error().error())) );
+ if( parser.query() == 0 || parser.operation() != ::KexiDB::Parser::OP_Select )
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Invalid query operation \"%1\"").arg(parser.operationString()) ) );
+ ::KexiDB::Cursor* cursor = connection()->executeQuery(sqlquery);
+ return cursor ? new KexiDBCursor(cursor) : 0;
+}
+
+KexiDBCursor* KexiDBConnection::executeQuerySchema(KexiDBQuerySchema* queryschema) {
+ ::KexiDB::Cursor* cursor = connection()->executeQuery( *queryschema->queryschema() );
+ return cursor ? new KexiDBCursor(cursor) : 0;
+}
+
+/*TODO
+bool KexiDBConnection::insertRecordIntoFieldlist(KexiDBFieldList* fieldlist, QValueList<QVariant> values) {
+ return connection()->insertRecord(*fieldlist->fieldlist(), values);
+}
+
+bool KexiDBConnection::insertRecordIntoTable(KexiDBTableSchema* tableschema, QValueList<QVariant> values) {
+ return connection()->insertRecord(*tableschema->tableschema(), values);
+}
+*/
+Kross::Api::Object::Ptr KexiDBConnection::insertRecord(Kross::Api::List::Ptr args) {
+ QValueList<QVariant> values = Kross::Api::Variant::toList(args->item(1));
+ Kross::Api::Object::Ptr obj = args->item(0);
+ if(obj->getClassName() == "Kross::KexiDB::KexiDBFieldList")
+ return new Kross::Api::Variant(
+ QVariant(connection()->insertRecord(
+ *Kross::Api::Object::fromObject<KexiDBFieldList>(obj)->fieldlist(),
+ values
+ ), 0));
+ return new Kross::Api::Variant(
+ QVariant(connection()->insertRecord(
+ *Kross::Api::Object::fromObject<KexiDBTableSchema>(obj)->tableschema(),
+ values
+ ), 0));
+}
+
+bool KexiDBConnection::createDatabase(const QString& dbname) { return connection()->createDatabase(dbname); }
+bool KexiDBConnection::dropDatabase(const QString& dbname) { return connection()->dropDatabase(dbname); }
+
+bool KexiDBConnection::createTable(KexiDBTableSchema* tableschema) { return connection()->createTable(tableschema->tableschema(), false); }
+bool KexiDBConnection::dropTable(const QString& tablename) { return true == connection()->dropTable(tablename); }
+bool KexiDBConnection::alterTable(KexiDBTableSchema* fromschema, KexiDBTableSchema* toschema) { return true == connection()->alterTable(*fromschema->tableschema(), *toschema->tableschema()); }
+bool KexiDBConnection::alterTableName(KexiDBTableSchema* tableschema, const QString& newtablename) { return connection()->alterTableName(*tableschema->tableschema(), newtablename); }
+
+KexiDBTableSchema* KexiDBConnection::tableSchema(const QString& tablename) const {
+ ::KexiDB::TableSchema* tableschema = connection()->tableSchema(tablename);
+ return tableschema ? new KexiDBTableSchema(tableschema) : 0;
+}
+
+bool KexiDBConnection::isEmptyTable(KexiDBTableSchema* tableschema) const {
+ bool success;
+ bool notempty = connection()->isEmpty(*tableschema->tableschema(), success);
+ return (! (success && notempty));
+}
+
+KexiDBQuerySchema* KexiDBConnection::querySchema(const QString& queryname) const {
+ ::KexiDB::QuerySchema* queryschema = connection()->querySchema(queryname);
+ return queryschema ? new KexiDBQuerySchema(queryschema) : 0;
+}
+
+bool KexiDBConnection::autoCommit() const { return connection()->autoCommit(); }
+bool KexiDBConnection::setAutoCommit(bool enabled) { return connection()->setAutoCommit(enabled); }
+
+KexiDBTransaction* KexiDBConnection::beginTransaction() {
+ ::KexiDB::Transaction t = connection()->beginTransaction();
+ return new KexiDBTransaction(t);
+}
+
+bool KexiDBConnection::commitTransaction(KexiDBTransaction* transaction) { return connection()->commitTransaction( transaction->transaction() ); }
+bool KexiDBConnection::rollbackTransaction(KexiDBTransaction* transaction) { return connection()->rollbackTransaction( transaction->transaction() ); }
+KexiDBTransaction* KexiDBConnection::defaultTransaction() { return new KexiDBTransaction( connection()->defaultTransaction() ); }
+void KexiDBConnection::setDefaultTransaction(KexiDBTransaction* transaction) { connection()->setDefaultTransaction( transaction->transaction() ); }
+
+Kross::Api::List* KexiDBConnection::transactions() {
+ return new Kross::Api::ListT<KexiDBTransaction>( connection()->transactions() );
+}
+
+KexiDBParser* KexiDBConnection::parser() { return new KexiDBParser(this, new ::KexiDB::Parser(connection())); }
diff --git a/kexi/plugins/scripting/kexidb/kexidbconnection.h b/kexi/plugins/scripting/kexidb/kexidbconnection.h
new file mode 100644
index 00000000..7e1a7d3a
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbconnection.h
@@ -0,0 +1,194 @@
+/***************************************************************************
+ * kexidbconnection.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_KEXIDB_KEXIDBCONNECTION_H
+#define KROSS_KEXIDB_KEXIDBCONNECTION_H
+
+#include <qstring.h>
+#include <ksharedptr.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/list.h>
+#include <api/class.h>
+
+//#include <kexidb/driver.h>
+#include <kexidb/connection.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward declarations.
+ class KexiDBDriver;
+ class KexiDBConnectionData;
+ class KexiDBCursor;
+ class KexiDBTableSchema;
+ class KexiDBQuerySchema;
+ class KexiDBTransaction;
+ class KexiDBParser;
+
+ /**
+ * A connection to a database.
+ *
+ * Example (in Python) ;
+ * @code
+ * # Import the kexidb module.
+ * import krosskexidb
+ * # Get the drivermanager.
+ * drivermanager = krosskexidb.DriverManager()
+ * # We need a connectiondata object.
+ * connectiondata = drivermanager.createConnectionData()
+ * # Fill the new connectiondata object with what we need to connect.
+ * connectiondata.setFileName("/home/user/kexisqlite3file.kexi")
+ * # Create the database-driver to access the SQLite3 backend.
+ * driver = drivermanager.driver("SQLite3")
+ * # Create the connection now.
+ * connection = driver.createConnection(connectiondata)
+ * # Establish the connection.
+ * if not connection.connect(): raise("Failed to connect with db")
+ * # Open database for usage. The filebased driver uses the filename as databasename.
+ * if not connection.useDatabase("/home/user/kexisqlite3file.kexi"): raise("Failed to use db")
+ * @endcode
+ */
+ class KexiDBConnection : public Kross::Api::Class<KexiDBConnection>
+ {
+ public:
+ KexiDBConnection(::KexiDB::Connection* connection, KexiDBDriver* driver = 0, KexiDBConnectionData* connectiondata = 0);
+ virtual ~KexiDBConnection();
+ virtual const QString getClassName() const;
+
+ private:
+
+ /** Return true if there was an error during last operation on the database. */
+ bool hadError() const;
+ /** Return the last errormessage. */
+ const QString lastError() const;
+
+ /** Return the KexiDBConnectionData object used to create this connection. */
+ KexiDBConnectionData* data();
+ /** Return the KexiDBDriver object this connection belongs too. */
+ KexiDBDriver* driver();
+
+ /** Try to connect and return true if we are successfully connected now. */
+ bool connect();
+ /** Return true if we are connected. */
+ bool isConnected();
+ /** Disconnect and return true if we are successfully disconnected now. */
+ bool disconnect();
+
+ /** Returns true if the connection is read-only. */
+ bool isReadOnly() const;
+
+ /** Return true if the as argument passed databasename exists. */
+ bool databaseExists(const QString& dbname);
+ /** Return the name of currently used database for this connection or empty
+ string if there is no used database. */
+ const QString currentDatabase() const;
+ /** Return list of database names for opened connection. */
+ const QStringList databaseNames() const;
+ /** Return true if connection is properly established. */
+ bool isDatabaseUsed() const;
+ /** Opens an existing database specified by the as argument passed databasename
+ and returns true if the database is used now. */
+ bool useDatabase(const QString& dbname);
+ /** Closes currently used database for this connection. */
+ bool closeDatabase();
+
+ /** Return names of all table schemas stored in currently used database include the
+ internal KexiDB system table names (kexi__*) */
+ const QStringList allTableNames() const;
+ /** Return names of all table schemas without the internal KexiDB system table names (kexi__*) */
+ const QStringList tableNames() const;
+ /** Return names of all query schemas stored in currently used database. */
+ const QStringList queryNames() const;
+
+ /** Executes query described by the as argument passed sqlstatement-string. Returns the
+ opened cursor created for results of this query. */
+ KexiDBCursor* executeQueryString(const QString& sqlquery);
+ /** Executes query described by the as argument passed KexiDBQuerySchema object. Returns
+ the opened cursor created for results of this query. */
+ KexiDBCursor* executeQuerySchema(KexiDBQuerySchema* queryschema);
+
+//TODO replace following method with a proxymethod.
+ /** Inserts the as argument passed KexiDBField object. */
+ Kross::Api::Object::Ptr insertRecord(Kross::Api::List::Ptr);
+
+ /** Creates new database with the as argument passed databasename. */
+ bool createDatabase(const QString& dbname);
+ /** Drops the as argument passed databasename. */
+ bool dropDatabase(const QString& dbname);
+
+ /** Creates table defined by the as argument passed KexiTableSchema object. */
+ bool createTable(KexiDBTableSchema* tableschema);
+ /** Drops table defined by the as argument passed KexiDBTableSchema object. */
+ bool dropTable(const QString& tablename);
+ /** Alters the as first argument passed KexiDBTableSchema object using the as
+ second argument passed KexiDBTableSchema. */
+ bool alterTable(KexiDBTableSchema* fromschema, KexiDBTableSchema* toschema);
+ /** Alters the tablename of the as first argument passed KexiDBTableSchema into
+ the as second argument passed new tablename. */
+ bool alterTableName(KexiDBTableSchema* tableschema, const QString& newtablename);
+
+ /** Returns the KexiDBTableSchema object of the table matching to the as argument
+ passed tablename. */
+ KexiDBTableSchema* tableSchema(const QString& tablename) const;
+ /** Returns true if there is at least one valid record in the as argument passed tablename. */
+ bool isEmptyTable(KexiDBTableSchema* tableschema) const;
+ /** Returns the KexiDBQuerySchema object of the query matching to the as argument passed queryname. */
+ KexiDBQuerySchema* querySchema(const QString& queryname) const;
+
+ /** Return true if the \"auto commit\" option is on. */
+ bool autoCommit() const;
+ /** Set the auto commit option. This does not affect currently started transactions and can
+ be changed even when connection is not established. */
+ bool setAutoCommit(bool enabled);
+
+ /** Creates new transaction handle and starts a new transaction. */
+ KexiDBTransaction* beginTransaction();
+ /** Commits the as rgument passed KexiDBTransaction object. */
+ bool commitTransaction(KexiDBTransaction* transaction);
+ /** Rollback the as rgument passed KexiDBTransaction object. */
+ bool rollbackTransaction(KexiDBTransaction* transaction);
+ /** Return the KEXIDBTransaction object for default transaction for this connection. */
+ KexiDBTransaction* defaultTransaction();
+ /** Sets default transaction that will be used as context for operations on data in opened
+ database for this connection. */
+ void setDefaultTransaction(KexiDBTransaction* transaction);
+
+ /** Return list of currently active KexiDBTransaction objects. */
+ Kross::Api::List* transactions();
+
+ /** Return a KexiDBParser object. */
+ KexiDBParser* parser();
+
+ private:
+ ::KexiDB::Connection* connection() const;
+ ::KexiDB::Connection* m_connection;
+
+ KSharedPtr<KexiDBConnectionData> m_connectiondata;
+ KSharedPtr<KexiDBDriver> m_driver;
+
+ /// Initialize the class instance.
+ void initialize();
+
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbconnectiondata.cpp b/kexi/plugins/scripting/kexidb/kexidbconnectiondata.cpp
new file mode 100644
index 00000000..61b81d3e
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbconnectiondata.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * kexidbconnectiondata.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 "kexidbconnectiondata.h"
+
+#include <qvariant.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBConnectionData::KexiDBConnectionData(::KexiDB::ConnectionData* data)
+ : Kross::Api::Class<KexiDBConnectionData>("KexiDBConnectionData")
+ , m_data(data)
+{
+ this->addFunction0< Kross::Api::Variant >("caption", this, &KexiDBConnectionData::caption);
+ this->addFunction1< void, Kross::Api::Variant >("setCaption", this, &KexiDBConnectionData::setCaption);
+
+ this->addFunction0< Kross::Api::Variant >("description", this, &KexiDBConnectionData::description);
+ this->addFunction1< void, Kross::Api::Variant >("setDescription", this, &KexiDBConnectionData::setDescription);
+
+ this->addFunction0< Kross::Api::Variant >("driverName", this, &KexiDBConnectionData::driverName);
+ this->addFunction1< void, Kross::Api::Variant >("setDriverName", this, &KexiDBConnectionData::setDriverName);
+
+ this->addFunction0< Kross::Api::Variant >("localSocketFileUsed", this, &KexiDBConnectionData::localSocketFileUsed);
+ this->addFunction1< void, Kross::Api::Variant >("setLocalSocketFileUsed", this, &KexiDBConnectionData::setLocalSocketFileUsed);
+
+ this->addFunction0< Kross::Api::Variant >("localSocketFileName", this, &KexiDBConnectionData::localSocketFileName);
+ this->addFunction1< void, Kross::Api::Variant >("setLocalSocketFileName", this, &KexiDBConnectionData::setLocalSocketFileName);
+
+ this->addFunction0< Kross::Api::Variant >("databaseName", this, &KexiDBConnectionData::databaseName);
+ this->addFunction1< void, Kross::Api::Variant >("setDatabaseName", this, &KexiDBConnectionData::setDatabaseName);
+
+ this->addFunction0< Kross::Api::Variant >("hostName", this, &KexiDBConnectionData::hostName);
+ this->addFunction1< void, Kross::Api::Variant >("setHostName", this, &KexiDBConnectionData::setHostName);
+
+ this->addFunction0< Kross::Api::Variant >("port", this, &KexiDBConnectionData::port);
+ this->addFunction1< void, Kross::Api::Variant >("setPort", this, &KexiDBConnectionData::setPort);
+
+ this->addFunction0< Kross::Api::Variant >("password", this, &KexiDBConnectionData::password);
+ this->addFunction1< void, Kross::Api::Variant >("setPassword", this, &KexiDBConnectionData::setPassword);
+
+ this->addFunction0< Kross::Api::Variant >("userName", this, &KexiDBConnectionData::userName);
+ this->addFunction1< void, Kross::Api::Variant >("setUserName", this, &KexiDBConnectionData::setUserName);
+
+ this->addFunction0< Kross::Api::Variant >("fileName", this, &KexiDBConnectionData::fileName);
+ this->addFunction1< void, Kross::Api::Variant >("setFileName", this, &KexiDBConnectionData::setFileName);
+
+ this->addFunction0< Kross::Api::Variant >("dbPath", this, &KexiDBConnectionData::dbPath);
+ this->addFunction0< Kross::Api::Variant >("dbFileName", this, &KexiDBConnectionData::dbFileName);
+ this->addFunction0< Kross::Api::Variant >("serverInfoString", this, &KexiDBConnectionData::serverInfoString);
+}
+
+KexiDBConnectionData::~KexiDBConnectionData()
+{
+ //delete m_data;
+}
+
+const QString KexiDBConnectionData::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBConnectionData";
+}
+
+const QString KexiDBConnectionData::caption() const { return m_data->caption; }
+void KexiDBConnectionData::setCaption(const QString& name) { m_data->caption = name; }
+
+const QString KexiDBConnectionData::description() const { return m_data->description; }
+void KexiDBConnectionData::setDescription(const QString& desc) { m_data->description = desc; }
+
+const QString KexiDBConnectionData::driverName() const { return m_data->driverName; }
+void KexiDBConnectionData::setDriverName(const QString& driver) { m_data->driverName = driver; }
+
+bool KexiDBConnectionData::localSocketFileUsed() const { return m_data->useLocalSocketFile; }
+void KexiDBConnectionData::setLocalSocketFileUsed(bool used) { m_data->useLocalSocketFile = used; }
+const QString KexiDBConnectionData::localSocketFileName() const { return m_data->localSocketFileName; }
+void KexiDBConnectionData::setLocalSocketFileName(const QString& socketfilename) { m_data->localSocketFileName = socketfilename; }
+
+const QString KexiDBConnectionData::databaseName() const { return m_dbname; }
+void KexiDBConnectionData::setDatabaseName(const QString& dbname) { m_dbname = dbname; }
+
+const QString KexiDBConnectionData::hostName() const { return m_data->hostName; }
+void KexiDBConnectionData::setHostName(const QString& hostname) { m_data->hostName = hostname; }
+
+int KexiDBConnectionData::port() const { return m_data->port; }
+void KexiDBConnectionData::setPort(int p) { m_data->port = p; }
+
+const QString KexiDBConnectionData::password() const { return m_data->password; }
+void KexiDBConnectionData::setPassword(const QString& passwd) { m_data->password = passwd; }
+
+const QString KexiDBConnectionData::userName() const { return m_data->userName; }
+void KexiDBConnectionData::setUserName(const QString& username) { m_data->userName = username; }
+
+const QString KexiDBConnectionData::fileName() const { return m_data->fileName(); }
+void KexiDBConnectionData::setFileName(const QString& filename) { m_data->setFileName(filename); }
+
+const QString KexiDBConnectionData::dbPath() const { return m_data->dbPath(); }
+const QString KexiDBConnectionData::dbFileName() const { return m_data->dbFileName(); }
+const QString KexiDBConnectionData::serverInfoString() const { return m_data->serverInfoString(true); }
diff --git a/kexi/plugins/scripting/kexidb/kexidbconnectiondata.h b/kexi/plugins/scripting/kexidb/kexidbconnectiondata.h
new file mode 100644
index 00000000..aaddffbd
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbconnectiondata.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * kexidbconnectiondata.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_KEXIDB_KEXIDBCONNECTIONDATA_H
+#define KROSS_KEXIDB_KEXIDBCONNECTIONDATA_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/connection.h>
+#include <kexidb/connectiondata.h>
+
+namespace Kross { namespace KexiDB {
+
+ /**
+ * A KexiDBConnectionData is used to store the details needed for
+ * a connection with a database.
+ */
+ class KexiDBConnectionData : public Kross::Api::Class<KexiDBConnectionData>
+ {
+ friend class KexiDBDriverManager;
+ public:
+ KexiDBConnectionData(::KexiDB::ConnectionData* data);
+ virtual ~KexiDBConnectionData();
+ operator ::KexiDB::ConnectionData& () { return *m_data; }
+ operator ::KexiDB::ConnectionData* () { return m_data; }
+ virtual const QString getClassName() const;
+ ::KexiDB::ConnectionData* data() { return m_data; }
+
+ private:
+
+ /** Return the connection name. */
+ const QString caption() const;
+ /** Set the connection name. */
+ void setCaption(const QString& name);
+
+ /** Return the description. */
+ const QString description() const;
+ /** Set the description. */
+ void setDescription(const QString& desc);
+
+ /** Return drivername. */
+ const QString driverName() const;
+ /** Set the drivername. */
+ void setDriverName(const QString& driver);
+
+ /** Return true if a local socket file is used else false. */
+ bool localSocketFileUsed() const;
+ /** Set if the local socket file should be used. */
+ void setLocalSocketFileUsed(bool used);
+ /** Return the local socket filename. */
+ const QString localSocketFileName() const;
+ /** Set the local socket filename. */
+ void setLocalSocketFileName(const QString& socketfilename);
+
+ // For serverbased drivers
+
+ /** Return the database name. */
+ const QString databaseName() const;
+ /** Set the database name. */
+ void setDatabaseName(const QString& dbname);
+
+ /** Return the hostname. */
+ const QString hostName() const;
+ /** Set the hostname. */
+ void setHostName(const QString& hostname);
+
+ /** Return the port number. */
+ int port() const;
+ /** Set the port number. */
+ void setPort(int p);
+
+ /** Return the password. */
+ const QString password() const;
+ /** Set the password. */
+ void setPassword(const QString& passwd);
+
+ /** Return the username. */
+ const QString userName() const;
+ /** Set the username. */
+ void setUserName(const QString& username);
+
+ // For filebased drivers
+
+ /** Return the filename. */
+ const QString fileName() const;
+ /** Set the filename. */
+ void setFileName(const QString& filename);
+
+ /** Return the database path. */
+ const QString dbPath() const;
+ /** Return the database filename. */
+ const QString dbFileName() const;
+
+ /** Return a user-friendly string representation. */
+ const QString serverInfoString() const;
+
+ private:
+ ::KexiDB::ConnectionData* m_data;
+ QString m_dbname;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbcursor.cpp b/kexi/plugins/scripting/kexidb/kexidbcursor.cpp
new file mode 100644
index 00000000..3bc1763d
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbcursor.cpp
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * kexidbcursor.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 "kexidbcursor.h"
+#include "kexidbconnection.h"
+
+#include <kexidb/tableschema.h>
+#include <kexidb/queryschema.h>
+
+#include <kdebug.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBCursor::KexiDBCursor(::KexiDB::Cursor* cursor)
+ : Kross::Api::Class<KexiDBCursor>("KexiDBCursor")
+ , m_cursor(cursor)
+{
+ this->addFunction0<Kross::Api::Variant>("open", this, &KexiDBCursor::open );
+ this->addFunction0<Kross::Api::Variant>("isOpened", this, &KexiDBCursor::isOpened );
+ this->addFunction0<Kross::Api::Variant>("reopen", this, &KexiDBCursor::reopen );
+ this->addFunction0<Kross::Api::Variant>("close", this, &KexiDBCursor::close );
+ this->addFunction0<Kross::Api::Variant>("moveFirst", this, &KexiDBCursor::moveFirst );
+ this->addFunction0<Kross::Api::Variant>("moveLast", this, &KexiDBCursor::moveLast );
+ this->addFunction0<Kross::Api::Variant>("movePrev", this, &KexiDBCursor::movePrev );
+ this->addFunction0<Kross::Api::Variant>("moveNext", this, &KexiDBCursor::moveNext );
+ this->addFunction0<Kross::Api::Variant>("bof", this, &KexiDBCursor::bof );
+ this->addFunction0<Kross::Api::Variant>("eof", this, &KexiDBCursor::eof );
+ this->addFunction0<Kross::Api::Variant>("at", this, &KexiDBCursor::at );
+ this->addFunction0<Kross::Api::Variant>("fieldCount", this, &KexiDBCursor::fieldCount );
+ this->addFunction1<Kross::Api::Variant, Kross::Api::Variant>("value", this, &KexiDBCursor::value );
+ this->addFunction2<Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant>("setValue", this, &KexiDBCursor::setValue );
+ this->addFunction0<Kross::Api::Variant>("save", this, &KexiDBCursor::save );
+}
+
+KexiDBCursor::~KexiDBCursor()
+{
+ ///@todo check ownership
+ //delete m_cursor;
+
+ clearBuffers();
+}
+
+void KexiDBCursor::clearBuffers()
+{
+ QMap<Q_LLONG, Record*>::ConstIterator
+ it( m_modifiedrecords.constBegin() ), end( m_modifiedrecords.constEnd() );
+ for( ; it != end; ++it)
+ delete it.data();
+ m_modifiedrecords.clear();
+}
+
+const QString KexiDBCursor::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBCursor";
+}
+
+bool KexiDBCursor::open() { return m_cursor->open(); }
+bool KexiDBCursor::isOpened() { return m_cursor->isOpened(); }
+bool KexiDBCursor::reopen() { return m_cursor->reopen(); }
+bool KexiDBCursor::close() { return m_cursor->close(); }
+
+bool KexiDBCursor::moveFirst() { return m_cursor->moveFirst(); }
+bool KexiDBCursor::moveLast() { return m_cursor->moveLast(); }
+bool KexiDBCursor::movePrev() { return m_cursor->movePrev(); }
+bool KexiDBCursor::moveNext() { return m_cursor->moveNext(); }
+
+bool KexiDBCursor::bof() { return m_cursor->bof(); }
+bool KexiDBCursor::eof() { return m_cursor->eof(); }
+
+Q_LLONG KexiDBCursor::at() { return m_cursor->at(); }
+uint KexiDBCursor::fieldCount() { return m_cursor->fieldCount(); }
+
+QVariant KexiDBCursor::value(uint index)
+{
+ return m_cursor->value(index);
+}
+
+bool KexiDBCursor::setValue(uint index, QVariant value)
+{
+ ::KexiDB::QuerySchema* query = m_cursor->query();
+ if(! query) {
+ kdDebug() << "Invalid query in KexiDBCursor::setValue index=" << index << " value=" << value << endl;
+ return false;
+ }
+
+ ::KexiDB::QueryColumnInfo* column = query->fieldsExpanded().at(index);
+ if(! column) {
+ kdDebug() << "Invalid column in KexiDBCursor::setValue index=" << index << " value=" << value << endl;
+ return false;
+ }
+
+ const Q_LLONG position = m_cursor->at();
+ if(! m_modifiedrecords.contains(position))
+ m_modifiedrecords.replace(position, new Record(m_cursor));
+ m_modifiedrecords[position]->buffer->insert(*column, value);
+ return true;
+}
+
+bool KexiDBCursor::save()
+{
+ if(m_modifiedrecords.count() < 1)
+ return true;
+
+ //It is needed to close the cursor before we are able to update the rows
+ //since else the database could be locked (e.g. at the case of SQLite a
+ //KexiDB: Object ERROR: 6: SQLITE_LOCKED would prevent updating).
+ //Maybe it works fine with other drivers like MySQL or Postqre?
+ m_cursor->close();
+
+ bool ok = true;
+ QMap<Q_LLONG, Record*>::ConstIterator
+ it( m_modifiedrecords.constBegin() ), end( m_modifiedrecords.constEnd() );
+ for( ; it != end; ++it) {
+ bool b = m_cursor->updateRow(it.data()->rowdata, * it.data()->buffer, m_cursor->isBuffered());
+ if(ok) {
+ ok = b;
+ //break;
+ }
+ }
+ //m_cursor->close();
+ clearBuffers();
+ return ok;
+}
diff --git a/kexi/plugins/scripting/kexidb/kexidbcursor.h b/kexi/plugins/scripting/kexidb/kexidbcursor.h
new file mode 100644
index 00000000..6e92a38e
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbcursor.h
@@ -0,0 +1,159 @@
+/***************************************************************************
+ * kexidbcursor.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_KEXIDB_KEXIDBCURSOR_H
+#define KROSS_KEXIDB_KEXIDBCURSOR_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/cursor.h>
+#include <kexidb/roweditbuffer.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward declaration.
+ class KexiDBConnection;
+
+ /**
+ * The cursor provides a control structure for the successive traversal
+ * of records in a result set as returned e.g. by a query.
+ *
+ * Example (in Python) that shows how to iterate over the result of a query;
+ * @code
+ * # Once we have a KexiDBConnection object we are able to execute a query string and get a cursor as result.
+ * cursor = connection.executeQueryString("SELECT * from emp")
+ * # Let's check if the query was successfully.
+ * if not cursor: raise("Query failed")
+ * # Walk through all items in the table.
+ * while(not cursor.eof()):
+ * # Iterate over the fields the record has.
+ * for i in range( cursor.fieldCount() ):
+ * # Print some information.
+ * print "%s %s %s" % (cursor.at(), i, cursor.value(i))
+ * # and move on to the next record.
+ * cursor.moveNext()
+ * @endcode
+ *
+ * Example (in Python) that shows how to use a cursor to strip
+ * all whitespaces at the beginning and the end from the values
+ * in a table;
+ * @code
+ * import krosskexidb
+ * drivermanager = krosskexidb.DriverManager()
+ * connectiondata = drivermanager.createConnectionDataByFile("/home/me/kexiprojectfile.kexi")
+ * driver = drivermanager.driver( connectiondata.driverName() )
+ * connection = driver.createConnection(connectiondata)
+ * if not connection.connect(): raise "Failed to connect"
+ * if not connection.useDatabase( connectiondata.databaseName() ):
+ * if not connection.useDatabase( connectiondata.fileName() ):
+ * raise "Failed to use database"
+ *
+ * table = connection.tableSchema("emp")
+ * query = table.query()
+ * cursor = connection.executeQuerySchema(query)
+ * if not cursor: raise("Query failed")
+ * while(not cursor.eof()):
+ * for i in range( cursor.fieldCount() ):
+ * v = str( cursor.value(i) )
+ * if v.startswith(' ') or v.endswith(' '):
+ * cursor.setValue(i, v.strip())
+ * cursor.moveNext()
+ * if not cursor.save(): raise "Failed to save changes"
+ * @endcode
+ */
+ class KexiDBCursor : public Kross::Api::Class<KexiDBCursor>
+ {
+ public:
+ KexiDBCursor(::KexiDB::Cursor* cursor);
+ virtual ~KexiDBCursor();
+ virtual const QString getClassName() const;
+
+ private:
+
+ /** Opens the cursor. */
+ bool open();
+ /** Returns true if the cursor is opened else false. */
+ bool isOpened();
+ /** Closes and then opens again the same cursor. */
+ bool reopen();
+ /** Closes previously opened cursor. */
+ bool close();
+
+ /** Moves current position to the first record and retrieves it. */
+ bool moveFirst();
+ /** Moves current position to the last record and retrieves it. */
+ bool moveLast();
+ /** Moves current position to the previous record and retrieves it. */
+ bool movePrev();
+ /** Moves current position to the next record and retrieves it. */
+ bool moveNext();
+
+ /** Returns true if current position is before first record. */
+ bool bof();
+ /** Returns true if current position is after last record. */
+ bool eof();
+
+ /** Returns current internal position of the cursor's query. Records
+ are numbered from 0; the value -1 means that the cursor does not
+ point to a valid record. */
+ Q_LLONG at();
+ /** Returns the number of fields available for this cursor. */
+ uint fieldCount();
+ /** Returns the value stored in the passed column number (counting from 0). */
+ QVariant value(uint index);
+ /** Set the value for the field defined with index. The new value is buffered
+ and does not got written as long as save() is not called. */
+ bool setValue(uint index, QVariant value);
+
+ /** Save any changes done with setValue(). You should call this only once at
+ the end of all value/setValue iterations cause the cursor is closed once
+ the changes got saved successfully. */
+ bool save();
+
+ private:
+ ::KexiDB::Cursor* m_cursor;
+
+ class Record {
+ public:
+ ::KexiDB::RowData rowdata;
+ ::KexiDB::RowEditBuffer* buffer;
+ Record(::KexiDB::Cursor* cursor)
+ : buffer( new ::KexiDB::RowEditBuffer(true) )
+ {
+ cursor->storeCurrentRow(rowdata);
+ }
+ ~Record()
+ {
+ delete buffer;
+ }
+ };
+ QMap<Q_LLONG, Record*> m_modifiedrecords;
+
+ void clearBuffers();
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbdriver.cpp b/kexi/plugins/scripting/kexidb/kexidbdriver.cpp
new file mode 100644
index 00000000..f019b237
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbdriver.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * kexidbdriver.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 "kexidbdriver.h"
+#include "kexidbdrivermanager.h"
+
+#include <qvaluelist.h>
+#include <qptrlist.h>
+#include <kdebug.h>
+
+#include <kexidb/connection.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBDriver::KexiDBDriver(::KexiDB::Driver* driver)
+ : Kross::Api::Class<KexiDBDriver>("KexiDBDriver")
+ , m_driver(driver)
+{
+ this->addFunction0<Kross::Api::Variant>("isValid", this, &KexiDBDriver::isValid );
+ this->addFunction0<Kross::Api::Variant>("versionMajor", this, &KexiDBDriver::versionMajor );
+ this->addFunction0<Kross::Api::Variant>("versionMinor", this, &KexiDBDriver::versionMinor );
+ this->addFunction1<Kross::Api::Variant, Kross::Api::Variant>("escapeString", this, &KexiDBDriver::escapeString);
+ this->addFunction0<Kross::Api::Variant>("isFileDriver", this, &KexiDBDriver::isFileDriver );
+ this->addFunction0<Kross::Api::Variant>("fileDBDriverMimeType", this, &KexiDBDriver::fileDBDriverMimeType );
+ this->addFunction1<Kross::Api::Variant, Kross::Api::Variant>("isSystemObjectName", this, &KexiDBDriver::isSystemObjectName );
+ this->addFunction1<Kross::Api::Variant, Kross::Api::Variant>("isSystemDatabaseName", this, &KexiDBDriver::isSystemDatabaseName );
+ this->addFunction1<Kross::Api::Variant, Kross::Api::Variant>("isSystemFieldName", this, &KexiDBDriver::isSystemFieldName );
+ this->addFunction2<Kross::Api::Variant, Kross::Api::Variant, Kross::Api::Variant> ("valueToSQL", this, &KexiDBDriver::valueToSQL );
+
+ this->addFunction1<KexiDBConnection, KexiDBConnectionData>("createConnection", this, &KexiDBDriver::createConnection);
+ this->addFunction0< Kross::Api::ListT< KexiDBConnection > >("connectionsList", this, &KexiDBDriver::connectionsList);
+}
+
+KexiDBDriver::~KexiDBDriver()
+{
+}
+
+const QString KexiDBDriver::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBDriver";
+}
+
+bool KexiDBDriver::isValid() { return m_driver->isValid(); }
+int KexiDBDriver::versionMajor() { return m_driver->version().major; }
+int KexiDBDriver::versionMinor() { return m_driver->version().minor; }
+QString KexiDBDriver::escapeString(const QString& s) { return m_driver->escapeString(s); }
+bool KexiDBDriver::isFileDriver() { return m_driver->isFileDriver(); }
+QString KexiDBDriver::fileDBDriverMimeType() { return m_driver->fileDBDriverMimeType(); }
+bool KexiDBDriver::isSystemObjectName(const QString& name) { return m_driver->isSystemObjectName(name); }
+bool KexiDBDriver::isSystemDatabaseName(const QString& name) { return m_driver->isSystemDatabaseName(name); }
+bool KexiDBDriver::isSystemFieldName(const QString& name) { return m_driver->isSystemFieldName(name); }
+QString KexiDBDriver::valueToSQL(const QString& fieldtype, const QVariant& value) { return m_driver->valueToSQL(fieldtype, value); }
+KexiDBConnection* KexiDBDriver::createConnection(KexiDBConnectionData* data) { return new KexiDBConnection( m_driver->createConnection(*data) ); }
+QPtrList< ::KexiDB::Connection > KexiDBDriver::connectionsList() { return m_driver->connectionsList(); }
diff --git a/kexi/plugins/scripting/kexidb/kexidbdriver.h b/kexi/plugins/scripting/kexidb/kexidbdriver.h
new file mode 100644
index 00000000..edf7283c
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbdriver.h
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * kexidbdriver.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_KEXIDB_KEXIDBDRIVER_H
+#define KROSS_KEXIDB_KEXIDBDRIVER_H
+
+#include <qstring.h>
+#include <qvaluelist.h>
+//#include <qguardedptr.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/driver.h>
+
+#include "kexidbconnection.h"
+#include "kexidbconnectiondata.h"
+
+namespace Kross { namespace KexiDB {
+
+ /**
+ * Drivers are the implementations Kexi uses to access the
+ * driver-backends.
+ *
+ * Example (in Python) ;
+ * @code
+ * # Import the kexidb module.
+ * import krosskexidb
+ * # Get the drivermanager.
+ * drivermanager = krosskexidb.DriverManager()
+ * # Create the driver now.
+ * driver = drivermanager.driver("SQLite3")
+ * # Check if the driver is valid.
+ * if not driver.isValid(): raise "Invalid driver"
+ * # Create a connectiondata object.
+ * connectiondata = drivermanager.createConnectionData()
+ * # Fill the new connectiondata object with what we need to connect.
+ * connectiondata.setFileName("/home/user/kexisqlite3file.kexi")
+ * # Print the list of connections before.
+ * print driver.connectionsList()
+ * # Create the connection now.
+ * connection = driver.createConnection(connectiondata)
+ * # Print the list of connections again. This includes our just created connection now.
+ * print driver.connectionsList()
+ * @endcode
+ */
+ class KexiDBDriver : public Kross::Api::Class<KexiDBDriver>
+ {
+ public:
+ KexiDBDriver(::KexiDB::Driver* driver);
+ virtual ~KexiDBDriver();
+ virtual const QString getClassName() const;
+
+ private:
+
+ /** Return true if this driver is valid else false. */
+ bool isValid();
+ /** The drivers major versionnumber. */
+ int versionMajor();
+ /** The drivers minor versionnumber. */
+ int versionMinor();
+ /** Driver-specific SQL string escaping. For example the " or ' char may
+ need to be escaped for values used within SQL-statements. */
+ QString escapeString(const QString& s);
+ /** Returns true if this driver is file-based. */
+ bool isFileDriver();
+ /** Return a name of MIME type of files handled by this driver if it is a
+ file-based database's driver otherwise returns null string. */
+ QString fileDBDriverMimeType();
+ /** Returns true if the passed string is a system object's name, eg. name
+ of build-in system table that cannot be used or created by a user. */
+ bool isSystemObjectName(const QString& name);
+ /** Returns true if the passed string is a system database's name, eg. name
+ of build-in, system database that cannot be used or created by a user. */
+ bool isSystemDatabaseName(const QString& name);
+ /** Returns true if the passed string is a system field's name, build-in
+ system field that cannot be used or created by a user. */
+ bool isSystemFieldName(const QString& name);
+ /** The as second argument passed string got escaped to be usable within
+ a SQL-statement and those escaped string got returned by the method.
+ The first argument defines the fieldtype to what we should escape the
+ second argument to. */
+ QString valueToSQL(const QString& fieldtype, const QVariant& value);
+ /** Create a new KexiDBConnection object and return it. */
+ KexiDBConnection* createConnection(KexiDBConnectionData* data);
+ /** Return a list of KexiDBConnection objects. */
+ QPtrList< ::KexiDB::Connection > connectionsList();
+
+ private:
+ ::KexiDB::Driver* m_driver;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbdrivermanager.cpp b/kexi/plugins/scripting/kexidb/kexidbdrivermanager.cpp
new file mode 100644
index 00000000..66a0df26
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbdrivermanager.cpp
@@ -0,0 +1,178 @@
+/***************************************************************************
+ * kexidbdrivermanager.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 "kexidbdrivermanager.h"
+#include "kexidbdriver.h"
+#include "kexidbconnectiondata.h"
+#include "kexidbfield.h"
+#include "kexidbschema.h"
+
+#include <api/exception.h>
+
+#include <qguardedptr.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+
+#include <kexidb/driver.h>
+#include <kexidb/connectiondata.h>
+#include <kexidb/field.h>
+#include <kexidb/tableschema.h>
+#include <kexidb/queryschema.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBDriverManager::KexiDBDriverManager()
+ : Kross::Api::Class<KexiDBDriverManager>("DriverManager")
+{
+ //krossdebug( QString("Kross::KexiDB::KexiDBDriverManager::KexiDBDriverManager()") );
+
+ this->addFunction0< Kross::Api::Variant >("driverNames", this, &KexiDBDriverManager::driverNames);
+
+ this->addFunction1< KexiDBDriver, Kross::Api::Variant >("driver", this, &KexiDBDriverManager::driver);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("lookupByMime", this, &KexiDBDriverManager::lookupByMime);
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("mimeForFile", this, &KexiDBDriverManager::mimeForFile);
+
+ this->addFunction0< KexiDBConnectionData >("createConnectionData", this, &KexiDBDriverManager::createConnectionData);
+ this->addFunction1< KexiDBConnectionData, Kross::Api::Variant >("createConnectionDataByFile", this, &KexiDBDriverManager::createConnectionDataByFile);
+ this->addFunction0< KexiDBField >("field", this, &KexiDBDriverManager::field);
+ this->addFunction1< KexiDBTableSchema, Kross::Api::Variant >("tableSchema", this, &KexiDBDriverManager::tableSchema);
+ this->addFunction0< KexiDBQuerySchema>("querySchema", this, &KexiDBDriverManager::querySchema);
+}
+
+KexiDBDriverManager::~KexiDBDriverManager() {
+ //krossdebug( QString("Kross::KexiDB::KexiDBDriverManager::~KexiDBDriverManager()") );
+}
+
+const QString KexiDBDriverManager::getClassName() const {
+ return "Kross::KexiDB::KexiDBDriverManager";
+}
+
+KexiDB::DriverManager& KexiDBDriverManager::driverManager()
+{
+ if(m_drivermanager.error())
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("KexiDB::DriverManager error: %1").arg(m_drivermanager.errorMsg())) );
+ return m_drivermanager;
+}
+
+const QStringList KexiDBDriverManager::driverNames() {
+ return driverManager().driverNames();
+}
+
+KexiDBDriver* KexiDBDriverManager::driver(const QString& drivername) {
+ QGuardedPtr< ::KexiDB::Driver > driver = driverManager().driver(drivername); // caching is done by the DriverManager
+ if(! driver) return 0;
+ if(driver->error()) throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("KexiDB::Driver error for drivername '%1': %2").arg(drivername).arg(driver->errorMsg())) );
+ return new KexiDBDriver(driver);
+}
+
+const QString KexiDBDriverManager::lookupByMime(const QString& mimetype) {
+ return driverManager().lookupByMime(mimetype);
+}
+
+const QString KexiDBDriverManager::mimeForFile(const QString& filename) {
+ QString mimename = KMimeType::findByFileContent( filename )->name();
+ if(mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain")
+ mimename = KMimeType::findByURL(filename)->name();
+ return mimename;
+}
+
+KexiDBConnectionData* KexiDBDriverManager::createConnectionData() {
+ return new KexiDBConnectionData( new ::KexiDB::ConnectionData() );
+}
+
+KexiDBConnectionData* KexiDBDriverManager::createConnectionDataByFile(const QString& filename) {
+ //! @todo reuse the original code!
+
+ QString mimename = KMimeType::findByFileContent(filename)->name();
+ if(mimename.isEmpty() || mimename=="application/octet-stream" || mimename=="text/plain")
+ mimename = KMimeType::findByURL(filename)->name();
+
+ if(mimename == "application/x-kexiproject-shortcut" || mimename == "application/x-kexi-connectiondata") {
+ KConfig config(filename, true, false);
+ QString groupkey;
+ QStringList groups(config.groupList());
+ QStringList::ConstIterator it, end( groups.constEnd() );
+ for( it = groups.constBegin(); it != end; ++it) {
+ if((*it).lower()!="file information") {
+ groupkey = *it;
+ break;
+ }
+ }
+ if(groupkey.isNull()) {
+ kdDebug() << "No groupkey in KexiDBDriverManager::createConnectionDataByFile filename=" << filename << endl;
+ return 0;
+ }
+
+ config.setGroup(groupkey);
+ //QString type( config.readEntry("type", "database").lower() );
+ //bool isDatabaseShortcut = (type == "database");
+
+ ::KexiDB::ConnectionData* data = new ::KexiDB::ConnectionData();
+ int version = config.readNumEntry("version", 2); //KexiDBShortcutFile_version
+ data->setFileName(QString::null);
+ data->caption = config.readEntry("caption");
+ data->description = config.readEntry("comment");
+ QString dbname = config.readEntry("name");
+ data->driverName = config.readEntry("engine");
+ data->hostName = config.readEntry("server");
+ data->port = config.readNumEntry("port", 0);
+ data->useLocalSocketFile = config.readBoolEntry("useLocalSocketFile", false);
+ data->localSocketFileName = config.readEntry("localSocketFile");
+
+ if(version >= 2 && config.hasKey("encryptedPassword")) {
+ data->password = config.readEntry("encryptedPassword");
+ uint len = data->password.length();
+ for (uint i=0; i<len; i++)
+ data->password[i] = QChar( data->password[i].unicode() - 47 - i );
+ }
+ if(data->password.isEmpty())
+ data->password = config.readEntry("password");
+
+ data->savePassword = ! data->password.isEmpty();
+ data->userName = config.readEntry("user");
+
+ KexiDBConnectionData* c = new KexiDBConnectionData(data);
+ c->setDatabaseName(dbname);
+ return c;
+ }
+
+ QString const drivername = driverManager().lookupByMime(mimename);
+ if(! drivername) {
+ kdDebug() << "No driver in KexiDBDriverManager::createConnectionDataByFile filename=" << filename << " mimename=" << mimename << endl;
+ return 0;
+ }
+
+ ::KexiDB::ConnectionData* data = new ::KexiDB::ConnectionData();
+ data->setFileName(filename);
+ data->driverName = drivername;
+ return new KexiDBConnectionData(data);
+}
+
+KexiDBField* KexiDBDriverManager::field() {
+ return new KexiDBField( new ::KexiDB::Field() );
+}
+
+KexiDBTableSchema* KexiDBDriverManager::tableSchema(const QString& tablename) {
+ return new KexiDBTableSchema( new ::KexiDB::TableSchema(tablename) );
+}
+
+KexiDBQuerySchema* KexiDBDriverManager::querySchema() {
+ return new KexiDBQuerySchema( new ::KexiDB::QuerySchema() );
+}
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbdrivermanager.h b/kexi/plugins/scripting/kexidb/kexidbdrivermanager.h
new file mode 100644
index 00000000..b6e31108
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbdrivermanager.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * kexidbdrivermanager.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_KEXIDB_KEXIDBDRIVERMANAGER_H
+#define KROSS_KEXIDB_KEXIDBDRIVERMANAGER_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/variant.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/drivermanager.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward declarations.
+ class KexiDBDriver;
+ class KexiDBConnectionData;
+ class KexiDBField;
+ class KexiDBTableSchema;
+ class KexiDBQuerySchema;
+
+ /**
+ * The drivermanager is the base class to access KexiDBDriver objects and provides
+ * common functionality to deal with the KexiDB module.
+ *
+ * Example (in Python) ;
+ * @code
+ * # Import the kexidb module.
+ * import krosskexidb
+ * # Get the drivermanager.
+ * drivermanager = krosskexidb.DriverManager()
+ * # Let's determinate the mimetype (e.g. "application/x-sqlite3").
+ * mimetype = drivermanager.mimeForFile("/home/user/mykexidbfile.kexi")
+ * # Now we use that mimetype to get the name of the driver to handle that file (e.g. "SQLite3")
+ * drivername = drivermanager.lookupByMime(mimetype)
+ * # We are able to create the driver now.
+ * driver = drivermanager.driver(drivername)
+ * @endcode
+ */
+ class KexiDBDriverManager : public Kross::Api::Class<KexiDBDriverManager>
+ {
+ public:
+ KexiDBDriverManager();
+ virtual ~KexiDBDriverManager();
+ virtual const QString getClassName() const;
+
+ private:
+
+ /** Returns a list with avaible drivernames. */
+ const QStringList driverNames();
+
+ /** Return the to the defined drivername matching KexiDBDriver object. */
+ KexiDBDriver* driver(const QString& drivername);
+
+ /** Return the to the defined mimetype-string matching drivername. */
+ const QString lookupByMime(const QString& mimetype);
+
+ /** Return the matching mimetype for the defined file. */
+ const QString mimeForFile(const QString& filename);
+
+ /** Return a new KexiDBConnectionData object. */
+ KexiDBConnectionData* createConnectionData();
+
+ /** Create and return a KexiDBConnectionData object. Fill the content of the
+ KexiDBConnectionData object with the defined file as. The file could be e.g.
+ a *.kexi file or a *.kexis file. */
+ KexiDBConnectionData* createConnectionDataByFile(const QString& filename);
+
+ /** Return a new KexiDBField object. */
+ KexiDBField* field();
+
+ /** Return a new KexiDBTableSchema object. */
+ KexiDBTableSchema* tableSchema(const QString& tablename);
+
+ /** Return a new KexiDBQuerySchema object. */
+ KexiDBQuerySchema* querySchema();
+
+ private:
+ inline ::KexiDB::DriverManager& driverManager();
+ ::KexiDB::DriverManager m_drivermanager;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbfield.cpp b/kexi/plugins/scripting/kexidb/kexidbfield.cpp
new file mode 100644
index 00000000..949b5e1a
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbfield.cpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * kexidbfield.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 "kexidbfield.h"
+
+#include <api/variant.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBField::KexiDBField(::KexiDB::Field* field)
+ : Kross::Api::Class<KexiDBField>("KexiDBField")
+ , m_field(field)
+{
+ this->addFunction0< Kross::Api::Variant >("type", this, &KexiDBField::type);
+ this->addFunction1< void, Kross::Api::Variant >("setType", this, &KexiDBField::setType);
+
+ this->addFunction0< Kross::Api::Variant >("subType", this, &KexiDBField::subType);
+ this->addFunction1< void, Kross::Api::Variant >("setSubType", this, &KexiDBField::setSubType);
+
+ this->addFunction0< Kross::Api::Variant >("variantType", this, &KexiDBField::variantType);
+ this->addFunction0< Kross::Api::Variant >("typeGroup", this, &KexiDBField::typeGroup);
+
+ this->addFunction0< Kross::Api::Variant >("isAutoInc", this, &KexiDBField::isAutoInc);
+ this->addFunction1< void, Kross::Api::Variant >("setAutoInc", this, &KexiDBField::setAutoInc);
+
+ this->addFunction0< Kross::Api::Variant >("isUniqueKey", this, &KexiDBField::isUniqueKey);
+ this->addFunction1< void, Kross::Api::Variant >("setUniqueKey", this, &KexiDBField::setUniqueKey);
+
+ this->addFunction0< Kross::Api::Variant >("isPrimaryKey", this, &KexiDBField::isPrimaryKey);
+ this->addFunction1< void, Kross::Api::Variant >("setPrimaryKey", this, &KexiDBField::setPrimaryKey);
+
+ this->addFunction0< Kross::Api::Variant >("isForeignKey", this, &KexiDBField::isForeignKey);
+ this->addFunction1< void, Kross::Api::Variant >("setForeignKey", this, &KexiDBField::setForeignKey);
+
+ this->addFunction0< Kross::Api::Variant >("isNotNull", this, &KexiDBField::isNotNull);
+ this->addFunction1< void, Kross::Api::Variant >("setNotNull", this, &KexiDBField::setNotNull);
+
+ this->addFunction0< Kross::Api::Variant >("isNotEmpty", this, &KexiDBField::isNotEmpty);
+ this->addFunction1< void, Kross::Api::Variant >("setNotEmpty", this, &KexiDBField::setNotEmpty);
+
+ this->addFunction0< Kross::Api::Variant >("isIndexed", this, &KexiDBField::isIndexed);
+ this->addFunction1< void, Kross::Api::Variant >("setIndexed", this, &KexiDBField::setIndexed);
+
+ this->addFunction0< Kross::Api::Variant >("isUnsigned", this, &KexiDBField::isUnsigned);
+ this->addFunction1< void, Kross::Api::Variant >("setUnsigned", this, &KexiDBField::setUnsigned);
+
+ this->addFunction0< Kross::Api::Variant >("name", this, &KexiDBField::name);
+ this->addFunction1< void, Kross::Api::Variant >("setName", this, &KexiDBField::setName);
+
+ this->addFunction0< Kross::Api::Variant >("caption", this, &KexiDBField::caption);
+ this->addFunction1< void, Kross::Api::Variant >("setCaption", this, &KexiDBField::setCaption);
+
+ this->addFunction0< Kross::Api::Variant >("description", this, &KexiDBField::description);
+ this->addFunction1< void, Kross::Api::Variant >("setDescription", this, &KexiDBField::setDescription);
+
+ this->addFunction0< Kross::Api::Variant >("length", this, &KexiDBField::length);
+ this->addFunction1< void, Kross::Api::Variant >("setLength", this, &KexiDBField::setLength);
+
+ this->addFunction0< Kross::Api::Variant >("precision", this, &KexiDBField::precision);
+ this->addFunction1< void, Kross::Api::Variant >("setPrecision", this, &KexiDBField::setPrecision);
+
+ this->addFunction0< Kross::Api::Variant >("width", this, &KexiDBField::width);
+ this->addFunction1< void, Kross::Api::Variant >("setWidth", this, &KexiDBField::setWidth);
+
+ this->addFunction0< Kross::Api::Variant >("defaultValue", this, &KexiDBField::defaultValue);
+ this->addFunction1< void, Kross::Api::Variant >("setDefaultValue", this, &KexiDBField::setDefaultValue);
+}
+
+KexiDBField::~KexiDBField()
+{
+}
+
+const QString KexiDBField::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBField";
+}
+
+const QString KexiDBField::type() { return m_field->typeString(); }
+void KexiDBField::setType(const QString type) { m_field->setType( ::KexiDB::Field::typeForString(type) ); }
+
+const QString KexiDBField::subType() { return m_field->subType(); }
+void KexiDBField::setSubType(const QString& subtype) { m_field->setSubType(subtype); }
+
+const QString KexiDBField::variantType() { return QVariant::typeToName( m_field->variantType() ); }
+const QString KexiDBField::typeGroup() { return m_field->typeGroupString(); }
+
+bool KexiDBField::isAutoInc() { return m_field->isAutoIncrement(); }
+void KexiDBField::setAutoInc(bool autoinc) { m_field->setAutoIncrement(autoinc); }
+
+bool KexiDBField::isUniqueKey() { return m_field->isUniqueKey(); }
+void KexiDBField::setUniqueKey(bool unique) { m_field->setUniqueKey(unique); }
+
+bool KexiDBField::isPrimaryKey() { return m_field->isPrimaryKey(); }
+void KexiDBField::setPrimaryKey(bool primary) { m_field->setPrimaryKey(primary); }
+
+bool KexiDBField::isForeignKey() { return m_field->isForeignKey(); }
+void KexiDBField::setForeignKey(bool foreign) { m_field->setForeignKey(foreign); }
+
+bool KexiDBField::isNotNull() { return m_field->isNotNull(); }
+void KexiDBField::setNotNull(bool notnull) { m_field->setNotNull(notnull); }
+
+bool KexiDBField::isNotEmpty() { return m_field->isNotEmpty(); }
+void KexiDBField::setNotEmpty(bool notempty) { m_field->setNotEmpty(notempty); }
+
+bool KexiDBField::isIndexed() { return m_field->isIndexed(); }
+void KexiDBField::setIndexed(bool indexed) { m_field->setIndexed(indexed); }
+
+bool KexiDBField::isUnsigned() { return m_field->isUnsigned(); }
+void KexiDBField::setUnsigned(bool isunsigned) { m_field->setUnsigned(isunsigned); }
+
+const QString KexiDBField::name() { return m_field->name(); }
+void KexiDBField::setName(const QString& name) { m_field->setName(name); }
+
+const QString KexiDBField::caption() { return m_field->caption(); }
+void KexiDBField::setCaption(const QString& caption) { m_field->setCaption(caption); }
+
+const QString KexiDBField::description() { return m_field->description(); }
+void KexiDBField::setDescription(const QString& desc) { m_field->setDescription(desc); }
+
+uint KexiDBField::length() { return m_field->length(); }
+void KexiDBField::setLength(uint length) { m_field->setLength(length); }
+
+uint KexiDBField::precision() { return m_field->precision(); }
+void KexiDBField::setPrecision(uint precision) { m_field->setPrecision(precision); }
+
+uint KexiDBField::width() { return m_field->width(); }
+void KexiDBField::setWidth(uint width) { m_field->setWidth(width); }
+
+QVariant KexiDBField::defaultValue() { return m_field->defaultValue(); }
+void KexiDBField::setDefaultValue(const QVariant& defaultvalue) { m_field->setDefaultValue(defaultvalue); }
diff --git a/kexi/plugins/scripting/kexidb/kexidbfield.h b/kexi/plugins/scripting/kexidb/kexidbfield.h
new file mode 100644
index 00000000..a4c2ef23
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbfield.h
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * kexidbfield.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_KEXIDB_KEXIDBFIELD_H
+#define KROSS_KEXIDB_KEXIDBFIELD_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/drivermanager.h>
+#include <kexidb/field.h>
+
+namespace Kross { namespace KexiDB {
+
+ /**
+ * A field in a record.
+ */
+ class KexiDBField : public Kross::Api::Class<KexiDBField>
+ {
+ public:
+ KexiDBField(::KexiDB::Field* field);
+ virtual ~KexiDBField();
+ virtual const QString getClassName() const;
+ ::KexiDB::Field* field() { return m_field; }
+
+ private:
+
+ /** Returns the type string for this field, e.g. "Integer" for Integer type. */
+ const QString type();
+ /** Sets the type string for this field, e.g. "Integer" for Integer type. */
+ void setType(const QString type);
+
+ /** Returns the optional subtype for this field. Subtype is a string providing
+ additional hint for field's type. E.g. for BLOB type, it can be a MIME type or
+ certain QVariant type name, for example: "QPixmap", "QColor" or "QFont". */
+ const QString subType();
+ /** Sets the optional subtype for this field. */
+ void setSubType(const QString& subtype);
+
+ /** Returns the QVariant::typeName which is equivalent to the type this field has. */
+ const QString variantType();
+ /** Returns type group string for this field, e.g. "IntegerGroup" for IntegerGroup type. */
+ const QString typeGroup();
+
+ /** Returns true if the field is autoincrement (e.g. integer/numeric). */
+ bool isAutoInc();
+ /** Sets auto increment flag. */
+ void setAutoInc(bool autoinc);
+
+ /** Returns true if the field is member of single-field unique key. */
+ bool isUniqueKey();
+ /** Specifies whether the field has single-field unique constraint or not. */
+ void setUniqueKey(bool unique);
+
+ /** Returns true if the field is member of single-field primary key. */
+ bool isPrimaryKey();
+ /** Specifies whether the field is single-field primary key or not. */
+ void setPrimaryKey(bool primary);
+
+ /** Returns true if the field is member of single-field foreign key. */
+ bool isForeignKey();
+ /** Sets whether the field has to be declared with single-field foreign key. */
+ void setForeignKey(bool foreign);
+
+ /** Returns true if the field is not allowed to be null. */
+ bool isNotNull();
+ /** Specifies whether the field has single-field unique constraint or not. */
+ void setNotNull(bool notnull);
+
+ /** Returns true if the field is not allowed to be empty. */
+ bool isNotEmpty();
+ /** Specifies whether the field has single-field unique constraint or not. */
+ void setNotEmpty(bool notempty);
+
+ /** Returns true if the field is indexed using single-field database index. */
+ bool isIndexed();
+ /** Specifies whether the field is indexed or not. */
+ void setIndexed(bool indexed);
+
+ /** Returns true if the field is an unsigned integer. */
+ bool isUnsigned();
+ /** Specifies whether the field is an unsigned integer or not. */
+ void setUnsigned(bool isunsigned);
+
+ /** Returns the name of this field. */
+ const QString name();
+ /** Sets the name of this field. */
+ void setName(const QString& name);
+
+ /** Returns the caption of this field. */
+ const QString caption();
+ /** Sets the caption of this field. */
+ void setCaption(const QString& caption);
+
+ /** Returns the descriptive text for this field. */
+ const QString description();
+ /** Set the description for this field. */
+ void setDescription(const QString& desc);
+
+ /** Returns the length of text if the field type is text. */
+ uint length();
+ /** Sets the length for this field. Only works for Text Type (not including LongText). */
+ void setLength(uint length);
+
+ /** Returns precision for numeric and other fields that have both length and
+ precision (floating point types). */
+ uint precision();
+ /** Sets the precision for numeric and other fields. */
+ void setPrecision(uint precision);
+
+ /** Returns the width of this field (usually in pixels or points).
+ 0 (the default) means there is no hint for the width. */
+ uint width();
+ /** Sets the width of this field. */
+ void setWidth(uint width);
+
+ /** Returns the default value this field has. */
+ QVariant defaultValue();
+ /** Sets the default value this field has. */
+ void setDefaultValue(const QVariant& defaultvalue);
+
+ private:
+ ::KexiDB::Field* m_field;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbfieldlist.cpp b/kexi/plugins/scripting/kexidb/kexidbfieldlist.cpp
new file mode 100644
index 00000000..f36bf0b0
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbfieldlist.cpp
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * kexidbfieldlist.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 "kexidbfieldlist.h"
+#include "kexidbfield.h"
+
+#include <api/variant.h>
+#include <api/exception.h>
+
+#include <kdebug.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBFieldList::KexiDBFieldList(::KexiDB::FieldList* fieldlist)
+ : Kross::Api::Class<KexiDBFieldList>("KexiDBFieldList")
+ , m_fieldlist(fieldlist)
+{
+ this->addFunction0< Kross::Api::Variant >("fieldCount", this, &KexiDBFieldList::fieldCount);
+ this->addFunction1< KexiDBField, Kross::Api::Variant >("field", this, &KexiDBFieldList::field);
+ this->addFunction1< KexiDBField, Kross::Api::Variant >("fieldByName", this, &KexiDBFieldList::fieldByName);
+
+ this->addFunction0< Kross::Api::List >("fields", this, &KexiDBFieldList::fields);
+
+ this->addFunction1< Kross::Api::Variant, KexiDBField >("hasField", this, &KexiDBFieldList::hasField);
+ this->addFunction0< Kross::Api::Variant >("names", this, &KexiDBFieldList::names);
+
+ this->addFunction1< void, KexiDBField >("addField", this, &KexiDBFieldList::addField);
+ this->addFunction2< void, Kross::Api::Variant, KexiDBField >("insertField", this, &KexiDBFieldList::insertField);
+ this->addFunction1< void, KexiDBField >("removeField", this, &KexiDBFieldList::removeField);
+ this->addFunction0< void >("clear", this, &KexiDBFieldList::clear);
+ this->addFunction1< void, KexiDBFieldList >("setFields", this, &KexiDBFieldList::setFields);
+
+ this->addFunction1< KexiDBFieldList, Kross::Api::Variant >("subList", this, &KexiDBFieldList::subList);
+}
+
+KexiDBFieldList::~KexiDBFieldList()
+{
+}
+
+const QString KexiDBFieldList::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBFieldList";
+}
+
+uint KexiDBFieldList::fieldCount() {
+ return m_fieldlist->fieldCount();
+}
+
+KexiDBField* KexiDBFieldList::field(uint index) {
+ ::KexiDB::Field* field = m_fieldlist->field(index);
+ return field ? new KexiDBField(field) : 0;
+}
+
+KexiDBField* KexiDBFieldList::fieldByName(const QString& name) {
+ ::KexiDB::Field* field = m_fieldlist->field(name);
+ return field ? new KexiDBField(field) : 0;
+}
+
+Kross::Api::List* KexiDBFieldList::fields() {
+ return new Kross::Api::ListT<KexiDBField>( *m_fieldlist->fields() );
+}
+
+bool KexiDBFieldList::hasField(KexiDBField* field) { return m_fieldlist->hasField( field->field() ); }
+const QStringList KexiDBFieldList::names() const { return m_fieldlist->names(); }
+void KexiDBFieldList::addField(KexiDBField* field) { m_fieldlist->addField( field->field() ); }
+void KexiDBFieldList::insertField(uint index, KexiDBField* field) { m_fieldlist->insertField(index, field->field()); }
+void KexiDBFieldList::removeField(KexiDBField* field) { m_fieldlist->removeField( field->field() ); }
+void KexiDBFieldList::clear() { m_fieldlist->clear(); }
+
+void KexiDBFieldList::setFields(KexiDBFieldList* fieldlist) {
+ m_fieldlist->clear();
+ ::KexiDB::FieldList* fl = fieldlist->fieldlist();
+ for(::KexiDB::Field::ListIterator it = *fl->fields(); it.current(); ++it)
+ m_fieldlist->addField( it.current() );
+}
+
+KexiDBFieldList* KexiDBFieldList::subList(QValueList<QVariant> list) {
+ QValueList<QVariant>::ConstIterator it( list.constBegin() ), end( list.constEnd() );
+ QStringList sl;
+ for(; it != end; ++it) sl.append( (*it).toString() );
+ ::KexiDB::FieldList* fl = m_fieldlist->subList(sl);
+ return fl ? new Kross::KexiDB::KexiDBFieldList(fl) : 0;
+}
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbfieldlist.h b/kexi/plugins/scripting/kexidb/kexidbfieldlist.h
new file mode 100644
index 00000000..ee990eb3
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbfieldlist.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ * kexidbfieldlist.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_KEXIDB_KEXIDBFIELDLIST_H
+#define KROSS_KEXIDB_KEXIDBFIELDLIST_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/drivermanager.h>
+#include <kexidb/fieldlist.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward declarations.
+ class KexiDBField;
+ class KexiDBFieldList;
+
+ /**
+ * A list of fields. The KexiDBFieldList can be used to handle KexiDBField objects
+ * in a backend-independent way.
+ *
+ * Example (in Python) ;
+ * @code
+ * # Get the tableschema for the "dept" table.
+ * table = connection.tableSchema("dept")
+ * # Create a KexiDBFieldList based on the table and filled with the selected fields.
+ * subfields = ["deptno","name","loc"]
+ * fieldlist = table.fieldlist().subList(subfields)
+ * # Create the "SELECT * from dept;" queryschema.
+ * query = table.query()
+ * # We change the queryschema to "SELECT deptno,name,loc FROM dept;" now.
+ * query.fieldlist().setFields(fieldlist)
+ * # and change the query to "SELECT deptno,name,loc FROM dept WHERE deptno=5;"
+ * query.setWhereExpression("deptno=5")
+ * # Execute the query and get a KexiDBCursor object as result which could be used to iterate through the result.
+ * cursor = connection.executeQuerySchema(query)
+ * @endcode
+ */
+ class KexiDBFieldList : public Kross::Api::Class<KexiDBFieldList>
+ {
+ public:
+ KexiDBFieldList(::KexiDB::FieldList* fieldlist);
+ virtual ~KexiDBFieldList();
+ virtual const QString getClassName() const;
+ ::KexiDB::FieldList* fieldlist() { return m_fieldlist; }
+
+ private:
+
+ /** Returns the number of fields. */
+ uint fieldCount();
+ /** Return the field specified by the index-number passed as an argument. */
+ KexiDBField* field(uint index);
+ /** Return the field specified by the as an argument passed fieldname. */
+ KexiDBField* fieldByName(const QString& name);
+
+ /** Returns a list of all fields. */
+ Kross::Api::List* fields();
+ /** Returns true if the KexiDBField object passed as an argument is in the field list. */
+ bool hasField(KexiDBField* field);
+ /** Return a list of field names. */
+ const QStringList names() const;
+
+ /** Adds the KexiDBField object passed as an argument to the field list. */
+ void addField(KexiDBField* field);
+ /** Inserts the KexiDBField object passed as the second argument
+ into the field list at the position defined by the first argument. */
+ void insertField(uint index, KexiDBField* field);
+ /** Removes the KexiDBField object passed as an argument from the field list. */
+ void removeField(KexiDBField* field);
+ /** Removes all KexiDBField objects from the fieldlist. */
+ void clear();
+ /** Set the fieldlist to the as argument passed list of fields. */
+ void setFields(KexiDBFieldList* fieldlist);
+ /** Creates and returns list that contain fields selected by name. */
+ KexiDBFieldList* subList(QValueList<QVariant> list);
+
+ private:
+ ::KexiDB::FieldList* m_fieldlist;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbmodule.cpp b/kexi/plugins/scripting/kexidb/kexidbmodule.cpp
new file mode 100644
index 00000000..36f7b71f
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbmodule.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * kexidbmodule.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 "kexidbmodule.h"
+#include "kexidbdrivermanager.h"
+#include "kexidbconnection.h"
+
+//#include <api/object.h>
+//#include <api/variant.h>
+#include <main/manager.h>
+
+#include <kdebug.h>
+
+// The as version() published versionnumber of this kross-module.
+#define KROSS_KEXIDB_VERSION 1
+
+extern "C"
+{
+ /**
+ * Exported an loadable function as entry point to use
+ * the \a KexiDBModule.
+ */
+ Kross::Api::Object* KDE_EXPORT init_module(Kross::Api::Manager* manager)
+ {
+ return new Kross::KexiDB::KexiDBModule(manager);
+ }
+}
+
+using namespace Kross::KexiDB;
+
+KexiDBModule::KexiDBModule(Kross::Api::Manager* /*manager*/)
+ : Kross::Api::Module("KexiDB")
+ //, m_manager(manager)
+{
+ //kdDebug() << "Kross::KexiDB::KexiDBModule Ctor" << endl;
+ addChild( "version", new Kross::Api::Variant(KROSS_KEXIDB_VERSION) );
+ addChild( new KexiDBDriverManager() );
+}
+
+KexiDBModule::~KexiDBModule()
+{
+ //kdDebug() << "Kross::KexiDB::KexiDBModule Dtor" << endl;
+}
+
+const QString KexiDBModule::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBModule";
+}
+
+Kross::Api::Object::Ptr KexiDBModule::get(const QString& name, void* p)
+{
+ if(name == "KexiDBConnection") {
+ ::KexiDB::Connection* connection = (::KexiDB::Connection*)p;
+ if(connection)
+ return new KexiDBConnection(connection);
+ }
+ return 0;
+}
diff --git a/kexi/plugins/scripting/kexidb/kexidbmodule.h b/kexi/plugins/scripting/kexidb/kexidbmodule.h
new file mode 100644
index 00000000..b91b6047
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbmodule.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * kexidbmodule.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_KEXIDB_KEXIDBMODULE_H
+#define KROSS_KEXIDB_KEXIDBMODULE_H
+
+#include <qstring.h>
+#include <qvariant.h>
+
+#include <api/module.h>
+
+namespace Kross { namespace Api {
+ class Manager;
+}}
+
+namespace Kross {
+
+/**
+ * KrossKexiDB provides access to the KexiDB database functionality.
+ */
+namespace KexiDB {
+
+ /**
+ * \internal
+ * The KexiDBModule is the implementation of a kross-module.
+ */
+ class KexiDBModule : public Kross::Api::Module
+ {
+ public:
+ KexiDBModule(Kross::Api::Manager* manager);
+ virtual ~KexiDBModule();
+ virtual const QString getClassName() const;
+
+ /**
+ * \internal
+ * Variable module-method use to call transparent some functionality
+ * the module provides.
+ *
+ * \param name A name passed to the method. This name is used internaly
+ * to determinate what the caller likes to do. Each implemented
+ * module have to implement what should be done.
+ * \param p A variable pointer passed to the method. It depends on
+ * the module and the name what this pointer is.
+ * \return a \a Kross::Api::Object or NULL.
+ */
+ virtual Kross::Api::Object::Ptr get(const QString& name, void* p = 0);
+
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbparser.cpp b/kexi/plugins/scripting/kexidb/kexidbparser.cpp
new file mode 100644
index 00000000..b022570d
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbparser.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * kexidbparser.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 "kexidbparser.h"
+#include "kexidbschema.h"
+#include "kexidbconnection.h"
+
+#include <api/variant.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBParser::KexiDBParser(KexiDBConnection* connection, ::KexiDB::Parser* parser)
+ : Kross::Api::Class<KexiDBParser>("KexiDBParser")
+ , m_connection(connection)
+ , m_parser(parser)
+{
+ this->addFunction1< Kross::Api::Variant, Kross::Api::Variant >("parse", this, &KexiDBParser::parse);
+ this->addFunction0< void >("clear", this, &KexiDBParser::clear);
+
+ this->addFunction0< Kross::Api::Variant >("operation", this, &KexiDBParser::operation);
+
+ this->addFunction0< KexiDBTableSchema >("table", this, &KexiDBParser::table);
+ this->addFunction0< KexiDBQuerySchema >("query", this, &KexiDBParser::query);
+ this->addFunction0< KexiDBConnection >("connection", this, &KexiDBParser::connection);
+ this->addFunction0< Kross::Api::Variant >("statement", this, &KexiDBParser::statement);
+
+ this->addFunction0< Kross::Api::Variant >("errorType", this, &KexiDBParser::errorType);
+ this->addFunction0< Kross::Api::Variant >("errorMsg", this, &KexiDBParser::errorMsg);
+ this->addFunction0< Kross::Api::Variant >("errorAt", this, &KexiDBParser::errorAt);
+}
+
+KexiDBParser::~KexiDBParser()
+{
+}
+
+const QString KexiDBParser::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBParser";
+}
+
+bool KexiDBParser::parse(const QString& sql) { return m_parser->parse(sql); }
+void KexiDBParser::clear() { m_parser->clear(); }
+const QString KexiDBParser::operation() { return m_parser->operationString(); }
+
+KexiDBTableSchema* KexiDBParser::table() {
+ ::KexiDB::TableSchema* t = m_parser->table();
+ return t ? new KexiDBTableSchema(t) : 0;
+}
+
+KexiDBQuerySchema* KexiDBParser::query() {
+ ::KexiDB::QuerySchema* q = m_parser->query();
+ return q ? new KexiDBQuerySchema(q) : 0;
+}
+
+KexiDBConnection* KexiDBParser::connection() { return m_connection; }
+const QString KexiDBParser::statement() { return m_parser->statement(); }
+
+const QString KexiDBParser::errorType() { return m_parser->error().type(); }
+const QString KexiDBParser::errorMsg() { return m_parser->error().error(); }
+int KexiDBParser::errorAt() { return m_parser->error().at(); }
diff --git a/kexi/plugins/scripting/kexidb/kexidbparser.h b/kexi/plugins/scripting/kexidb/kexidbparser.h
new file mode 100644
index 00000000..09ac22da
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbparser.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * kexidbparser.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_KEXIDB_KEXIDBPARSER_H
+#define KROSS_KEXIDB_KEXIDBPARSER_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/list.h>
+#include <api/class.h>
+
+#include <kexidb/drivermanager.h>
+#include <kexidb/parser/parser.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward declaration.
+ class KexiDBConnection;
+ class KexiDBTableSchema;
+ class KexiDBQuerySchema;
+
+ /**
+ * The KexiDBParser could be used to parse SQL-statements.
+ *
+ * Example (in Python) ;
+ * @code
+ * # First we need a parser object.
+ * parser = connection.parser()
+ * # Parse a SQL-statement.
+ * parser.parse("SELECT * from table1")
+ * # The operation could be e.g. SELECT or INSERT.
+ * if parser.operation() == 'Error':
+ * raise parser.errorMsg()
+ * # Print some feedback.
+ * print "Successfully parsed the SQL-statement %s" % parser.statement()
+ * @endcode
+ */
+ class KexiDBParser : public Kross::Api::Class<KexiDBParser>
+ {
+ public:
+ KexiDBParser(KexiDBConnection* connection, ::KexiDB::Parser* parser);
+ virtual ~KexiDBParser();
+ virtual const QString getClassName() const;
+
+ private:
+
+ /** Clears previous results and runs the parser on the SQL statement passed as an argument. */
+ bool parse(const QString& sql);
+ /** Clears parsing results. */
+ void clear();
+ /** Returns the resulting operation. */
+ const QString operation();
+
+ /** Returns the KexiDBTableSchema object on a CREATE TABLE operation. */
+ KexiDBTableSchema* table();
+ /** Returns the KexiDBQuerySchema object on a SELECT operation. */
+ KexiDBQuerySchema* query();
+ /** Returns the KexiDBConnection object pointing to the used database connection. */
+ KexiDBConnection* connection();
+ /** Returns the SQL query statement. */
+ const QString statement();
+
+ /** Returns the type string of the last error. */
+ const QString errorType();
+ /** Returns the message of the last error. */
+ const QString errorMsg();
+ /** Returns the position where the last error occurred. */
+ int errorAt();
+
+ private:
+ KexiDBConnection* m_connection;
+ ::KexiDB::Parser* m_parser;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbschema.cpp b/kexi/plugins/scripting/kexidb/kexidbschema.cpp
new file mode 100644
index 00000000..e07917f3
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbschema.cpp
@@ -0,0 +1,197 @@
+/***************************************************************************
+ * kexidbschema.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 "kexidbschema.h"
+#include "kexidbfieldlist.h"
+
+#include <qregexp.h>
+#include <kdebug.h>
+
+#include <api/variant.h>
+
+using namespace Kross::KexiDB;
+
+/***************************************************************************
+ *KexiDBSchema
+ */
+
+template<class T>
+KexiDBSchema<T>::KexiDBSchema(const QString& name, ::KexiDB::SchemaData* schema, ::KexiDB::FieldList* fieldlist)
+ : Kross::Api::Class<T>(name)
+ , m_schema(schema)
+ , m_fieldlist(fieldlist)
+{
+ this->template addFunction0<Kross::Api::Variant>("name", this, &KexiDBSchema<T>::name);
+ this->template addFunction1<void, Kross::Api::Variant>("setName", this, &KexiDBSchema<T>::setName);
+
+ this->template addFunction0<Kross::Api::Variant>("caption", this, &KexiDBSchema<T>::caption);
+ this->template addFunction1<void, Kross::Api::Variant>("setCaption", this, &KexiDBSchema<T>::setCaption);
+
+ this->template addFunction0<Kross::Api::Variant>("description", this, &KexiDBSchema<T>::description);
+ this->template addFunction1<void, Kross::Api::Variant>("setDescription", this, &KexiDBSchema<T>::setDescription);
+
+ this->template addFunction0<KexiDBFieldList>("fieldlist", this, &KexiDBSchema<T>::fieldlist);
+}
+
+template<class T>
+KexiDBSchema<T>::~KexiDBSchema<T>() {
+}
+
+template<class T>
+const QString KexiDBSchema<T>::name() const {
+ return m_schema->name();
+}
+
+template<class T>
+void KexiDBSchema<T>::setName(const QString& name) {
+ m_schema->setName(name);
+}
+
+template<class T>
+const QString KexiDBSchema<T>::caption() const {
+ return m_schema->caption();
+}
+
+template<class T>
+void KexiDBSchema<T>::setCaption(const QString& caption) {
+ m_schema->setCaption(caption);
+}
+
+template<class T>
+const QString KexiDBSchema<T>::description() const {
+ return m_schema->description();
+}
+
+template<class T>
+void KexiDBSchema<T>::setDescription(const QString& description) {
+ m_schema->setDescription(description);
+}
+
+template<class T>
+KexiDBFieldList* KexiDBSchema<T>::fieldlist() const {
+ return new KexiDBFieldList(m_fieldlist);
+}
+
+/***************************************************************************
+ * KexiDBTableSchema
+ */
+
+KexiDBTableSchema::KexiDBTableSchema(::KexiDB::TableSchema* tableschema)
+ : KexiDBSchema<KexiDBTableSchema>("KexiDBTableSchema", tableschema, tableschema)
+{
+ this->addFunction0<KexiDBQuerySchema>("query", this, &KexiDBTableSchema::query);
+}
+
+KexiDBTableSchema::~KexiDBTableSchema() {
+}
+
+const QString KexiDBTableSchema::getClassName() const {
+ return "Kross::KexiDB::KexiDBTableSchema";
+}
+
+::KexiDB::TableSchema* KexiDBTableSchema::tableschema() {
+ return static_cast< ::KexiDB::TableSchema* >(m_schema);
+}
+
+KexiDBQuerySchema* KexiDBTableSchema::query() {
+ return new KexiDBQuerySchema( tableschema()->query() );
+}
+
+/***************************************************************************
+ * KexiDBQuerySchema
+ */
+
+KexiDBQuerySchema::KexiDBQuerySchema(::KexiDB::QuerySchema* queryschema)
+ : KexiDBSchema<KexiDBQuerySchema>("KexiDBQuerySchema", queryschema, queryschema)
+{
+ this->addFunction0<Kross::Api::Variant>("statement", this, &KexiDBQuerySchema::statement);
+ this->addFunction1<void, Kross::Api::Variant>("setStatement", this, &KexiDBQuerySchema::setStatement);
+ this->addFunction1<Kross::Api::Variant, Kross::Api::Variant>("setWhereExpression", this, &KexiDBQuerySchema::setWhereExpression);
+}
+
+KexiDBQuerySchema::~KexiDBQuerySchema() {
+}
+
+const QString KexiDBQuerySchema::getClassName() const {
+ return "Kross::KexiDB::KexiDBQuerySchema";
+}
+
+::KexiDB::QuerySchema* KexiDBQuerySchema::queryschema() {
+ return static_cast< ::KexiDB::QuerySchema* >(m_schema);
+}
+
+const QString KexiDBQuerySchema::statement() const {
+ return static_cast< ::KexiDB::QuerySchema* >(m_schema)->statement();
+}
+
+void KexiDBQuerySchema::setStatement(const QString& statement) {
+ static_cast< ::KexiDB::QuerySchema* >(m_schema)->setStatement(statement);
+}
+
+bool KexiDBQuerySchema::setWhereExpression(const QString& whereexpression) {
+ ::KexiDB::BaseExpr* oldexpr = static_cast< ::KexiDB::QuerySchema* >(m_schema)->whereExpression();
+
+ ///@todo use ::KexiDB::Parser for such kind of parser-functionality.
+ QString s = whereexpression;
+ try {
+ QRegExp re("[\"',]{1,1}");
+ while(true) {
+ s.remove(QRegExp("^[\\s,]+"));
+ int pos = s.find('=');
+ if(pos < 0) break;
+ QString key = s.left(pos).stripWhiteSpace();
+ s = s.mid(pos + 1).stripWhiteSpace();
+
+ QString value;
+ int sp = s.find(re);
+ if(sp >= 0) {
+ if(re.cap(0) == ",") {
+ value = s.left(sp).stripWhiteSpace();
+ s = s.mid(sp+1).stripWhiteSpace();
+ }
+ else {
+ int ep = s.find(re.cap(0),sp+1);
+ value = s.mid(sp+1,ep-1);
+ s = s.mid(ep + 1);
+ }
+ }
+ else {
+ value = s;
+ s = QString::null;
+ }
+
+ ::KexiDB::Field* field = static_cast< ::KexiDB::QuerySchema* >(m_schema)->field(key);
+ if(! field)
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Invalid WHERE-expression: Field \"%1\" does not exists in tableschema \"%2\".").arg(key).arg(m_schema->name())) );
+
+ QVariant v(value);
+ if(! v.cast(field->variantType()))
+ throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Invalid WHERE-expression: The for Field \"%1\" defined value is of type \"%2\" rather then the expected type \"%3\"").arg(key).arg(v.typeName()).arg(field->variantType())) );
+
+ static_cast< ::KexiDB::QuerySchema* >(m_schema)->addToWhereExpression(field,v);
+ }
+ }
+ catch(Kross::Api::Exception::Ptr e) {
+ Kross::krosswarning("Exception in Kross::KexiDB::KexiDBQuerySchema::setWhereExpression: ");
+ static_cast< ::KexiDB::QuerySchema* >(m_schema)->setWhereExpression(oldexpr); // fallback
+ return false;
+ }
+ return true;
+}
diff --git a/kexi/plugins/scripting/kexidb/kexidbschema.h b/kexi/plugins/scripting/kexidb/kexidbschema.h
new file mode 100644
index 00000000..61b6bc88
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbschema.h
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * kexidbschema.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_KEXIDB_KEXIDBSCHEMA_H
+#define KROSS_KEXIDB_KEXIDBSCHEMA_H
+
+#include <qstring.h>
+
+#include <api/object.h>
+#include <api/class.h>
+
+#include <kexidb/drivermanager.h>
+#include <kexidb/schemadata.h>
+#include <kexidb/tableschema.h>
+#include <kexidb/queryschema.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward-declarations.
+ class KexiDBFieldList;
+ class KexiDBQuerySchema;
+
+ /**
+ * The KexiDBSchema object provides common functionality for schemas
+ * like KexiDBTableSchema or KexiDBQuerySchema.
+ *
+ * Example (in Python) ;
+ * @code
+ * # Get the tableschema from a KexiDBConnection object.
+ * tableschema = connection.tableSchema("dept")
+ * # Print some information.
+ * print "table=%s description=%s" % (tableschema.name(), tableschema.description())
+ * # Get the "SELECT * FROM dept;" queryschema for the table.
+ * queryschema = tableschema.query()
+ * # Walk through the fields/columns the queryschema has and print the fieldnames.
+ * for field in queryschema.fieldlist().fields():
+ * print "fieldname=%s" % field.name()
+ * # Execute the query. The returned KexiDBCursor object could be used then to iterate through the result.
+ * cursor = connection.executeQuerySchema(queryschema)
+ * @endcode
+ */
+ template<class T>
+ class KexiDBSchema : public Kross::Api::Class<T>
+ {
+ public:
+ KexiDBSchema(const QString& name, ::KexiDB::SchemaData* schema, ::KexiDB::FieldList* fieldlist);
+ virtual ~KexiDBSchema();
+
+ private:
+
+ /** Returns the name of the schema. */
+ const QString name() const;
+ /** Set the name of the schema. */
+ void setName(const QString& name);
+
+ /** Returns the caption of the schema. */
+ const QString caption() const;
+ /** Set the caption of the schema. */
+ void setCaption(const QString& caption);
+
+ /** Returns a description of the schema. */
+ const QString description() const;
+ /** Set a description of the schema. */
+ void setDescription(const QString& description);
+
+ /** Returns the KexiDBFieldList object this schema has. */
+ KexiDBFieldList* fieldlist() const;
+
+ protected:
+ ::KexiDB::SchemaData* m_schema;
+ ::KexiDB::FieldList* m_fieldlist;
+ };
+
+ /**
+ * The KexiDBTableSchema object implements a KexiDBSchema for tables.
+ */
+ class KexiDBTableSchema : public KexiDBSchema<KexiDBTableSchema>
+ {
+ public:
+ KexiDBTableSchema(::KexiDB::TableSchema* tableschema);
+ virtual ~KexiDBTableSchema();
+ virtual const QString getClassName() const;
+ ::KexiDB::TableSchema* tableschema();
+
+ private:
+
+ /** Return the KexiDBQuerySchema object that represents a
+ "SELECT * FROM this_KexiDBTableSchema_object" SQL-statement. */
+ KexiDBQuerySchema* query();
+
+ };
+
+ /**
+ * The KexiDBTableSchema object implements a KexiDBSchema for queries.
+ */
+ class KexiDBQuerySchema : public KexiDBSchema<KexiDBQuerySchema>
+ {
+ public:
+ KexiDBQuerySchema(::KexiDB::QuerySchema* queryschema);
+ virtual ~KexiDBQuerySchema();
+ virtual const QString getClassName() const;
+ ::KexiDB::QuerySchema* queryschema();
+
+ private:
+
+ /** Returns the SQL-statement of this query schema. */
+ const QString statement() const;
+ /** Set the SQL-statement of this query schema. */
+ void setStatement(const QString& statement);
+ /** Set the where-expression. */
+ bool setWhereExpression(const QString& whereexpression);
+
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/kexidbtransaction.cpp b/kexi/plugins/scripting/kexidb/kexidbtransaction.cpp
new file mode 100644
index 00000000..d4cdff24
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbtransaction.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * kexidbtransaction.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 "kexidbtransaction.h"
+#include "kexidbconnection.h"
+#include <api/variant.h>
+
+//#include <kdebug.h>
+
+using namespace Kross::KexiDB;
+
+KexiDBTransaction::KexiDBTransaction(::KexiDB::Transaction& transaction)
+ : Kross::Api::Class<KexiDBTransaction>("KexiDBTransaction")
+ , m_transaction(transaction)
+{
+ this->addFunction0< Kross::Api::Variant >("isActive", this, &KexiDBTransaction::isActive);
+ this->addFunction0< Kross::Api::Variant >("isNull", this, &KexiDBTransaction::isNull);
+}
+
+KexiDBTransaction::~KexiDBTransaction()
+{
+}
+
+const QString KexiDBTransaction::getClassName() const
+{
+ return "Kross::KexiDB::KexiDBTransaction";
+}
+
+::KexiDB::Transaction& KexiDBTransaction::transaction()
+{
+ return m_transaction;
+}
+
+bool KexiDBTransaction::isActive() const { return m_transaction.active(); }
+bool KexiDBTransaction::isNull() const { return m_transaction.isNull(); }
diff --git a/kexi/plugins/scripting/kexidb/kexidbtransaction.h b/kexi/plugins/scripting/kexidb/kexidbtransaction.h
new file mode 100644
index 00000000..6a6b5785
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/kexidbtransaction.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * kexidbtransaction.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_KEXIDB_KEXIDBTRANSACTION_H
+#define KROSS_KEXIDB_KEXIDBTRANSACTION_H
+
+#include <qstring.h>
+
+#include <api/class.h>
+
+#include <kexidb/drivermanager.h>
+#include <kexidb/transaction.h>
+
+namespace Kross { namespace KexiDB {
+
+ // Forward declaration.
+ class KexiDBConnection;
+
+ /**
+ * Transactions are used to ensure that integrity of a database is
+ * maintained.
+ */
+ class KexiDBTransaction : public Kross::Api::Class<KexiDBTransaction>
+ {
+ public:
+ KexiDBTransaction(::KexiDB::Transaction& transaction);
+ virtual ~KexiDBTransaction();
+ virtual const QString getClassName() const;
+ ::KexiDB::Transaction& transaction();
+
+ private:
+
+ /** Return true if the transaction is active (ie. started). */
+ bool isActive() const;
+
+ /** Return true if the transaction is uninitialized (null). */
+ bool isNull() const;
+
+ private:
+ ::KexiDB::Transaction& m_transaction;
+ };
+
+}}
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexidb/readme.dox b/kexi/plugins/scripting/kexidb/readme.dox
new file mode 100644
index 00000000..c4e33a5b
--- /dev/null
+++ b/kexi/plugins/scripting/kexidb/readme.dox
@@ -0,0 +1,32 @@
+/** @mainpage KrossKexiDB
+ *
+ * The Kross KexiDB module provides a scripting bridge to the
+ * KexiDB library. KexiDB is the database abstraction layer used
+ * within Kexi to deal with all supported database-backends like
+ * SQLite, MySQL and Postqre.
+ *
+ * The @a KexiDBDriverManager is the manager module which provides
+ * the entry point to access the KexiDB functionality from
+ * scripting languages like Python and Ruby.
+ *
+ * @see http://www.kexi-project.org/scripting/
+ * @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/kexi/plugins/scripting/kexiscripting/Makefile.am b/kexi/plugins/scripting/kexiscripting/Makefile.am
new file mode 100644
index 00000000..ed3e2264
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/Makefile.am
@@ -0,0 +1,37 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = kexihandler_script.la
+
+kexihandler_script_la_SOURCES = \
+ kexiscriptpart.cpp kexiscripteditor.cpp kexiscriptdesignview.cpp
+
+kexihandler_script_la_LDFLAGS = \
+ $(KDE_PLUGIN) -module -no-undefined -Wnounresolved $(all_libraries) $(VER_INFO)
+
+kexihandler_script_la_LIBADD = \
+ $(top_builddir)/lib/kross/main/libkrossmain.la \
+ $(top_builddir)/kexi/core/libkexicore.la \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ $(top_builddir)/lib/koproperty/libkoproperty.la
+
+INCLUDES = \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/kexi/core \
+ -I$(top_srcdir)/kexi \
+ -I$(top_srcdir)/kexi/widget \
+ $(all_includes)
+
+servicesdir=$(kde_servicesdir)/kexi
+services_DATA=kexiscripthandler.desktop
+
+rcdir = $(kde_datadir)/kexi
+rc_DATA = kexiscriptpartui.rc kexiscriptpartinstui.rc
+
+METASOURCES = AUTO
+
+SUBDIRS = .
+
+include ../../Makefile.common
+
+noinst_HEADERS = kexiscriptpart.h kexiscripteditor.h kexiscriptdesignview.h
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp b/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp
new file mode 100644
index 00000000..ff2f93d0
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp
@@ -0,0 +1,337 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 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 "kexiscriptdesignview.h"
+#include "kexiscripteditor.h"
+
+#include <kross/main/manager.h>
+#include <kross/main/scriptcontainer.h>
+#include <kross/main/scriptaction.h>
+#include <kross/api/interpreter.h>
+
+#include <qlayout.h>
+#include <qsplitter.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qdom.h>
+#include <qstylesheet.h>
+#include <ktextbrowser.h>
+#include <kdebug.h>
+
+#include <kexidialogbase.h>
+#include <kexidb/connection.h>
+
+/// @internal
+class KexiScriptDesignViewPrivate
+{
+ public:
+
+ /**
+ * The \a Kross::Api::ScriptAction instance which provides
+ * us access to the scripting framework Kross.
+ */
+ Kross::Api::ScriptAction* scriptaction;
+
+ /// The \a KexiScriptEditor to edit the scripting code.
+ KexiScriptEditor* editor;
+
+ /// The \a KoProperty::Set used in the propertyeditor.
+ KoProperty::Set* properties;
+
+ /// Boolean flag to avoid infinite recursion.
+ bool updatesProperties;
+
+ /// Used to display statusmessages.
+ KTextBrowser* statusbrowser;
+};
+
+KexiScriptDesignView::KexiScriptDesignView(KexiMainWindow *mainWin, QWidget *parent, Kross::Api::ScriptAction* scriptaction)
+ : KexiViewBase(mainWin, parent, "KexiScriptDesignView")
+ , d( new KexiScriptDesignViewPrivate() )
+{
+ d->scriptaction = scriptaction;
+ d->updatesProperties = false;
+
+ QSplitter* splitter = new QSplitter(this);
+ splitter->setOrientation(Vertical);
+ QHBoxLayout* layout = new QHBoxLayout(this);
+ layout->addWidget(splitter);
+
+ d->editor = new KexiScriptEditor(mainWin, splitter, "ScriptEditor");
+ splitter->setFocusProxy(d->editor);
+ addChildView(d->editor);
+ setViewWidget(d->editor);
+
+ d->statusbrowser = new KTextBrowser(splitter, "ScriptStatusBrowser");
+ d->statusbrowser->setReadOnly(true);
+ d->statusbrowser->setTextFormat(QTextBrowser::RichText);
+ //d->browser->setWordWrap(QTextEdit::WidgetWidth);
+ d->statusbrowser->installEventFilter(this);
+ splitter->setResizeMode(d->statusbrowser, QSplitter::KeepSize);
+
+ plugSharedAction( "data_execute", this, SLOT(execute()) );
+ if(KexiEditor::isAdvancedEditor()) // the configeditor is only in advanced mode avaiable.
+ plugSharedAction( "script_config_editor", d->editor, SLOT(slotConfigureEditor()) );
+
+ loadData();
+
+ d->properties = new KoProperty::Set(this, "KexiScripting");
+ connect(d->properties, SIGNAL( propertyChanged(KoProperty::Set&, KoProperty::Property&) ),
+ this, SLOT( slotPropertyChanged(KoProperty::Set&, KoProperty::Property&) ));
+
+ // To schedule the initialize fixes a crasher in Kate.
+ QTimer::singleShot(50, this, SLOT( initialize() ));
+}
+
+KexiScriptDesignView::~KexiScriptDesignView()
+{
+ delete d->properties;
+ delete d;
+}
+
+Kross::Api::ScriptAction* KexiScriptDesignView::scriptAction() const
+{
+ return d->scriptaction;
+}
+
+void KexiScriptDesignView::initialize()
+{
+ updateProperties();
+ d->editor->initialize( d->scriptaction );
+}
+
+void KexiScriptDesignView::updateProperties()
+{
+ if(d->updatesProperties)
+ return;
+ d->updatesProperties = true;
+
+ Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
+
+ QString interpretername = d->scriptaction->getInterpreterName();
+ Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
+
+ {
+ // if interpreter isn't defined or invalid, try to fallback.
+ QStringList list;
+ list << "python" << "ruby";
+ QStringList::ConstIterator it( list.constBegin() ), end( list.constEnd() );
+ while( (! info) && (it != end) ) {
+ interpretername = (*it);
+ info = manager->getInterpreterInfo(interpretername);
+ if(info)
+ d->scriptaction->setInterpreterName(interpretername);
+ ++it;
+ }
+ }
+
+ if(info) {
+ d->properties->clear();
+
+ QStringList interpreters = manager->getInterpreters();
+ KoProperty::Property::ListData* proplist = new KoProperty::Property::ListData(interpreters, interpreters);
+ KoProperty::Property* prop = new KoProperty::Property(
+ "language", // name
+ proplist, // ListData
+ d->scriptaction->getInterpreterName(), // value
+ i18n("Interpreter"), // caption
+ i18n("The used scripting interpreter."), // description
+ KoProperty::List // type
+ );
+ d->properties->addProperty(prop);
+
+ Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
+ Kross::Api::InterpreterInfo::Option::Map::ConstIterator it, end( options.constEnd() );
+ for( it = options.constBegin(); it != end; ++it) {
+ Kross::Api::InterpreterInfo::Option* option = it.data();
+ KoProperty::Property* prop = new KoProperty::Property(
+ it.key().latin1(), // name
+ d->scriptaction->getOption(it.key(), option->value), // value
+ option->name, // caption
+ option->comment, // description
+ KoProperty::Auto // type
+ );
+ d->properties->addProperty(prop);
+ }
+ }
+
+ //propertySetSwitched();
+ propertySetReloaded(true);
+ d->updatesProperties = false;
+}
+
+KoProperty::Set* KexiScriptDesignView::propertySet()
+{
+ return d->properties;
+}
+
+void KexiScriptDesignView::slotPropertyChanged(KoProperty::Set& /*set*/, KoProperty::Property& property)
+{
+ if(property.isNull())
+ return;
+
+ if(property.name() == "language") {
+ QString language = property.value().toString();
+ kdDebug() << QString("KexiScriptDesignView::slotPropertyChanged() language=%1").arg(language) << endl;
+ d->scriptaction->setInterpreterName( language );
+ // We assume Kross and the HighlightingInterface are using same
+ // names for the support languages...
+ d->editor->setHighlightMode( language );
+ updateProperties();
+ }
+ else {
+ bool ok = d->scriptaction->setOption( property.name(), property.value() );
+ if(! ok) {
+ kdWarning() << QString("KexiScriptDesignView::slotPropertyChanged() unknown property '%1'.").arg(property.name()) << endl;
+ return;
+ }
+ }
+
+ setDirty(true);
+}
+
+void KexiScriptDesignView::execute()
+{
+ d->statusbrowser->clear();
+ QTime time;
+ time.start();
+ d->statusbrowser->append( i18n("Execution of the script \"%1\" started.").arg(d->scriptaction->name()) );
+
+ d->scriptaction->activate();
+ if( d->scriptaction->hadException() ) {
+ QString errormessage = d->scriptaction->getException()->getError();
+ d->statusbrowser->append(QString("<b>%2</b><br>").arg(QStyleSheet::escape(errormessage)) );
+
+ QString tracedetails = d->scriptaction->getException()->getTrace();
+ d->statusbrowser->append( QStyleSheet::escape(tracedetails) );
+
+ long lineno = d->scriptaction->getException()->getLineNo();
+ if(lineno >= 0)
+ d->editor->setLineNo(lineno);
+ }
+ else {
+ d->statusbrowser->append( i18n("Successfully executed. Time elapsed: %1ms").arg(time.elapsed()) );
+ }
+}
+
+bool KexiScriptDesignView::loadData()
+{
+ QString data;
+ if(! loadDataBlock(data)) {
+ kexipluginsdbg << "KexiScriptDesignView::loadData(): no DataBlock" << endl;
+ return false;
+ }
+
+ QString errMsg;
+ int errLine;
+ int errCol;
+
+ QDomDocument domdoc;
+ bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol);
+
+ if(! parsed) {
+ kexipluginsdbg << "KexiScriptDesignView::loadData() XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg << endl;
+ return false;
+ }
+
+ QDomElement scriptelem = domdoc.namedItem("script").toElement();
+ if(scriptelem.isNull()) {
+ kexipluginsdbg << "KexiScriptDesignView::loadData(): script domelement is null" << endl;
+ return false;
+ }
+
+ QString interpretername = scriptelem.attribute("language");
+ Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
+ Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
+ if(info) {
+ d->scriptaction->setInterpreterName(interpretername);
+
+ Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
+ Kross::Api::InterpreterInfo::Option::Map::ConstIterator it, end = options.constEnd();
+ for( it = options.constBegin(); it != end; ++it) {
+ QString value = scriptelem.attribute( it.data()->name );
+ if(! value.isNull()) {
+ QVariant v(value);
+ if( v.cast( it.data()->value.type() ) ) // preserve the QVariant's type
+ d->scriptaction->setOption(it.data()->name, v);
+ }
+ }
+ }
+
+ d->scriptaction->setCode( scriptelem.text() );
+
+ return true;
+}
+
+KexiDB::SchemaData* KexiScriptDesignView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
+{
+ KexiDB::SchemaData *s = KexiViewBase::storeNewData(sdata, cancel);
+ kexipluginsdbg << "KexiScriptDesignView::storeNewData(): new id:" << s->id() << endl;
+
+ if(!s || cancel) {
+ delete s;
+ return 0;
+ }
+
+ if(! storeData()) {
+ kdWarning() << "KexiScriptDesignView::storeNewData Failed to store the data." << endl;
+ //failure: remove object's schema data to avoid garbage
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ conn->removeObject( s->id() );
+ delete s;
+ return 0;
+ }
+
+ return s;
+}
+
+tristate KexiScriptDesignView::storeData(bool /*dontAsk*/)
+{
+ kexipluginsdbg << "KexiScriptDesignView::storeData(): " << parentDialog()->partItem()->name() << " [" << parentDialog()->id() << "]" << endl;
+
+ QDomDocument domdoc("script");
+ QDomElement scriptelem = domdoc.createElement("script");
+ domdoc.appendChild(scriptelem);
+
+ QString language = d->scriptaction->getInterpreterName();
+ scriptelem.setAttribute("language", language);
+
+ Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo(language);
+ if(info) {
+ Kross::Api::InterpreterInfo::Option::Map defoptions = info->getOptions();
+ QMap<QString, QVariant>& options = d->scriptaction->getOptions();
+ QMap<QString, QVariant>::ConstIterator it, end( options.constEnd() );
+ for( it = options.constBegin(); it != end; ++it) {
+ if( defoptions.contains(it.key()) ) { // only remember options which the InterpreterInfo knows about...
+ scriptelem.setAttribute(it.key(), it.data().toString());
+ }
+ }
+ }
+
+ QDomText scriptcode = domdoc.createTextNode(d->scriptaction->getCode());
+ scriptelem.appendChild(scriptcode);
+
+ return storeDataBlock( domdoc.toString() );
+}
+
+#include "kexiscriptdesignview.moc"
+
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.h b/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.h
new file mode 100644
index 00000000..cee1ed76
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.h
@@ -0,0 +1,124 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 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 KEXISCRIPTDESIGNVIEW_H
+#define KEXISCRIPTDESIGNVIEW_H
+
+#include <kexiviewbase.h>
+
+#include <koproperty/set.h>
+#include <koproperty/property.h>
+
+// Forward declarations.
+class KexiScriptContainer;
+class KexiScriptEditor;
+class KexiScriptDesignViewPrivate;
+
+namespace Kross { namespace Api {
+ class ScriptAction;
+}}
+
+/**
+ * The KexiScriptDesignView class provides the \a KexiViewBase to
+ * manage script modules in the design-view. The design-view
+ * is used to be able to view and edit the scripting code via
+ * a \a KexiScriptEditor instance.
+ */
+class KexiScriptDesignView : public KexiViewBase
+{
+ Q_OBJECT
+
+ public:
+
+ /**
+ * Constructor.
+ */
+ KexiScriptDesignView(KexiMainWindow *mainWin, QWidget *parent, Kross::Api::ScriptAction* scriptaction);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KexiScriptDesignView();
+
+ /**
+ * \return the \a Kross::Api::ScriptAction this \a KexiScriptDesignView
+ * is responsible for.
+ */
+ Kross::Api::ScriptAction* scriptAction() const;
+
+ /**
+ * \return a property set for this view.
+ */
+ virtual KoProperty::Set* propertySet();
+
+ /**
+ * Try to call \a storeData with new data we like to store. On
+ * success the matching \a KexiDB::SchemaData is returned.
+ *
+ * \param sdata The source \a KexiDB::SchemaData instance.
+ * \param cancel Cancel on failure and don't try to clean
+ * possible temporary created data up.
+ * \return The matching \a KexiDB::SchemaData instance or NULL
+ * if storing failed.
+ */
+ virtual KexiDB::SchemaData* storeNewData(const KexiDB::SchemaData& sdata, bool &cancel);
+
+ /**
+ * Try to store the modified data in the already opened and
+ * currently used \a KexiDB::SchemaData instance.
+ */
+ virtual tristate storeData(bool dontAsk = false);
+
+ private slots:
+
+ /**
+ * Deferred initialization.
+ */
+ void initialize();
+
+ /**
+ * Handle changes in the property editor.
+ */
+ void slotPropertyChanged(KoProperty::Set& set, KoProperty::Property& property);
+
+ /**
+ * Update the \a KoProperty::Property::Dict propertymap of the
+ * interpreter-dependent options.
+ */
+ void updateProperties();
+
+ /**
+ * Execute the scripting code.
+ */
+ void execute();
+
+ private:
+ KexiScriptDesignViewPrivate* d;
+
+ /**
+ * Load the data from XML source and fill the internally
+ * used \a Kross::Api::ScriptContainer instance.
+ */
+ bool loadData();
+};
+
+#endif
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscripteditor.cpp b/kexi/plugins/scripting/kexiscripting/kexiscripteditor.cpp
new file mode 100644
index 00000000..a638af36
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscripteditor.cpp
@@ -0,0 +1,104 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 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 "kexiscripteditor.h"
+
+#include <kross/main/scriptaction.h>
+
+#include <kdebug.h>
+//#include <kparts/factory.h>
+//#include <klibloader.h>
+//#include <kmdimainfrm.h>
+//#include <kmainwindow.h>
+#include <kpopupmenu.h>
+
+#include <kexidialogbase.h>
+
+/// \internal d-pointer class
+class KexiScriptEditor::Private
+{
+ public:
+ Kross::Api::ScriptAction* scriptaction;
+ Private() : scriptaction(0) {}
+};
+
+KexiScriptEditor::KexiScriptEditor(KexiMainWindow *mainWin, QWidget *parent, const char *name)
+ : KexiEditor(mainWin, parent, name)
+ , d( new Private() )
+{
+}
+
+KexiScriptEditor::~KexiScriptEditor()
+{
+ delete d;
+}
+
+bool KexiScriptEditor::isInitialized() const
+{
+ return d->scriptaction != 0;
+}
+
+void KexiScriptEditor::initialize(Kross::Api::ScriptAction* scriptaction)
+{
+ d->scriptaction = scriptaction;
+ Q_ASSERT(d->scriptaction);
+
+ disconnect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));
+
+ QString code = d->scriptaction->getCode();
+ if(code.isNull()) {
+ // If there is no code we just add some information.
+///@todo remove after release
+ code = "# " + QStringList::split("\n", i18n(
+ "This note will appear for a user in the script's source code "
+ "as a comment. Keep every row not longer than 60 characters and use '\n.'",
+
+ "This is Technology Preview (BETA) version of scripting\n"
+ "support in Kexi. The scripting API may change in details\n"
+ "in the next Kexi version.\n"
+ "For more information and documentation see\n%1"
+ ).arg("http://www.kexi-project.org/scripting/"), true).join("\n# ") + "\n";
+ }
+ KexiEditor::setText(code);
+ // We assume Kross and the HighlightingInterface are using same
+ // names for the support languages...
+ setHighlightMode(d->scriptaction->getInterpreterName());
+
+ clearUndoRedo();
+ KexiEditor::setDirty(false);
+ connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));
+}
+
+void KexiScriptEditor::slotTextChanged()
+{
+ KexiScriptEditor::setDirty(true);
+ if(d->scriptaction)
+ d->scriptaction->setCode( KexiEditor::text() );
+}
+
+void KexiScriptEditor::setLineNo(long lineno)
+{
+ setCursorPosition(lineno, 0);
+}
+
+#include "kexiscripteditor.moc"
+
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscripteditor.h b/kexi/plugins/scripting/kexiscripting/kexiscripteditor.h
new file mode 100644
index 00000000..1ef02ff9
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscripteditor.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 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 KEXISCRIPTEDITOR_H
+#define KEXISCRIPTEDITOR_H
+
+#include <kexieditor.h>
+
+namespace Kross { namespace Api {
+ class ScriptAction;
+}}
+
+/**
+ * The KexiEditor class embeds text editor
+ * for editing scripting code.
+ */
+class KexiScriptEditor : public KexiEditor
+{
+ Q_OBJECT
+
+ public:
+
+ /**
+ * Constructor.
+ */
+ KexiScriptEditor(KexiMainWindow *mainWin, QWidget *parent, const char *name = 0);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KexiScriptEditor();
+
+ /**
+ * \returns true if this editor is already initialized (\a initialize was
+ * called) else false is returned.
+ */
+ bool isInitialized() const;
+
+ /**
+ * Initializes the editor. Call this if you like to start
+ * with a clear editor instance. Thinks like the language
+ * highlighter will be reset, undo/redo are cleared and
+ * setDirty(false) is set.
+ */
+ void initialize(Kross::Api::ScriptAction* scriptaction);
+
+ public slots:
+ void slotTextChanged();
+ void setLineNo(long);
+
+ private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscripthandler.desktop b/kexi/plugins/scripting/kexiscripting/kexiscripthandler.desktop
new file mode 100644
index 00000000..66e5f9fb
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscripthandler.desktop
@@ -0,0 +1,105 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Kexi/Handler
+
+GenericName=Scripts
+GenericName[bg]=Скриптове
+GenericName[br]=Urzhiaouegoù
+GenericName[ca]=Seqüències
+GenericName[cs]=Skripty
+GenericName[cy]=Sgriptiau
+GenericName[da]=Scripter
+GenericName[de]=Skripte
+GenericName[el]=Σενάρια
+GenericName[eo]=Skriptoj
+GenericName[es]=Guiones
+GenericName[et]=Skriptid
+GenericName[eu]=Script-ak
+GenericName[fa]=دست‌نوشته‌ها
+GenericName[fi]=Skriptit
+GenericName[fy]=Skripts
+GenericName[ga]=Scripteanna
+GenericName[gl]=Programas
+GenericName[he]=תסריטים
+GenericName[hr]=Skripte
+GenericName[hu]=Szkriptek
+GenericName[is]=Skriftur
+GenericName[it]=Script
+GenericName[ja]=スクリプト
+GenericName[km]=ស្គ្រីប​
+GenericName[lt]=Scenarijai
+GenericName[lv]=Skripti
+GenericName[ms]=Skrip
+GenericName[nb]=Skript
+GenericName[nds]=Skripten
+GenericName[ne]=स्क्रिप्टहरू
+GenericName[nn]=Skript
+GenericName[pl]=Skrypty
+GenericName[pt]=Programas
+GenericName[ru]=Сценарии
+GenericName[se]=Skriptat
+GenericName[sk]=Skripty
+GenericName[sl]=Skripti
+GenericName[sr]=Скрипте
+GenericName[sr@Latn]=Skripte
+GenericName[sv]=Skript
+GenericName[uk]=Скрипти
+GenericName[uz]=Skriptlar
+GenericName[uz@cyrillic]=Скриптлар
+GenericName[zh_CN]=脚本
+GenericName[zh_TW]=命令稿
+Name=Scripts
+Name[bg]=Скриптове
+Name[br]=Urzhiaouegoù
+Name[ca]=Seqüències
+Name[cs]=Skripty
+Name[cy]=Sgriptiau
+Name[da]=Scripter
+Name[de]=Skripte
+Name[el]=Σενάρια
+Name[eo]=Skriptoj
+Name[es]=Guiones
+Name[et]=Skriptid
+Name[eu]=Script-ak
+Name[fa]=دست‌نوشته‌ها
+Name[fi]=Skriptit
+Name[fy]=Skripts
+Name[ga]=Scripteanna
+Name[gl]=Programas
+Name[he]=תסריטים
+Name[hr]=Skripte
+Name[hu]=Szkriptek
+Name[is]=Skriftur
+Name[it]=Script
+Name[ja]=スクリプト
+Name[km]=ស្គ្រីប​
+Name[lt]=Scenarijai
+Name[lv]=Skripti
+Name[ms]=Skrip
+Name[nb]=Skript
+Name[nds]=Skripten
+Name[ne]=स्क्रिप्टहरू
+Name[nn]=Skript
+Name[pl]=Skrypty
+Name[pt]=Programas
+Name[ru]=Сценарии
+Name[se]=Skriptat
+Name[sk]=Skripty
+Name[sl]=Skripti
+Name[sr]=Скрипте
+Name[sr@Latn]=Skripte
+Name[sv]=Skript
+Name[uk]=Скрипти
+Name[uz]=Skriptlar
+Name[uz@cyrillic]=Скриптлар
+Name[zh_CN]=脚本
+Name[zh_TW]=命令稿
+X-KDE-Library=kexihandler_script
+X-KDE-ParentApp=kexi
+X-Kexi-PartVersion=2
+X-Kexi-TypeName=script
+X-Kexi-TypeMime=kexi/script
+X-Kexi-ItemIcon=script
+X-Kexi-SupportsExecution=true
+X-Kexi-SupportsDataExport=false
+X-Kexi-SupportsPrinting=false
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscriptpart.cpp b/kexi/plugins/scripting/kexiscripting/kexiscriptpart.cpp
new file mode 100644
index 00000000..d650e958
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscriptpart.cpp
@@ -0,0 +1,201 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Sebastian Sauer <mail@dipe.org>
+
+ This library 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 library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "kexiscriptpart.h"
+#include "kexiscriptdesignview.h"
+
+#include "kexiviewbase.h"
+#include "keximainwindow.h"
+#include "kexiproject.h"
+
+#include <kross/main/manager.h>
+#include <kross/main/scriptaction.h>
+#include <kross/main/scriptguiclient.h>
+
+#include <kgenericfactory.h>
+#include <kexipartitem.h>
+#include <kxmlguiclient.h>
+#include <kexidialogbase.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+/// \internal
+class KexiScriptPart::Private
+{
+ public:
+ Kross::Api::ScriptGUIClient* scriptguiclient;
+};
+
+KexiScriptPart::KexiScriptPart(QObject *parent, const char *name, const QStringList &l)
+ : KexiPart::Part(parent, name, l)
+ , d( new Private() )
+{
+ d->scriptguiclient = 0;
+
+ // REGISTERED ID:
+ m_registeredPartID = (int)KexiPart::ScriptObjectType;
+
+ m_names["instanceName"]
+ = i18n("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). "
+ "Use '_' character instead of spaces. First character should be a..z character. "
+ "If you cannot use latin characters in your language, use english word.",
+ "script");
+ m_names["instanceCaption"] = i18n("Script");
+ m_supportedViewModes = Kexi::DesignViewMode;
+}
+
+KexiScriptPart::~KexiScriptPart()
+{
+ delete d->scriptguiclient;
+ delete d;
+}
+
+bool KexiScriptPart::execute(KexiPart::Item* item, QObject* sender)
+{
+ Q_UNUSED(sender);
+
+ if(! item) {
+ kdWarning() << "KexiScriptPart::execute: Invalid item." << endl;
+ return false;
+ }
+
+ KexiDialogBase* dialog = new KexiDialogBase(m_mainWin);
+ dialog->setId( item->identifier() );
+ KexiScriptDesignView* view = dynamic_cast<KexiScriptDesignView*>( createView(dialog, dialog, *item, Kexi::DesignViewMode) );
+ if(! view) {
+ kdWarning() << "KexiScriptPart::execute: Failed to create a view." << endl;
+ return false;
+ }
+
+ Kross::Api::ScriptAction* scriptaction = view->scriptAction();
+ if(scriptaction) {
+
+ const QString dontAskAgainName = "askExecuteScript";
+ KConfig* config = KGlobal::config();
+ QString dontask = config->readEntry(dontAskAgainName).lower();
+
+ bool exec = (dontask == "yes");
+ if( !exec && dontask != "no" ) {
+ exec = KMessageBox::warningContinueCancel(0,
+ i18n("Do you want to execute the script \"%1\"?\n\nScripts obtained from unknown sources can contain dangerous code.").arg(scriptaction->text()),
+ i18n("Execute Script?"), KGuiItem(i18n("Execute"), "exec"),
+ dontAskAgainName, KMessageBox::Notify | KMessageBox::Dangerous
+ ) == KMessageBox::Continue;
+ }
+
+ if(exec) {
+ //QTimer::singleShot(10, scriptaction, SLOT(activate()));
+ d->scriptguiclient->executeScriptAction( scriptaction );
+ }
+ }
+
+ view->deleteLater(); // not needed any longer.
+ return true;
+}
+
+void KexiScriptPart::initPartActions()
+{
+ if(m_mainWin) {
+ // At this stage the KexiPart::Part::m_mainWin should be defined, so
+ // that we are able to use it's KXMLGUIClient.
+
+ // Initialize the ScriptGUIClient.
+ d->scriptguiclient = new Kross::Api::ScriptGUIClient( m_mainWin );
+
+ // Publish the KexiMainWindow singelton instance. At least the KexiApp
+ // scripting-plugin depends on this instance and loading the plugin will
+ // fail if it's not avaiable.
+ if(! Kross::Api::Manager::scriptManager()->hasChild("KexiMainWindow")) {
+ Kross::Api::Manager::scriptManager()->addQObject(m_mainWin, "KexiMainWindow");
+
+ // Add the KAction's provided by the ScriptGUIClient to the
+ // KexiMainWindow.
+ //FIXME: fix+use createSharedPartAction() whyever it doesn't work as expected right now...
+ QPopupMenu* popup = m_mainWin->findPopupMenu("tools");
+ if(popup) {
+ KAction* execscriptaction = d->scriptguiclient->action("executescriptfile");
+ if(execscriptaction)
+ execscriptaction->plug( popup );
+ KAction* configscriptaction = d->scriptguiclient->action("configurescripts");
+ if(configscriptaction)
+ configscriptaction->plug( popup );
+ KAction* scriptmenuaction = d->scriptguiclient->action("installedscripts");
+ if(scriptmenuaction)
+ scriptmenuaction->plug( popup );
+ /*
+ KAction* execscriptmenuaction = d->scriptguiclient->action("executedscripts");
+ if(execscriptmenuaction)
+ execscriptmenuaction->plug( popup );
+ KAction* loadedscriptmenuaction = d->scriptguiclient->action("loadedscripts");
+ if(loadedscriptmenuaction)
+ loadedscriptmenuaction->plug( popup );
+ */
+ }
+ }
+ }
+}
+
+void KexiScriptPart::initInstanceActions()
+{
+ //createSharedAction(Kexi::DesignViewMode, i18n("Execute Script"), "player_play", 0, "data_execute");
+ createSharedAction(Kexi::DesignViewMode, i18n("Configure Editor..."), "configure", 0, "script_config_editor");
+}
+
+KexiViewBase* KexiScriptPart::createView(QWidget *parent, KexiDialogBase* dialog, KexiPart::Item& item, int viewMode, QMap<QString,QString>*)
+{
+ QString partname = item.name();
+ if( ! partname.isNull() ) {
+ KexiMainWindow *win = dialog->mainWin();
+ if(!win || !win->project() || !win->project()->dbConnection())
+ return 0;
+
+ Kross::Api::ScriptActionCollection* collection = d->scriptguiclient->getActionCollection("projectscripts");
+ if(! collection) {
+ collection = new Kross::Api::ScriptActionCollection( i18n("Scripts"), d->scriptguiclient->actionCollection(), "projectscripts" );
+ d->scriptguiclient->addActionCollection("projectscripts", collection);
+ }
+
+ const char* name = partname.latin1();
+ Kross::Api::ScriptAction::Ptr scriptaction = collection->action(name);
+ if(! scriptaction) {
+ scriptaction = new Kross::Api::ScriptAction(partname);
+ collection->attach(scriptaction); //TODO remove again on unload!
+ }
+
+ if(viewMode == Kexi::DesignViewMode) {
+ return new KexiScriptDesignView(win, parent, scriptaction);
+ }
+ }
+ return 0;
+}
+
+QString KexiScriptPart::i18nMessage(const QCString& englishMessage) const
+{
+ if (englishMessage=="Design of object \"%1\" has been modified.")
+ return i18n("Design of script \"%1\" has been modified.");
+ if (englishMessage=="Object \"%1\" already exists.")
+ return i18n("Script \"%1\" already exists.");
+ return englishMessage;
+}
+
+K_EXPORT_COMPONENT_FACTORY( kexihandler_script, KGenericFactory<KexiScriptPart>("kexihandler_script") )
+
+#include "kexiscriptpart.moc"
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscriptpart.h b/kexi/plugins/scripting/kexiscripting/kexiscriptpart.h
new file mode 100644
index 00000000..ddba0d72
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscriptpart.h
@@ -0,0 +1,100 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Sebastian Sauer <mail@dipe.org>
+
+ This library 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 library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXISCRIPTPART_H
+#define KEXISCRIPTPART_H
+
+#include <qdom.h>
+#include <qcstring.h>
+
+#include <kexi.h>
+#include <kexipart.h>
+#include <kexidialogbase.h>
+
+/**
+ * Kexi Scripting Plugin.
+ */
+class KexiScriptPart : public KexiPart::Part
+{
+ Q_OBJECT
+
+ public:
+
+ /**
+ * Constructor.
+ *
+ * \param parent The parent QObject this part is child of.
+ * \param name The name this part has.
+ * \param args Optional list of arguments passed to this part.
+ */
+ KexiScriptPart(QObject *parent, const char *name, const QStringList& args);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KexiScriptPart();
+
+ /**
+ * Implementation of the \a KexiPart::Part::execute method used to
+ * execute the passed \p item instance.
+ */
+ virtual bool execute(KexiPart::Item* item, QObject* sender = 0);
+
+ /**
+ * \return the i18n message for the passed \p englishMessage string.
+ */
+ virtual QString i18nMessage(const QCString& englishMessage) const;
+
+ protected:
+
+ /**
+ * Create a new view.
+ *
+ * \param parent The parent QWidget the new view is displayed in.
+ * \param dialog The \a KexiDialogBase the view is child of.
+ * \param item The \a KexiPart::Item this view is for.
+ * \param viewMode The viewmode we like to have a view for.
+ */
+ virtual KexiViewBase* createView(QWidget *parent,
+ KexiDialogBase* dialog,
+ KexiPart::Item& item,
+ int viewMode = Kexi::DesignViewMode,
+ QMap<QString,QString>* staticObjectArgs = 0);
+
+ /**
+ * Initialize the part's actions.
+ */
+ virtual void initPartActions();
+
+ /**
+ * Initialize the instance actions.
+ */
+ virtual void initInstanceActions();
+
+ private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif
+
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscriptpartinstui.rc b/kexi/plugins/scripting/kexiscripting/kexiscriptpartinstui.rc
new file mode 100644
index 00000000..16124c34
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscriptpartinstui.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kexiscriptpartinst" version="14">
+
+ <MenuBar>
+ <Menu name="settings" noMerge="1">
+ <Action name="script_config_editor"/>
+ </Menu>
+ </MenuBar>
+
+</kpartgui>
diff --git a/kexi/plugins/scripting/kexiscripting/kexiscriptpartui.rc b/kexi/plugins/scripting/kexiscripting/kexiscriptpartui.rc
new file mode 100644
index 00000000..171d643f
--- /dev/null
+++ b/kexi/plugins/scripting/kexiscripting/kexiscriptpartui.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kexiscriptpart" version="10">
+
+ <MenuBar>
+ <Menu name="settings" noMerge="1">
+ <Action name="script_config_editor"/>
+ </Menu>
+ </MenuBar>
+
+</kpartgui>
diff --git a/kexi/plugins/scripting/scripts/Makefile.am b/kexi/plugins/scripting/scripts/Makefile.am
new file mode 100644
index 00000000..b63eedee
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = exportxhtml importxhtml projectdocumentor copycenter python
diff --git a/kexi/plugins/scripting/scripts/copycenter/CopyCenter.py b/kexi/plugins/scripting/scripts/copycenter/CopyCenter.py
new file mode 100644
index 00000000..3718512f
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/copycenter/CopyCenter.py
@@ -0,0 +1,644 @@
+"""
+Copy Center
+
+Description:
+Python script to copy data between different datastores.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+Dual-licensed under LGPL v2+higher and the BSD license.
+"""
+
+class CopyCenter:
+
+ class Plugin:
+ def __init__(self, plugin):
+ self.plugin = plugin
+ self.name = plugin.name
+ self.source = self.load("Source")
+ self.destination = self.load("Destination")
+
+ def load(self, plugintype):
+ instance = None
+ try:
+ if hasattr(self.plugin, plugintype):
+ return getattr(self.plugin, plugintype)(self.plugin)
+ except:
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ return None
+
+ def __init__(self, scriptpath):
+ self.scriptpath = scriptpath
+ self.homepath = self.getHomePath()
+ self.plugins = {}
+
+ import os
+ import sys
+ if not os.path.exists(scriptpath):
+ print "The Path %s does not exist" % scriptpath
+ else:
+ import re
+ regexp = re.compile('^CopyCenterPlugin(.*)\\.py$')
+ for f in os.listdir(scriptpath):
+ file = os.path.join(scriptpath, f)
+ if not os.path.isfile(file): continue
+ m = regexp.match(f)
+ if not m: continue
+ print "Plugin name=%s file=%s" % (m.group(1),file)
+ mylocals = {}
+ try:
+ execfile(file, globals(), mylocals)
+ if mylocals.has_key("CopyCenterPlugin"):
+ plugin = mylocals.get("CopyCenterPlugin")(self)
+ self.plugins[plugin.name] = self.Plugin(plugin)
+ except:
+ print "Failed to import file=%s" % file
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+
+ def getHomePath(self):
+ """ 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 Copierer:
+ def __init__(self): pass
+ def appendProgressMessage(self,messagetext): pass
+ def writeSuccess(self,record,rowcount): pass
+ def writeFailed(self,record): pass
+
+def runGuiApp(copycenter, name):
+ import qt
+ import sys
+
+ #--------------------------------------------------------------------
+
+ class ListViewDialog(qt.QDialog):
+ def __init__(self, parent, caption):
+ qt.QDialog.__init__(self, parent, "ProgressDialog", 1)
+ self.parent = parent
+ self.setCaption(caption)
+ layout = qt.QVBoxLayout(self)
+ box = qt.QVBox(self)
+ box.setMargin(2)
+ layout.addWidget(box)
+ self.listview = qt.QListView(box)
+ self.listview.setAllColumnsShowFocus(True)
+ self.listview.header().setStretchEnabled(True,0)
+ btnbox = qt.QHBox(box)
+ btnbox.setMargin(6)
+ btnbox.setSpacing(6)
+ self.okbtn = qt.QPushButton(btnbox)
+ self.okbtn.setText("Ok")
+ #qt.QObject.connect(okbtn, qt.SIGNAL("clicked()"), self.okClicked)
+ self.cancelbtn = qt.QPushButton(btnbox)
+ self.cancelbtn.setText("Cancel")
+ qt.QObject.connect(self.cancelbtn, qt.SIGNAL("clicked()"), self.close)
+ box.setMinimumSize(qt.QSize(460,380))
+ def addItem(self,valuelist,afteritem = None):
+ if afteritem == None:
+ item = qt.QListViewItem(self.listview)
+ else:
+ item = qt.QListViewItem(self.listview,afteritem)
+ i = 0
+ for value in valuelist:
+ item.setText(i,value)
+ i += 1
+ return item
+
+ #--------------------------------------------------------------------
+
+ class CopyJobWidget(qt.QVBox):
+ def __init__(self,dialog,parent):
+ self.dialog = dialog
+ qt.QVBox.__init__(self,parent)
+ self.setSpacing(6)
+ typebox = qt.QHBox(self)
+ typebox.setSpacing(6)
+ label = qt.QLabel("Job File:",typebox)
+ self.jobfilecombobox = qt.QComboBox(typebox)
+ typebox.setStretchFactor(self.jobfilecombobox,1)
+ self.jobfilecombobox.setEditable(True)
+ self.jobfilecombobox.insertItem("")
+ label.setBuddy(self.jobfilecombobox)
+ qt.QObject.connect(self.jobfilecombobox, qt.SIGNAL("textChanged(const QString&)"), self.jobfilecomboboxChanged)
+
+ import os
+ import re
+ for f in os.listdir(self.dialog.copycenter.homepath):
+ file = os.path.join(self.dialog.copycenter.homepath,f)
+ if os.path.isfile(file) and re.search(".+\\.copycenterjob.xml$",f):
+ self.jobfilecombobox.insertItem(file)
+
+ loadbtn = qt.QPushButton(typebox)
+ loadbtn.setText("Open...")
+ qt.QObject.connect(loadbtn, qt.SIGNAL("clicked()"), self.openClicked)
+ savebtn = qt.QPushButton(typebox)
+ savebtn.setText("Save...")
+ qt.QObject.connect(savebtn, qt.SIGNAL("clicked()"), self.saveClicked)
+
+ self.listview = qt.QListView(self)
+ self.listview.setAllColumnsShowFocus(True)
+ self.listview.setSorting(-1)
+ self.listview.setDefaultRenameAction(qt.QListView.Reject)
+ self.listview.header().setClickEnabled(False)
+ self.listview.addColumn("Name")
+ self.listview.addColumn("Value")
+ qt.QObject.connect(self.listview, qt.SIGNAL("doubleClicked(QListViewItem*, const QPoint&, int)"), self.doubleClicked)
+ #qt.QObject.connect(self.listview, qt.SIGNAL("itemRenamed(QListViewItem*, int, const QString&)"), self.itemRenamed)
+
+ def doubleClicked(self, **args):
+ print "CopyJobWidget.doubleClicked"
+ item = self.listview.selectedItem()
+ if item and item.parent(): item.startRename(1)
+
+ def readOptions(self,domnode,plugininst):
+ print "CopyJobWidget.readOptions plugintype=\"%s\"" % plugininst.plugintype
+ for node in domnode.childNodes:
+ if node.nodeType == node.ELEMENT_NODE:
+ v = node.getAttribute("value")
+ plugininst.options[node.nodeName] = v
+ print "Option \"%s\" has value \"%s\" now." % (node.nodeName, v)
+
+ def jobfilecomboboxChanged(self, **args):
+ print "CopyJobWidget.jobfilecomboboxChanged"
+ import os
+ import xml.dom.minidom
+ filename = str(self.jobfilecombobox.currentText())
+ if not os.path.isfile(filename): return
+ domdoc = xml.dom.minidom.parse(filename)
+ try:
+ elements = domdoc.getElementsByTagName("CopyCenterJob")[0]
+ sourcenode = elements.getElementsByTagName("Source")[0]
+ destinationnode = elements.getElementsByTagName("Destination")[0]
+ except:
+ raise "The XML-file \"%s\" does not contain a valid copy-job." % filename
+
+ sourcepluginname = str(sourcenode.getAttribute('plugin'))
+ if not self.dialog.sourcedata.combobox.listBox().findItem(sourcepluginname,qt.Qt.ExactMatch):
+ raise "There exists no plugin with the name \"%s\"." % sourcepluginname
+ self.dialog.sourcedata.combobox.setCurrentText(sourcepluginname)
+
+ destinationpluginname = str(destinationnode.getAttribute('plugin'))
+ if not self.dialog.destinationdata.combobox.listBox().findItem(destinationpluginname,qt.Qt.ExactMatch):
+ raise "There exists no plugin with the name \"%s\"." % destinationpluginname
+ self.dialog.destinationdata.combobox.setCurrentText(destinationpluginname)
+
+ self.readOptions(sourcenode,self.dialog.getSourcePluginImpl())
+ self.readOptions(destinationnode,self.dialog.getDestinationPluginImpl())
+ self.maybeUpdate()
+
+ def openClicked(self):
+ text = str(self.jobfilecombobox.currentText())
+ if text == "": text = self.dialog.copycenter.homepath
+ filename = str(qt.QFileDialog.getOpenFileName(text,"*.copycenterjob.xml;;*",self.dialog))
+ if filename != "": self.jobfilecombobox.setCurrentText(filename)
+
+ def escape(self,s):
+ return s.replace("&", "&amp;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;")
+
+ def writeOptions(self,writer,pluginname,plugininst):
+ print "CopyJobWidget.writeOptions"
+ writer.write("<%s plugin=\"%s\">\n" % (plugininst.plugintype, pluginname))
+ for optionname in plugininst.options:
+ value = self.escape( unicode(plugininst.options[optionname]).encode("utf-8") )
+ writer.write("\t<%s value=\"%s\" />\n" % (optionname,value))
+ writer.write("</%s>\n" % plugininst.plugintype)
+
+ def saveClicked(self):
+ text = str(self.jobfilecombobox.currentText())
+ if text == "":
+ import os
+ text = os.path.join(self.dialog.copycenter.homepath,"default.copycenterjob.xml")
+ filename = str(qt.QFileDialog.getSaveFileName(text,"*.copycenterjob.xml;;*",self.dialog))
+ if str(filename) == "": return
+ f = open(filename, "w")
+ f.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+ f.write("<CopyCenterJob>\n")
+ sourcepluginname = self.dialog.sourcedata.combobox.currentText()
+ self.writeOptions(f, sourcepluginname, self.dialog.getSourcePluginImpl())
+ destinationpluginname = self.dialog.destinationdata.combobox.currentText()
+ self.writeOptions(f, destinationpluginname, self.dialog.getDestinationPluginImpl())
+ f.write("</CopyCenterJob>\n")
+ f.close()
+ print "File \%s\" successfully written." % filename
+
+ def addItem(self, pluginimpl, afteritem = None, parentitem = None):
+ #print "CopyJobWidget.addItem"
+ class ListViewItem(qt.QListViewItem):
+ def __init__(self, pluginimpl, listview, parentitem = None, afteritem = None):
+ self.pluginimpl = pluginimpl
+ if parentitem == None:
+ qt.QListViewItem.__init__(self,listview)
+ self.setOpen(True)
+ else:
+ if afteritem == None:
+ qt.QListViewItem.__init__(self,parentitem)
+ else:
+ qt.QListViewItem.__init__(self,parentitem,afteritem)
+ self.setRenameEnabled(1,True)
+ def startRename(self, columnindex):
+ qt.QListViewItem.startRename(self,columnindex)
+ #lineedit = self.listView().viewport().child("qt_renamebox")
+ #if lineedit:
+ # regexp = qt.QRegExp("^[_A-Z]+[_A-Z0-9]*$", False)
+ # v = qt.QRegExpValidator(regexp, self.listView());
+ # lineedit.setValidator(v)
+ def okRename(self, columnindex):
+ if columnindex == 1:
+ n = str(self.text(0))
+ if not self.pluginimpl.options.has_key(n):
+ raise "No such option \"%s\"" % n
+ qt.QListViewItem.okRename(self,columnindex)
+ v = str(qt.QListViewItem.text(self,1))
+ print "Option \"%s\" has value \"%s\" now." % (n,v)
+ self.pluginimpl.options[n] = v
+
+ def text(self, columnindex):
+ if columnindex == 1:
+ if qt.QListViewItem.text(self,0).contains("password"):
+ return "*" * len(str(qt.QListViewItem.text(self,1)))
+ return qt.QListViewItem.text(self,columnindex)
+ return ListViewItem(pluginimpl, self.listview, parentitem, afteritem)
+
+ def updateItem(self,pluginname,pluginimpl):
+ #print "CopyJobWidget.updateItem"
+ if pluginimpl == None: return
+ #plugin = self.dialog.plugins[pluginname]
+ item = self.addItem(pluginimpl)
+ item.setText(0,"%s: %s" % (pluginimpl.plugintype, pluginname))
+ afteritem = None
+ for i in pluginimpl.options:
+ afteritem = self.addItem(pluginimpl, afteritem, item)
+ afteritem.setText(0,str(i))
+ afteritem.setText(1,str(pluginimpl.options[i]))
+ print "CopyJobWidget.updateItem Added item with name \"%s\" and value \"%s\"" % (str(i),str(pluginimpl.options[i]))
+ pass
+
+ def maybeUpdate(self):
+ print "CopyJobWidget.maybeUpdate"
+ self.listview.clear()
+ try:
+ self.updateItem(self.dialog.getDestinationPluginName(), self.dialog.getDestinationPluginImpl())
+ self.updateItem(self.dialog.getSourcePluginName(), self.dialog.getSourcePluginImpl())
+ except:
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ self.listview.clear()
+
+ #--------------------------------------------------------------------
+
+ class ProgressDialog(qt.QDialog):
+ def __init__(self, dialog):
+ self.dialog = dialog
+ self.starttime = None
+ qt.QDialog.__init__(self, dialog, "ProgressDialog", 1)
+ self.setCaption("Copying...")
+ layout = qt.QVBoxLayout(self)
+ box = qt.QVBox(self)
+ box.setSpacing(6)
+ box.setMargin(6)
+ layout.addWidget(box)
+ self.textbrowser = qt.QTextBrowser(box)
+ self.textbrowser.setWordWrap(qt.QTextEdit.WidgetWidth)
+ self.textbrowser.setTextFormat(qt.Qt.RichText)
+ statusbox = qt.QFrame(box)
+ layout = qt.QGridLayout(statusbox,4,2,0,2)
+ layout.addWidget(qt.QLabel("Number of records done:",statusbox),0,0)
+ self.donecounter = 0
+ self.donelabel = qt.QLabel("-",statusbox)
+ layout.addWidget(self.donelabel,0,1)
+ layout.addWidget(qt.QLabel("Successfully copied records:",statusbox),1,0)
+ self.successcounter = 0
+ self.successlabel = qt.QLabel("-",statusbox)
+ layout.addWidget(self.successlabel,1,1)
+ layout.addWidget(qt.QLabel("Failed to copy records:",statusbox),2,0)
+ self.failedcounter = 0
+ self.failedlabel = qt.QLabel("-",statusbox)
+ layout.addWidget(self.failedlabel,2,1)
+ layout.addWidget(qt.QLabel("Elapsed time in seconds:",statusbox),3,0)
+ self.elapsedlabel = qt.QLabel("-",statusbox)
+ layout.addWidget(self.elapsedlabel,3,1)
+ btnbox = qt.QHBox(box)
+ btnbox.setSpacing(6)
+ self.donebtn = qt.QPushButton(btnbox)
+ self.donebtn.setText("Done")
+ self.donebtn.setEnabled(False)
+ qt.QObject.connect(self.donebtn,qt.SIGNAL("clicked()"),self.close)
+ self.cancelbtn = qt.QPushButton(btnbox)
+ self.cancelbtn.setText("Cancel")
+ qt.QObject.connect(self.cancelbtn,qt.SIGNAL("clicked()"),self.close)
+ box.setMinimumSize( qt.QSize(500,380) )
+
+ def updateStates(self):
+ if self.starttime != None:
+ self.donelabel.setText(str(self.donecounter))
+ self.failedlabel.setText(str(self.failedcounter))
+ self.successlabel.setText(str(self.successcounter))
+ self.elapsedlabel.setText( str(self.starttime.elapsed() / 1000) )
+ self.donelabel.update()
+ self.failedlabel.update()
+ self.successlabel.update()
+ self.elapsedlabel.update()
+
+ def writeSuccess(self, record, rowcount):
+ self.donecounter += rowcount
+ self.successcounter += rowcount
+ qt.qApp.processEvents()
+ def writeFailed(self, record):
+ self.donecounter += 1
+ self.failedcounter += 1
+ qt.qApp.processEvents()
+
+ def startCopy(self):
+ try:
+ global Copierer
+ copierer = Copierer()
+ copierer.appendProgressMessage = self.textbrowser.append
+ copierer.writeSuccess = self.writeSuccess
+ copierer.writeFailed = self.writeFailed
+
+ self.starttime = qt.QTime()
+ self.updatetimer = qt.QTimer(self)
+ qt.QObject.connect(self.updatetimer,qt.SIGNAL("timeout()"),self.updateStates)
+
+ # Initialize the source
+ sourcename = self.dialog.getSourcePluginName()
+ sourceimpl = self.dialog.getSourcePluginImpl()
+ self.textbrowser.append("Source: %s" % sourcename)
+ if sourceimpl == None:
+ raise "No such source."
+ try:
+ sourceimpl.init(copierer)
+
+ # Initialize the destination
+ destinationname = self.dialog.getDestinationPluginName()
+ destinationimpl = self.dialog.getDestinationPluginImpl()
+ self.textbrowser.append("<hr>Destination: %s" % destinationname)
+ if destinationimpl == None:
+ raise "No such destination."
+ try:
+ destinationimpl.init(copierer)
+
+ self.starttime.start()
+ self.updatetimer.start(500)
+ qt.qApp.processEvents()
+
+ # Copy the records
+ self.textbrowser.append("<hr><i>Copy the records...</i>")
+ while True:
+ record = sourceimpl.read()
+ if record == None: break
+ destinationimpl.write(record)
+
+ self.updateStates()
+ finally:
+ destinationimpl.finish()
+ finally:
+ sourceimpl.finish()
+
+ self.setCaption("Copy done")
+ self.textbrowser.append("<hr><b>Copy done.</b>")
+ except:
+ self.setCaption("Copy failed")
+ self.textbrowser.append("<b>Error: %s</b>" % sys.exc_info()[0])
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ #self.progressbar.setEnabled(False)
+ self.donebtn.setEnabled(True)
+ self.cancelbtn.setEnabled(False)
+ self.updatetimer.stop()
+ self.starttime = None
+
+ def show(self):
+ qt.QDialog.show(self)
+ qt.QTimer.singleShot(10,self.startCopy)
+ qt.qApp.processEvents()
+
+ def closeEvent(self, closeevent):
+ if not self.dialog.getSourcePluginImpl().isFinished():
+ if qt.QMessageBox.warning(self,"Abort?","Abort the copy?",qt.QMessageBox.Yes,qt.QMessageBox.No) != qt.QMessageBox.Yes:
+ closeevent.ignore()
+ return
+ self.dialog.getSourcePluginImpl().finish()
+ self.dialog.getDestinationPluginImpl().finish()
+ closeevent.accept()
+
+ #--------------------------------------------------------------------
+
+ class DataSelector(qt.QVGroupBox):
+ def __init__(self, plugintype, title, caption, parent, dialog, items):
+ self.plugintype = plugintype
+ self.pluginimpl = None
+ self.dialog = dialog
+ self.mainbox = None
+
+ qt.QVGroupBox.__init__(self,title,parent)
+ self.setInsideMargin(6)
+ self.setInsideSpacing(0)
+
+ typebox = qt.QHBox(self)
+ label = qt.QLabel(caption,typebox)
+ self.combobox = qt.QComboBox(typebox)
+ for item in items:
+ self.combobox.insertItem(str(item))
+ label.setBuddy(self.combobox)
+ typebox.setStretchFactor(self.combobox,1)
+
+ self.scrollview = qt.QScrollView(self)
+ try:
+ self.scrollview.setResizePolicy(qt.QScrollView.AutoOne)
+ self.scrollview.setFrameStyle(qt.QFrame.NoFrame);
+ self.scrollview.setResizePolicy(qt.QScrollView.AutoOneFit);
+ self.scrollview.viewport().setPaletteBackgroundColor(self.paletteBackgroundColor())
+ except:
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ qt.QObject.connect(self.combobox, qt.SIGNAL("activated(int)"), self.activated)
+
+ def updatePlugin(self):
+ print "DataSelector.updatePlugin"
+ self.pluginimpl = None
+ text = str(self.combobox.currentText())
+ plugin = self.dialog.copycenter.plugins[text]
+ self.pluginimpl = getattr(plugin, self.plugintype)
+
+ def removeMainBox(self):
+ if self.mainbox == None: return
+ try:
+ self.scrollview.removeChild(self.mainbox)
+ self.mainbox.destroy()
+ except:
+ pass
+ self.mainbox = None
+
+ def updateMainBox(self):
+ print "DataSelector.updateMainBox"
+ self.removeMainBox()
+ self.mainbox = qt.QVBox( self.scrollview.viewport() )
+ self.mainbox.setSpacing(2)
+ if self.pluginimpl != None:
+ try:
+ self.pluginimpl.createWidget(self.dialog, self.mainbox)
+ except:
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ self.mainbox.setStretchFactor(qt.QWidget(self.mainbox), 1)
+ self.mainbox.show()
+ self.scrollview.addChild(self.mainbox)
+
+ def activated(self, **args):
+ self.updatePlugin()
+ self.updateMainBox()
+
+ def maybeUpdate(self):
+ print "DataSelector.maybeUpdate"
+ self.removeMainBox()
+ qt.QTimer.singleShot(50, self.activated)
+
+ def maybeDone(self):
+ print "DataSelector.maybeDone"
+ if self.pluginimpl.widget == None: return
+ for optionname in self.pluginimpl.options:
+ self.pluginimpl.options[optionname] = self.pluginimpl.widget.getOptionValue(optionname)
+
+ #--------------------------------------------------------------------
+
+ class Dialog(qt.QDialog):
+ def __init__(self, copycenter, parent):
+ self.copycenter = copycenter
+
+ import qt
+ import os
+ import sys
+
+ self.ListViewDialog = ListViewDialog
+ qt.QDialog.__init__(self, parent, "Dialog", 1, qt.Qt.WDestructiveClose)
+ self.setCaption("Copy Center")
+ layout = qt.QVBoxLayout(self)
+ box = qt.QVBox(self)
+ box.setMargin(6)
+ box.setSpacing(6)
+ layout.addWidget(box)
+ self.tab = qt.QTabWidget(box)
+ self.tab.setMargin(6)
+ box.setStretchFactor(self.tab,1)
+
+ self.jobsbox = CopyJobWidget(self,self.tab)
+ self.tab.addTab(self.jobsbox,"Jobs")
+
+ self.splitter = qt.QSplitter(self.tab)
+
+ sourceplugins = []
+ destinationplugins = []
+ for pluginname in self.copycenter.plugins:
+ if self.copycenter.plugins[pluginname].source != None:
+ sourceplugins.append(pluginname)
+ if self.copycenter.plugins[pluginname].destination != None:
+ destinationplugins.append(pluginname)
+ sourceplugins.sort()
+ destinationplugins.sort()
+
+ self.sourcedata = DataSelector(
+ "source", # id
+ "Read Data From", # title
+ "Source:", # caption
+ self.splitter, self, sourceplugins)
+ self.destinationdata = DataSelector(
+ "destination", # id
+ "Write Data to", # title
+ "Destination:", # caption
+ self.splitter, self, destinationplugins)
+
+ btnbox = qt.QHBox(box)
+ btnbox.setSpacing(6)
+ okbtn = qt.QPushButton(btnbox)
+ okbtn.setText("Start Copy")
+ okbtn.setDefault(True)
+ qt.QObject.connect(okbtn,qt.SIGNAL("clicked()"),self.startCopy)
+ cancelbtn = qt.QPushButton(btnbox)
+ cancelbtn.setText("Cancel")
+ qt.QObject.connect(cancelbtn,qt.SIGNAL("clicked()"),self.close)
+
+ self.tab.addTab(self.splitter,"Copy")
+ self.tab.setCurrentPage(1)
+
+ self.helpbrowser = qt.QTextBrowser(self.tab)
+ self.helpbrowser.setLinkUnderline(False)
+ self.helpbrowser.setUndoRedoEnabled(False)
+ self.tab.addTab(self.helpbrowser,"Help")
+ qt.QObject.connect(self.tab,qt.SIGNAL("currentChanged(QWidget*)"),self.currentTabChanged)
+
+ box.setMinimumSize( qt.QSize(760,500) )
+
+ defaultfile = os.path.join(self.copycenter.homepath,"default.copycenterjob.xml")
+ if os.path.isfile(defaultfile):
+ print "Reading default copy job file: %s" % defaultfile
+ self.jobsbox.jobfilecombobox.setCurrentText(defaultfile)
+
+ def getSourcePluginName(self):
+ return str(self.sourcedata.combobox.currentText())
+ def getSourcePluginImpl(self):
+ return self.copycenter.plugins[self.getSourcePluginName()].source
+ def getDestinationPluginName(self):
+ return str(self.destinationdata.combobox.currentText())
+ def getDestinationPluginImpl(self):
+ return self.copycenter.plugins[self.getDestinationPluginName()].destination
+
+ def currentTabChanged(self,widget):
+ if self.tab.currentPage() == self.jobsbox:
+ # The "Copy" page is done
+ self.sourcedata.maybeDone()
+ self.destinationdata.maybeDone()
+ # Update the "Jobs" page
+ self.jobsbox.maybeUpdate()
+ elif self.tab.currentPage() == self.splitter:
+ # Update the "Copy" page
+ self.sourcedata.maybeUpdate()
+ self.destinationdata.maybeUpdate()
+ elif self.tab.currentPage() == self.helpbrowser and self.helpbrowser.lines() <= 1:
+ # Update the "Help" page
+ import os
+ file = os.path.join(self.copycenter.scriptpath, "readme.html")
+ if not os.path.isfile(file): return
+ fh = open(file,'r')
+ self.helpbrowser.setText( fh.read() )
+ fh.close()
+
+ def startCopy(self):
+ dlg = ProgressDialog(self)
+ dlg.show()
+
+ #--------------------------------------------------------------------
+
+ if name == "__main__":
+ qtapp = qt.QApplication(sys.argv)
+ else:
+ qtapp = qt.qApp
+ dialog = Dialog(copycenter, qtapp.mainWidget())
+ dialog.exec_loop()
+
+import os
+
+if __name__ == "__main__":
+ scriptpath = os.getcwd()
+else:
+ scriptpath = os.path.dirname(__name__)
+
+copycenter = CopyCenter(scriptpath)
+runGuiApp(copycenter, __name__)
diff --git a/kexi/plugins/scripting/scripts/copycenter/CopyCenter.rc b/kexi/plugins/scripting/scripts/copycenter/CopyCenter.rc
new file mode 100644
index 00000000..e3e758b4
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/copycenter/CopyCenter.rc
@@ -0,0 +1,10 @@
+<KrossScripting>
+ <ScriptAction
+ name="CopyCenter"
+ version="1"
+ text="Copy Center"
+ description="Copy data from one source to another."
+ icon="editcopy"
+ interpreter="python"
+ file="CopyCenter.py" />
+</KrossScripting>
diff --git a/kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginKexiDB.py b/kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginKexiDB.py
new file mode 100644
index 00000000..e8241405
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginKexiDB.py
@@ -0,0 +1,646 @@
+"""
+CopyCenterPlugin to provide 'KexiDB'.
+
+Description:
+This python-script is a plugin for the CopyCenter.py.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+GPL v2 or higher.
+"""
+
+class CopyCenterPlugin:
+ """ The CopyCenterPlugin to provide abstract access to the 'KexiDB'
+ framework to CopyCenter.py """
+
+ name = "Kexi Database"
+ """ The name this plugin has. The name should be unique and
+ will be used for displaying a caption. """
+
+ class Plugin:
+ """ The implementation of a plugin which is published to the
+ CopyCenter.py script. While there exists only one instance of
+ the CopyCenterPlugin class, there will be n instances of this
+ Plugin class (one for 'source' aka read-data-from and one for
+ 'destination' aka write-data-to) created from within the
+ CopyCenter.py. The Source and Destination classes are extending
+ this Plugin class with specialized functionality. """
+ def __init__(self,copycenterplugin):
+ """ Constructor. """
+ self.copycenterplugin = copycenterplugin
+ self.widget = None
+ self.options = {
+ 'autoconnect' : False,
+ 'project' : '', #'~/test.kexi',
+ 'driver' : '', #'MySQL', #'SQLite3','MySQL',...
+ 'file' : '', #'/path/to/mysqlite3dbfile.kexi'
+ 'hostname' : '127.0.0.1',
+ 'port' : '',
+ 'usesocketfile' : False,
+ 'socketfile' : '',
+ 'username' : '',
+ 'password' : '',
+ 'database' : '',
+ 'table' : '',
+ 'fields' : '',
+ 'where' : '',
+ }
+ self.connection = copycenterplugin.Connection(self)
+ def isFinished(self):
+ return self.connection.isFinished()
+ def finish(self):
+ """ Called if reading is finished."""
+ self.connection.finish()
+ def createWidget(self, dialog, parent):
+ """ Create and return a widget to modify the plugin settings. """
+ return self.copycenterplugin.createWidget(dialog, self, parent)
+
+ class Source(Plugin):
+ """ Specialization of the Plugin class to implement the
+ 'source' aka read-data-from functionality. """
+ plugintype = "Source"
+ def init(self,copierer):
+ """ Called if reading should be initialize. """
+ self.connection.init(copierer)
+ self.connection.initRead()
+ # Called if a record should be readed.
+ self.read = self.connection.readRecord
+
+ class Destination(Plugin):
+ """ Specialization of the Plugin class to implement the
+ 'destination' aka write-data-to functionality. """
+ plugintype = "Destination"
+ def init(self,copierer):
+ """ Called if writing should be initialize. """
+ self.connection.init(copierer)
+ self.connection.initWrite()
+ # Called if a record should be written.
+ self.write = self.connection.writeRecord
+
+ class Connection:
+ """ Abstract access to work with KexiDB. """
+ def __init__(self,plugin):
+ self.plugin = plugin
+ self.copierer = None
+ self.kexidbconnection = None
+ self.kexidbcursor = None
+ self.tableschema = None
+ self.fieldlist = None
+ def lastError(self): return self.kexidbconnection.lastError()
+ def connect(self): return self.kexidbconnection.connect()
+ def disconnect(self):
+ if self.kexidbconnection == None or self.kexidbconnection.disconnect():
+ self.kexidbconnection = None
+ return True
+ return False
+ def isConnected(self): return self.kexidbconnection != None and self.kexidbconnection.isConnected()
+ def tableNames(self): return self.kexidbconnection.tableNames()
+ def hasTableName(self,tablename): return tablename in self.kexidbconnection.tableNames()
+ def tableSchema(self,tablename): return self.kexidbconnection.tableSchema(tablename)
+
+ def init(self,copierer):
+ self.copierer = copierer
+ if self.kexidbconnection == None:
+ if self.plugin.widget == None:
+ raise "No connection established."
+ self.copierer.appendProgressMessage("<i>Trying to connect...</i>")
+ if self.plugin.widget.driverbox.driver == None:
+ raise "Invalid driver."
+ if not self.plugin.widget.connectClicked():
+ raise "Failed to connect."
+ connectiondata = self.kexidbconnection.data()
+ self.copierer.appendProgressMessage("Connected: %s %s" % (connectiondata.driverName(),connectiondata.serverInfoString()))
+
+ tablename = str(self.plugin.widget.tablebox.tableedit.text())
+ if tablename == "":
+ raise "No table defined"
+ fields = [ f.strip() for f in str(self.plugin.widget.fieldbox.fieldsedit.text()).split(",") if len(f) > 0 ]
+ if len(fields) < 1:
+ raise "No fields defined"
+
+ self.tableschema = self.kexidbconnection.tableSchema(tablename)
+ if not self.tableschema: raise "No such tableschema \"%s\"" % tablename
+ self.copierer.appendProgressMessage("Table: %s" % self.tableschema.name())
+
+ if len(fields) == 1 and fields[0] == "*":
+ self.fieldlist = self.tableschema.fieldlist()
+ else:
+ self.fieldlist = self.tableschema.fieldlist().subList(fields)
+ if not self.fieldlist: raise "No such fields \"%s\"" % fields
+ fieldlistnames = self.fieldlist.names()
+ if len(fieldlistnames) < 1: raise "No valid fields defined for \"%s\"" % fields
+ self.copierer.appendProgressMessage("Fields: %s" % fieldlistnames)
+ def finish(self):
+ if self.plugin.widget == None:
+ self.disconnect()
+ else:
+ self.plugin.widget.disconnectClicked()
+ self.kexidbcursor = None
+ self.kexidbconnection = None
+ self.tableschema = None
+ self.fieldlist = None
+ self.copierer = None
+ def isFinished(self):
+ return self.copierer == None
+
+ def initRead(self):
+ print "Initialize read"
+ #queryschema = self.plugin.copycenterplugin.drivermanager.querySchema()
+ queryschema = self.tableschema.query()
+ queryschema.fieldlist().setFields(self.fieldlist)
+ print "QuerySchema: %s" % queryschema.fieldlist().names()
+
+ whereexpression = str(self.plugin.widget.whereedit.text())
+ if whereexpression != "":
+ print "WHERE-expression: %s" % whereexpression
+ if not queryschema.setWhereExpression(whereexpression):
+ raise "Invalid WHERE-expression."
+
+ #print "QuerySchema statement=%s" % queryschema.statement()
+ self.kexidbcursor = self.kexidbconnection.executeQuerySchema(queryschema)
+ if not self.kexidbcursor:
+ raise "Failed to create cursor."
+ if not self.kexidbcursor.moveFirst():
+ raise "The cursor has no records to read from."
+
+ def readRecord(self):
+ if self.kexidbcursor == None or self.kexidbcursor.eof():
+ return None
+ record = []
+ for i in range( self.kexidbcursor.fieldCount() ):
+ record.append( self.kexidbcursor.value(i) )
+ self.kexidbcursor.moveNext()
+ #print "read record: %s" % record
+ return record
+
+ def initWrite(self):
+ print "Initialize write"
+
+ def writeRecord(self,record):
+ print "write record: %s" % record
+ if self.kexidbconnection.insertRecord(self.fieldlist,record):
+ print "=> insert successfully"
+ self.copierer.writeSuccess(record, 1)
+ else:
+ print "=> insert failed: %s" % self.kexidbconnection.lastError()
+ self.copierer.writeFailed(record)
+ #import time
+ #time.sleep(1)
+ return True
+
+ def __init__(self, copycenter):
+ """ Constructor. """
+ import krosskexidb
+ self.drivermanager = krosskexidb.DriverManager()
+ self.copycenter = copycenter
+
+ def createWidget(self, dialog, plugin, parent):
+ """ Each plugin may provide a qt.QWidget back to the
+ CopyCenter.py. The widget will be used to configure our
+ plugin settings. """
+
+ import qt
+ import os
+ import re
+
+ self.dialog = dialog
+ self.mainbox = None
+ class ProjectBox(qt.QHBox):
+ def __init__(self,main,copycenterplugin,plugin,parent):
+ self.main = main
+ self.copycenterplugin = copycenterplugin
+ self.plugin = plugin
+
+ qt.QHBox.__init__(self,parent)
+ prjlabel = qt.QLabel("Project File:",self)
+ self.prjcombo = qt.QComboBox(self)
+ self.prjcombo.setEditable(True)
+ self.prjcombo.insertItem("")
+
+ path = copycenterplugin.copycenter.homepath
+ for f in os.listdir(path):
+ file = os.path.join(path,f)
+ if os.path.isfile(file) and re.search(".+\\.(kexi|kexis|kexic)$",f):
+ self.prjcombo.insertItem(os.path.join("~",f))
+
+ prjlabel.setBuddy(self.prjcombo)
+ prjsavebtn = qt.QPushButton("...",self)
+ qt.QObject.connect(prjsavebtn, qt.SIGNAL("clicked()"),self.buttonClicked)
+ qt.QObject.connect(self.prjcombo, qt.SIGNAL("textChanged(const QString&)"), self.main.projectChanged)
+ self.setStretchFactor(self.prjcombo,1)
+ def buttonClicked(self):
+ text = str(self.prjcombo.currentText())
+ if text == "":
+ text = self.copycenterplugin.copycenter.homepath
+ elif re.search("^\\~(\\/|\\\\)",text):
+ import os
+ text = os.path.join(self.copycenterplugin.copycenter.homepath,text[2:])
+ if self.plugin.plugintype == "Source":
+ filename = qt.QFileDialog.getOpenFileName(text,"*.kexi *.kexis *.kexic;;*",self.copycenterplugin.dialog)
+ else: # "Destination":
+ filename = qt.QFileDialog.getSaveFileName(text,"*.kexi *.kexis *.kexic;;*",self.copycenterplugin.dialog)
+ if str(filename) != "": self.prjcombo.setCurrentText(str(filename))
+
+ class DriverBox(qt.QVBox):
+ def __init__(self,main,parent):
+ qt.QVBox.__init__(self,parent)
+ self.main = main
+ self.copycenterplugin = main.copycenterplugin
+ self.plugin = main.plugin
+ self.driver = None
+
+ driverbox = qt.QHBox(self)
+ driverlabel = qt.QLabel("Driver:",driverbox)
+ self.drivercombo = qt.QComboBox(driverbox)
+ self.drivercombo.insertItem("")
+ for driver in self.copycenterplugin.drivermanager.driverNames():
+ self.drivercombo.insertItem(driver)
+
+ qt.QObject.connect(self.drivercombo, qt.SIGNAL("activated(int)"), self.activated)
+ driverlabel.setBuddy(self.drivercombo)
+ driverbox.setStretchFactor(self.drivercombo,1)
+
+ self.box = qt.QVBox(self)
+ self.mainbox = None
+
+ def activated(self,index):
+ drivertext = str(self.drivercombo.currentText())
+
+ self.box.hide()
+ if self.mainbox:
+ self.mainbox.hide()
+ self.mainbox.destroy()
+ self.mainbox = None
+ if index == 0 or drivertext == "":
+ self.driver = None
+ self.box.show()
+ self.main.updateConnectButtons()
+ return False
+
+ self.driver = self.copycenterplugin.drivermanager.driver(drivertext)
+
+ mainbox = qt.QVBox(self.box)
+ mainbox.setSpacing(2)
+
+ if self.driver.isFileDriver():
+ filebox = qt.QHBox(mainbox)
+ filelabel = qt.QLabel("File:",filebox)
+ self.fileedit = qt.QLineEdit(self.plugin.options['file'],filebox)
+ filelabel.setBuddy(self.fileedit)
+ filebox.setStretchFactor(self.fileedit,1)
+ filebtn = qt.QPushButton("...",filebox)
+ qt.QObject.connect(filebtn, qt.SIGNAL("clicked()"), self.fileClicked)
+ else:
+ hostbox = qt.QHBox(mainbox)
+ hostlabel = qt.QLabel("Hostname:",hostbox)
+ self.hostedit = qt.QLineEdit(self.plugin.options['hostname'],hostbox)
+ hostlabel.setBuddy(self.hostedit)
+ hostbox.setStretchFactor(self.hostedit,1)
+
+ portbox = qt.QHBox(mainbox)
+ portlabel = qt.QLabel("Port:",portbox)
+ self.portedit = qt.QLineEdit(self.plugin.options['port'],portbox)
+ portlabel.setBuddy(self.portedit)
+ portbox.setStretchFactor(self.portedit,1)
+
+ sockbox = qt.QHBox(mainbox)
+ self.sockfilecheckbox = qt.QCheckBox("Socket File:",sockbox)
+ qt.QObject.connect(self.sockfilecheckbox, qt.SIGNAL("toggled(bool)"), self.sockfilecheckboxClicked)
+ self.sockfilebox = qt.QHBox(sockbox)
+ self.sockfileedit = qt.QLineEdit(self.plugin.options['socketfile'],self.sockfilebox)
+ self.sockfilebox.setEnabled(False)
+ sockfilebtn = qt.QPushButton("...",self.sockfilebox)
+ self.sockfilecheckbox.setChecked( str(self.plugin.options['usesocketfile']) == str(True) )
+ qt.QObject.connect(sockfilebtn, qt.SIGNAL("clicked()"), self.sockfileClicked)
+ self.sockfilebox.setStretchFactor(self.sockfileedit,1)
+ sockbox.setStretchFactor(self.sockfilebox,1)
+
+ userbox = qt.QHBox(mainbox)
+ userlabel = qt.QLabel("Username:",userbox)
+ self.useredit = qt.QLineEdit(self.plugin.options['username'],userbox)
+ userlabel.setBuddy(self.useredit)
+ userbox.setStretchFactor(self.useredit,1)
+
+ passbox = qt.QHBox(mainbox)
+ passlabel = qt.QLabel("Password:",passbox)
+ self.passedit = qt.QLineEdit(self.plugin.options['password'],passbox)
+ self.passedit.setEchoMode(qt.QLineEdit.Password)
+ passlabel.setBuddy(self.passedit)
+ passbox.setStretchFactor(self.passedit,1)
+
+ dbbox = qt.QHBox(mainbox)
+ dblabel = qt.QLabel("Database:",dbbox)
+ self.dbedit = qt.QLineEdit(self.plugin.options['database'],dbbox)
+ dblabel.setBuddy(self.dbedit)
+ dbbox.setStretchFactor(self.dbedit,1)
+ #self.tablecombo.setText("")
+
+ self.mainbox = mainbox
+ self.mainbox.show()
+ self.box.show()
+ self.main.updateConnectButtons()
+ return True
+
+ def fileClicked(self):
+ text = str(self.fileedit.text())
+ if text == "": text = self.copycenterplugin.copycenter.homepath
+ if self.plugin.plugintype == "Source":
+ filename = qt.QFileDialog.getOpenFileName(text,"*",self.copycenterplugin.dialog)
+ else: # "Destination":
+ filename = qt.QFileDialog.getSaveFileName(text,"*",self.copycenterplugin.dialog)
+ if str(filename) != "": self.fileedit.setText(str(filename))
+ def sockfilecheckboxClicked(self,checked):
+ self.sockfilebox.setEnabled(checked)
+
+ def sockfileClicked(self):
+ text = str(self.sockfileedit.text())
+ if text == "": text = self.copycenterplugin.copycenter.homepath
+ if self.plugin.plugintype == "Source":
+ filename = qt.QFileDialog.getOpenFileName(text,"*",self.copycenterplugin.dialog)
+ else: # "Destination":
+ filename = qt.QFileDialog.getSaveFileName(text,"*",self.copycenterplugin.dialog)
+ if str(filename) != "": self.sockfileedit.setText(str(filename))
+
+ class TableBox(qt.QHBox):
+ def __init__(self,copycenterplugin,plugin,parent):
+ qt.QHBox.__init__(self,parent)
+ self.copycenterplugin = copycenterplugin
+ self.plugin = plugin
+ tablelabel = qt.QLabel("Table:",self)
+ self.tableedit = qt.QLineEdit(self.plugin.options['table'],self)
+ self.tablebtn = qt.QPushButton("...",self)
+ self.tablebtn.setEnabled(False)
+ qt.QObject.connect(self.tablebtn, qt.SIGNAL("clicked()"), self.buttonClicked)
+ tablelabel.setBuddy(self.tableedit)
+ self.setStretchFactor(self.tableedit,1)
+ def buttonClicked(self):
+ ListViewDialog = self.copycenterplugin.dialog.ListViewDialog
+ class TableDialog(ListViewDialog):
+ def __init__(self,tablebox):
+ ListViewDialog.__init__(self,tablebox,"Tables")
+ self.mainwidget = tablebox
+ self.listview.addColumn("Name")
+ text = str(self.mainwidget.tableedit.text())
+ item = None
+ for table in self.mainwidget.plugin.connection.tableNames():
+ if item == None:
+ item = qt.QListViewItem(self.listview,table)
+ else:
+ item = qt.QListViewItem(self.listview,item,table)
+ if table == text:
+ self.listview.setSelected(item,True)
+ self.listview.ensureItemVisible(item)
+ qt.QObject.connect(self.listview, qt.SIGNAL("doubleClicked(QListViewItem*, const QPoint&, int)"), self.okClicked)
+ qt.QObject.connect(self.okbtn, qt.SIGNAL("clicked()"), self.okClicked)
+ def okClicked(self):
+ item = self.listview.selectedItem()
+ if item == None:
+ self.mainwidget.tableedit.setText("")
+ else:
+ self.mainwidget.tableedit.setText(item.text(0))
+ self.close()
+ dialog = TableDialog(self)
+ dialog.show()
+
+ class FieldBox(qt.QHBox):
+ def __init__(self,copycenterplugin,plugin,parent):
+ qt.QHBox.__init__(self,parent)
+ self.copycenterplugin = copycenterplugin
+ self.plugin = plugin
+ self.tablename = ""
+ fieldslabel = qt.QLabel("Fields:",self)
+ self.fieldsedit = qt.QLineEdit(self.plugin.options['fields'],self)
+ self.setStretchFactor(self.fieldsedit,1)
+ fieldslabel.setBuddy(self.fieldsedit)
+ self.fieldsbtn = qt.QPushButton("...",self)
+ self.fieldsbtn.setEnabled(False)
+ qt.QObject.connect(self.fieldsbtn, qt.SIGNAL("clicked()"), self.fieldsClicked)
+ def fieldsClicked(self):
+ ListViewDialog = self.copycenterplugin.dialog.ListViewDialog
+ class FieldsDialog(ListViewDialog):
+ def __init__(self, fieldbox):
+ ListViewDialog.__init__(self,fieldbox,"Fields")
+ self.fieldbox = fieldbox
+ self.listview.setSelectionMode(qt.QListView.Multi)
+ self.listview.setSorting(-1)
+ self.listview.header().setClickEnabled(False)
+ self.listview.addColumn("Name")
+ self.listview.addColumn("Type")
+ self.listview.addColumn("Options")
+ fieldslist = str(self.fieldbox.fieldsedit.text()).split(",")
+ allfields = ("*" in fieldslist)
+ tableschema = self.fieldbox.plugin.connection.tableSchema(self.fieldbox.tablename)
+ item = None
+ for field in tableschema.fieldlist().fields():
+ opts = []
+ for opt in ("isAutoInc","isNotNull","isNotEmpty"):
+ if getattr(field,opt)():
+ opts.append(opt[2:])
+ item = self.addItem(( field.name(),field.type(),",".join(opts) ),item)
+ if allfields or field.name() in fieldslist:
+ self.listview.setSelected(item,True)
+ qt.QObject.connect(self.okbtn, qt.SIGNAL("clicked()"), self.okClicked)
+ def okClicked(self):
+ selitems = []
+ item = self.listview.firstChild()
+ while item:
+ if item.isSelected():
+ selitems.append(str(item.text(0)))
+ item = item.nextSibling()
+ self.fieldbox.fieldsedit.setText(",".join(selitems))
+ self.close()
+ dialog = FieldsDialog(self)
+ dialog.show()
+ def tableChanged(self, text):
+ self.tablename = str(text)
+ if self.plugin.connection.isConnected():
+ if self.plugin.connection.hasTableName(self.tablename):
+ self.fieldsbtn.setEnabled(True)
+ return
+ self.fieldsbtn.setEnabled(False)
+
+ class MainBox(qt.QHBox):
+ def __init__(self,copycenterplugin,plugin,parent):
+ qt.QHBox.__init__(self,parent)
+ self.copycenterplugin = copycenterplugin
+ self.plugin = plugin
+
+ self.prjbox = ProjectBox(self,copycenterplugin,plugin,parent)
+ self.driverbox = DriverBox(self,parent)
+
+ statusbar = qt.QHBox(parent)
+ statusbar.setSpacing(2)
+ #self.statuslabel = qt.QLabel("Disconnected",statusbar)
+ #statusbar.setStretchFactor(self.statuslabel,1)
+ statusbar.setStretchFactor(qt.QWidget(statusbar),1)
+ self.connectbtn = qt.QPushButton("Connect",statusbar)
+ self.connectbtn.setEnabled(False)
+ qt.QObject.connect(self.connectbtn, qt.SIGNAL("clicked()"),self.connectClicked)
+ self.disconnectbtn = qt.QPushButton("Disconnect",statusbar)
+ self.disconnectbtn.setEnabled(False)
+ qt.QObject.connect(self.disconnectbtn, qt.SIGNAL("clicked()"),self.disconnectClicked)
+
+ #self.connectionbox = ConnectionBox(copycenterplugin,plugin,parent)
+ self.tablebox = TableBox(copycenterplugin,plugin,parent)
+ self.fieldbox = FieldBox(copycenterplugin,plugin,parent)
+ qt.QObject.connect(self.tablebox.tableedit, qt.SIGNAL("textChanged(const QString&)"), self.fieldbox.tableChanged)
+
+ if self.plugin.options['project'] != '':
+ self.prjbox.prjcombo.setCurrentText(self.plugin.options['project'])
+
+ if self.plugin.options['driver'] != '':
+ try:
+ item = str(self.driverbox.drivercombo.listBox().findItem(self.plugin.options['driver'],qt.Qt.ExactMatch).text())
+ self.driverbox.drivercombo.setCurrentText(item)
+ self.driverbox.activated(item)
+ except:
+ pass
+
+ if self.plugin.plugintype == "Destination":
+ #typebox = qt.QHBox(parent)
+ #label = qt.QLabel("Operation:",typebox)
+ #combobox = qt.QComboBox(typebox)
+ #combobox.insertItem("Append")
+ #combobox.insertItem("Replace")
+ #combobox.insertItem("Update")
+ #combobox.insertItem("Update/Insert")
+ #combobox.insertItem("Insert new")
+ #label.setBuddy(combobox)
+ #typebox.setStretchFactor(combobox,1)
+ pass
+ elif self.plugin.plugintype == "Source":
+ wherebox = qt.QHBox(parent)
+ wherelabel = qt.QLabel("Where:",wherebox)
+ self.whereedit = qt.QLineEdit(self.plugin.options['where'],wherebox)
+
+ #orderbox = qt.QHBox(parent)
+ #orderlabel = qt.QLabel("Order By:",orderbox)
+ #orderedit = qt.QLineEdit("",orderbox)
+
+ #errbox = qt.QHBox(parent)
+ #errlabel = qt.QLabel("On Error:",errbox)
+ #errcombo = qt.QComboBox(errbox)
+ #errcombo.insertItem("Ask")
+ #errcombo.insertItem("Skip")
+ #errcombo.insertItem("Abort")
+ #errlabel.setBuddy(errcombo)
+ #errbox.setStretchFactor(errcombo,1)
+
+ if self.plugin.options['autoconnect']:
+ self.connectClicked()
+
+ def projectChanged(self, text):
+ #if self.driverbox.drivercombo.currentItem() != 0:
+ # self.driverbox.drivercombo.setCurrentItem(0)
+
+ file = str(text)
+ import os
+ if re.search("^\\~(\\/|\\\\)",file):
+ file = os.path.join(self.copycenterplugin.copycenter.homepath,file[2:])
+ if file == "" or not os.path.isfile(file):
+ self.driverbox.drivercombo.setCurrentItem(0)
+ self.driverbox.activated(0)
+ return
+
+ connectiondata = self.copycenterplugin.drivermanager.createConnectionDataByFile(file)
+ if connectiondata == None:
+ raise "Unsupported file."
+
+ drivername = connectiondata.driverName().lower()
+ print "driver: %s" % drivername
+ for i in range(1,self.driverbox.drivercombo.count()):
+ if drivername == self.driverbox.drivercombo.text(i).lower():
+ self.driverbox.drivercombo.setCurrentItem(i)
+ self.driverbox.activated(i)
+ break
+
+ if self.driverbox.driver != None:
+ if self.driverbox.driver.isFileDriver():
+ self.driverbox.fileedit.setText(connectiondata.fileName())
+ else: # server
+ self.driverbox.hostedit.setText(connectiondata.hostName())
+ self.driverbox.portedit.setText(str(connectiondata.port()))
+ self.driverbox.sockfilecheckbox.setChecked(connectiondata.localSocketFileUsed())
+ self.driverbox.sockfileedit.setText(connectiondata.localSocketFileName())
+ self.driverbox.useredit.setText(connectiondata.userName())
+ self.driverbox.passedit.setText(connectiondata.password())
+ self.driverbox.dbedit.setText(connectiondata.databaseName())
+
+ def connectClicked(self):
+ if self.driverbox.driver == None:
+ print "No driver selected."
+ return False
+ connectiondata = self.copycenterplugin.drivermanager.createConnectionData()
+ if self.driverbox.driver.isFileDriver():
+ file = str(self.driverbox.fileedit.text())
+ if file == "" or not os.path.isfile(file):
+ qt.QMessageBox.critical(self,"Failed to connect","There exists no such database file \"%s\"" % file)
+ return False
+ connectiondata.setFileName(file)
+ connectiondata.setDatabaseName(file)
+ else:
+ connectiondata.setHostName(str(self.driverbox.hostedit.text()))
+ connectiondata.setPort(str(self.driverbox.portedit.text()))
+ connectiondata.setLocalSocketFileUsed(self.driverbox.sockfilecheckbox.isChecked())
+ connectiondata.setLocalSocketFileName(str(self.driverbox.sockfileedit.text()))
+ connectiondata.setPassword(str(self.driverbox.passedit.text()))
+ connectiondata.setUserName(str(self.driverbox.useredit.text()))
+ connectiondata.setDatabaseName(str(self.driverbox.dbedit.text()))
+ print "Creating connection"
+ connection = self.driverbox.driver.createConnection(connectiondata)
+ print "Trying to connect"
+ if not connection.connect():
+ qt.QMessageBox.critical(self,"Failed to connect",connection.lastError())
+ return False
+ print "Use database \"%s\"" % connectiondata.databaseName()
+ if not connection.useDatabase( connectiondata.databaseName() ):
+ qt.QMessageBox.critical(self,"Failed to connect",connection.lastError())
+ return False
+ print "dbnames = %s" % connection.databaseNames()
+ print "tablenames = %s" % connection.tableNames()
+ #self.useDatabase(connection, filename)
+
+ self.plugin.connection.kexidbconnection = connection
+ self.updateConnectButtons()
+ return True
+
+ def disconnectClicked(self):
+ if not self.plugin.connection.disconnect():
+ qt.QMessageBox.critical(self,"Failed to disconnect",self.plugin.connection.lastError())
+ return
+ self.updateConnectButtons()
+
+ def updateConnectButtons(self):
+ connected = self.plugin.connection.isConnected()
+ self.prjbox.setEnabled(not connected)
+ self.driverbox.setEnabled(not connected)
+ self.connectbtn.setEnabled( (not connected) and (self.driverbox.driver != None) )
+ self.disconnectbtn.setEnabled(connected)
+ self.tablebox.tablebtn.setEnabled(connected)
+ self.fieldbox.tableChanged(self.tablebox.tableedit.text())
+
+ def getOptionValue(self,optionname):
+ try:
+ if optionname == 'project': return str(self.prjbox.prjcombo.currentText())
+ elif optionname == 'driver': return str(self.driverbox.drivercombo.currentText())
+ elif optionname == 'file': return str(self.driverbox.fileedit.text())
+ elif optionname == 'hostname': return str(self.driverbox.hostedit.text())
+ elif optionname == 'port': return str(self.driverbox.portedit.text())
+ elif optionname == 'usesocketfile': return str(self.driverbox.sockfilecheckbox.isChecked())
+ elif optionname == 'socketfile': return str(self.driverbox.sockfileedit.text())
+ elif optionname == 'username': return str(self.driverbox.useredit.text())
+ elif optionname == 'password': return str(self.driverbox.passedit.text())
+ elif optionname == 'database': return str(self.driverbox.dbedit.text())
+ elif optionname == 'table': return str(self.tablebox.tableedit.text())
+ elif optionname == 'fields': return str(self.fieldbox.fieldsedit.text())
+ elif optionname == 'where': return str(self.whereedit.text())
+ except:
+ pass
+ return ""
+
+ mainbox = MainBox(self,plugin,parent)
+ plugin.widget = mainbox
+ return mainbox
+
diff --git a/kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginQtSQL.py b/kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginQtSQL.py
new file mode 100644
index 00000000..985d757d
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/copycenter/CopyCenterPluginQtSQL.py
@@ -0,0 +1,495 @@
+"""
+CopyCenterPlugin to provide 'QtSQL'.
+
+Description:
+This python-script is a plugin for the CopyCenter.py.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+GPL v2 or higher.
+"""
+
+class CopyCenterPlugin:
+ """ The CopyCenterPlugin to provide 'QtSQL' to CopyCenter.py """
+
+ name = "QtSQL Database"
+ """ The name this plugin has. The name should be unique and
+ will be used for displaying a caption. """
+
+ class Plugin:
+ def _init_(self,copycenterplugin):
+ self.copycenterplugin = copycenterplugin
+ self.widget = None
+ self.database = None
+ self.cursor = None
+ self.isfinished = True
+ def _init(self,copierer):
+ self.copierer = copierer
+ if not self.widget.connectClicked():
+ raise "Failed to connect with database."
+ if self.database == None or not self.database.isOpen():
+ raise "Database is not initialized or not opened."
+ self.copierer.appendProgressMessage("Connected: %s %s@%s:%i %s" %
+ (str(self.database.driverName()),str(self.database.userName()),str(self.database.hostName()),self.database.port(),str(self.database.databaseName())) )
+ self.isfinished = False
+ def isFinished(self):
+ return self.isfinished
+ def finish(self):
+ self.isfinished = True
+ self.widget.disconnectClicked()
+ def createWidget(self,dialog,parent):
+ return self.copycenterplugin.widget(dialog, self, parent)
+
+ class Source(Plugin):
+ plugintype = "Source"
+ def __init__(self,copycenterplugin):
+ self._init_(copycenterplugin)
+ self.options = {
+ 'driver': 'QMYSQL3', #'QMYSQL3','QPSQL7','QODBC3',...
+ 'hostname': '127.0.0.1',
+ 'port': 3306,
+ 'username': 'root', #'MyUsername',
+ 'password': '', #'MySecretPassword',
+ 'database': '', #'MyQtSQLDatabase',
+ 'table': '', #'table1',
+ 'fields': '', #'f1,f2',
+ 'where': '',
+ }
+ def init(self,copierer):
+ self._init(copierer)
+ tablename = str(self.widget.tableedit.text())
+ wherestatement = str(self.widget.whereedit.text())
+ import qt
+ import qtsql
+ self.cursor = qtsql.QSqlCursor(tablename,True,self.database)
+ self.cursor.setFilter(wherestatement)
+ if not self.cursor.select():
+ raise "Select on cursor failed.<br>%s<br>%s" % ( str(self.cursor.lastError().driverText()),str(self.cursor.lastError().databaseText()) )
+ self.fieldlist = []
+ for fieldname in str(self.widget.fieldedit.text()).split(","):
+ fn = fieldname.strip()
+ if fn != "":
+ field = self.cursor.field(fn)
+ if not field:
+ raise "There exists no such field \"%s\" in the table \"%s\"." % (fn,tablename)
+ self.fieldlist.append(str(field.name()))
+ if len(self.fieldlist) < 1:
+ raise "No fields for table \"%s\" defined." % tablename
+ copierer.appendProgressMessage("SQL: %s" % str(self.cursor.executedQuery()))
+
+ def read(self):
+ if not self.cursor.next():
+ return None
+ record = []
+ for fieldname in self.fieldlist:
+ record.append( unicode(self.cursor.value(fieldname).toString()).encode("latin-1") )
+ #print "read record: %s" % record
+ return record
+
+ class Destination(Plugin):
+ plugintype = "Destination"
+ def __init__(self,copycenterplugin):
+ self._init_(copycenterplugin)
+ self.options = {
+ 'driver': 'QMYSQL3', #'QMYSQL3','QPSQL7','QODBC3',...
+ 'hostname': '127.0.0.1',
+ 'port': 3306,
+ 'username': 'root', #'MyUsername',
+ 'password': '', #'MySecretPassword',
+ 'database': '', #'MyQtSQLDatabase',
+ 'table': '', #'table2',
+ 'fields': '', #'field1,field2',
+ 'operation': 'Insert', #'Insert','Update'...
+ 'indexfield': '',
+ }
+ def init(self,copierer):
+ self._init(copierer)
+ import qt
+ import qtsql
+
+ self.fieldlist = []
+ for fieldname in str(self.widget.fieldedit.text()).split(","):
+ fn = fieldname.strip()
+ if fn != "": self.fieldlist.append(fn)
+
+ tablename = str(self.widget.tableedit.text())
+ self.cursor = qtsql.QSqlCursor(tablename,True,self.database)
+ {
+ 0: self.initInsert,
+ 1: self.initUpdate
+ }[ self.widget.operationedit.currentItem() ]()
+
+ def initInsert(self):
+ self.write = self.writeInsert
+ if not self.cursor.select():
+ raise "Select on cursor failed.<br>%s<br>%s" % ( str(self.cursor.lastError().driverText()),str(self.cursor.lastError().databaseText()) )
+ for fieldname in self.fieldlist: # check fieldlist
+ field = self.cursor.field(fieldname)
+ if not field: raise "There exists no such field \"%s\" in the table \"%s\"." % (fieldname, self.cursor.name())
+ self.copierer.appendProgressMessage("Insert SQL: %s" % str(self.cursor.executedQuery()))
+
+ def writeInsert(self, record):
+ print "insert record: %s" % record
+ import qt
+ cursorrecord = self.cursor.primeInsert()
+ count = len(record)
+ for i in range(len(self.fieldlist)):
+ if i == count: break
+ r = record[i]
+ if r == None:
+ v = qt.QVariant()
+ else:
+ v = qt.QVariant(r)
+ cursorrecord.setValue(self.fieldlist[i], v)
+ rowcount = self.cursor.insert()
+ if rowcount < 1:
+ drv = unicode(self.cursor.lastError().driverText()).encode("latin-1")
+ db = unicode(self.cursor.lastError().databaseText()).encode("latin-1")
+ print "failed: %s %s" % (drv,db)
+ self.copierer.writeFailed(record)
+ else:
+ self.copierer.writeSuccess(record,rowcount)
+ #import time
+ #time.sleep(1)
+ return True
+
+ def initUpdate(self):
+ self.write = self.writeUpdate
+ self.indexfieldname = str(self.widget.indexedit.text()).strip()
+ if self.indexfieldname == "": raise "No index-field defined."
+ pkindex = self.cursor.index(self.indexfieldname)
+ if not pkindex: raise "Invalid index-field defined."
+ self.cursor.setPrimaryIndex(pkindex)
+ #self.cursor.setMode( qtsql.QSqlCursor.Insert | qtsql.QSqlCursor.Update )
+ self.copierer.appendProgressMessage("Update SQL: %s" % str(self.cursor.executedQuery()))
+
+ def writeUpdate(self, record):
+ import qt
+ # determinate the primary-index
+ try:
+ idx = self.fieldlist.index(self.indexfieldname)
+ indexvalue = record[idx]
+ except:
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ raise "Failed to determinate the value for the primary key."
+ # select cursor and go to matching record.
+ wherestatement = "%s = \"%s\"" % (self.indexfieldname, indexvalue)
+ if not self.cursor.select(wherestatement):
+ raise "Select on cursor failed.<br>%s<br>%s" % ( str(self.cursor.lastError().driverText()),str(self.cursor.lastError().databaseText()) )
+ if not self.cursor.next():
+ #print "No such record to update !"
+ return False
+ # Prepare updating the record.
+ cursorrecord = self.cursor.primeUpdate()
+ # Update the fields in the record.
+ count = len(record)
+ for i in range(len(self.fieldlist)):
+ if i == count: break
+ fieldname = self.fieldlist[i]
+ if self.indexfieldname != fieldname: # don't update the indexfield!
+ r = record[i]
+ if r == None:
+ v = qt.QVariant()
+ else:
+ v = qt.QVariant(r)
+ cursorrecord.setValue(fieldname, v)
+ # Write updated record.
+ rowcount = self.cursor.update()
+ if rowcount < 1:
+ self.copierer.writeFailed(record)
+ else:
+ self.copierer.writeSuccess(record,rowcount)
+ print "updated record (rowcount %s): %s" % (rowcount,record)
+ return True
+
+ def __init__(self, copycenter):
+ """ Constructor. """
+ pass
+
+ def widget(self,dialog,plugin,parent):
+ """ Each plugin may provide a qt.QWidget back to the
+ CopyCenter.py. The widget will be used to configure our
+ plugin settings. """
+
+ import qt
+ import os
+
+ self.dialog = dialog
+ ListViewDialog = self.dialog.ListViewDialog
+ class TableDialog(ListViewDialog):
+ def __init__(self, mainwidget):
+ ListViewDialog.__init__(self,mainwidget,"Tables")
+ self.mainwidget = mainwidget
+ self.listview.addColumn("Name")
+ text = str(self.mainwidget.tableedit.text())
+ item = None
+ for table in self.mainwidget.plugin.database.tables():
+ if item == None:
+ item = qt.QListViewItem(self.listview,table)
+ else:
+ item = qt.QListViewItem(self.listview,item,table)
+ if table == text:
+ self.listview.setSelected(item,True)
+ self.listview.ensureItemVisible(item)
+ qt.QObject.connect(self.listview, qt.SIGNAL("doubleClicked(QListViewItem*, const QPoint&, int)"), self.okClicked)
+ qt.QObject.connect(self.okbtn, qt.SIGNAL("clicked()"), self.okClicked)
+ def okClicked(self):
+ item = self.listview.selectedItem()
+ if item == None:
+ self.mainwidget.tableedit.setText("")
+ else:
+ self.mainwidget.tableedit.setText(item.text(0))
+ self.close()
+
+ class FieldsDialog(ListViewDialog):
+ def __init__(self, mainwidget):
+ ListViewDialog.__init__(self,parent,"Fields")
+ self.mainwidget = mainwidget
+ self.listview.setSelectionMode(qt.QListView.Multi)
+ self.listview.setSorting(-1)
+ self.listview.header().setClickEnabled(False)
+ self.listview.addColumn("Name")
+ self.listview.addColumn("Type")
+ self.listview.addColumn("Options")
+ tablename = str(self.mainwidget.tableedit.text())
+ recinfo = self.mainwidget.plugin.database.recordInfo(tablename)
+ if recinfo != None:
+ fieldslist = str(self.mainwidget.fieldedit.text()).split(",")
+ allfields = ("*" in fieldslist)
+ item = None
+ for fieldinfo in recinfo:
+ opts = ""
+ for s in ('Required','Calculated'): #,'Generated'):
+ if getattr(fieldinfo,"is%s" % s)(): opts += "%s " % s
+ item = self.addItem((fieldinfo.name(), qt.QVariant.typeToName(fieldinfo.type()), opts),item)
+ if allfields or fieldinfo.name() in fieldslist:
+ self.listview.setSelected(item,True)
+ qt.QObject.connect(self.okbtn, qt.SIGNAL("clicked()"), self.okClicked)
+ def okClicked(self):
+ selitems = []
+ item = self.listview.firstChild()
+ while item:
+ if item.isSelected():
+ selitems.append(str(item.text(0)))
+ item = item.nextSibling()
+ self.mainwidget.fieldedit.setText(",".join(selitems))
+ self.close()
+
+
+ class MainWidget(qt.QHBox):
+ def __init__(self,plugin,dialog,parent):
+ import qt
+ import qtsql
+ qt.QHBox.__init__(self,parent)
+ self.dialog = dialog
+ self.plugin = plugin
+
+ self.connectionbox = qt.QVBox(parent)
+ self.connectionbox.setSpacing(2)
+
+ driverbox = qt.QHBox(self.connectionbox)
+ driverlabel = qt.QLabel("Driver:",driverbox)
+ self.driveredit = qt.QComboBox(driverbox)
+ for driver in qtsql.QSqlDatabase.drivers():
+ self.driveredit.insertItem(driver)
+ if self.plugin.options['driver'] == driver:
+ self.driveredit.setCurrentItem(self.driveredit.count() - 1)
+ driverlabel.setBuddy(self.driveredit)
+ driverbox.setStretchFactor(self.driveredit,1)
+
+ hostbox = qt.QHBox(self.connectionbox)
+ hostlabel = qt.QLabel("Hostname:",hostbox)
+ self.hostedit = qt.QLineEdit(self.plugin.options['hostname'],hostbox)
+ hostlabel.setBuddy(self.hostedit)
+ hostbox.setStretchFactor(self.hostedit,1)
+
+ portbox = qt.QHBox(self.connectionbox)
+ portlabel = qt.QLabel("Port:",portbox)
+ self.portedit = qt.QLineEdit(str(self.plugin.options['port']),portbox)
+ portlabel.setBuddy(self.portedit)
+ portbox.setStretchFactor(self.portedit,1)
+
+ userbox = qt.QHBox(self.connectionbox)
+ userlabel = qt.QLabel("Username:",userbox)
+ self.useredit = qt.QLineEdit(self.plugin.options['username'],userbox)
+ userlabel.setBuddy(self.useredit)
+ userbox.setStretchFactor(self.useredit,1)
+
+ passbox = qt.QHBox(self.connectionbox)
+ passlabel = qt.QLabel("Password:",passbox)
+ self.passedit = qt.QLineEdit(self.plugin.options['password'],passbox)
+ self.passedit.setEchoMode(qt.QLineEdit.Password)
+ passlabel.setBuddy(self.passedit)
+ passbox.setStretchFactor(self.passedit,1)
+
+ dbbox = qt.QHBox(self.connectionbox)
+ dblabel = qt.QLabel("Database:",dbbox)
+ self.dbedit = qt.QLineEdit(self.plugin.options['database'],dbbox)
+ dblabel.setBuddy(self.dbedit)
+ dbbox.setStretchFactor(self.dbedit,1)
+
+ statusbar = qt.QHBox(parent)
+ statusbar.setSpacing(2)
+ statusbar.setStretchFactor(qt.QWidget(statusbar),1)
+ self.connectbtn = qt.QPushButton("Connect",statusbar)
+ qt.QObject.connect(self.connectbtn, qt.SIGNAL("clicked()"),self.connectClicked)
+ self.disconnectbtn = qt.QPushButton("Disconnect",statusbar)
+ self.disconnectbtn.setEnabled(False)
+ qt.QObject.connect(self.disconnectbtn, qt.SIGNAL("clicked()"),self.disconnectClicked)
+
+ tablebox = qt.QHBox(parent)
+ tablelabel = qt.QLabel("Table:",tablebox)
+ self.tableedit = qt.QLineEdit(self.plugin.options['table'],tablebox)
+ qt.QObject.connect(self.tableedit, qt.SIGNAL("textChanged(const QString&)"), self.tableEditChanged)
+ self.tablebtn = qt.QPushButton("...",tablebox)
+ self.tablebtn.setEnabled(False)
+ qt.QObject.connect(self.tablebtn, qt.SIGNAL("clicked()"), self.tableBtnClicked)
+ tablelabel.setBuddy(self.tableedit)
+ tablebox.setStretchFactor(self.tableedit,1)
+
+ fieldbox = qt.QHBox(parent)
+ fieldlabel = qt.QLabel("Fields:",fieldbox)
+ self.fieldedit = qt.QLineEdit(self.plugin.options['fields'],fieldbox)
+ self.fieldbtn = qt.QPushButton("...",fieldbox)
+ self.fieldbtn.setEnabled(False)
+ qt.QObject.connect(self.fieldbtn, qt.SIGNAL("clicked()"), self.fieldBtnClicked)
+ fieldlabel.setBuddy(self.fieldedit)
+ fieldbox.setStretchFactor(self.fieldedit,1)
+
+ if self.plugin.plugintype == "Source":
+ box = qt.QHBox(parent)
+ wherelabel = qt.QLabel("Where:",box)
+ self.whereedit = qt.QLineEdit(self.plugin.options['where'],box)
+ wherelabel.setBuddy(self.whereedit)
+ box.setStretchFactor(self.whereedit,1)
+ elif self.plugin.plugintype == "Destination":
+
+ class OperationBox(qt.QVBox):
+ def __init__(self, mainwidget, parent):
+ self.mainwidget = mainwidget
+ qt.QVBox.__init__(self, parent)
+ opbox = qt.QHBox(self)
+ operationlabel = qt.QLabel("Operation:",opbox)
+ self.mainwidget.operationedit = qt.QComboBox(opbox)
+ for op in ('Insert','Update'):
+ self.mainwidget.operationedit.insertItem(op)
+ if self.mainwidget.plugin.options['operation'] == op:
+ self.mainwidget.operationedit.setCurrentItem(self.mainwidget.operationedit.count() - 1)
+ operationlabel.setBuddy(self.mainwidget.operationedit)
+ opbox.setStretchFactor(self.mainwidget.operationedit,1)
+ self.box = None
+ qt.QObject.connect(self.mainwidget.operationedit, qt.SIGNAL("activated(int)"), self.operationActivated)
+ self.operationActivated()
+ def operationActivated(self, **args):
+ if self.box:
+ self.box.hide()
+ self.box.destroy()
+ self.box = None
+ def showInsert(self):
+ pass
+ def showUpdate(self):
+ self.box = qt.QHBox(self)
+ indexlabel = qt.QLabel("Indexfield:", self.box)
+ self.mainwidget.indexedit = qt.QLineEdit(self.mainwidget.plugin.options['indexfield'], self.box)
+ indexlabel.setBuddy(self.mainwidget.indexedit)
+ self.box.setStretchFactor(self.mainwidget.indexedit,1)
+ {
+ 0: showInsert,
+ 1: showUpdate,
+ }[ self.mainwidget.operationedit.currentItem() ](self)
+ if self.box != None: self.box.show()
+ OperationBox(self,parent)
+
+ def tableEditChanged(self,text):
+ if self.plugin.database != None and self.plugin.database.isOpen():
+ if str(text) in self.plugin.database.tables():
+ self.fieldbtn.setEnabled(True)
+ return
+ self.fieldbtn.setEnabled(False)
+
+ def tableBtnClicked(self):
+ dialog = TableDialog(self)
+ dialog.show()
+
+ def fieldBtnClicked(self):
+ dialog = FieldsDialog(self)
+ dialog.show()
+
+ def updateConnectState(self):
+ connected = self.plugin.database != None and self.plugin.database.isOpen()
+ self.connectionbox.setEnabled(not connected)
+ self.connectbtn.setEnabled(not connected)
+ self.disconnectbtn.setEnabled(connected)
+ self.tablebtn.setEnabled(connected)
+ self.tableEditChanged(self.tableedit.text())
+
+ def getOptionValue(self,optionname):
+ try:
+ if optionname == 'driver': return str(self.driveredit.currentText())
+ if optionname == 'hostname': return str(self.hostedit.text())
+ if optionname == 'port': return str(self.portedit.text())
+ if optionname == 'username': return str(self.useredit.text())
+ if optionname == 'password': return str(self.passedit.text())
+ if optionname == 'database': return str(self.dbedit.text())
+ if optionname == 'table': return str(self.tableedit.text())
+ if optionname == 'fields': return str(self.fieldedit.text())
+ if optionname == 'where': return str(self.whereedit.text())
+ if optionname == 'operation': return str(self.operationedit.currentText())
+ if optionname == 'indexfield': return str(self.indexedit.text())
+ except:
+ import traceback
+ print "".join( traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]) )
+ return ""
+
+ def connectClicked(self):
+ if self.plugin.database != None and self.plugin.database.isOpen():
+ print "already connected. not needed to reconnect..."
+ self.updateConnectState()
+ return True
+ print "trying to connect..."
+
+ import qtsql
+ drivername = str(self.driveredit.currentText())
+ print "drivername: %s" % drivername
+ connectionname = "CopyCenter%s" % self.plugin.plugintype
+ print "connectionname: %s" % connectionname
+ self.plugin.database = qtsql.QSqlDatabase.addDatabase(drivername,connectionname)
+ if not self.plugin.database:
+ qt.QMessageBox.critical(self,"Failed to connect","<qt>Failed to create database for driver \"%s\"</qt>" % drivername)
+ return False
+
+ hostname = str(self.hostedit.text())
+ self.plugin.database.setHostName(hostname)
+
+ portnumber = int(str(self.portedit.text()))
+ self.plugin.database.setPort(portnumber)
+
+ username = str(self.useredit.text())
+ self.plugin.database.setUserName(username)
+
+ password = str(self.passedit.text())
+ self.plugin.database.setPassword(password)
+
+ databasename = str(self.dbedit.text())
+ self.plugin.database.setDatabaseName(databasename)
+
+ if not self.plugin.database.open():
+ qt.QMessageBox.critical(self,"Failed to connect","<qt>%s<br><br>%s</qt>" % (self.plugin.database.lastError().driverText(),self.plugin.database.lastError().databaseText()))
+ return False
+ print "database is opened now!"
+ self.updateConnectState()
+ return True
+
+ def disconnectClicked(self):
+ print "trying to disconnect..."
+ if self.plugin.database:
+ self.plugin.database.close()
+ self.plugin.database = None
+ print "database is closed now!"
+ self.updateConnectState()
+
+ plugin.widget = MainWidget(plugin,self.dialog,parent)
+ return plugin.widget
diff --git a/kexi/plugins/scripting/scripts/copycenter/Makefile.am b/kexi/plugins/scripting/scripts/copycenter/Makefile.am
new file mode 100644
index 00000000..d46928ed
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/copycenter/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+scriptsdir = $(kde_datadir)/kexi/scripts/copycenter
+scripts_SCRIPTS = CopyCenter.py CopyCenterPluginQtSQL.py CopyCenterPluginKexiDB.py CopyCenter.rc readme.html
diff --git a/kexi/plugins/scripting/scripts/copycenter/readme.html b/kexi/plugins/scripting/scripts/copycenter/readme.html
new file mode 100644
index 00000000..2aff6152
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/copycenter/readme.html
@@ -0,0 +1,20 @@
+<html><body>
+<h1>Copy Center</h1>
+
+<b>Version 1.2</b>
+
+<p>Python script to copy data between database backends. The flexible
+plugin-architecture allows transparent copies between different backends.</p>
+
+<ul>
+<li>Read+write Kexi Databases. This includes all database backends supported by Kexi (like SQLite, MySQL or PostgreSQL).</li>
+<li>Read+write QtSQL Databases. MySQL, PostgreSQL and UnixODBC are supported. There might even be more like Oracle in the commercial Qt version or 3rd party backends.</li>
+<li>Runs embedded in Kexi (from the tools=>scripts menu) as well as independent of Kexi (use "krossrunner ~/.kde/share/apps/kexi/scripts/copycenter/CopyCenter.py" or python direct).</li>
+<li>Depends only on PyQt. PyKDE is not used at all and Kross (included in KOffice 1.5) is optional.</li>
+</ul>
+
+Author: (C)2006 Sebastian Sauer (mail at dipe dot org)<br>
+Website: http://www.kde-files.org/content/show.php?content=35251<br>
+License: GPL v2 or higher<br>
+
+</body></html>
diff --git a/kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.py b/kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.py
new file mode 100644
index 00000000..cace0340
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.py
@@ -0,0 +1,196 @@
+"""
+Export table or query data.
+
+Description:
+This script exports a KexiDB table or query to different fileformats.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+Dual-licensed under LGPL v2+higher and the BSD license.
+"""
+
+class Datasource:
+ def __init__(self):
+ import kexiapp
+ keximainwindow = kexiapp.get("KexiAppMainWindow")
+
+ try:
+ self.connection = keximainwindow.getConnection()
+ except:
+ raise "No connection established. Please open a project before."
+
+ self.schema = None
+
+ def getSources(self):
+ sources = []
+ for table in self.connection.tableNames():
+ sources.append("Tables/%s" % table)
+ for query in self.connection.queryNames():
+ sources.append("Queries/%s" % query)
+ sources.sort()
+ return sources
+
+ def setSource(self, source):
+ s = source.split("/",1)
+ if s[0] == "Tables":
+ self.schema = self.connection.tableSchema( s[1] )
+ self.queryschema = self.schema.query()
+ elif s[0] == "Queries":
+ self.schema = self.connection.querySchema( s[1] )
+ self.queryschema = self.schema
+ self.cursor = None
+ return self.schema != None
+
+ def name(self):
+ return self.schema.name()
+
+ def caption(self):
+ return self.schema.caption()
+
+ def description(self):
+ return self.schema.description()
+
+ def header(self):
+ h = []
+ for field in self.schema.fieldlist().fields():
+ s = field.caption()
+ if s == None or s == "":
+ s = field.name()
+ h.append(s)
+ return h
+
+ def getNext(self):
+ if not self.cursor:
+ self.cursor = self.connection.executeQuerySchema( self.queryschema )
+ if not self.cursor:
+ raise "Failed to execute queryschema."
+ if not self.cursor.moveFirst():
+ raise "Failed to move cursor to first record."
+ if self.cursor.eof():
+ self.cursor = None
+ return None
+ items = []
+ for i in range( self.cursor.fieldCount() ):
+ items.append( self.cursor.value(i) )
+ self.cursor.moveNext()
+ return items
+
+class HtmlExporter:
+ def __init__(self, datasource):
+ self.datasource = datasource
+
+ def htmlescape(self, text):
+ import string
+ return string.replace(string.replace(string.replace(str(text),'&','&amp;'),'<','&lt;'),'>','&gt;')
+
+ def write(self, output, style):
+ name = self.datasource.name()
+
+ output.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n")
+ output.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n")
+ output.write("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n")
+ output.write("<head><title>%s</title>\n" % name)
+ output.write("<style type=\"text/css\">\n<!--\n")
+ if style == "Paper":
+ output.write("html { background-color:#efefef; }")
+ output.write("body { background-color:#fafafa; color:#303030; margin:1em; padding:1em; border:#606060 1px solid; }")
+ elif style == "Blues":
+ output.write("html { background-color:#0000aa; }")
+ output.write("body { background-color:#000066; color:#efefff; margin:1em; padding:1em; border:#00f 1px solid; }")
+ output.write("h1 { color:#0000ff; }")
+ output.write("th { color:#0000aa; }")
+ else:
+ output.write("html { background-color:#ffffff; color:#000; }")
+ output.write("body { margin:1em; }")
+ output.write("\n//-->\n</style>\n")
+ output.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n")
+ output.write("</head><body><h1>%s</h1>\n" % name)
+
+ caption = self.datasource.caption()
+ if caption and caption != name:
+ output.write("caption: %s<br />\n" % caption)
+
+ description = self.datasource.description()
+ if description:
+ output.write("description: %s<br />\n" % description)
+
+ #import datetime
+ #output.write("date: %s<br />" % datetime.datetime.now())
+
+ output.write("<table border='1'>\n")
+
+ output.write("<tr>")
+ for h in self.datasource.header():
+ output.write("<th>%s</th>" % h)
+ output.write("</tr>")
+
+ while 1 == 1:
+ items = self.datasource.getNext()
+ if items == None: break
+ output.write("<tr>")
+ for item in items:
+ u = unicode(str(self.htmlescape(item)),"latin-1")
+ output.write("<td>%s</td>" % u.encode("utf-8"))
+ output.write("</tr>\n")
+ output.write("</table>\n")
+ output.write("</body></html>\n")
+
+class GuiApp:
+ def __init__(self, datasource):
+ self.datasource = datasource
+
+ try:
+ import gui
+ except:
+ raise "Import of the Kross GUI module failed."
+
+ self.dialog = gui.Dialog("Export XHTML")
+ self.dialog.addLabel(self.dialog, "Export a table- or query-datasource to a XHTML-file.")
+
+ datasourceitems = self.datasource.getSources()
+ self.datasourcelist = self.dialog.addList(self.dialog, "Datasource:", datasourceitems)
+
+ styleitems = ["Plain", "Paper", "Blues"]
+ self.stylelist = self.dialog.addList(self.dialog, "Style:", styleitems)
+
+ #queryframe = Tkinter.Frame(frame)
+ #queryframe.pack()
+ #Tkinter.Label(queryframe, text="Table or query to export:").pack(side=Tkinter.LEFT)
+ #self.querycontent = Tkinter.StringVar()
+ #self.query = apply(Tkinter.OptionMenu, (queryframe, self.querycontent) + tuple( self.datasource.getSources() ))
+ #self.query.pack(side=Tkinter.LEFT)
+
+ self.file = self.dialog.addFileChooser(self.dialog,
+ "File:",
+ gui.getHome() + "/kexidata.xhtml",
+ (('XHTML files', '*.xhtml'),('All files', '*')))
+
+ btnframe = self.dialog.addFrame(self.dialog)
+ self.dialog.addButton(btnframe, "Export", self.doExport)
+ self.dialog.addButton(btnframe, "Cancel", self.dialog.close)
+
+ self.dialog.show()
+
+ def doExport(self):
+ file = str( self.file.get() )
+ query = str( self.datasourcelist.get() )
+ print "Exporting '%s' to file '%s' ..." % (query,file)
+
+ if not self.datasource.setSource(query):
+ raise "Invalid datasource selected."
+ #return
+
+ style = str( self.stylelist.get() )
+
+ f = open(file, "w")
+ global HtmlExporter
+ exporter = HtmlExporter(self.datasource)
+ exporter.write(f, style)
+ f.close()
+
+ print "Successfully exported '%s' to file %s" % (query,file)
+ self.dialog.close()
+
+GuiApp( Datasource() )
diff --git a/kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.rc b/kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.rc
new file mode 100644
index 00000000..11c1dcdf
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/exportxhtml/ExportXHTML.rc
@@ -0,0 +1,8 @@
+<KrossScripting>
+ <ScriptAction
+ name="exportxhtml"
+ text="Export Data to XHTML File"
+ icon="fileexport"
+ interpreter="python"
+ file="ExportXHTML.py" />
+</KrossScripting>
diff --git a/kexi/plugins/scripting/scripts/exportxhtml/Makefile.am b/kexi/plugins/scripting/scripts/exportxhtml/Makefile.am
new file mode 100644
index 00000000..1c7b9ca6
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/exportxhtml/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+scriptsdir = $(kde_datadir)/kexi/scripts/exportxhtml
+scripts_SCRIPTS = ExportXHTML.py ExportXHTML.rc
diff --git a/kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.py b/kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.py
new file mode 100755
index 00000000..200b3dee
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.py
@@ -0,0 +1,434 @@
+"""
+Import data from a XHTML file to a KexiDB table.
+
+Description:
+This script implements import of data from a XHTML file to a KexiDB table. The
+table needs to be an already existing table the data should be added to.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+Dual-licensed under LGPL v2+higher and the BSD license.
+"""
+
+class SaxInput:
+ """ The inputsource we like to import the data from. This class
+ provides us abstract access to the SAX XML parser we use internaly
+ to import data from the XML-file. """
+
+ xmlfile = None
+ """ The XML file we should read the content from. """
+
+ def __init__(self):
+ """ Constructor. """
+
+ # try to import the xml.sax python module.
+ try:
+ import xml.sax.saxlib
+ import xml.sax.saxexts
+ except:
+ raise "Import of the python xml.sax.saxlib module failed. This module is needed by the ImportXHTML python script."
+
+ def read(self, outputwriter):
+ """ Start reading and parsing the XML-file. """
+
+ import xml.sax.saxlib
+ import xml.sax.saxexts
+
+ class SaxHandler(xml.sax.saxlib.HandlerBase):
+ """ The SaxHandler is our event-handler SAX calls on
+ parsing the XML-file. """
+
+ tablebase = ["html","body","table"]
+ """ The table-base defines where we will find our table-tag
+ that holds all the data we are interessted at. The default
+ is to look at <html><body><table></table></body></html>. """
+
+ def __init__(self, inputreader, outputwriter):
+ """ Constructor. """
+
+ # The to a SaxInput instance pointing inputreader.
+ self.inputreader = inputreader
+ # The to a KexiDBOutput instance pointing outputwriter.
+ self.outputwriter = outputwriter
+ # The hierachy-level in the DOM-tree we are in.
+ self.level = 0
+ # Defines if we are in the with tablebase defined DOM-element.
+ self.intable = False
+
+ # Points to a KexiDBOutput.Record instance if we are in a DOM-element that defines a record.
+ self.record = None
+ # Points to a KexiDBOutput.Field instance if we are in a record's field.
+ self.field = None
+
+ def startDocument(self):
+ sys.stdout.write('=> Starting parsing\n')
+
+ def endDocument(self):
+ sys.stdout.write('=> Fineshed parsing\n')
+
+ def startElement(self, name, attrs):
+ """ This method is called by SAX if a DOM-element starts. """
+
+ if self.level < len(self.tablebase):
+ if self.tablebase[self.level] != name:
+ self.intable = False
+ else:
+ self.intable = True
+ self.level += 1
+ if not self.intable:
+ return
+
+ # Print some debugging-output to stdout.
+ for idx in range(self.level): sys.stdout.write(' ')
+ sys.stdout.write('Element: %s' % name)
+ for attrName in attrs.keys():
+ sys.stdout.write(' %s="%s"' % (attrName,attrs.get(attrName)))
+ sys.stdout.write('\n')
+
+ # handle tr-, th- and td-tags inside the table.
+ if name == "tr" and (self.level == len(self.tablebase) + 1):
+ self.record = self.outputwriter.Record()
+ elif name == "td" and (self.level == len(self.tablebase) + 2):
+ self.field = self.outputwriter.Field()
+ elif name == "th" and (self.level == len(self.tablebase) + 2):
+ self.field = self.outputwriter.Field()
+
+ def endElement(self, name):
+ """ This method is called by SAX if a DOM-Element ends. """
+
+ self.level -= 1
+ #sys.stdout.write('EndElement:%s level:%s len(self.tablebase):%s\n' % (name,self.level,len(self.tablebase)))
+
+ if self.record != None:
+ # a record is defined. so, we are looking for the matching
+ # end-tags to close a record or a field.
+ if name == "tr" and (self.level == len(self.tablebase)):
+ self.outputwriter.write(self.record)
+ self.record = None
+ self.field = None
+ elif name == "td" and (self.level == len(self.tablebase) + 1):
+ #if self.field == None:
+ # raise "Unexpected closing </td>"
+ self.record.setField( self.field )
+ self.field = None
+ elif name == "th" and (self.level == len(self.tablebase) + 1):
+ #if self.field == None:
+ # raise "Unexpected closing </td>"
+ self.record.setHeader( self.field )
+ self.field = None
+
+ def characters(self, chars, offset, length):
+ """ This method is called by SAX if the text-content of a DOM-Element
+ was parsed. """
+
+ if self.field != None:
+ # the xml-data is unicode and we need to encode it
+ # to latin-1 cause KexiDB deals only with latin-1.
+ u = unicode(chars[offset:offset+length])
+ self.field.append(u.encode("latin-1"))
+
+ # start the job
+ outputwriter.begin()
+ # create saxhandler to handle parsing events.
+ handler = SaxHandler(self, outputwriter)
+ # we need a sax-parser and connect it with the handler.
+ parser = xml.sax.saxexts.make_parser()
+ parser.setDocumentHandler(handler)
+ # open the XML-file, parse the content and close the file again.
+ f = file(self.xmlfile, 'r')
+ parser.parseFile(f)
+ f.close()
+ # job is done
+ outputwriter.end()
+
+class KexiDBOutput:
+ """ The destination target we like to import the data to. This class
+ provides abstract access to the KexiDB module. """
+
+ class Result:
+ """ Holds some informations about the import-result. """
+ def __init__(self, outputwriter):
+ self.outputwriter = outputwriter
+ # number of records successfully imported.
+ self.successcount = 0
+ # number of records where import failed.
+ self.failedcount = 0
+
+ def addLog(self, record, state):
+ import datetime
+ date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M.%S")
+ self.outputwriter.logfile.write("%s (%s) %s\n" % (date,state,str(record)))
+
+ def success(self, record):
+ """ Called if a record was written successfully. """
+ print "SUCCESS: %s" % str(record)
+ self.successcount += 1
+ if hasattr(self.outputwriter,"logfile"):
+ self.addLog(record, "Success")
+
+ def failed(self, record):
+ """ Called if we failed to write a record. """
+ print "FAILED: %s" % str(record)
+ self.failedcount += 1
+ if hasattr(self.outputwriter,"logfile"):
+ self.addLog(record, "Failed")
+
+ class Record:
+ """ A Record in the dataset. """
+ def __init__(self):
+ self.fields = []
+ def setHeader(self, headerfield):
+ self.fields.append( headerfield )
+ self.isHeader = True
+ def setField(self, field):
+ self.fields.append( field )
+ def __str__(self):
+ s = "["
+ for f in self.fields:
+ s += "%s, " % str(f)
+ return s + "]"
+
+ class Field:
+ """ A field in a record. """
+ def __init__(self):
+ self.content = []
+ def append(self, content):
+ self.content.append( content )
+ def __str__(self):
+ return "".join(self.content)
+
+ def __init__(self):
+ """ Constructor. """
+ import kexiapp
+ keximainwindow = kexiapp.get("KexiAppMainWindow")
+
+ try:
+ self.connection = keximainwindow.getConnection()
+ except:
+ raise "No connection established. Please open a project before."
+
+ self.fieldlist = None
+ self.headerrecord = None
+ self.mapping = {}
+
+ def begin(self):
+ """ Called before parsing starts. """
+ print "START JOB"
+ if self.fieldlist == None:
+ raise "Invalid tableschema or fieldlist!"
+ global KexiDBOutput
+ self.result = KexiDBOutput.Result(self)
+ if hasattr(self,"logfilename") and self.logfilename != None and self.logfilename != "":
+ self.logfile = open(self.logfilename,'w')
+
+ def end(self):
+ """ Called if parsing is fineshed. """
+ print "END JOB"
+ self.logfile = None
+ self.mapping = {}
+ #self.headerrecord = None
+
+ def getTables(self):
+ """ return a list of avaiable tablenames. """
+ tables = self.connection.tableNames()
+ tables.sort()
+ return tables
+
+ def setTable(self, tablename):
+ """ Set the tablename we like to import the data to. """
+ tableschema = self.connection.tableSchema(tablename)
+ if tableschema == None:
+ raise "There exists no table with the name '%s'!" % tablename
+ self.fieldlist = tableschema.fieldlist()
+ fields = self.fieldlist.fields()
+ for field in fields:
+ print "KexiDBOutput.setTable(%s): %s(%s)" % (tablename,field.name(),field.type())
+ print "names=%s" % self.fieldlist.names()
+
+ def setMapping(self, mapping):
+ """ Set the tablefieldname=xmlcolnr dictonary we should map the data to. """
+ self.mapping = mapping
+
+ def setLogFile(self, logfilename):
+ """ Set the name of the logfile. """
+ self.logfilename = logfilename
+
+ def write(self, record):
+ """ Write the record to the KexiDB table. """
+
+ if hasattr(record, "isHeader"):
+ self.headerrecord = record
+ return
+
+ sys.stdout.write('KexiDBOutput.write:')
+ for f in record.fields:
+ sys.stdout.write(' "%s"' % f)
+ sys.stdout.write('\n')
+
+ if hasattr(self,"onWrite"):
+ if not self.onWrite(record):
+ raise RuntimeError()
+ delattr(self,"onWrite")
+ self.fieldlist = self.fieldlist.subList( list( self.mapping ) )
+
+ # Translate a KexiDBOutput.Record into a list of values.
+ values = []
+ for k in self.fieldlist.names():
+ values.append( str(record.fields[ int(self.mapping[k]) ]) )
+ print "Import values: %s" % values
+
+ try:
+ if self.connection.insertRecord(self.fieldlist, values):
+ self.result.success(record)
+ else:
+ self.result.failed(record)
+ except:
+ err = self.connection.lastError()
+ raise Exception( "Failed to insert the record:\n%s\n\n%s" % (values,err) )
+ #raise Exception( "Failed to insert into table \"%s\" the record:\n%s\n%s" % (self.tableschema.name(),values,self.connection.lastError()) )
+
+class GuiApp:
+ """ The GUI-dialog displayed to let the user define the source
+ XML-file and the destination KexiDB table. """
+
+ class InitialDialog:
+ def __init__(self, guiapp):
+ self.guiapp = guiapp
+ self.ok = False
+
+ import gui
+ self.dialog = gui.Dialog("Import XHTML")
+ self.dialog.addLabel(self.dialog, "Import data from a XHTML-file to a KexiDB table.\n"
+ "The destination table needs to be an existing table the data should be added to.")
+ self.importfile = self.dialog.addFileChooser(self.dialog,
+ "Source File:",
+ gui.getHome() + "/kexidata.xhtml",
+ (('XHTML files', '*.xhtml'),('All files', '*')))
+
+ self.desttable = self.dialog.addList(self.dialog, "Destination Table:", self.guiapp.outputwriter.getTables())
+
+ #self.operation = self.dialog.addList(self.dialog, "Operation:", ("Insert","Update","Insert/Update"))
+ #self.error = self.dialog.addList(self.dialog, "On error:", ("Ask","Skip","Abort"))
+
+ self.logfile = self.dialog.addFileChooser(self.dialog,
+ "Log File:",
+ "",
+ (('Logfiles', '*.log'),('All files', '*')))
+
+ btnframe = self.dialog.addFrame(self.dialog)
+ self.dialog.addButton(btnframe, "Next", self.doNext)
+ self.dialog.addButton(btnframe, "Cancel", self.doCancel)
+ self.dialog.show()
+
+ def doCancel(self):
+ """ Called if the Cancel-button was pressed. """
+ self.dialog.close()
+ self.dialog = None
+ #self.guiapp.InitialDialog
+
+ def doNext(self):
+ """ Start to import the XML-file into the KexiDB table. """
+
+ self.guiapp.inputreader.xmlfile = str(self.importfile.get())
+ self.guiapp.outputwriter.setTable( str(self.desttable.get()) )
+ self.guiapp.outputwriter.setLogFile( str(self.logfile.get()) )
+
+ try:
+ self.guiapp.inputreader.read( self.guiapp.outputwriter )
+
+ msgbox = self.dialog.showMessageBox("info","Import done",
+ "Successfully imported records: %s\nFailed to import records: %s" % (self.guiapp.outputwriter.result.successcount, self.guiapp.outputwriter.result.failedcount) )
+ msgbox.show()
+
+ self.doCancel()
+ except RuntimeError, e:
+ pass
+ #except Exception, e:
+ # import traceback
+ # traceback.print_exc()
+ # msgbox = self.dialog.showMessageBox("error", "Error", e)
+ # msgbox.show()
+
+ class MapperDialog:
+ """ The dialog that provides us a way to map
+ XHTML columns to the destination table. """
+
+ def __init__(self, outputwriter, record):
+ self.outputwriter = outputwriter
+ self.ok = False
+ fieldlist = outputwriter.fieldlist
+
+ import gui
+ self.dlg = gui.Dialog("Import XHTML")
+ self.dlg.addLabel(self.dlg, "Define how the destination table should be mapped to the data from the XHTML file.")
+ values = ["",]
+ for i in range(len(record.fields)):
+ try:
+ values.append( "%s: %s" % (i,str(outputwriter.headerrecord.fields[i])) )
+ except:
+ values.append( "%s: (%s)" % (i,str(record.fields[i])) )
+
+ self.items = []
+ i = 0
+ for field in fieldlist.fields():
+ f = self.dlg.addFrame(self.dlg)
+
+ l = self.dlg.addList(f, "%s:" % field.name(), values)
+ self.items.append( (field,l) )
+
+ details = "%s:" % str( field.type() )
+ if field.isAutoInc(): details += "autoinc,"
+ if field.isUniqueKey(): details += "unique,"
+ if field.isNotNull(): details += "notnull,"
+ if field.isNotEmpty(): details += "notempty,"
+ self.dlg.addLabel(f, "(%s)" % details[:-1])
+
+ try:
+ variable = str( record.fields[i] )
+ try:
+ int(variable)
+ i += 1
+ if not field.isAutoInc():
+ l.set(i)
+ except ValueError, e:
+ if not field.type() in ("Integer","BigInteger","ShortInteger","Float","Double"):
+ i += 1
+ l.set(i)
+ except:
+ pass
+
+ btnframe = self.dlg.addFrame(self.dlg)
+ self.dlg.addButton(btnframe, "Next", self.doNext)
+ self.dlg.addButton(btnframe, "Cancel", self.dlg.close)
+ self.dlg.show()
+
+ def doNext(self):
+ mapping = {}
+ for item in self.items:
+ (field,l) = item
+ fieldname = field.name()
+ colnr = str( l.get() ).split(":",1)[0]
+ if colnr.isdigit():
+ print "Table field '%s' is mapped to XML column '%s'" % (fieldname,colnr)
+ mapping[ fieldname ] = colnr
+ self.outputwriter.setMapping(mapping)
+ self.ok = True
+ self.dlg.close()
+
+ def __init__(self, inputreader, outputwriter):
+ """ Constructor. """
+
+ self.inputreader = inputreader
+ self.outputwriter = outputwriter
+ self.outputwriter.onWrite = self.onWrite
+
+ self.InitialDialog(self)
+
+ def onWrite(self, record):
+ """ This method got called after the first record got
+ readed and before we start to import. """
+ return self.MapperDialog(self.outputwriter, record).ok
+
+GuiApp( SaxInput(), KexiDBOutput() )
diff --git a/kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.rc b/kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.rc
new file mode 100644
index 00000000..0cfe7718
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/importxhtml/ImportXHTML.rc
@@ -0,0 +1,8 @@
+<KrossScripting>
+ <ScriptAction
+ name="importxhtml"
+ text="Import Data From XHTML File"
+ icon="fileimport"
+ interpreter="python"
+ file="ImportXHTML.py" />
+</KrossScripting>
diff --git a/kexi/plugins/scripting/scripts/importxhtml/Makefile.am b/kexi/plugins/scripting/scripts/importxhtml/Makefile.am
new file mode 100644
index 00000000..a0a424fa
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/importxhtml/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+scriptsdir = $(kde_datadir)/kexi/scripts/importxhtml
+scripts_SCRIPTS = ImportXHTML.py ImportXHTML.rc
diff --git a/kexi/plugins/scripting/scripts/projectdocumentor/Makefile.am b/kexi/plugins/scripting/scripts/projectdocumentor/Makefile.am
new file mode 100644
index 00000000..9d32e165
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/projectdocumentor/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+scriptsdir = $(kde_datadir)/kexi/scripts/projectdocumentor
+scripts_SCRIPTS = ProjectDocumentor.py ProjectDocumentor.rc
diff --git a/kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.py b/kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.py
new file mode 100755
index 00000000..89a60301
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.py
@@ -0,0 +1,186 @@
+"""
+Project Documentor
+
+Description:
+This script collects various informations about a Kexi project
+and exports them to a HTML file.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+Dual-licensed under LGPL v2+higher and the BSD license.
+"""
+
+class DataProvider:
+ def __init__(self):
+ import kexiapp
+ keximainwindow = kexiapp.get("KexiAppMainWindow")
+
+ try:
+ self.connection = keximainwindow.getConnection()
+ except:
+ raise "No connection established. Please open the project to be documented first."
+
+ def printConnection(self):
+ condata = self.connection.data()
+ infos = []
+ for item in ("caption", "description", "driverName", "hostName", "port", "userName", "fileName", "dbPath", "localSocketFileName", "serverInfoString"):
+ result = getattr(condata, item)()
+ if result != None and result != "" and (item != "port" or result != 0):
+ infos.append( (item, result) )
+ return infos
+
+ def printDriver(self):
+ driver = self.connection.driver()
+ result = [ ("Version", "%s.%s" % (driver.versionMajor(),driver.versionMinor())) ]
+ conlist = driver.connectionsList()
+ if len(conlist) > 0:
+ result.append( ("Connections",str(conlist)) )
+ return result
+
+ def printDatabases(self):
+ result = [ ("Current database", self.connection.currentDatabase()) ]
+ dbnames = self.connection.databaseNames()
+ if len(dbnames) > 0:
+ result.append( ("Databases",str(dbnames)) )
+ return result
+
+ def printTables(self):
+ result = []
+ for t in self.connection.tableNames():
+ tableschema = self.connection.tableSchema(t)
+ ti = []
+ for i in ("name", "caption", "description"):
+ v = getattr(tableschema,i)()
+ if v != None and v != "":
+ ti.append( (i,v) )
+ tf = []
+ for field in tableschema.fieldlist().fields():
+ tfi = []
+ for n in ("caption","description","type","subType","typeGroup","length","defaultValue"):
+ v = getattr(field,n)()
+ if v != None and v != "":
+ tfi.append( (n,v) )
+ props = []
+ for n in ("PrimaryKey","ForeignKey","AutoInc","UniqueKey","NotNull", "NotEmpty","Indexed","Unsigned"):
+ v = getattr(field,"is%s" % n)()
+ if v != None and v != "" and v != False and v != 0:
+ props.append( "%s " % n )
+ if len(props) > 0:
+ tfi.append( ("properties",props) )
+
+ tf.append( (field.name(), tfi) )
+ ti.append( ("fields", tf) )
+ if len(ti) > 0:
+ result.append( (t, ti) )
+ return result
+
+ def printQueries(self):
+ result = []
+ for q in self.connection.queryNames():
+ queryschema = self.connection.querySchema(q)
+ qi = []
+ for i in ("name", "caption", "description", "statement"):
+ v = getattr(queryschema,i)()
+ if v != None and v != "":
+ qi.append( (i,v) )
+ if len(qi) > 0:
+ result.append( (q, qi) )
+ return result
+
+class GuiApp:
+ def __init__(self, dataprovider):
+ self.dataprovider = dataprovider
+
+ try:
+ import gui
+ except:
+ raise "Import of the Kross GUI module failed."
+
+ self.dialog = gui.Dialog("Project Documentor")
+
+ self.dialog.addLabel(self.dialog, "Save information about the project to an HTML file.")
+
+ self.file = self.dialog.addFileChooser(self.dialog,
+ "File:",
+ gui.getHome() + "/projectdoc.html",
+ (('HTML files', '*.html'),('All files', '*')))
+
+ self.printCheckBoxes = {}
+ for d in dir(self.dataprovider):
+ if d.startswith("print"):
+ self.printCheckBoxes[d] = self.dialog.addCheckBox(self.dialog, d[5:], True)
+
+ #value = getattr(self.dataprovider,d)()
+ #if value != None and len(value) > 0:
+ # f.write("<h2>%s</h2>" % d[5:])
+ # f.write( self.toHTML(value) )
+
+ #self.exportProjectdetails =
+ #self.exportTableschemas = self.dialog.addCheckBox(self.dialog, "Table schemas", True)
+ #self.exportQueryschemas = self.dialog.addCheckBox(self.dialog, "Query schemas", True)
+
+ btnframe = self.dialog.addFrame(self.dialog)
+ self.dialog.addButton(btnframe, "Save", self.doSave)
+ self.dialog.addButton(btnframe, "Cancel", self.dialog.close)
+
+ self.dialog.show()
+
+ def toHTML(self, value):
+ import types
+ result = ""
+ if isinstance(value, types.TupleType):
+ result += "<ul>"
+ if len(value) == 1:
+ result += "<li>%s</li>" % value
+ elif len(value) == 2:
+ result += "<li>%s: %s</li>" % (value[0], self.toHTML(value[1]))
+ elif len(value) > 2:
+ for item in value:
+ i = self.toHTML(item)
+ if i != "":
+ result += "<li>%s</li>" % i
+ result += "</ul>"
+ elif isinstance(value, types.ListType):
+ for item in value:
+ result += "%s" % self.toHTML(item)
+ else:
+ result += "%s" % value
+ return result
+
+ def doSave(self):
+ file = str( self.file.get() )
+ print "Attempting to save project documentation to file: %s" % file
+
+ f = open(file, "w")
+
+ f.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>")
+ f.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 4.01 Strict//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11-strict.dtd\">")
+ f.write("<html><head><title>Project information</title>")
+ f.write("<style type=\"text/css\">")
+ f.write(" html { background-color:#fafafa; }")
+ f.write(" body { background-color:#ffffff; margin:1em; padding:1em; border:#99a 1px solid; color:#003; }")
+ f.write("</style>")
+ f.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />")
+ f.write("</head><body><h1>Project information</h1>")
+
+ for d in dir(self.dataprovider):
+ if d.startswith("print"):
+ print "GuiApp.doSave() CHECK %s" % d
+ a = self.printCheckBoxes[d]
+ if a and a.isChecked():
+ print "GuiApp.doSave() BEGIN %s" % d
+ value = getattr(self.dataprovider,d)()
+ if value != None and len(value) > 0:
+ f.write("<h2>%s</h2>" % d[5:])
+ f.write( self.toHTML(value) )
+ print "GuiApp.doSave() END %s" % d
+
+ f.close()
+
+ print "Successfully saved project documentation to file: %s" % file
+ self.dialog.close()
+
+GuiApp( DataProvider() )
+
diff --git a/kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.rc b/kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.rc
new file mode 100644
index 00000000..bb0f6c69
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/projectdocumentor/ProjectDocumentor.rc
@@ -0,0 +1,8 @@
+<KrossScripting>
+ <ScriptAction
+ name="projectdocumentor"
+ text="Project Documentation Generator"
+ icon="contents"
+ interpreter="python"
+ file="ProjectDocumentor.py" />
+</KrossScripting>
diff --git a/kexi/plugins/scripting/scripts/python/Makefile.am b/kexi/plugins/scripting/scripts/python/Makefile.am
new file mode 100644
index 00000000..4b31c35a
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/python/Makefile.am
@@ -0,0 +1,2 @@
+include $(top_srcdir)/kexi/Makefile.global
+SUBDIRS = kexiapp
diff --git a/kexi/plugins/scripting/scripts/python/kexiapp/Makefile.am b/kexi/plugins/scripting/scripts/python/kexiapp/Makefile.am
new file mode 100644
index 00000000..f0f0492d
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/python/kexiapp/Makefile.am
@@ -0,0 +1,2 @@
+kexiapppythondir = $(kde_datadir)/kexi/kross/python/kexiapp
+kexiapppython_SCRIPTS = __init__.py
diff --git a/kexi/plugins/scripting/scripts/python/kexiapp/__init__.py b/kexi/plugins/scripting/scripts/python/kexiapp/__init__.py
new file mode 100755
index 00000000..b5224304
--- /dev/null
+++ b/kexi/plugins/scripting/scripts/python/kexiapp/__init__.py
@@ -0,0 +1,25 @@
+"""
+Initializer for the krosskexiapp-module.
+
+Description:
+This module provides the entry-point for python scripts
+to work with a running Kexi application instance.
+
+Author:
+Sebastian Sauer <mail@dipe.org>
+
+Copyright:
+Dual-licensed under LGPL v2+higher and the BSD license.
+"""
+
+try:
+ import krosskexiapp
+except ImportError, e:
+ raise "Import of the Kross KexiApp module failed.\n%s" % e
+
+def get(modulename):
+ return krosskexiapp.get(modulename)
+
+def currentConnection():
+ mainwindow = krosskexiapp.get("KexiAppMainWindow")
+ return mainwindow.getConnection()