summaryrefslogtreecommitdiffstats
path: root/kexi/core
diff options
context:
space:
mode:
Diffstat (limited to 'kexi/core')
-rw-r--r--kexi/core/Makefile.am41
-rw-r--r--kexi/core/kexi.cpp348
-rw-r--r--kexi/core/kexi.h147
-rw-r--r--kexi/core/kexi_global.cpp50
-rw-r--r--kexi/core/kexiaboutdata.cpp81
-rw-r--r--kexi/core/kexiaboutdata.h33
-rw-r--r--kexi/core/kexiactioncategories.cpp149
-rw-r--r--kexi/core/kexiactioncategories.h108
-rw-r--r--kexi/core/kexiactionproxy.cpp282
-rw-r--r--kexi/core/kexiactionproxy.h190
-rw-r--r--kexi/core/kexiactionproxy_p.h42
-rw-r--r--kexi/core/kexiblobbuffer.cpp373
-rw-r--r--kexi/core/kexiblobbuffer.h223
-rw-r--r--kexi/core/kexicmdlineargs.h181
-rw-r--r--kexi/core/kexicontexthelp.cpp49
-rw-r--r--kexi/core/kexicontexthelp.h41
-rw-r--r--kexi/core/kexicontexthelp_p.h35
-rw-r--r--kexi/core/kexidataiteminterface.cpp146
-rw-r--r--kexi/core/kexidataiteminterface.h249
-rw-r--r--kexi/core/kexidbconnectionset.cpp183
-rw-r--r--kexi/core/kexidbconnectionset.h77
-rw-r--r--kexi/core/kexidbshortcutfile.cpp314
-rw-r--r--kexi/core/kexidbshortcutfile.h124
-rw-r--r--kexi/core/kexidialogbase.cpp661
-rw-r--r--kexi/core/kexidialogbase.h352
-rw-r--r--kexi/core/kexidragobjects.cpp146
-rw-r--r--kexi/core/kexidragobjects.h82
-rw-r--r--kexi/core/kexievents.cpp92
-rw-r--r--kexi/core/kexievents.h100
-rw-r--r--kexi/core/kexiguimsghandler.cpp176
-rw-r--r--kexi/core/kexiguimsghandler.h62
-rw-r--r--kexi/core/kexiinternalpart.cpp209
-rw-r--r--kexi/core/kexiinternalpart.h159
-rw-r--r--kexi/core/keximainwindow.cpp36
-rw-r--r--kexi/core/keximainwindow.h189
-rw-r--r--kexi/core/kexipart.cpp452
-rw-r--r--kexi/core/kexipart.h333
-rw-r--r--kexi/core/kexipartdatasource.cpp49
-rw-r--r--kexi/core/kexipartdatasource.h72
-rw-r--r--kexi/core/kexipartguiclient.h56
-rw-r--r--kexi/core/kexipartinfo.cpp133
-rw-r--r--kexi/core/kexipartinfo.h160
-rw-r--r--kexi/core/kexipartinfo_p.h51
-rw-r--r--kexi/core/kexipartitem.cpp33
-rw-r--r--kexi/core/kexipartitem.h117
-rw-r--r--kexi/core/kexipartmanager.cpp280
-rw-r--r--kexi/core/kexipartmanager.h141
-rw-r--r--kexi/core/kexiproject.cpp1023
-rw-r--r--kexi/core/kexiproject.h334
-rw-r--r--kexi/core/kexiprojectconnectiondata.cpp152
-rw-r--r--kexi/core/kexiprojectconnectiondata.h69
-rw-r--r--kexi/core/kexiprojectdata.cpp176
-rw-r--r--kexi/core/kexiprojectdata.h108
-rw-r--r--kexi/core/kexiprojectset.cpp112
-rw-r--r--kexi/core/kexiprojectset.h67
-rw-r--r--kexi/core/kexisearchandreplaceiface.cpp41
-rw-r--r--kexi/core/kexisearchandreplaceiface.h106
-rw-r--r--kexi/core/kexisharedactionhost.cpp291
-rw-r--r--kexi/core/kexisharedactionhost.h165
-rw-r--r--kexi/core/kexisharedactionhost_p.h64
-rw-r--r--kexi/core/kexistartupdata.cpp84
-rw-r--r--kexi/core/kexistartupdata.h90
-rw-r--r--kexi/core/kexistaticpart.cpp63
-rw-r--r--kexi/core/kexistaticpart.h64
-rw-r--r--kexi/core/kexitabledesignerinterface.cpp28
-rw-r--r--kexi/core/kexitabledesignerinterface.h104
-rw-r--r--kexi/core/kexitemplateloader.cpp112
-rw-r--r--kexi/core/kexitemplateloader.h44
-rw-r--r--kexi/core/kexitextmsghandler.cpp57
-rw-r--r--kexi/core/kexitextmsghandler.h37
-rw-r--r--kexi/core/kexiuseraction.cpp108
-rw-r--r--kexi/core/kexiuseraction.h81
-rw-r--r--kexi/core/kexiuseractionmethod.cpp32
-rw-r--r--kexi/core/kexiuseractionmethod.h42
-rw-r--r--kexi/core/kexiviewbase.cpp328
-rw-r--r--kexi/core/kexiviewbase.h280
76 files changed, 11869 insertions, 0 deletions
diff --git a/kexi/core/Makefile.am b/kexi/core/Makefile.am
new file mode 100644
index 00000000..4a69feda
--- /dev/null
+++ b/kexi/core/Makefile.am
@@ -0,0 +1,41 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+lib_LTLIBRARIES = libkexicore.la
+libkexicore_la_SOURCES = kexi_global.cpp kexi.cpp kexiaboutdata.cpp \
+ keximainwindow.cpp \
+ kexidbconnectionset.cpp kexiprojectset.cpp \
+ kexiactionproxy.cpp kexiactioncategories.cpp kexisharedactionhost.cpp \
+ kexiproject.cpp kexidialogbase.cpp kexiviewbase.cpp \
+ kexipartmanager.cpp kexipartinfo.cpp kexipartitem.cpp kexipart.cpp \
+ kexiprojectdata.cpp kexiinternalpart.cpp \
+ kexidragobjects.cpp \
+ kexiuseraction.cpp kexiuseractionmethod.cpp \
+ kexistartupdata.cpp kexiguimsghandler.cpp kexitextmsghandler.cpp \
+ kexidataiteminterface.cpp kexievents.cpp \
+ kexidbshortcutfile.cpp \
+ kexiblobbuffer.cpp kexistaticpart.cpp \
+ kexitabledesignerinterface.cpp kexisearchandreplaceiface.cpp \
+ kexitemplateloader.cpp
+
+#kexipartdatasource.cpp
+
+libkexicore_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) $(VER_INFO) -Wnounresolved -no-undefined
+
+SUBDIRS = .
+
+libkexicore_la_LIBADD = $(LIB_KEXI_KMDI) \
+ $(top_builddir)/kexi/kexiutils/libkexiutils.la \
+ $(top_builddir)/kexi/kexidb/libkexidb.la \
+ $(top_builddir)/kexi/kexidb/parser/libkexidbparser.la \
+ $(top_builddir)/lib/koproperty/libkoproperty.la
+
+INCLUDES = $(LIB_KEXI_KMDI_INCLUDES) \
+ -I$(top_srcdir)/lib/kofficecore \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/kexi \
+ $(all_includes)
+
+noinst_HEADERS = kexiactionproxy_p.h kexicontexthelp_p.h kexisharedactionhost_p.h \
+ kexipartinfo_p.h
+
+METASOURCES = AUTO
diff --git a/kexi/core/kexi.cpp b/kexi/core/kexi.cpp
new file mode 100644
index 00000000..74e158f6
--- /dev/null
+++ b/kexi/core/kexi.cpp
@@ -0,0 +1,348 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexi.h"
+#include "kexiaboutdata.h"
+#include "kexicmdlineargs.h"
+
+#include <kexiutils/identifier.h>
+#include <kexidb/msghandler.h>
+
+#include <qtimer.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+#include <qcolor.h>
+#include <qfileinfo.h>
+
+#include <kdebug.h>
+#include <kcursor.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kiconeffect.h>
+#include <ksharedptr.h>
+#include <kmimetype.h>
+#include <kstaticdeleter.h>
+#include <kglobalsettings.h>
+
+using namespace Kexi;
+
+//! used for speedup
+//! @internal
+class KexiInternal : public KShared
+{
+ public:
+ KexiInternal() : KShared()
+ , connset(0)
+ , smallFont(0)
+ {
+ }
+ ~KexiInternal()
+ {
+ delete connset;
+ delete smallFont;
+ }
+ KexiDBConnectionSet* connset;
+ KexiProjectSet recentProjects;
+ KexiDBConnectionSet recentConnections;
+ KexiDB::DriverManager driverManager;
+ KexiPart::Manager partManager;
+ QFont *smallFont;
+};
+
+static KStaticDeleter<KexiInternal> Kexi_intDeleter;
+KexiInternal* _int = 0;
+
+#define _INIT_SHARED { if (!_int) Kexi_intDeleter.setObject( _int, new KexiInternal() ); }
+
+KexiDBConnectionSet& Kexi::connset()
+{
+ _INIT_SHARED;
+ //delayed
+ if (!_int->connset) {
+ //load stored set data, OK?
+ _int->connset = new KexiDBConnectionSet();
+ _int->connset->load();
+ }
+ return *_int->connset;
+}
+
+KexiProjectSet& Kexi::recentProjects() {
+ _INIT_SHARED;
+ return _int->recentProjects;
+}
+
+KexiDB::DriverManager& Kexi::driverManager()
+{
+ _INIT_SHARED;
+ return _int->driverManager;
+}
+
+KexiPart::Manager& Kexi::partManager()
+{
+ _INIT_SHARED;
+ return _int->partManager;
+}
+
+void Kexi::deleteGlobalObjects()
+{
+ delete _int;
+}
+
+//temp
+bool _tempShowForms = true;
+bool& Kexi::tempShowForms() {
+#ifndef KEXI_FORMS_SUPPORT
+ _tempShowForms = false;
+#endif
+ return _tempShowForms;
+}
+
+bool _tempShowReports = true;
+bool& Kexi::tempShowReports() {
+#ifndef KEXI_REPORTS_SUPPORT
+ _tempShowReports = false;
+#endif
+ return _tempShowReports;
+}
+
+bool _tempShowMacros = true;
+bool& Kexi::tempShowMacros() {
+#ifndef KEXI_MACROS_SUPPORT
+ _tempShowMacros = false;
+#endif
+ return _tempShowMacros;
+}
+
+bool _tempShowScripts = true;
+bool& Kexi::tempShowScripts() {
+#ifndef KEXI_SCRIPTS_SUPPORT
+ _tempShowScripts = false;
+#endif
+ return _tempShowScripts;
+}
+
+//--------------------------------------------------------------------------------
+
+QFont Kexi::smallFont(QWidget *init)
+{
+ _INIT_SHARED;
+ if (!_int->smallFont) {
+ _int->smallFont = new QFont( init->font() );
+ const int wdth = KGlobalSettings::desktopGeometry(init).width();
+ int size = 10 + QMAX(0, wdth - 1100) / 100;
+ size = QMIN( init->fontInfo().pixelSize(), size );
+ _int->smallFont->setPixelSize( size );
+ }
+ return *_int->smallFont;
+}
+
+//--------------------------------------------------------------------------------
+QString Kexi::nameForViewMode(int m)
+{
+ if (m==NoViewMode) return i18n("No View");
+ else if (m==DataViewMode) return i18n("Data View");
+ else if (m==DesignViewMode) return i18n("Design View");
+ else if (m==TextViewMode) return i18n("Text View");
+
+ return i18n("Unknown");
+}
+
+//--------------------------------------------------------------------------------
+
+QString Kexi::msgYouCanImproveData() {
+ return i18n("You can correct data in this row or use \"Cancel row changes\" function.");
+}
+
+//--------------------------------------------------------------------------------
+
+ObjectStatus::ObjectStatus()
+: msgHandler(0)
+{
+}
+
+ObjectStatus::ObjectStatus(const QString& message, const QString& description)
+: msgHandler(0)
+{
+ setStatus(message, description);
+}
+
+ObjectStatus::ObjectStatus(KexiDB::Object* dbObject, const QString& message, const QString& description)
+: msgHandler(0)
+{
+ setStatus(dbObject, message, description);
+}
+
+ObjectStatus::~ObjectStatus()
+{
+ delete msgHandler;
+}
+
+const ObjectStatus& ObjectStatus::status() const
+{
+ return *this;
+}
+
+bool ObjectStatus::error() const
+{
+ return !message.isEmpty()
+ || (dynamic_cast<KexiDB::Object*>((QObject*)dbObj) && dynamic_cast<KexiDB::Object*>((QObject*)dbObj)->error());
+}
+
+void ObjectStatus::setStatus(const QString& message, const QString& description)
+{
+ this->dbObj=0;
+ this->message=message;
+ this->description=description;
+}
+
+void ObjectStatus::setStatus(KexiDB::Object* dbObject, const QString& message, const QString& description)
+{
+ if (dynamic_cast<QObject*>(dbObject)) {
+ dbObj = dynamic_cast<QObject*>(dbObject);
+ }
+ this->message=message;
+ this->description=description;
+}
+
+void ObjectStatus::setStatus(KexiDB::ResultInfo* result, const QString& message, const QString& description)
+{
+ if (result) {
+ if (message.isEmpty())
+ this->message = result->msg;
+ else
+ this->message = message + " " + result->msg;
+
+ if (description.isEmpty())
+ this->description = result->desc;
+ else
+ this->description = description + " " + result->desc;
+ }
+ else
+ clearStatus();
+}
+
+void ObjectStatus::setStatus(KexiDB::Object* dbObject, KexiDB::ResultInfo* result,
+ const QString& message, const QString& description)
+{
+ if (!dbObject)
+ setStatus(result, message, description);
+ else if (!result)
+ setStatus(dbObject, message, description);
+ else {
+ setStatus(dbObject, message, description);
+ setStatus(result, this->message, this->description);
+ }
+}
+
+void ObjectStatus::clearStatus()
+{
+ message=QString::null;
+ description=QString::null;
+}
+
+QString ObjectStatus::singleStatusString() const {
+ if (message.isEmpty() || description.isEmpty())
+ return message;
+ return message + " " + description;
+}
+
+void ObjectStatus::append( const ObjectStatus& otherStatus ) {
+ if (message.isEmpty()) {
+ message = otherStatus.message;
+ description = otherStatus.description;
+ return;
+ }
+ const QString s( otherStatus.singleStatusString() );
+ if (s.isEmpty())
+ return;
+ if (description.isEmpty()) {
+ description = s;
+ return;
+ }
+ description = description + " " + s;
+}
+
+//! @internal
+class ObjectStatusMessageHandler : public KexiDB::MessageHandler
+{
+ public:
+ ObjectStatusMessageHandler(ObjectStatus *status)
+ : KexiDB::MessageHandler()
+ , m_status(status)
+ {
+ }
+ virtual ~ObjectStatusMessageHandler()
+ {
+ }
+
+ virtual void showErrorMessage(const QString &title,
+ const QString &details = QString::null)
+ {
+ m_status->setStatus(title, details);
+ }
+
+ virtual void showErrorMessage(KexiDB::Object *obj, const QString& msg = QString::null)
+ {
+ m_status->setStatus(obj, msg);
+ }
+
+ ObjectStatus *m_status;
+};
+
+ObjectStatus::operator KexiDB::MessageHandler*()
+{
+ if (!msgHandler)
+ msgHandler = new ObjectStatusMessageHandler(this);
+ return msgHandler;
+}
+
+void Kexi::initCmdLineArgs(int argc, char *argv[], KAboutData* aboutData)
+{
+ KAboutData *about = aboutData;
+ if (!about)
+ about = Kexi::createAboutData();
+#ifdef CUSTOM_VERSION
+# include "../custom_startup.h"
+#endif
+ KCmdLineArgs::init( argc, argv, about );
+ KCmdLineArgs::addCmdLineOptions( options );
+}
+
+void KEXI_UNFINISHED(const QString& feature_name, const QString& extra_text)
+{
+ QString msg;
+ if (feature_name.isEmpty())
+ msg = i18n("This function is not available for version %1 of %2 application.")
+ .arg(KEXI_VERSION_STRING)
+ .arg(KEXI_APP_NAME);
+ else {
+ QString feature_name_(feature_name);
+ msg = i18n("\"%1\" function is not available for version %2 of %3 application.")
+ .arg(feature_name_.replace("&",""))
+ .arg(KEXI_VERSION_STRING)
+ .arg(KEXI_APP_NAME);
+ }
+
+ QString extra_text_(extra_text);
+ if (!extra_text_.isEmpty())
+ extra_text_.prepend("\n");
+
+ KMessageBox::sorry(0, msg + extra_text_);
+}
diff --git a/kexi/core/kexi.h b/kexi/core/kexi.h
new file mode 100644
index 00000000..8490ca29
--- /dev/null
+++ b/kexi/core/kexi.h
@@ -0,0 +1,147 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXI_H
+#define KEXI_H
+
+#include <qguardedptr.h>
+#include <qfont.h>
+
+#include <kexi_version.h>
+#include "kexiprojectdata.h"
+#include "kexipartmanager.h"
+#include "kexidbconnectionset.h"
+#include "kexiprojectset.h"
+#include <kexidb/drivermanager.h>
+#include <kexidb/driver.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+namespace Kexi
+{
+ KEXICORE_EXPORT void initCmdLineArgs(int argc, char *argv[], KAboutData* aboutData = 0);
+
+ /*! Modes of view for the dialogs. Used mostly for parts and KexiDialogBase. */
+ enum ViewMode {
+ AllViewModes = 0, //!< Usable primarily in KexiPart::initInstanceActions()
+ NoViewMode = 0, //!< In KexiViewBase::afterSwitchFrom() and KexiViewBase::beforeSwitchTo()
+ //!< means that parent dialog of the view has not yet view defined.
+ DataViewMode = 1,
+ DesignViewMode = 2,
+ TextViewMode = 4 //!< Also known as SQL View Mode
+ };
+ //! i18n'ed name of view mode \a m
+ KEXICORE_EXPORT QString nameForViewMode(int m);
+
+ //! A set of known connections
+ KEXICORE_EXPORT KexiDBConnectionSet& connset();
+
+ //! A set avaiulable of project infos
+ KEXICORE_EXPORT KexiProjectSet& recentProjects();
+
+ //! shared driver manager
+ KEXICORE_EXPORT KexiDB::DriverManager& driverManager();
+
+ //! shared part manager
+ KEXICORE_EXPORT KexiPart::Manager& partManager();
+
+ //! can be called to delete global objects like driverManager and partManager
+ //! (and thus, all loaded factories/plugins)
+ //! before KLibrary::~KLibrary() do this for us
+ KEXICORE_EXPORT void deleteGlobalObjects();
+
+ //some temporary flags
+
+ //! false by default, flag loaded on main window startup
+ KEXICORE_EXPORT bool& tempShowForms();
+
+ //! false by default, flag loaded on main window startup
+ KEXICORE_EXPORT bool& tempShowReports();
+
+ //! false by default, flag loaded on main window startup
+ KEXICORE_EXPORT bool& tempShowMacros();
+
+ //! false by default, flag loaded on main window startup
+ KEXICORE_EXPORT bool& tempShowScripts();
+
+ /*! A global setting for minimal readable font.
+ Note: this is defined because KDE has no such setting yet.
+ \a init is a widget that should be passed if no qApp->mainWidget() is available yet. */
+ KEXICORE_EXPORT QFont smallFont(QWidget *init = 0);
+
+ /*! Helper class for storing object status. */
+ class KEXICORE_EXPORT ObjectStatus
+ {
+ public:
+ ObjectStatus();
+
+ ObjectStatus(const QString& message, const QString& description);
+
+ ObjectStatus(KexiDB::Object* dbObject, const QString& message, const QString& description);
+
+ ~ObjectStatus();
+
+ const ObjectStatus& status() const;
+
+ bool error() const;
+
+ void setStatus(const QString& message, const QString& description);
+
+ //! Note: for safety, \a dbObject needs to be derived from QObject,
+ //! otherwise it won't be assigned
+ void setStatus(KexiDB::Object* dbObject,
+ const QString& message = QString::null, const QString& description = QString::null);
+
+ void setStatus(KexiDB::ResultInfo* result,
+ const QString& message = QString::null, const QString& description = QString::null);
+
+ void setStatus(KexiDB::Object* dbObject, KexiDB::ResultInfo* result,
+ const QString& message = QString::null, const QString& description = QString::null);
+
+ void clearStatus();
+
+ QString singleStatusString() const;
+
+ void append( const ObjectStatus& otherStatus );
+
+ KexiDB::Object *dbObject() const { return dynamic_cast<KexiDB::Object*>((QObject*)dbObj); }
+
+ //! Helper returning pseudo handler that just updates this ObjectStatus object
+ //! by receiving a message
+ operator KexiDB::MessageHandler*();
+
+ QString message, description;
+ protected:
+ QGuardedPtr<QObject> dbObj; //! This is in fact KexiDB::Object
+ KexiDB::MessageHandler* msgHandler;
+ };
+
+ KEXICORE_EXPORT QString msgYouCanImproveData();
+
+}//namespace Kexi
+
+//! Displays information that feature "feature_name" is not availabe in the current application version
+KEXICORE_EXPORT void KEXI_UNFINISHED(const QString& feature_name, const QString& extra_text = QString::null);
+
+//! Like above - for use inside KexiActionProxy subclass - reuses feature name from shared action's text
+#define KEXI_UNFINISHED_SHARED_ACTION(action_name) \
+ KEXI_UNFINISHED(sharedAction(action_name) ? sharedAction(action_name)->text() : QString::null)
+
+#endif
diff --git a/kexi/core/kexi_global.cpp b/kexi/core/kexi_global.cpp
new file mode 100644
index 00000000..db0b9b60
--- /dev/null
+++ b/kexi/core/kexi_global.cpp
@@ -0,0 +1,50 @@
+/* This file is part of the KOffice libraries
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ (version information based on kofficeversion.h)
+
+ 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 "kexi_version.h"
+
+using namespace Kexi;
+
+KEXICORE_EXPORT unsigned int version()
+{
+ return KEXI_VERSION;
+}
+
+KEXICORE_EXPORT unsigned int versionMajor()
+{
+ return KEXI_VERSION_MAJOR;
+}
+
+KEXICORE_EXPORT unsigned int versionMinor()
+{
+ return KEXI_VERSION_MINOR;
+}
+
+KEXICORE_EXPORT unsigned int versionRelease()
+{
+ return KEXI_VERSION_RELEASE;
+}
+
+KEXICORE_EXPORT const char *versionString()
+{
+ return KEXI_VERSION_STRING;
+}
+
diff --git a/kexi/core/kexiaboutdata.cpp b/kexi/core/kexiaboutdata.cpp
new file mode 100644
index 00000000..eeaaf07e
--- /dev/null
+++ b/kexi/core/kexiaboutdata.cpp
@@ -0,0 +1,81 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiaboutdata.h"
+#include <kexi_version.h>
+#include <kdeversion.h>
+#include <kofficeversion.h> //only for KOFFICE_VERSION_STRING
+#include <klocale.h>
+
+static const char *description =
+ I18N_NOOP("Database creation for everyone")
+#ifndef CUSTOM_VERSION
+#ifdef KEXI_STANDALONE
+ "\n\n" I18N_NOOP("This is standalone version of the application distributed outside of KOffice suite.")
+#else
+ "\n\n" I18N_NOOP("This application version is distributed with KOffice suite.")
+#endif
+#endif
+ ;
+
+using namespace Kexi;
+
+KAboutData* Kexi::createAboutData()
+{
+ KAboutData *aboutData=new KAboutData( "kexi", KEXI_APP_NAME,
+ KEXI_VERSION_STRING
+#ifndef CUSTOM_VERSION
+ " (KOffice " KOFFICE_VERSION_STRING ")"
+#endif
+ , description,
+ KAboutData::License_LGPL_V2,
+ I18N_NOOP( "(c) 2002-2007, Kexi Team\n"
+ "(c) 2003-2007, OpenOffice Polska LLC\n"),
+ I18N_NOOP( "This software is developed by Kexi Team - an international group\n"
+ "of independent developers, with additional assistance and support\n"
+ "from the OpenOffice Polska company.\n\n"
+ "Visit the company Home Page: http://www.openoffice.com.pl"),
+ "http://www.koffice.org/kexi",
+ "submit@bugs.kde.org"
+ );
+ // authors sorted by last contribution date
+ aboutData->addAuthor("Jarosław Staniek / OpenOffice Polska", I18N_NOOP("Project maintainer & developer, design, KexiDB, commercially supported version, win32 port"), "js@iidea.pl");
+ aboutData->addAuthor("Lucijan Busch",I18N_NOOP("Former project maintainer & developer"), "lucijan@kde.org");
+ aboutData->addAuthor("Cedric Pasteur", I18N_NOOP("KexiPropertyEditor and FormDesigner"), "cedric.pasteur@free.fr");
+ aboutData->addAuthor("Adam Pigg", I18N_NOOP("PostgreSQL database driver, Migration module"), "adam@piggz.fsnet.co.uk");
+ aboutData->addAuthor("Martin Ellis", I18N_NOOP("Contributions for MySQL and KexiDB, fixes, Migration module, MDB support"), "martin.ellis@kdemail.net");
+ aboutData->addAuthor("Sebastian Sauer", I18N_NOOP("Scripting module (KROSS), Python language bindings, design"), "mail@dipe.org");
+ aboutData->addAuthor("Christian Nitschkowski", I18N_NOOP("Graphics effects, helper dialogs"), "segfault_ii@web.de");
+ aboutData->addAuthor("Peter Simonsson",I18N_NOOP("Former developer"),"psn@linux.se");
+ aboutData->addAuthor("Joseph Wenninger", I18N_NOOP("Original Form Designer, original user interface & much more"), "jowenn@kde.org");
+ aboutData->addAuthor("Seth Kurzenberg",I18N_NOOP("CQL++, SQL assistance"), "seth@cql.com");
+ aboutData->addAuthor("Laurent Montel", I18N_NOOP("Original code cleanings"), "montel@kde.org");
+ aboutData->addAuthor("Till Busch", I18N_NOOP("Bugfixes, original Table Widget"), "till@bux.at");
+ aboutData->addCredit("Daniel Molkentin",I18N_NOOP("Initial design improvements"), "molkentin@kde.org");
+ aboutData->addCredit("Kristof Borrey", I18N_NOOP("Icons and user interface research"), "kristof.borrey@skynet.be");
+ aboutData->addCredit("Tomas Krassnig", I18N_NOOP("Coffee sponsoring"), "tkrass05@hak1.at");
+ aboutData->addCredit("Paweł Wirecki / OpenOffice Polska", I18N_NOOP("Numerous bug reports, usability tests, technical support"), "");
+ aboutData->setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"), I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails"));
+#if defined(CUSTOM_VERSION) && defined(Q_WS_WIN)
+ aboutData->setProgramLogo(KEXI_APP_LOGO);
+#endif
+ return aboutData;
+}
diff --git a/kexi/core/kexiaboutdata.h b/kexi/core/kexiaboutdata.h
new file mode 100644
index 00000000..948906c5
--- /dev/null
+++ b/kexi/core/kexiaboutdata.h
@@ -0,0 +1,33 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 _KEXI_ABOU_DATA_
+#define _KEXI_ABOU_DATA_
+
+#include <kaboutdata.h>
+
+namespace Kexi {
+
+KEXICORE_EXPORT KAboutData* createAboutData();
+
+}
+
+#endif
diff --git a/kexi/core/kexiactioncategories.cpp b/kexi/core/kexiactioncategories.cpp
new file mode 100644
index 00000000..4f399342
--- /dev/null
+++ b/kexi/core/kexiactioncategories.cpp
@@ -0,0 +1,149 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiactioncategories.h"
+
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+
+#include <qmap.h>
+#include <qasciidict.h>
+
+namespace Kexi {
+
+//! @internal
+class ActionInternal
+{
+ public:
+ ActionInternal(int _categories)
+ : categories(_categories)
+ , supportedObjectTypes(0)
+ , allObjectTypesAreSupported(false)
+ {
+ }
+ ~ActionInternal() {
+ delete supportedObjectTypes;
+ }
+ int categories;
+ QMap<int, bool> *supportedObjectTypes;
+ bool allObjectTypesAreSupported : 1;
+};
+
+static KStaticDeleter<ActionCategories> Kexi_actionCategoriesDeleter;
+ActionCategories* Kexi_actionCategories = 0;
+
+//! @internal
+class ActionCategories::Private
+{
+ public:
+ Private()
+ {
+ actions.setAutoDelete(true);
+ }
+
+ QAsciiDict<ActionInternal> actions;
+};
+
+KEXICORE_EXPORT ActionCategories *actionCategories()
+{
+ if (!Kexi_actionCategories)
+ Kexi_actionCategoriesDeleter.setObject( Kexi_actionCategories, new ActionCategories() );
+ return Kexi_actionCategories;
+}
+
+}
+
+using namespace Kexi;
+
+//----------------------------------
+
+ActionCategories::ActionCategories()
+ : d( new Private() )
+{
+}
+
+ActionCategories::~ActionCategories()
+{
+ delete d;
+}
+
+void ActionCategories::addAction(const char* name, int categories,
+ KexiPart::ObjectTypes supportedObjectType1, KexiPart::ObjectTypes supportedObjectType2,
+ KexiPart::ObjectTypes supportedObjectType3, KexiPart::ObjectTypes supportedObjectType4,
+ KexiPart::ObjectTypes supportedObjectType5, KexiPart::ObjectTypes supportedObjectType6,
+ KexiPart::ObjectTypes supportedObjectType7, KexiPart::ObjectTypes supportedObjectType8)
+{
+ ActionInternal * a = d->actions.find( name );
+ if (a) {
+ a->categories |= categories;
+ }
+ else {
+ a = new ActionInternal(categories);
+ d->actions.insert(name, a);
+ }
+ if (supportedObjectType1) {
+ if (!a->supportedObjectTypes)
+ a->supportedObjectTypes = new QMap<int, bool>();
+ a->supportedObjectTypes->insert(supportedObjectType1, true);
+ if (supportedObjectType2) {
+ a->supportedObjectTypes->insert(supportedObjectType2, true);
+ if (supportedObjectType3) {
+ a->supportedObjectTypes->insert(supportedObjectType3, true);
+ if (supportedObjectType4) {
+ a->supportedObjectTypes->insert(supportedObjectType4, true);
+ if (supportedObjectType5) {
+ a->supportedObjectTypes->insert(supportedObjectType5, true);
+ if (supportedObjectType6) {
+ a->supportedObjectTypes->insert(supportedObjectType6, true);
+ if (supportedObjectType7) {
+ a->supportedObjectTypes->insert(supportedObjectType7, true);
+ if (supportedObjectType8) {
+ a->supportedObjectTypes->insert(supportedObjectType8, true);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void ActionCategories::setAllObjectTypesSupported(const char* name, bool set)
+{
+ ActionInternal * a = d->actions.find( name );
+ if (a)
+ a->allObjectTypesAreSupported = set;
+ else
+ kexiwarn << "ActionCategories::setAllObjectTypesSupported(): no such action \"" << name << "\"" << endl;
+}
+
+int ActionCategories::actionCategories(const char* name) const
+{
+ const ActionInternal * a = d->actions.find( name );
+ return a ? a->categories : 0;
+}
+
+bool ActionCategories::actionSupportsObjectType(const char* name, KexiPart::ObjectTypes objectType) const
+{
+ const ActionInternal * a = d->actions.find( name );
+ if (a && a->allObjectTypesAreSupported)
+ return true;
+ return (a && a->supportedObjectTypes) ? a->supportedObjectTypes->contains(objectType) : false;
+}
diff --git a/kexi/core/kexiactioncategories.h b/kexi/core/kexiactioncategories.h
new file mode 100644
index 00000000..6e672133
--- /dev/null
+++ b/kexi/core/kexiactioncategories.h
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXI_ACTION_CATEGORIES_H
+#define KEXI_ACTION_CATEGORIES_H
+
+#include <ksharedptr.h>
+#include "kexipart.h"
+
+namespace Kexi {
+
+enum ActionCategory
+{
+ NoActionCategory = 0, //!< no category at all
+ GlobalActionCategory = 1, //!< global application action like editcopy;
+ //!< can be applied to focused widget (of many types)
+ PartItemActionCategory = 2,//!< action related to part item, e.g. data_execute;
+ //!< requires context, used only in the navigator
+ WindowActionCategory = 4 //!< action related to active window, which can display
+ //!< table, query, form, report...
+};
+
+//! @short A set of functions used to declare action categories
+/*! Note: we do not declare actions used in design/text view modes,
+ because the categories are used in the data view,
+ for now in the 'assign action to a push button' function. */
+class KEXICORE_EXPORT ActionCategories : public KShared
+{
+ public:
+ ActionCategories();
+ ~ActionCategories();
+
+ /*! Declares action \a name for categories \a category (a combination of ActionCategory enum values).
+ The categories is merged with the previous declaration (if any).
+ \a supportedObjectTypes can be specified for ActionCategory::WindowAction to declare what object types
+ the action allows, it is a combination of KexiPart::ObjectTypes enum values. */
+ void addAction(const char* name, int categories,
+ KexiPart::ObjectTypes supportedObjectType1 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType2 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType3 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType4 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType5 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType6 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType7 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType8 = (KexiPart::ObjectTypes)0);
+
+ void addGlobalAction(const char* name)
+ { addAction(name, Kexi::GlobalActionCategory); }
+
+ //! Convenience function for adding action of category "part item", uses \ref addAction().
+ void addPartItemAction(const char* name)
+ { addAction(name, Kexi::PartItemActionCategory); }
+
+ /*! Convenience function for adding action of category "window", uses \ref addAction().
+ \a supportedObjectTypes is a combination of KexiPart::ObjectTypes enum values describing
+ object types supported by the action. */
+ void addWindowAction(const char* name,
+ KexiPart::ObjectTypes supportedObjectType1 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType2 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType3 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType4 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType5 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType6 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType7 = (KexiPart::ObjectTypes)0,
+ KexiPart::ObjectTypes supportedObjectType8 = (KexiPart::ObjectTypes)0)
+ { addAction(name, Kexi::WindowActionCategory, supportedObjectType1, supportedObjectType2,
+ supportedObjectType3, supportedObjectType4, supportedObjectType5, supportedObjectType6,
+ supportedObjectType7, supportedObjectType8); }
+
+ /*! If \a set is true, action with name \a name will support any possible object type
+ that can be checked by actionSupportsObjectType().
+ Makes sense for action of category Kexi::WindowActionCategory. */
+ void setAllObjectTypesSupported(const char* name, bool set);
+
+ //! \return categories for action \a name (a combination of ActionCategory enum values).
+ //! If there is no such actions declared at all, -1 is returned.
+ int actionCategories(const char* name) const;
+
+ /*! \return true if action \a name supports \a objectType.
+ Only works for actions of WindowAction category. */
+ bool actionSupportsObjectType(const char* name, KexiPart::ObjectTypes objectType) const;
+ protected:
+ class Private;
+ Private *d;
+};
+
+//! \return ActionCategories singleton object
+KEXICORE_EXPORT ActionCategories *actionCategories();
+
+}
+
+#endif
diff --git a/kexi/core/kexiactionproxy.cpp b/kexi/core/kexiactionproxy.cpp
new file mode 100644
index 00000000..0dbcf637
--- /dev/null
+++ b/kexi/core/kexiactionproxy.cpp
@@ -0,0 +1,282 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiactionproxy.h"
+#include "kexiactionproxy_p.h"
+
+#include <kdebug.h>
+#include <kaction.h>
+#include <kmainwindow.h>
+#include <kshortcut.h>
+
+#include <qwidget.h>
+#include <qsignal.h>
+#include <qiconset.h>
+
+KAction_setEnabled_Helper::KAction_setEnabled_Helper(KexiActionProxy* proxy)
+ : QObject(0,"KAction_setEnabled_Helper")
+ , m_proxy( proxy )
+{
+}
+
+void KAction_setEnabled_Helper::slotSetEnabled(bool enabled)
+{
+ if (sender()->inherits("KAction")) {
+ const KAction *a = static_cast<const KAction*>(sender());
+ m_proxy->setAvailable(a->name(), enabled);
+ }
+}
+
+//=======================
+
+KexiSharedActionConnector::KexiSharedActionConnector( KexiActionProxy* proxy, QObject *obj )
+ : m_proxy(proxy)
+ , m_object(obj)
+{
+}
+
+KexiSharedActionConnector::~KexiSharedActionConnector()
+{
+}
+
+void KexiSharedActionConnector::plugSharedAction(const char *action_name, const char *slot)
+{
+ m_proxy->plugSharedAction(action_name, m_object, slot);
+}
+
+void KexiSharedActionConnector::plugSharedActionToExternalGUI(
+ const char *action_name, KXMLGUIClient *client)
+{
+ m_proxy->plugSharedActionToExternalGUI(action_name, client);
+}
+
+void KexiSharedActionConnector::plugSharedActionsToExternalGUI(
+ const QValueList<QCString>& action_names, KXMLGUIClient *client)
+{
+ m_proxy->plugSharedActionsToExternalGUI(action_names, client);
+}
+
+
+//=======================
+
+KexiActionProxy::KexiActionProxy(QObject *receiver, KexiSharedActionHost *host)
+ : m_host( host ? host : &KexiSharedActionHost::defaultHost() )
+ , m_receiver(receiver)
+ , m_signals(47)
+ , m_actionProxyParent(0)
+ , m_signal_parent( 0, "signal_parent" )
+ , m_KAction_setEnabled_helper( new KAction_setEnabled_Helper(this) )
+ , m_focusedChild(0)
+{
+ m_signals.setAutoDelete(true);
+ m_sharedActionChildren.setAutoDelete(false);
+ m_alternativeActions.setAutoDelete(true);
+ m_host->plugActionProxy( this );
+}
+
+KexiActionProxy::~KexiActionProxy()
+{
+ QPtrListIterator<KexiActionProxy> it(m_sharedActionChildren);
+ //detach myself from every child
+ for (;it.current();++it) {
+ it.current()->setActionProxyParent_internal( 0 );
+ }
+ //take me from parent
+ if (m_actionProxyParent)
+ m_actionProxyParent->takeActionProxyChild( this );
+
+ m_host->takeActionProxyFor(m_receiver);
+
+ delete m_KAction_setEnabled_helper;
+}
+
+void KexiActionProxy::plugSharedAction(const char *action_name, QObject* receiver, const char *slot)
+{
+ if (!action_name)// || !receiver || !slot)
+ return;
+ QPair<QSignal*,bool> *p = m_signals[action_name];
+ if (!p) {
+ p = new QPair<QSignal*,bool>( new QSignal(&m_signal_parent), true );
+ m_signals.insert(action_name, p);
+ }
+ if (receiver && slot)
+ p->first->connect( receiver, slot );
+}
+
+void KexiActionProxy::unplugSharedAction(const char *action_name)
+{
+ QPair<QSignal*,bool> *p = m_signals.take(action_name);
+ if (!p)
+ return;
+ delete p->first;
+ delete p;
+}
+
+int KexiActionProxy::plugSharedAction(const char *action_name, QWidget* w)
+{
+ KAction *a = sharedAction(action_name);
+ if (!a) {
+ kdWarning() << "KexiActionProxy::plugSharedAction(): NO SUCH ACTION: " << action_name << endl;
+ return -1;
+ }
+ return a->plug(w);
+}
+
+void KexiActionProxy::unplugSharedAction(const char *action_name, QWidget* w)
+{
+ KAction *a = sharedAction(action_name);
+ if (!a) {
+ kdWarning() << "KexiActionProxy::unplugSharedAction(): NO SUCH ACTION: " << action_name << endl;
+ return;
+ }
+ a->unplug(w);
+}
+
+KAction* KexiActionProxy::plugSharedAction(const char *action_name, const QString& alternativeText, QWidget* w)
+{
+ KAction *a = sharedAction(action_name);
+ if (!a) {
+ kdWarning() << "KexiActionProxy::plugSharedAction(): NO SUCH ACTION: " << action_name << endl;
+ return 0;
+ }
+ QCString altName = a->name();
+ altName += "_alt";
+ KAction *alt_act = new KAction(alternativeText, a->iconSet(), a->shortcut(),
+ 0, 0, a->parent(), altName);
+ QObject::connect(alt_act, SIGNAL(activated()), a, SLOT(activate()));
+ alt_act->plug(w);
+
+//OK?
+ m_host->updateActionAvailable(action_name, true, m_receiver);
+
+ return alt_act;
+}
+
+void KexiActionProxy::plugSharedActionToExternalGUI(const char *action_name, KXMLGUIClient *client)
+{
+ KAction *a = client->action(action_name);
+ if (!a)
+ return;
+ plugSharedAction(a->name(), a, SLOT(activate()));
+
+ //update availability
+ setAvailable(a->name(), a->isEnabled());
+ //changes will be signaled
+ QObject::connect(a, SIGNAL(enabled(bool)), m_KAction_setEnabled_helper, SLOT(slotSetEnabled(bool)));
+}
+
+void KexiActionProxy::plugSharedActionsToExternalGUI(
+ const QValueList<QCString>& action_names, KXMLGUIClient *client)
+{
+ for (QValueList<QCString>::const_iterator it = action_names.constBegin(); it!=action_names.constEnd(); ++it) {
+ plugSharedActionToExternalGUI(*it, client);
+ }
+}
+
+bool KexiActionProxy::activateSharedAction(const char *action_name, bool alsoCheckInChildren)
+{
+ QPair<QSignal*,bool> *p = m_signals[action_name];
+ if (!p || !p->second) {
+ //try in children...
+ if (alsoCheckInChildren) {
+ QPtrListIterator<KexiActionProxy> it( m_sharedActionChildren );
+ for( ; it.current(); ++it ) {
+ if (it.current()->activateSharedAction( action_name, alsoCheckInChildren ))
+ return true;
+ }
+ }
+ return m_actionProxyParent ? m_actionProxyParent->activateSharedAction(action_name, false) : false; //last chance: parent
+ }
+ //activate in this proxy...
+ p->first->activate();
+ return true;
+}
+
+KAction* KexiActionProxy::sharedAction(const char* action_name)
+{
+ return m_host->mainWindow()->actionCollection()->action(action_name);
+}
+
+bool KexiActionProxy::isSupported(const char* action_name) const
+{
+ QPair<QSignal*,bool> *p = m_signals[action_name];
+ if (!p) {
+ //not supported explicitly - try in children...
+ if (m_focusedChild)
+ return m_focusedChild->isSupported(action_name);
+ QPtrListIterator<KexiActionProxy> it( m_sharedActionChildren );
+ for( ; it.current(); ++it ) {
+ if (it.current()->isSupported(action_name))
+ return true;
+ }
+ return false; //not suported
+ }
+ return p != 0;
+}
+
+bool KexiActionProxy::isAvailable(const char* action_name, bool alsoCheckInChildren) const
+{
+ QPair<QSignal*,bool> *p = m_signals[action_name];
+ if (!p) {
+ //not supported explicitly - try in children...
+ if (alsoCheckInChildren) {
+ if (m_focusedChild)
+ return m_focusedChild->isAvailable(action_name, alsoCheckInChildren);
+ QPtrListIterator<KexiActionProxy> it( m_sharedActionChildren );
+ for( ; it.current(); ++it ) {
+ if (it.current()->isSupported(action_name))
+ return it.current()->isAvailable(action_name, alsoCheckInChildren);
+ }
+ }
+ return m_actionProxyParent ? m_actionProxyParent->isAvailable(action_name, false) : false; //last chance: parent
+ }
+ //supported explicitly:
+ return p->second != 0;
+}
+
+void KexiActionProxy::setAvailable(const char* action_name, bool set)
+{
+ QPair<QSignal*,bool> *p = m_signals[action_name];
+ if (!p)
+ return;
+ p->second = set;
+ m_host->updateActionAvailable(action_name, set, m_receiver);
+}
+
+void KexiActionProxy::addActionProxyChild( KexiActionProxy* child )
+{
+ if (!child || child==this)
+ return;
+ child->setActionProxyParent_internal( this );
+ m_sharedActionChildren.append( child );
+}
+
+void KexiActionProxy::takeActionProxyChild( KexiActionProxy* child )
+{
+ if (m_sharedActionChildren.findRef( child ) != -1)
+ m_sharedActionChildren.take();
+}
+
+void KexiActionProxy::setActionProxyParent_internal( KexiActionProxy* parent )
+{
+ m_actionProxyParent = parent;
+}
+
+#include "kexiactionproxy_p.moc"
+
diff --git a/kexi/core/kexiactionproxy.h b/kexi/core/kexiactionproxy.h
new file mode 100644
index 00000000..63093d29
--- /dev/null
+++ b/kexi/core/kexiactionproxy.h
@@ -0,0 +1,190 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIACTIONPROXY_H
+#define KEXIACTIONPROXY_H
+
+#include <qguardedptr.h>
+#include <qasciidict.h>
+#include <qobject.h>
+#include <qpair.h>
+#include <qptrlist.h>
+
+#include <kaction.h>
+
+#include "kexiproject.h"
+#include "kexisharedactionhost.h"
+
+class QSignal;
+class KAction;
+class KXMLGUIClient;
+class KAction_setEnabled_Helper;
+class KexiActionProxy;
+
+//! Abstract helper class used to connect shared actions from outside of shared-action-aware object.
+/*! Methods like KexiActionProxy::plugSharedAction() are not public, but
+ sometimes there's need for plugging an object that implements KexiActionProxy interface
+ from outside.
+
+ Reimplement KexiSharedActionConnector: do all needed connections in the constructor.
+
+ For example, with KexiQueryDesignerSQLEditor class we're using KTextEdit
+ (or KTextEditor::View) that's not shared-action-aware. So it's needed to conenct
+ e.g. "edit_undo" shared action to undo() slot, and so on. It is impelmented in more
+ generic way by implementing KTextEdit_SharedActionConnector class,
+ so the conenction can be reused many times by just allocating KTextEdit_SharedActionConnector
+ object for any KTextEditor when required (not only within KexiQueryDesignerSQLEditor).
+*/
+//TODO add method for setAvailable()
+class KEXICORE_EXPORT KexiSharedActionConnector
+{
+ public:
+ /* Connects shared actions offered by \a proxy to \a obj. */
+ KexiSharedActionConnector(KexiActionProxy* proxy, QObject *obj);
+ ~KexiSharedActionConnector();
+
+ protected:
+ void plugSharedAction(const char *action_name, const char *slot);
+
+ void plugSharedActionToExternalGUI(const char *action_name, KXMLGUIClient *client);
+
+ void plugSharedActionsToExternalGUI(
+ const QValueList<QCString>& action_names, KXMLGUIClient *client);
+
+ KexiActionProxy* m_proxy;
+ QObject *m_object;
+};
+
+//! An interface that acts as proxy for shared actions within the application.
+/*!
+ For example, edit->copy action can be reused to copy different types of items.
+ Availability and meaning of given action depends on the context, while
+ the context changes e.g. when another window is activated.
+ This class is mostly used by subclassing in KexiDialogBase or KexiDockBase
+ - you can subclass in a similar way.
+*/
+
+class KEXICORE_EXPORT KexiActionProxy
+{
+ public:
+ /*! Constructs action proxy for object \a receiver, using \a host.
+ If \a host is NULL, KexiSharedActionHost::defaultHost() is used.
+ (you must be sure that it's true) -- it is casted to QObject and assigned as the receiver.*/
+ KexiActionProxy(QObject *receiver , KexiSharedActionHost *host = 0 );
+ virtual ~KexiActionProxy();
+
+ /*! Activates action named \a action_name for this proxy. If the action is executed
+ (accepted), true is returned. */
+ bool activateSharedAction(const char *action_name, bool alsoCheckInChildren = true);
+
+ /*! Sets host to \a host; rerely used. */
+ void setSharedActionHost(KexiSharedActionHost& host) { m_host = &host; }
+
+ /*! \return true, if action named \a action_name is enabled within the proxy.
+ False is returned either if the action is not available or is not supported.
+ \ sa isSupported() */
+ bool isAvailable(const char* action_name, bool alsoCheckInChildren = true) const;
+
+ /*! \return true, if action named \a action_name is supported by the proxy. */
+ bool isSupported(const char* action_name) const;
+
+ protected:
+ /*! Plugs shared action named \a action_name to slot \a slot in \a receiver.
+ \a Receiver is usually a child of _this_ widget. */
+ void plugSharedAction(const char *action_name, QObject* receiver, const char *slot);
+
+ void unplugSharedAction(const char *action_name);
+
+ /*! Typical version of plugAction() method -- plugs action named \a action_name
+ to slot \a slot in _this_ widget. */
+ inline void plugSharedAction(const char *action_name, const char *slot) {
+ plugSharedAction(action_name, m_receiver, slot);
+ }
+
+ /*! Plugs action named \a action_name to a widget \a w, so the action is visible on this widget
+ as an item. \a w will typically be a menu, popup menu or a toolbar.
+ Does nothing if no action found, so generally this is safer than just caling e.g.
+ <code> action("myaction")->plug(myPopup); </code>
+ \return index of inserted item, or -1 if there is not action with name \a action_name.
+ \sa action(), KAction::plug(QWidget*, int) */
+ int plugSharedAction(const char *action_name, QWidget* w);
+
+ void plugSharedActionToExternalGUI(const char *action_name, KXMLGUIClient *client);
+
+ void plugSharedActionsToExternalGUI(
+ const QValueList<QCString>& action_names, KXMLGUIClient *client);
+
+ /*! Unplugs action named \a action_name from a widget \a w.
+ \sa plugSharedAction(const char *action_name, QWidget* w) */
+ void unplugSharedAction(const char *action_name, QWidget* w);
+
+ /*! Like above, but creates alternative action as a copy of \a action_name,
+ with \a alternativeText set. When this action is activated, just original action
+ specified by \a action_name is activated. The aternative action has autmatically set name as:
+ action_name + "_alt".
+ \return newly created action or 0 if \a action_name not found. */
+ KAction* plugSharedAction(const char *action_name, const QString& alternativeText, QWidget* w);
+
+ /*! \return action named with \a name or NULL if there is no such action. */
+ virtual KAction* sharedAction(const char* action_name);
+
+ inline QObject *receiver() const { return m_receiver; }
+
+ virtual void setAvailable(const char* action_name, bool set);
+
+ /*! Adds \a child of this proxy. Children will receive activateSharedAction() event,
+ If activateSharedAction() "event" is not consumed by the main proxy,
+ we start to iterate over proxy children (in unspecified order) to and call
+ activateSharedAction() on every child until one of them accept the "event".
+
+ If proxy child is destroyed, it is automatically detached from its parent proxy.
+ Parent proxy is 0 by default. This pointer is properly cleared when parent proxy is destroyed. */
+ void addActionProxyChild( KexiActionProxy* child );
+
+ void takeActionProxyChild( KexiActionProxy* child );
+
+ KexiSharedActionHost *m_host;
+ QGuardedPtr<QObject> m_receiver;
+ QAsciiDict< QPair<QSignal*,bool> > m_signals;
+
+ QPtrList<KexiActionProxy> m_sharedActionChildren;
+
+ QPtrList<KAction> m_alternativeActions;
+
+ KexiActionProxy* m_actionProxyParent;
+
+ QObject m_signal_parent; //!< it's just to have common parent for owned signals
+
+ //! For internal use by plugSharedActionToExternalGUI()
+ KAction_setEnabled_Helper *m_KAction_setEnabled_helper;
+
+ public:
+ //! For internal use by addActionProxyChild(). \a parent can be 0.
+ void setActionProxyParent_internal( KexiActionProxy* parent );
+
+ //! @internal
+ KexiActionProxy *m_focusedChild;
+
+ friend class KexiSharedActionHost;
+ friend class KAction_setEnabled_Helper;
+ friend class KexiSharedActionConnector;
+};
+
+#endif
+
diff --git a/kexi/core/kexiactionproxy_p.h b/kexi/core/kexiactionproxy_p.h
new file mode 100644
index 00000000..73579299
--- /dev/null
+++ b/kexi/core/kexiactionproxy_p.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIACTIONPROXY_P_H
+#define KEXIACTIONPROXY_P_H
+
+#include <qobject.h>
+
+class KexiActionProxy;
+
+//! Helper class for KexiActionProxy::plugSharedActionToExternalGUI() method.
+class KAction_setEnabled_Helper : public QObject
+{
+ Q_OBJECT
+ public:
+ KAction_setEnabled_Helper(KexiActionProxy* proxy);
+
+ public slots:
+ void slotSetEnabled(bool enabled);
+
+ protected:
+ KexiActionProxy *m_proxy;
+};
+
+#endif
+
diff --git a/kexi/core/kexiblobbuffer.cpp b/kexi/core/kexiblobbuffer.cpp
new file mode 100644
index 00000000..d66d69af
--- /dev/null
+++ b/kexi/core/kexiblobbuffer.cpp
@@ -0,0 +1,373 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiblobbuffer.h"
+
+#include <assert.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qbuffer.h>
+
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+#include <kimageio.h>
+
+#include <kexidb/connection.h>
+
+static KStaticDeleter<KexiBLOBBuffer> m_bufferDeleter;
+static KexiBLOBBuffer* m_buffer = 0;
+
+//-----------------
+
+class KexiBLOBBuffer::Private
+{
+ public:
+ Private()
+ : maxId(0)
+ , inMemoryItems(1009)
+ , storedItems(1009)
+ , itemsByURL(1009)
+ {
+ }
+ Id_t maxId; //!< Used to compute maximal recently used identifier for unstored BLOB
+//! @todo will be changed to QHash<quint64, Item>
+ QIntDict<Item> inMemoryItems; //!< for unstored BLOBs
+ QIntDict<Item> storedItems; //!< for stored items
+ QDict<Item> itemsByURL;
+ QGuardedPtr<KexiDB::Connection> conn;
+};
+
+//-----------------
+
+KexiBLOBBuffer::Handle::Handle(Item* item)
+ : m_item(item)
+{
+ if (m_item)
+ m_item->refs++;
+}
+
+KexiBLOBBuffer::Handle::Handle(const Handle& handle)
+{
+ *this = handle;
+}
+
+KexiBLOBBuffer::Handle::Handle()
+ : m_item(0)
+{
+}
+
+KexiBLOBBuffer::Handle::~Handle()
+{
+ if (m_item) {
+ m_item->refs--;
+ if (m_item->refs<=0)
+ KexiBLOBBuffer::self()->removeItem(m_item->id, m_item->stored);
+ }
+}
+
+KexiBLOBBuffer::Handle& KexiBLOBBuffer::Handle::operator=(const Handle& handle)
+{
+ m_item = handle.m_item;
+ if (m_item)
+ m_item->refs++;
+ return *this;
+}
+
+void KexiBLOBBuffer::Handle::setStoredWidthID(KexiBLOBBuffer::Id_t id)
+{
+ if (!m_item)
+ return;
+ if (m_item->stored) {
+ kdWarning() << "KexiBLOBBuffer::Handle::setStoredWidthID(): object for id=" << id
+ << " is aleady stored" << endl;
+ return;
+ }
+
+ KexiBLOBBuffer::self()->takeItem(m_item);
+ m_item->id = id; //new id
+ m_item->stored = true;
+//! @todo What about other handles for this item?
+//! @todo They were assuming it's unstored item, but it's stored now....
+ KexiBLOBBuffer::self()->insertItem(m_item);
+}
+
+//-----------------
+
+KexiBLOBBuffer::Item::Item(const QByteArray& data, KexiBLOBBuffer::Id_t ident, bool _stored,
+ const QString& _name, const QString& _caption, const QString& _mimeType,
+ Id_t _folderId, const QPixmap& pixmap)
+ : name(_name), caption(_caption), mimeType(_mimeType), refs(0),
+ id(ident), folderId(_folderId), stored(_stored),
+ m_pixmapLoaded(new bool(false)/*workaround for pixmap() const*/)
+{
+ if (pixmap.isNull())
+ m_pixmap = new QPixmap();
+ else
+ m_pixmap = new QPixmap(pixmap);
+
+ if (data.isEmpty())
+ m_data = new QByteArray();
+ else
+ m_data = new QByteArray(data);
+}
+
+KexiBLOBBuffer::Item::~Item()
+{
+ kexipluginsdbg << "KexiBLOBBuffer::Item::~Item()" << endl;
+ delete m_pixmap;
+ m_pixmap = 0;
+ delete m_data;
+ m_data = 0;
+ delete m_pixmapLoaded;
+}
+
+QPixmap KexiBLOBBuffer::Item::pixmap() const
+{
+ if (!*m_pixmapLoaded && m_pixmap->isNull() && !m_data->isEmpty()) {
+ QString type( KImageIO::typeForMime(mimeType) );
+ if (!KImageIO::canRead( type ) || !m_pixmap->loadFromData(*m_data, type.latin1())) {
+ //! @todo inform about error?
+ }
+ *m_pixmapLoaded = true;
+ }
+ return *m_pixmap;
+}
+
+QByteArray KexiBLOBBuffer::Item::data() const
+{
+ if (!m_data->isEmpty())
+ return *m_data;
+
+ if (m_data->isEmpty() && m_pixmap->isNull())
+ return QByteArray();
+
+ if (m_data->isEmpty() && !m_pixmap->isNull()) {
+ //convert pixmap to byte array
+ //(do it only on demand)
+ QBuffer buffer( *m_data );
+ buffer.open( IO_WriteOnly );
+ m_pixmap->save( &buffer, mimeType.isEmpty() ? (const char*)"PNG"/*! @todo default? */ : mimeType.latin1() );
+ }
+ return *m_data;
+}
+
+//-----------------
+
+KexiBLOBBuffer::KexiBLOBBuffer()
+ : QObject()
+ , d(new Private())
+{
+ Q_ASSERT(!m_buffer);
+ d->inMemoryItems.setAutoDelete(true);
+ d->storedItems.setAutoDelete(true);
+}
+
+KexiBLOBBuffer::~KexiBLOBBuffer()
+{
+ delete d;
+}
+
+KexiBLOBBuffer::Handle KexiBLOBBuffer::insertPixmap(const KURL& url)
+{
+ if (url.isEmpty() )
+ return KexiBLOBBuffer::Handle();
+ if (!url.isValid()) {
+ kexipluginswarn << "::insertPixmap: INVALID URL '" << url << "'" << endl;
+ return KexiBLOBBuffer::Handle();
+ }
+//! @todo what about searching by filename only and then compare data?
+ Item * item = d->itemsByURL.find(url.prettyURL());
+ if (item)
+ return KexiBLOBBuffer::Handle(item);
+
+ QString fileName = url.isLocalFile() ? url.path() : url.prettyURL();
+//! @todo download the file if remote, then set fileName properly
+ QFile f(fileName);
+ if (!f.open(IO_ReadOnly)) {
+ //! @todo err msg
+ return KexiBLOBBuffer::Handle();
+ }
+ QString mimeType( KImageIO::mimeType( fileName ) );
+
+ QByteArray data( f.readAll() );
+ if (f.status()!=IO_Ok) {
+ //! @todo err msg
+ return KexiBLOBBuffer::Handle();
+ }
+ QFileInfo fi(url.fileName());
+ QString caption(fi.baseName().replace('_', " ").simplifyWhiteSpace());
+
+ item = new Item(data, ++d->maxId, /*!stored*/false, url.fileName(), caption, mimeType);
+ insertItem(item);
+
+ //cache
+ item->prettyURL = url.prettyURL();
+ d->itemsByURL.replace(url.prettyURL(), item);
+ return KexiBLOBBuffer::Handle(item);
+}
+
+KexiBLOBBuffer::Handle KexiBLOBBuffer::insertObject(const QByteArray& data,
+ const QString& name, const QString& caption, const QString& mimeType, KexiBLOBBuffer::Id_t identifier)
+{
+ KexiBLOBBuffer::Id_t newIdentifier;
+ if (identifier>0)
+ newIdentifier = identifier;
+ else
+ newIdentifier = ++d->maxId;
+
+ Item *item = new Item(data, newIdentifier, identifier>0, name, caption, mimeType);
+ insertItem( item );
+ return KexiBLOBBuffer::Handle(item);
+}
+
+KexiBLOBBuffer::Handle KexiBLOBBuffer::insertPixmap(const QPixmap& pixmap)
+{
+ if (pixmap.isNull())
+ return KexiBLOBBuffer::Handle();
+
+ Item * item = new Item(
+ QByteArray(), //(pixmap will be converted to byte array on demand)
+ ++d->maxId,
+ false, //not stored
+ QString::null,
+ QString::null,
+ "image/png", //!< @todo OK? What about jpegs?
+ 0, //folder id
+ pixmap);
+
+ insertItem(item);
+ return KexiBLOBBuffer::Handle(item);
+}
+
+KexiBLOBBuffer::Handle KexiBLOBBuffer::objectForId(Id_t id, bool stored)
+{
+ if (id<=0)
+ return KexiBLOBBuffer::Handle();
+ if (stored) {
+ Item *item = d->storedItems.find(id);
+ if (item || !d->conn)
+ return KexiBLOBBuffer::Handle(item);
+ //retrieve stored BLOB:
+
+//#if 0
+ assert(d->conn);
+ KexiDB::TableSchema *blobsTable = d->conn->tableSchema("kexi__blobs");
+ if (!blobsTable) {
+ //! @todo err msg
+ return KexiBLOBBuffer::Handle();
+ }
+/* QStringList where;
+ where << "o_id";
+ KexiDB::PreparedStatement::Ptr st = d->conn->prepareStatement(
+ KexiDB::PreparedStatement::SelectStatement, *blobsTable, where);*/
+//! @todo use PreparedStatement
+ KexiDB::QuerySchema schema;
+ schema.addField( blobsTable->field("o_data") );
+ schema.addField( blobsTable->field("o_name") );
+ schema.addField( blobsTable->field("o_caption") );
+ schema.addField( blobsTable->field("o_mime") );
+ schema.addField( blobsTable->field("o_folder_id") );
+ schema.addToWhereExpression(blobsTable->field("o_id"), QVariant((Q_LLONG)id));
+
+ KexiDB::RowData rowData;
+ tristate res = d->conn->querySingleRecord(
+ schema,
+// QString::fromLatin1("SELECT o_data, o_name, o_caption, o_mime FROM kexi__blobs where o_id=")
+// +QString::number(id),
+ rowData);
+ if (res!=true || rowData.size()<4) {
+ //! @todo err msg
+ kdWarning() << "KexiBLOBBuffer::objectForId("<<id<<","<<stored
+ <<"): res!=true || rowData.size()<4; res=="<<res.toString()<<" rowData.size()=="<<rowData.size()<< endl;
+ return KexiBLOBBuffer::Handle();
+ }
+
+ item = new Item(
+ rowData[0].toByteArray(),
+ id,
+ true, //stored
+ rowData[1].toString(),
+ rowData[2].toString(),
+ rowData[3].toString(),
+ (Id_t)rowData[4].toInt() //!< @todo folder id: fix Id_t for Qt4
+ );
+
+ insertItem(item);
+ return KexiBLOBBuffer::Handle(item);
+//#endif
+ }
+ else
+ return KexiBLOBBuffer::Handle(d->inMemoryItems.find(id));
+}
+
+KexiBLOBBuffer::Handle KexiBLOBBuffer::objectForId(Id_t id)
+{
+ KexiBLOBBuffer::Handle h(objectForId(id, false/*!stored*/));
+ if (h)
+ return h;
+ return objectForId(id, true/*stored*/);
+}
+
+void KexiBLOBBuffer::removeItem(Id_t id, bool stored)
+{
+ Item *item;
+ if (stored)
+ item = d->storedItems.take(id);
+ else
+ item = d->inMemoryItems.take(id);
+
+ if (item && !item->prettyURL.isEmpty()) {
+ d->itemsByURL.remove(item->prettyURL);
+ }
+ delete item;
+}
+
+void KexiBLOBBuffer::takeItem(Item *item)
+{
+ assert(item);
+ if (item->stored)
+ d->storedItems.take(item->id);
+ else
+ d->inMemoryItems.take(item->id);
+}
+
+void KexiBLOBBuffer::insertItem(Item *item)
+{
+ assert(item);
+ if (item->stored)
+ d->storedItems.insert(item->id, item);
+ else
+ d->inMemoryItems.insert(item->id, item);
+}
+
+void KexiBLOBBuffer::setConnection(KexiDB::Connection *conn)
+{
+ KexiBLOBBuffer::self()->d->conn = conn;
+}
+
+KexiBLOBBuffer* KexiBLOBBuffer::self()
+{
+ if(!m_buffer) {
+ m_bufferDeleter.setObject( m_buffer, new KexiBLOBBuffer() );
+ }
+ return m_buffer;
+}
+
+#include "kexiblobbuffer.moc"
diff --git a/kexi/core/kexiblobbuffer.h b/kexi/core/kexiblobbuffer.h
new file mode 100644
index 00000000..bd593ab2
--- /dev/null
+++ b/kexi/core/kexiblobbuffer.h
@@ -0,0 +1,223 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIBLOBBUFFER_H
+#define KEXIBLOBBUFFER_H
+
+#include <qobject.h>
+#include <qintdict.h>
+#include <qdict.h>
+#include <qpixmap.h>
+
+#include <kurl.h>
+
+namespace KexiDB
+{
+ class Connection;
+}
+
+//! Application-wide buffer for local BLOB data like pixmaps.
+/*! For now only pixmaps are supported
+ @todo support any KPart-compatible objects and more...
+
+ Use this class by acessing to its singleton: KexiBLOBBuffer::self().
+
+ This class is used for buffering BLOB data,
+ to avoid duplicating object's data in memory and a need for loading (decoding)
+ the same object many times.
+ The data is always local, what means database storage is not employed here.
+
+ Each BLOB instance is identified by an unsigned integer number (Id_t type),
+ uniquely generated on BLOB loading. Each BLOB can have assigned source url
+ it has been loaded from (the url can be empty though, e.g. for data coming from clipboard).
+
+ References to KexiBLOBBuffer are counted, so when last reference is lost, data is freed
+ and the integer identifier is no longer pointing any valid data.
+ KexiBLOBBuffer::Handle is value-based class that describes handle based in an identifier.
+ Objects of this class are obtained e.g. from insertPixmap() method.
+
+ There are two kinds of identifiers:
+ - integers assigned for BLOBs already saved to a db backend,
+ when KexiBLOBBuffer::Handle::stored() is true
+ - temporary integers assigned for new BLOBs not yet saved to a db backend,
+ when KexiBLOBBuffer::Handle::stored() is false
+ KexiBLOBBuffer::Handle::setStoredWidthID() can be used to switch from unstored to stored state.
+ Among others, the state has effect on saving forms: only unstored BLOBs will be saved back
+ to the database; when a BLOB needs to be removed, only it will be physically removed only if it was stored.
+
+ KexiBLOBBuffer is also useful for two more reasons:
+ - Property editor's item for "image" property displays a preview of pixmap contents.
+ Without buffering, it would be needed to load pixmap data again: what if the file
+ it is loaded from is located remote and connection is slow? Memory would be also unnecessary doubled.
+ - Undo/Redo framework requires to store previous property values. Having a reference defined
+ by a single interger, memory can be handled more effectively.
+
+ Example use cases:
+ A large pixmap file "abc.jpg" is loaded as QByteArray <b>once</b> and buffered:
+ integer identifier is returned.
+ Then, multiple image widgets are using "abc.jpg" for displaying.
+ Duplicating an image widget means only duplicating it's properties
+ like position and BLOB's id: BLOB itself (data of "abc.jpg") is not duplicated.
+ Creating a new image widget and assiging the same "abc.jpg" pixmap, means only
+ referencing KexiBLOBBuffer using the same identifier.
+*/
+class KEXICORE_EXPORT KexiBLOBBuffer : public QObject
+{
+ Q_OBJECT
+
+ private:
+ class Item;
+ public:
+ //! long integer for unique identifying blobs
+//! @todo Qt4: will be changed
+ typedef long Id_t;
+
+ //! Access to KexiBLOBBuffer singleton
+ static KexiBLOBBuffer* self();
+
+ static void setConnection(KexiDB::Connection *conn);
+
+ //! Object handle used by KexiBLOBBuffer
+ class KEXICORE_EXPORT Handle {
+ public:
+ //! Constructs a null handle.
+ //! Null handles have empty pixap and data members, id == 0 and cast to boolean false.
+ Handle();
+
+ //! Constructs a copy of \a handle.
+ Handle(const Handle& handle);
+
+ ~Handle();
+
+ Id_t id() const { return m_item ? m_item->id : 0; }
+
+ /*! \return true if this BLOB data pointed by this handle is stored at the db backend
+ or false if it is kept in memory. Null handles return false. */
+ bool stored() const { return m_item ? m_item->stored : false; }
+
+ //! \return true if this is null handle (i.e. one not pointing to any data)
+ operator bool() const { return m_item; }
+
+ Handle& operator=(const Handle& handle);
+
+ QByteArray data() const { return m_item ? m_item->data() : QByteArray(); }
+
+ QPixmap pixmap() const { return m_item ? m_item->pixmap() : QPixmap(); }
+
+ /*! Sets "stored" flag to true by setting non-temporary identifier.
+ Only call this method for unstored (in memory) BLOBs */
+ void setStoredWidthID(Id_t id);
+
+ QString originalFileName() const { return m_item ? m_item->name: QString::null; }
+
+ QString mimeType() const { return m_item ? m_item->mimeType : QString::null; }
+
+ Id_t folderId() const { return m_item ? m_item->folderId : 0; }
+
+ protected:
+ //! Constructs a handle based on \a item. Null handle is constructed for null \a item.
+ Handle(Item* item);
+ private:
+ Item* m_item;
+ friend class KexiBLOBBuffer;
+ };
+
+ //! @internal
+ KexiBLOBBuffer();
+
+ ~KexiBLOBBuffer();
+
+ /*! Inserts a new pixmap loaded from a file at \a url.
+ If the same file has already been loaded before, it can be found in cache
+ and returned instantly. It is assumed that the BLOB is unstored, because it is loaded from
+ external source, so stored() will be equal to false for returned handle.
+ \return handle to the pixmap data or a null handle if such pixmap could not be loaded. */
+ Handle insertPixmap(const KURL& url);
+
+ /*! Inserts a new BLOB data.
+ @param data The data for BLOB object.
+ @param name The name for the object, usually a file name or empty
+ @param caption The more friendly than name, can be based on file name or empty or
+ defined by a user (this case is not yet used)
+ @param mimeType The mimeType for the object for easier and mor accurate decoding.
+ @param identifier Object's identifier. If positive, the "stored" flag for the data
+ will be set to true with \a identifer, otherwise (the default) the BLOB data will
+ have "stored" flag set to false, and a new temporary identifier will be assigned. */
+ Handle insertObject(const QByteArray& data, const QString& name,
+ const QString& caption, const QString& mimeType, Id_t identifier = 0);
+
+ /*! Inserts a new pixmap available in memory, e.g. coming from clipboard. */
+ Handle insertPixmap(const QPixmap& pixmap);
+
+ /*! \return an object for a given \a id. If \a stored is true, stored BLOBs buffer
+ is browsed, otherwise unstored (in memory) BLOBs buffer is browsed.
+ If no object is cached for this id, null handle is returned. */
+ Handle objectForId(Id_t id, bool stored);
+
+ /*! \return an object for a given \a id. First, unstored object is checked, then unstored,
+ if stored was not found. */
+ Handle objectForId(Id_t id);
+
+ protected:
+ /*! Removes an object for a given \a id. If \a stored is true, stored BLOB is removed,
+ otherwise unstored (in memory) BLOB is removed. */
+ void removeItem(Id_t id, bool stored);
+
+ /*! Takes an object for a \a item out of the buffer. */
+ void takeItem(Item* item);
+
+ /*! Inserts an object for a given \a id into the buffer. */
+ void insertItem(Item* item);
+
+ private:
+ class KEXICORE_EXPORT Item {
+ public:
+ Item(const QByteArray& data, Id_t ident,
+ bool stored,
+ const QString& name = QString::null,
+ const QString& caption = QString::null,
+ const QString& mimeType = QString::null,
+ Id_t folderId = 0,
+ const QPixmap& pixmap = QPixmap());
+ ~Item();
+ QPixmap pixmap() const;
+ QByteArray data() const;
+// KexiBLOBBuffer* buf;
+// KURL url;
+ QString name;
+ QString caption; //!< @todo for future use within image gallery
+ QString mimeType;
+ uint refs;
+ Id_t id;
+ Id_t folderId;
+ bool stored : 1;
+ QString prettyURL; //!< helper
+ private:
+ QByteArray *m_data;
+ QPixmap *m_pixmap;
+ bool *m_pixmapLoaded; //!< *m_pixmapLoaded will be set in Info::pixmap(),
+ //!< to avoid multiple pixmap decoding when it previously failed
+ friend class KexiBLOBBuffer;
+ };
+ class Private;
+ Private *d;
+ friend class Handle;
+};
+
+#endif
diff --git a/kexi/core/kexicmdlineargs.h b/kexi/core/kexicmdlineargs.h
new file mode 100644
index 00000000..d67c5e61
--- /dev/null
+++ b/kexi/core/kexicmdlineargs.h
@@ -0,0 +1,181 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXICMDLINEARGS_H
+#define KEXICMDLINEARGS_H
+
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static KCmdLineOptions options[] =
+{
+ { ":", I18N_NOOP("Options related to entire projects:"), 0 },
+ { "createdb", I18N_NOOP(
+ "Create a new, blank project using specified\n"
+ "database driver and database name\n"
+ "and exit immediately.\n"
+ "You will be asked for confirmation\n"
+ "if overwriting is needed."), 0 },
+ { "create-opendb", I18N_NOOP(
+ "Like --createdb, but also open newly\n"
+ "created database.\n"), 0 },
+ { "dropdb", I18N_NOOP(
+ "Drop (remove) a project using specified\n"
+ "database driver and database name.\n"
+ "You will be asked for confirmation."), 0 },
+ { "drv", 0, 0 },
+ { "dbdriver <name>", I18N_NOOP(
+ "Database driver to be used\n"
+ "for connecting to a database project\n"
+ "(SQLite by default).\n"
+ "Ignored if a shortcut filename\n"
+ "is provided."), 0 },
+ { "t", 0, 0 },
+ { "type <name>", I18N_NOOP(
+ "Specify the type of file provided as an argument.\n"
+ "This option is only useful if the filename does\n"
+ "not have a valid extension set and its type\n"
+ "cannot be determined unambiguously by examining\n"
+ "its contents.\n"
+ "This option is ignored if no file is specified as\n"
+ "an argument.\n"
+ "Available file types are:\n"
+ "- \"project\" for a project file (the default)\n"
+ "- \"shortcut\" for a shortcut file pointing to a\n"
+ " project.\n"
+ "- \"connection\" for database connection data.\n"
+ ), 0 },
+ { "conn", 0, 0 },
+ { "connection <shortcut_filename>", I18N_NOOP(
+ "\nSpecify a database connection shortcut .kexic\n"
+ "file containing connection data.\n"
+ "Can be used with --createdb or --create-opendb\n"
+ "for convenience instead of using options like \n"
+ "--user, --host or --port.\n"
+ "Note: Options like --user, --host have\n"
+ "precedence over settings defined in the shortcut\n"
+ "file." ), 0 },
+ { "readonly", I18N_NOOP(
+ "Specify that any database connections will\n"
+ "be performed without write support. This option\n"
+ "is ignored when \"createdb\" option is present,\n"
+ "otherwise the database could not be created."), 0 },
+ { "user-mode", I18N_NOOP(
+ "Start project in User Mode, regardless \n"
+ "of the project settings."), 0 },
+ { "design-mode", I18N_NOOP(
+ "Start project in Design Mode, regardless \n"
+ "of the project settings."), 0 },
+ { "show-navigator", I18N_NOOP(
+ "Show the Project Navigator side pane even\n"
+ "if Kexi runs in User Mode."), 0 },
+ { "skip-startup-dialog", I18N_NOOP(
+ "Skip displaying startup dialog window.\n"
+ "If there is no project name specified to open,\n"
+ "empty application window will appear."), 0 },
+
+ { ":", I18N_NOOP("Options related to opening objects within a project:"), 0 },
+ { "open [<object_type>:]<object_name>", I18N_NOOP(
+ "\nOpen object of type <object_type>\n"
+ "and name <object_name> from specified project\n"
+ "on application start.\n"
+ "<object_type>: is optional, if omitted - table\n"
+ "type is assumed.\n"
+ "Other object types can be query, report, form,\n"
+ "script (may be more or less, depending on your\n"
+ "plugins installed).\n"
+ "Use \"\" chars to specify names containing spaces.\n"
+ "Examples: --open MyTable,\n"
+ " --open query:\"My very big query\""), 0 },
+ { "design [<object_type>:]<object_name>", I18N_NOOP(
+ "\nLike --open, but the object will\n"
+ "be opened in Design Mode, if one is available."), 0 },
+ { "edittext [<object_type>:]<object_name>", I18N_NOOP(
+ "\nLike --open, but the object will\n"
+ "be opened in Text Mode, if one is available."), 0 },
+ { "exec", 0, 0 },
+ { "execute [<object_type>:]<object_name>", I18N_NOOP(
+ "\nStart execution of object of type <object_type>\n"
+ "and name <object_name> on application start.\n"
+ "<object_type>: is optional, if omitted - macro\n"
+ "type is assumed.\n"
+ "Other object types can be script (may be more\n"
+ "or less, depending on your plugins installed).\n"
+ "Use \"\" chars to specify names containing spaces."), 0 },
+ { "new <object_type>", I18N_NOOP(
+ "Start new object design of type <object_type>."), 0 },
+ { "print [<object_type>:]<object_name>", I18N_NOOP(
+ "\nOpen the Print dialog window for an object of type\n"
+ "<object_type> and name <object_name> in the specified\n"
+ "project when the application starts, for quick printing\n"
+ "of the object's data.\n"
+ "<object_type>: is optional; if omitted, table\n"
+ "type is assumed. Object type can also be query."), 0 },
+ { "print-preview [<object_type>:]<object_name>", I18N_NOOP(
+ "\nOpen Print Preview window for object\n"
+ "of type <object_type> and name <object_name>\n"
+ "from specified project on application start.\n"
+ "See --print for more details."), 0 },
+
+ { ":", I18N_NOOP("Options related to database servers:"), 0 },
+ { "u", 0, 0 },
+ { "user <name>", I18N_NOOP(
+ "User name to be used\n"
+ "for connecting to a database project.\n"
+ "Ignored if a shortcut filename\n"
+ "is provided."), 0 },
+/* { "password <password>", I18N_NOOP(
+ "User password to be used\n"
+ "for connecting to a database project.\n"
+ "Ignored if a shortcut filename\n"
+ "is provided."), 0 },*/
+ { "h", 0, 0 },
+ { "host <name>", I18N_NOOP(
+ "Server (host) name to be used\n"
+ "for connecting to a database project.\n"
+ "Ignored if a shortcut filename\n"
+ "is provided."), 0 },
+ { "port <number>", I18N_NOOP(
+ "Server's port number to be used\n"
+ "for connecting to a database project.\n"
+ "Ignored if a shortcut filename\n"
+ "is provided."), 0 },
+ { "local-socket <filename>", I18N_NOOP(
+ "Server's local socket filename\n"
+ "to be used for connecting to a database\n"
+ "project. Ignored if a shortcut filename\n"
+ "is provided."), 0 },
+ { "skip-conn-dialog", I18N_NOOP(
+ "Skip displaying connection dialog window\n"
+ "and connect directly. Available when\n"
+ "opening .kexic or .kexis shortcut files."), 0 },
+
+ { "+[project-name]", I18N_NOOP(
+ "Kexi database project filename,\n"
+ "Kexi shortcut filename,\n"
+ "or name of a Kexi database\n"
+ "project on a server to open."), 0 },
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+ KCmdLineLastOption
+};
+
+#endif
+
diff --git a/kexi/core/kexicontexthelp.cpp b/kexi/core/kexicontexthelp.cpp
new file mode 100644
index 00000000..4ccfa2fe
--- /dev/null
+++ b/kexi/core/kexicontexthelp.cpp
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.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 "kexicontexthelp.h"
+#include <KoContextCelp.h>
+#include <kxmlguiclient.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kaction.h>
+#include <qlayout.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+KexiContextHelp::KexiContextHelp(KexiMainWindow *view, QWidget *parent)
+ :KoContextHelpWidget(parent,"kexi_contexthelp")
+{
+ kdDebug()<<"KexiContextHelp::KexiContextHelp()"<<endl;
+ setCaption(i18n("Context Help"));
+ setIcon(SmallIcon("help"));
+ connect(this,SIGNAL(linkClicked( const QString& )),
+ this,SLOT(linkClickedInternal( const QString& )));
+}
+
+void KexiContextHelp::linkClickedInternal(const QString& link) {
+ kdDebug()<<"KexiContextHelp: Link: "<<link<<endl;
+ unhandledLink(link);
+}
+
+KexiContextHelp::~KexiContextHelp()
+{
+}
+
+#include "kexicontexthelp.moc"
diff --git a/kexi/core/kexicontexthelp.h b/kexi/core/kexicontexthelp.h
new file mode 100644
index 00000000..3a97e20c
--- /dev/null
+++ b/kexi/core/kexicontexthelp.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.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 KEXICONTEXTHELP_H
+#define KEXICONTEXTHELP_H
+
+
+#include "keximainwindow.h"
+#include <KoContextCelp.h>
+
+class KEXICORE_EXPORT KexiContextHelp : public KoContextHelpWidget
+{
+ Q_OBJECT
+
+ public:
+ KexiContextHelp(KexiMainWindow *view, QWidget *parent=0);
+ ~KexiContextHelp();
+ private slots:
+ void linkClickedInternal(const QString &link);
+
+ signals:
+ void unhandledLink( const QString& link );
+};
+
+#endif
diff --git a/kexi/core/kexicontexthelp_p.h b/kexi/core/kexicontexthelp_p.h
new file mode 100644
index 00000000..ab9af166
--- /dev/null
+++ b/kexi/core/kexicontexthelp_p.h
@@ -0,0 +1,35 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.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 _kexicontexthelp_p_h_
+#define _kexicontexthelp_p_h_
+
+class KexiContextHelpInfo {
+public:
+ KexiContextHelpInfo() {
+ caption="";
+ text="";
+ iconName="";
+ }
+ QString caption;
+ QString text;
+ QString iconName;
+
+};
+#endif
diff --git a/kexi/core/kexidataiteminterface.cpp b/kexi/core/kexidataiteminterface.cpp
new file mode 100644
index 00000000..8fe78c85
--- /dev/null
+++ b/kexi/core/kexidataiteminterface.cpp
@@ -0,0 +1,146 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexidataiteminterface.h"
+
+#include <kdebug.h>
+
+KexiDataItemChangesListener::KexiDataItemChangesListener()
+{
+}
+
+KexiDataItemChangesListener::~KexiDataItemChangesListener()
+{
+}
+
+//-----------------------------------------------
+
+KexiDataItemInterface::KexiDataItemInterface()
+ : m_listener(0)
+ , m_listenerIsQObject(false)
+ , m_parentDataItemInterface(0)
+ , m_hasFocusableWidget(true)
+ , m_disable_signalValueChanged(false)
+ , m_acceptEditorAfterDeleteContents(false)
+{
+}
+
+KexiDataItemInterface::~KexiDataItemInterface()
+{
+}
+
+void KexiDataItemInterface::setValue(const QVariant& value, const QVariant& add,
+ bool removeOld, const QVariant* visibleValue)
+{
+ m_disable_signalValueChanged = true; //to prevent emmiting valueChanged()
+//needed? clear();
+ if (dynamic_cast<QObject*>(this)) {
+ kdDebug() << "KexiDataItemInterface::setValue(): " <<
+ dynamic_cast<QObject*>(this)->className() << " "
+ << dynamic_cast<QWidget*>(this)->name()
+ << " value=" << value << " add=" << add << endl;
+ }
+ m_origValue = value;
+ setValueInternal(add, removeOld);
+ if (visibleValue)
+ setVisibleValueInternal(*visibleValue);
+ m_disable_signalValueChanged = false;
+}
+
+void KexiDataItemInterface::setVisibleValueInternal(const QVariant& value)
+{
+ Q_UNUSED(value);
+}
+
+void KexiDataItemInterface::signalValueChanged()
+{
+ if (m_disable_signalValueChanged || isReadOnly())
+ return;
+ if (m_parentDataItemInterface) {
+ m_parentDataItemInterface->signalValueChanged();
+ return;
+ }
+ if (m_listener) {
+ beforeSignalValueChanged();
+ m_listener->valueChanged(this);
+ }
+}
+
+bool KexiDataItemInterface::valueChanged()
+{
+// bool ok;
+// kdDebug() << m_origValue.toString() << " ? " << value(ok).toString() << endl;
+// return (m_origValue != value(ok)) && ok;
+ kdDebug() << "KexiDataItemInterface::valueChanged(): " << m_origValue.toString() << " ? " << value().toString() << endl;
+ return m_origValue != value();
+}
+
+/*
+void KexiDataItemInterface::setValue(const QVariant& value)
+{
+ m_disable_signalValueChanged = true; //to prevent emmiting valueChanged()
+ setValueInternal( value );
+ m_disable_signalValueChanged = false;
+}*/
+
+KexiDataItemChangesListener* KexiDataItemInterface::listener()
+{
+ if (!m_listener || !m_listenerIsQObject)
+ return m_listener;
+ if (!m_listenerObject)
+ m_listener = 0; //destroyed, update pointer
+ return m_listener;
+}
+
+void KexiDataItemInterface::installListener(KexiDataItemChangesListener* listener)
+{
+ m_listener = listener;
+ m_listenerIsQObject = dynamic_cast<QObject*>(listener);
+ if (m_listenerIsQObject)
+ m_listenerObject = dynamic_cast<QObject*>(listener);
+}
+
+void KexiDataItemInterface::showFocus( const QRect& r, bool readOnly )
+{
+ Q_UNUSED(r);
+ Q_UNUSED(readOnly);
+}
+
+void KexiDataItemInterface::hideFocus()
+{
+}
+
+void KexiDataItemInterface::clickedOnContents()
+{
+}
+
+bool KexiDataItemInterface::valueIsValid()
+{
+ return true;
+}
+
+void KexiDataItemInterface::setParentDataItemInterface(KexiDataItemInterface* parentDataItemInterface)
+{
+ m_parentDataItemInterface = parentDataItemInterface;
+}
+
+bool KexiDataItemInterface::cursorAtNewRow()
+{
+ return listener() ? listener()->cursorAtNewRow() : false;
+}
diff --git a/kexi/core/kexidataiteminterface.h b/kexi/core/kexidataiteminterface.h
new file mode 100644
index 00000000..dbd38005
--- /dev/null
+++ b/kexi/core/kexidataiteminterface.h
@@ -0,0 +1,249 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIDATAITEMINTERFACE_H
+#define KEXIDATAITEMINTERFACE_H
+
+#include <qvariant.h>
+#include <qwidget.h>
+#include <qguardedptr.h>
+
+class KexiDataItemInterface;
+namespace KexiDB {
+ class Field;
+ class QueryColumnInfo;
+}
+
+//! An helper class used to react on KexiDataItemInterface objects' changes.
+class KEXICORE_EXPORT KexiDataItemChangesListener
+{
+ public:
+ KexiDataItemChangesListener();
+ virtual ~KexiDataItemChangesListener();
+
+ /*! Implement this to react for change of \a item.
+ Called by KexiDataItemInterface::valueChanged() */
+ virtual void valueChanged(KexiDataItemInterface* item) = 0;
+
+ /*! Implement this to return information whether we're currently at new row or not.
+ This can be used e.g. by data-aware widgets to determine if "(autonumber)"
+ label should be displayed. */
+ virtual bool cursorAtNewRow() const = 0;
+};
+
+//! An interface for declaring widgets to be data-aware.
+class KEXICORE_EXPORT KexiDataItemInterface
+{
+ public:
+ KexiDataItemInterface();
+ virtual ~KexiDataItemInterface();
+
+ /*! Just initializes \a value, and calls setValueInternal(const QString& add, bool removeOld).
+ If \a removeOld is true, current value is set up as \a add.
+ If \a removeOld if false, current value is set up as \a value + \a add.
+ \a value is stored as 'old value' -it'd be usable in the future
+ (e.g. Combo Box editor can use old value if current value does not
+ match any item on the list).
+
+ \a visibleValue (if not NULL) is passed to provide visible value to display instead of \a value.
+ This is currently used only in case of the combo box form widget, where displayed content
+ (usually a text of image) differs from the value of the widget (a numeric index).
+
+ This method is called by table view's and form's editors. */
+ void setValue(const QVariant& value, const QVariant& add = QVariant(), bool removeOld = false,
+ const QVariant* visibleValue = 0);
+
+ //! \return field information for this item
+ virtual KexiDB::Field *field() const = 0;
+
+ //! \return column information for this item
+ virtual KexiDB::QueryColumnInfo* columnInfo() const = 0;
+
+ //! Used internally to set column information.
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo) = 0;
+
+ //! Sets listener. No need to reimplement this.
+ virtual void installListener(KexiDataItemChangesListener* listener);
+
+// //! Sets value \a value for a widget.
+// //! Just calls setValueInternal(), but also blocks valueChanged()
+// //! as you we don't want to react on our own change
+// void setValue(const QVariant& value);
+
+ //! \return value currently represented by this item.
+ virtual QVariant value() = 0;
+
+ //! \return true if editor's value is valid for a given type
+ //! Used for checking if an entered value is valid,
+ //! E.g. a part of time value can be entered: "12:8" and this is invalid, not only null.
+ //! Null time or date is valid in Kexi, so it is not enough to test value().isValid().
+ //! Default implementation just returns true.
+ virtual bool valueIsValid();
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table or form is met.
+ virtual bool valueIsNull() = 0;
+
+ //! \return true if editor's value is empty (not necessary null).
+ //! Only few data types can accept "EMPTY" property
+ //! (use KexiDB::Field::hasEmptyProperty() to check this).
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsEmpty() = 0;
+
+ //! \return value that should be displayed for this item.
+ //! Only used for items like combo box, where real value is an integer while
+ //! displayed value is usually a text. For other item types this method should be empty.
+ virtual QVariant visibleValue() { return QVariant(); }
+
+ /*! \return 'readOnly' flag for this item. The flag is usually taken from
+ the item's widget, e.g. KLineEdit::isReadOnly().
+ By default, always returns false. */
+ virtual bool isReadOnly() const { return false; }
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget() = 0;
+
+ /*! Hides item's widget, if available. */
+ virtual void hideWidget() { if (widget()) widget()->hide(); }
+
+ /*! Shows item's widget, if available. */
+ virtual void showWidget() { if (widget()) widget()->show(); }
+
+ //! \return true if editor's value is changed (compared to original value)
+ virtual bool valueChanged();
+
+ /*! \return true if the item widget's cursor (whatever that means, eg. line edit cursor)
+ is at the beginning of editor's contents. This can inform table/form view that
+ after pressing "left arrow" key should stop editing and move to a field on the left hand. */
+ virtual bool cursorAtStart() = 0;
+
+ /*! \return true if the item widget's cursor (whatever that means, eg. line edit cursor)
+ is at the end of editor's contents. This can inform table/form view that
+ after pressing "right arrow" key should stop editing and move to a field on the right hand. */
+ virtual bool cursorAtEnd() = 0;
+
+ /*! Moves cursor after the last character (or element).
+ For implementation in items supporting text cursor's movement; by default does nothing. */
+ virtual void moveCursorToEnd() {};
+
+ /*! Moves cursor before the first character (or element).
+ For implementation in items supporting text cursor's movement; by default does nothing. */
+ virtual void moveCursorToStart() {};
+
+ /*! Selects all characters (or elements) of the item.
+ For implementation in items supporting text or elements; by default does nothing. */
+ virtual void selectAll() {};
+
+ //! clears item's data, so the data will contain NULL data
+ virtual void clear() = 0;
+
+ /*! \return true if this editor offers a widget (e.g. line edit) that we can move focus to.
+ Editor for boolean values has this set to false (see KexiBoolTableEdit).
+ This is true by default. You can override this flag by changing
+ m_hasFocusableWidget in your subclass' constructor. */
+ inline bool hasFocusableWidget() const { return m_hasFocusableWidget; }
+
+ /*! Displays additional elements that are needed for indicating that the current cell
+ is selected. For example, combobox editor (KexiComboBoxTableEdit) moves and shows
+ dropdown button. \a r is the rectangle for the cell.
+ If \a readOnly is true, additional elements should be visually disabled,
+ e.g. dropdown button of the combobox editor should be disabled.
+ For reimplementation. By default does nothing. */
+ virtual void showFocus( const QRect& r, bool readOnly );
+
+ /*! Hides additional elements that are needed for indicating that the current cell
+ is selected.
+ For reimplementation. By default does nothing. */
+ virtual void hideFocus();
+
+ /*! Allows to define reaction for clicking on cell's contents.
+ Currently it's used for editor of type boolean, where we want to toggle true/false
+ on single mouse click. \sa hasFocusableWidget(), KexiBoolTableEdit.
+ Default implementation does nothing. */
+ virtual void clickedOnContents();
+
+ /*! \return true if editing should be accepted immediately after
+ deleting contents for the cell (usually using Delete key).
+ This flag is false by default, and is true e.g. for date, time and datetime types. */
+ bool acceptEditorAfterDeleteContents() const { return m_acceptEditorAfterDeleteContents; }
+
+ inline virtual void setFocus() { if (widget()) widget()->setFocus(); }
+
+ bool cursorAtNewRow();
+
+ /*! Sets a pointer to a Parent Data Item Interface. This pointer is 0 by default,
+ but can be set by parent widget if this interface is a building block of a larger data widget.
+ It is the case for KexiDBFieldEdit widget (see KexiDBFieldEdit::createEditor()). Use with care.
+ signalValueChanged() method will check this pointer, and if it's not 0,
+ m_parentDataItemInterface->signalValueChanged() is called, so a changes can be signalled at higher level. */
+ void setParentDataItemInterface(KexiDataItemInterface* parentDataItemInterface);
+
+ /*! \return a pointer to a Parent Data Item Interface.
+ @see setParentDataItemInterface() */
+ inline KexiDataItemInterface* parentInterface() const { return m_parentDataItemInterface; }
+
+ /*! Handles action having standard name \a actionName.
+ Action could be: "edit_cut", "edit_paste", etc.
+ For reimplementation. */
+ virtual void handleAction(const QString& actionName) { Q_UNUSED(actionName); }
+
+ protected:
+ /*! Initializes this editor with \a add value, which should be somewhat added to the current
+ value (already storted in m_origValue).
+ If \a removeOld is true, a value should be set to \a add, otherwise
+ -it should be set to current \a m_origValue + \a add, if possible.
+ Implement this. */
+ virtual void setValueInternal(const QVariant& add, bool removeOld) = 0;
+
+ /*! Initializes this editor with \a value visible value.
+ This is currently used only in case of the combo box form widget, where displayed content
+ (usually a text of image) differs from the value of the widget (a numeric index).
+ For implementation in the combo box widget, by default does nothing. */
+ virtual void setVisibleValueInternal(const QVariant& value);
+
+// //! Sets value \a value for a widget.
+// //! Implement this method to allow setting value for this widget item.
+// virtual void setValueInternal(const QVariant& value) = 0;
+
+ /*! Call this in your implementation when value changes,
+ so installed listener can react on this change. If there is a parent data item defined
+ (see setParentDataItemInterface()), parent's signalValueChanged() method will be called instead. */
+ virtual void signalValueChanged();
+
+ /*! Used to perform some actions before signalValueChanged() call.
+ We need this because the intrface is not QObject and thus has got no real signals.
+ Used in KexiDBComboBox. */
+ virtual void beforeSignalValueChanged() {};
+
+ KexiDataItemChangesListener* listener();
+
+//moved to KexiFormDataItemInterface: QString m_dataSource;
+ QGuardedPtr<QObject> m_listenerObject;
+ KexiDataItemChangesListener* m_listener;
+ bool m_listenerIsQObject;
+ QVariant m_origValue;
+
+ /*! @see parentDataItemInterface() */
+ KexiDataItemInterface* m_parentDataItemInterface;
+ bool m_hasFocusableWidget : 1;
+ bool m_disable_signalValueChanged : 1;
+ bool m_acceptEditorAfterDeleteContents : 1;
+};
+
+#endif
diff --git a/kexi/core/kexidbconnectionset.cpp b/kexi/core/kexidbconnectionset.cpp
new file mode 100644
index 00000000..1a0eb774
--- /dev/null
+++ b/kexi/core/kexidbconnectionset.cpp
@@ -0,0 +1,183 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexidbconnectionset.h"
+#include "kexidbshortcutfile.h"
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+
+#include <qfile.h>
+
+//! @internal
+class KexiDBConnectionSetPrivate
+{
+public:
+ KexiDBConnectionSetPrivate()
+ : dataForFilenames(101)
+ {
+ list.setAutoDelete(true);
+ maxid=-1;
+ }
+ KexiDB::ConnectionData::List list;
+ QMap<KexiDB::ConnectionData*, QString> filenamesForData;
+ QDict<KexiDB::ConnectionData> dataForFilenames;
+ int maxid;
+};
+
+KexiDBConnectionSet::KexiDBConnectionSet()
+: QObject()
+, d(new KexiDBConnectionSetPrivate())
+{
+}
+
+KexiDBConnectionSet::~KexiDBConnectionSet()
+{
+ delete d;
+}
+
+bool KexiDBConnectionSet::addConnectionData(KexiDB::ConnectionData *data, const QString& _filename)
+{
+ if (!data)
+ return false;
+ if (data->id<0)
+ data->id = d->maxid+1;
+ //TODO: check for id-duplicates
+
+ d->maxid = QMAX(d->maxid,data->id);
+// d->list.append(data);
+
+ QString filename( _filename );
+ bool generateUniqueFilename = filename.isEmpty()
+ || !filename.isEmpty() && data==d->dataForFilenames[filename];
+
+ if (generateUniqueFilename) {
+ QString dir = KGlobal::dirs()->saveLocation("data", "kexi/connections/", false /*!create*/);
+ if (dir.isEmpty())
+ return false;
+ QString baseFilename( dir + (data->hostName.isEmpty() ? "localhost" : data->hostName) );
+ int i = 0;
+ while (KStandardDirs::exists(baseFilename+(i>0 ? QString::number(i) : QString::null)+".kexic"))
+ i++;
+ if (!KStandardDirs::exists(dir)) {
+ //make 'connections' dir and protect it
+ if (!KStandardDirs::makeDir(dir, 0700))
+ return false;
+ }
+ filename = baseFilename+(i>0 ? QString::number(i) : QString::null)+".kexic";
+ }
+ addConnectionDataInternal(data, filename);
+ bool result = saveConnectionData(data, data);
+ if (!result)
+ removeConnectionDataInternal(data);
+ return result;
+}
+
+void KexiDBConnectionSet::addConnectionDataInternal(KexiDB::ConnectionData *data, const QString& filename)
+{
+ d->filenamesForData.insert(data, filename);
+ d->dataForFilenames.insert(filename, data);
+ d->list.append(data);
+}
+
+bool KexiDBConnectionSet::saveConnectionData(KexiDB::ConnectionData *oldData,
+ KexiDB::ConnectionData *newData)
+{
+ if (!oldData || !newData)
+ return false;
+ QMap<KexiDB::ConnectionData*, QString>::ConstIterator it = d->filenamesForData.find( oldData );
+ if (it == d->filenamesForData.constEnd() || it.data().isEmpty())
+ return false;
+ const QString filename( it.data() );
+ KexiDBConnShortcutFile shortcutFile(filename);
+ if (!shortcutFile.saveConnectionData(*newData, newData->savePassword)) // true/*savePassword*/))
+ return false;
+ if (oldData!=newData)
+ *oldData = *newData;
+ return true;
+}
+
+void KexiDBConnectionSet::removeConnectionDataInternal(KexiDB::ConnectionData *data)
+{
+ QMap<KexiDB::ConnectionData*, QString>::ConstIterator it = d->filenamesForData.find( data );
+ const QString filename( it.data() );
+ d->filenamesForData.remove(data);
+ d->dataForFilenames.remove(filename);
+ d->list.removeRef(data);
+}
+
+bool KexiDBConnectionSet::removeConnectionData(KexiDB::ConnectionData *data)
+{
+ if (!data)
+ return false;
+ QMap<KexiDB::ConnectionData*, QString>::ConstIterator it = d->filenamesForData.find( data );
+ if (it == d->filenamesForData.constEnd() || it.data().isEmpty())
+ return false;
+ QFile file( it.data() );
+ if (!file.remove())
+ return false;
+ removeConnectionDataInternal(data);
+ return true;
+}
+
+const KexiDB::ConnectionData::List& KexiDBConnectionSet::list() const
+{
+ return d->list;
+}
+
+void KexiDBConnectionSet::clear()
+{
+ d->list.clear();
+ d->filenamesForData.clear();
+ d->dataForFilenames.clear();
+}
+
+void KexiDBConnectionSet::load()
+{
+ clear();
+// QStringList dirs( KGlobal::dirs()->findDirs("data", "kexi/connections") );
+// kexidbg << dirs << endl;
+ QStringList files( KGlobal::dirs()->findAllResources("data", "kexi/connections/*.kexic") );
+// //also try for capital file extension
+// files += KGlobal::dirs()->findAllResources("data", "kexi/connections/*.KEXIC");
+// kexidbg << files << endl;
+
+ foreach(QStringList::ConstIterator, it, files) {
+ KexiDB::ConnectionData *data = new KexiDB::ConnectionData();
+ KexiDBConnShortcutFile shortcutFile( *it );
+ if (!shortcutFile.loadConnectionData(*data)) {
+ delete data;
+ continue;
+ }
+ addConnectionDataInternal(data, *it);
+ }
+}
+
+QString KexiDBConnectionSet::fileNameForConnectionData(KexiDB::ConnectionData *data) const
+{
+ if (!data)
+ return QString::null;
+ QMap<KexiDB::ConnectionData*, QString>::ConstIterator it = d->filenamesForData.find( data );
+ return (it == d->filenamesForData.constEnd()) ? QString::null : it.data();
+}
+
+KexiDB::ConnectionData* KexiDBConnectionSet::connectionDataForFileName(const QString& fileName) const
+{
+ return d->dataForFilenames[fileName];
+}
diff --git a/kexi/core/kexidbconnectionset.h b/kexi/core/kexidbconnectionset.h
new file mode 100644
index 00000000..78d4649a
--- /dev/null
+++ b/kexi/core/kexidbconnectionset.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIDBCONNSET_H
+#define KEXIDBCONNSET_H
+
+#include <qstring.h>
+#include <kexidb/connectiondata.h>
+
+class KexiDBConnectionSetPrivate;
+
+/*! Stores information about multiple connection-data items. */
+class KEXICORE_EXPORT KexiDBConnectionSet : public QObject
+{
+public:
+ KexiDBConnectionSet();
+ ~KexiDBConnectionSet();
+
+ /*! Loads connection data set from storage, currently from
+ .kexic files saved in dirs returned by
+ KStandardDirs::findDirs("data", "connections") */
+ void load();
+
+ /*! Adds \a data as connection data.
+ \a data will be owned by a KexiDBConnectionSet object.
+ If \a filename is not empty, it will be kept for use in saveConnectionData().
+ saveConnectionData() is called automatically, if there's no \a filename provided
+ or the filename is already used, a new unique will be generated.
+ \return true on successful creating corresponding .kexic file */
+ bool addConnectionData(KexiDB::ConnectionData *data, const QString& filename = QString::null);
+
+ /*! Saves changes made to \a oldData to a file which name has been provided by addConnectionData().
+ This function does nothing if \a oldData hasn't been added to this set.
+ \return true on success (data is then copied from \a newData to \a oldData) */
+ bool saveConnectionData(KexiDB::ConnectionData *oldData, KexiDB::ConnectionData *newData);
+
+ /*! Removed \a data from this set.
+ \return true on successful removing of corresponding .kexic file */
+ bool removeConnectionData(KexiDB::ConnectionData *data);
+
+ /*! \return the list of connection data items. */
+ const KexiDB::ConnectionData::List& list() const;
+
+ /*! \return a filename of a connection data file for \a data. */
+ QString fileNameForConnectionData(KexiDB::ConnectionData *data) const;
+
+ /*! \return a connection data for a .kexic shortcut filename.
+ 0 is returned if the filename does not match. */
+ KexiDB::ConnectionData* connectionDataForFileName(const QString& fileName) const;
+
+private:
+ /*! Removes all connection data items from this set. */
+ void clear();
+ void addConnectionDataInternal(KexiDB::ConnectionData *data, const QString& filename);
+ void removeConnectionDataInternal(KexiDB::ConnectionData *data);
+
+ KexiDBConnectionSetPrivate *d;
+};
+
+#endif // KEXIDBCONNSET_H
+
diff --git a/kexi/core/kexidbshortcutfile.cpp b/kexi/core/kexidbshortcutfile.cpp
new file mode 100644
index 00000000..4a503d43
--- /dev/null
+++ b/kexi/core/kexidbshortcutfile.cpp
@@ -0,0 +1,314 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexidbshortcutfile.h"
+#include <core/kexiprojectdata.h>
+#include <kexidb/connectiondata.h>
+#include <kexiutils/utils.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include <qstringlist.h>
+#include <qdir.h>
+
+//! Version of the KexiDBShortcutFile format.
+#define KexiDBShortcutFile_version 2
+/* CHANGELOG:
+ v1: initial version
+ v2: "encryptedPassword" field added.
+ For backward compatibility, it is not used if the connection data has been loaded from
+ a file saved with version 1. In such cases unencrypted "password" field is used.
+*/
+
+//! @internal
+class KexiDBShortcutFile::Private
+{
+ public:
+ Private()
+ : isDatabaseShortcut(true)
+ {
+ }
+ QString fileName;
+ bool isDatabaseShortcut : 1;
+};
+
+KexiDBShortcutFile::KexiDBShortcutFile( const QString& fileName )
+ : d( new KexiDBShortcutFile::Private() )
+{
+ d->fileName = QDir(fileName).absPath();
+}
+
+KexiDBShortcutFile::~KexiDBShortcutFile()
+{
+ delete d;
+}
+
+bool KexiDBShortcutFile::loadProjectData(KexiProjectData& data, QString* _groupKey)
+{
+ KConfig config(d->fileName, true /* readOnly */, false /* local */ );
+ config.setGroup("File Information");
+ data.formatVersion = config.readNumEntry("version", KexiDBShortcutFile_version);
+
+ QString groupKey;
+ if (!_groupKey || _groupKey->isEmpty()) {
+ QStringList groups(config.groupList());
+ foreach (QStringList::ConstIterator, it, groups) {
+ if ((*it).lower()!="file information") {
+ groupKey = *it;
+ break;
+ }
+ }
+ if (groupKey.isEmpty()) {
+ //ERR: "File %1 contains no connection information"
+ return false;
+ }
+ if (_groupKey)
+ *_groupKey = groupKey;
+ }
+ else {
+ if (!config.hasGroup(*_groupKey))
+ return false;
+ groupKey = *_groupKey;
+ }
+
+ config.setGroup(groupKey);
+ QString type( config.readEntry("type", "database").lower() );
+
+ if (type=="database") {
+ d->isDatabaseShortcut = true;
+ } else if (type=="connection") {
+ d->isDatabaseShortcut = false;
+ }
+ else {
+ //ERR: i18n("No valid "type" field specified for section \"%1\": unknown value \"%2\".").arg(group).arg(type)
+ return false;
+ }
+
+/* kexidbg << "version=" << version
+ << " using group key=" << groupKey
+ << " type=" << type
+ << " caption=" << config.readEntry("caption")
+ << " name=" << config.readEntry("name")
+ << " engine=" << config.readEntry("engine")
+ << " server=" << config.readEntry("server")
+ << " user=" << config.readEntry("user")
+ << " password=" << QString().fill('*', config.readEntry("password").length())
+ << " comment=" << config.readEntry("comment")
+ << endl;*/
+
+ //no filename by default
+ data.connectionData()->setFileName(QString::null);
+
+ if (d->isDatabaseShortcut) {
+ data.setCaption( config.readEntry("caption") );
+ data.setDescription( config.readEntry("comment") );
+ data.connectionData()->description = QString::null;
+ data.connectionData()->caption = QString::null; /* connection name is not specified... */
+ data.setDatabaseName( config.readEntry("name") );
+ }
+ else {
+ data.setCaption( QString::null );
+ data.connectionData()->caption = config.readEntry("caption");
+ data.setDescription( QString::null );
+ data.connectionData()->description = config.readEntry("comment");
+ data.setDatabaseName( QString::null ); /* db name is not specified... */
+ }
+ data.connectionData()->driverName = config.readEntry("engine");
+ if (data.connectionData()->driverName.isEmpty()) {
+ //ERR: "No valid "engine" field specified for %1 section" group
+ return false;
+ }
+ data.connectionData()->hostName = config.readEntry("server"); //empty allowed
+ data.connectionData()->port = config.readNumEntry("port", 0);
+ data.connectionData()->useLocalSocketFile = config.readBoolEntry("useLocalSocketFile", false);
+ data.connectionData()->localSocketFileName = config.readEntry("localSocketFile");
+ data.connectionData()->savePassword = config.hasKey("password") || config.hasKey("encryptedPassword");
+ if (data.formatVersion >= 2) {
+ kdDebug() << config.hasKey("encryptedPassword") << endl;
+ data.connectionData()->password = config.readEntry("encryptedPassword");
+ KexiUtils::simpleDecrypt(data.connectionData()->password);
+ }
+ if (data.connectionData()->password.isEmpty()) {//no "encryptedPassword", for compatibility
+ //UNSAFE
+ data.connectionData()->password = config.readEntry("password");
+ }
+// data.connectionData()->savePassword = !data.connectionData()->password.isEmpty();
+ data.connectionData()->userName = config.readEntry("user");
+/* @todo add "options=", eg. as string list? */
+ return true;
+}
+
+bool KexiDBShortcutFile::saveProjectData(const KexiProjectData& data,
+ bool savePassword, QString* _groupKey, bool overwriteFirstGroup)
+{
+ KConfig config(d->fileName, false /*rw*/, false /* local */);
+ config.setGroup("File Information");
+
+ uint realFormatVersion = data.formatVersion;
+ if (realFormatVersion == 0) /* 0 means "default version"*/
+ realFormatVersion = KexiDBShortcutFile_version;
+ config.writeEntry("version", realFormatVersion);
+
+ const bool thisIsConnectionData = data.databaseName().isEmpty();
+
+ //use or find a nonempty group key
+ QString groupKey;
+ if (_groupKey && !_groupKey->isEmpty()) {
+ groupKey = *_groupKey;
+ }
+ else {
+ QString groupPrefix;
+ const QStringList groups(config.groupList());
+ if (overwriteFirstGroup && !groups.isEmpty()) {
+// groupKey = groups.first(); //found
+ foreach (QStringList::ConstIterator, it, groups) {
+ if ((*it).lower()!="file information") {
+ groupKey = *it;
+ break;
+ }
+ }
+ }
+
+ if (groupKey.isEmpty()) {
+ //find a new unique name
+ if (thisIsConnectionData)
+ groupPrefix = "Connection%1"; //do not i18n!
+ else
+ groupPrefix = "Database%1"; //do not i18n!
+
+ int number = 1;
+ while (config.hasGroup(groupPrefix.arg(number))) //a new group key couldn't exist
+ number++;
+ groupKey = groupPrefix.arg(number);
+ }
+ if (_groupKey) //return this one (generated or found)
+ *_groupKey = groupKey;
+ }
+
+ config.deleteGroup(groupKey);
+ config.setGroup(groupKey);
+ if (thisIsConnectionData) {
+ config.writeEntry("type", "connection");
+ config.writeEntry("caption", data.constConnectionData()->caption);
+ if (!data.constConnectionData()->description.isEmpty())
+ config.writeEntry("comment", data.constConnectionData()->description);
+ }
+ else {//database
+ config.writeEntry("type", "database");
+ config.writeEntry("caption", data.caption());
+ config.writeEntry("name", data.databaseName());
+ if (!data.description().isEmpty())
+ config.writeEntry("comment", data.description());
+ }
+
+ config.writeEntry("engine", data.constConnectionData()->driverName);
+ if (!data.constConnectionData()->hostName.isEmpty())
+ config.writeEntry("server", data.constConnectionData()->hostName);
+
+ if (data.constConnectionData()->port!=0)
+ config.writeEntry("port", data.constConnectionData()->port);
+ config.writeEntry("useLocalSocketFile", data.constConnectionData()->useLocalSocketFile);
+ if (!data.constConnectionData()->localSocketFileName.isEmpty())
+ config.writeEntry("localSocketFile", data.constConnectionData()->localSocketFileName);
+
+ if (savePassword || data.constConnectionData()->savePassword) {
+ if (realFormatVersion < 2) {
+ config.writeEntry("password", data.constConnectionData()->password);
+ }
+ else {
+ QString encryptedPassword = data.constConnectionData()->password;
+ KexiUtils::simpleCrypt(encryptedPassword);
+ config.writeEntry("encryptedPassword", encryptedPassword);
+ encryptedPassword.fill(' '); //for security
+ }
+ }
+
+ if (!data.constConnectionData()->userName.isEmpty())
+ config.writeEntry("user", data.constConnectionData()->userName);
+/* @todo add "options=", eg. as string list? */
+ config.sync();
+ return true;
+}
+
+QString KexiDBShortcutFile::fileName() const
+{
+ return d->fileName;
+}
+
+//---------------------------------------------
+
+KexiDBConnShortcutFile::KexiDBConnShortcutFile( const QString& fileName )
+ : KexiDBShortcutFile( fileName )
+{
+}
+
+KexiDBConnShortcutFile::~KexiDBConnShortcutFile()
+{
+}
+
+bool KexiDBConnShortcutFile::loadConnectionData(KexiDB::ConnectionData& data, QString* _groupKey)
+{
+ KexiProjectData pdata(data);
+ if (!loadProjectData(pdata, _groupKey))
+ return false;
+ data = *pdata.connectionData();
+ return true;
+}
+
+bool KexiDBConnShortcutFile::saveConnectionData(const KexiDB::ConnectionData& data,
+ bool savePassword, QString* groupKey, bool overwriteFirstGroup)
+{
+ KexiProjectData pdata(data);
+ return saveProjectData(pdata, savePassword, groupKey, overwriteFirstGroup);
+}
+
+//---------------------------------------------
+
+#if 0
+/*! Loads connection data into \a data. */
+bool KexiDBConnSetShortcutFiles::loadConnectionDataSet(KexiDBConnectionSet& set)
+{
+ set.clear();
+// QStringList dirs( KGlobal::dirs()->findDirs("data", "kexi/connections") );
+// kexidbg << dirs << endl;
+ QStringList files( KGlobal::dirs()->findAllResources("data", "kexi/connections/*.kexic") );
+// //also try for capital file extension
+// files += KGlobal::dirs()->findAllResources("data", "kexi/connections/*.KEXIC");
+ kexidbg << files << endl;
+
+ foreach(QStringList::ConstIterator, it, files) {
+ KexiDB::ConnectionData *data = new KexiDB::ConnectionData();
+ KexiDBConnShortcutFile shortcutFile( *it );
+ if (!shortcutFile.loadConnectionData(*data)) {
+ delete data;
+ continue;
+ }
+ set.addConnectionData(data);
+ }
+}
+
+
+/*! Saves a set of connection data \a set to a shortcut files.
+ Existing files are overwritten with a new data. */
+bool KexiDBConnSetShortcutFiles::saveConnectionDataSet(const KexiDBConnectionSet& set)
+{
+}
+
+#endif
diff --git a/kexi/core/kexidbshortcutfile.h b/kexi/core/kexidbshortcutfile.h
new file mode 100644
index 00000000..3dfa9c13
--- /dev/null
+++ b/kexi/core/kexidbshortcutfile.h
@@ -0,0 +1,124 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIDBSHORTCUTFILE_H
+#define KEXIDBSHORTCUTFILE_H
+
+#include <qstring.h>
+
+class KexiProjectData;
+namespace KexiDB { class ConnectionData; }
+
+/*! Loads and saves information for a "shortcut to a connection" file containing
+ connection information with database name (i.e. ProjectData).
+ This is implementation for handling .KEXIS files.
+ See http://www.kexi-project.org/wiki/wikiview/index.php?KexiMimeTypes_DataSaving_Loading
+*/
+class KEXICORE_EXPORT KexiDBShortcutFile
+{
+ public:
+ /*! Creates a new object for \a fileName. */
+ KexiDBShortcutFile( const QString& fileName );
+
+ ~KexiDBShortcutFile();
+
+ /*! Loads project data (with connection data) into \a data.
+ Database name and caption can be set there but these are optional.
+ \a groupKey, if provided will be set to a group key,
+ so you can later use it in saveConnectionData().
+ \return true on success. */
+ bool loadProjectData(KexiProjectData& data, QString* groupKey = 0);
+
+ /*! Saves project data \a data (with connection data) to a shortcut file.
+ If \a storePassword is true, password will be saved in the file,
+ even if data.connectionData()->savePassword is false.
+ Existing data is merged with new data. \a groupKey is reused, if specified.
+ If \a overwriteFirstGroup is true (the default) first found group will be overwritten
+ instead of creating of a new unique group. This mode is usable for updating .kexic files
+ containing single connection data, what's used for storing connections repository.
+ \return true on success. */
+ bool saveProjectData(const KexiProjectData& data, bool savePassword,
+ QString* groupKey = 0, bool overwriteFirstGroup = true);
+
+ //! \return filename provided on this object's construction. */
+ QString fileName() const;
+
+ protected:
+ class Private;
+ Private *d;
+};
+
+/*! Loads and saves information for a "shortcut" file containing
+ connection information (i.e. KexiDB::ConnectionData).
+ This is implementation for handling .KEXIC files.
+ See http://www.kexi-project.org/wiki/wikiview/index.php?KexiMimeTypes_DataSaving_Loading
+*/
+class KEXICORE_EXPORT KexiDBConnShortcutFile : protected KexiDBShortcutFile
+{
+ public:
+ /*! Creates a new object for \a fileName. */
+ KexiDBConnShortcutFile( const QString& fileName );
+
+ ~KexiDBConnShortcutFile();
+
+ /*! Loads connection data into \a data.
+ \a groupKey, if provided will be set to a group key,
+ so you can later use it in saveConnectionData().
+ \return true on success. */
+ bool loadConnectionData(KexiDB::ConnectionData& data, QString* groupKey = 0);
+
+ /*! Saves connection data \a data to a shortcut file.
+ If \a storePassword is true, password will be saved in the file,
+ even if data.savePassword is false.
+ Existing data is merged with new data. \a groupKey is reused, if specified.
+ If \a overwriteFirstGroup is true (the default) first found group will be overwritten
+ instead of creating of a new unique group. This mode is usable for updating .kexic files
+ containing single connection data, what's used for storing connections repository.
+ \return true on success. */
+ bool saveConnectionData(const KexiDB::ConnectionData& data,
+ bool savePassword, QString* groupKey = 0, bool overwriteFirstGroup = true);
+
+ //! \return filename provided on this object's construction. */
+ QString fileName() const { return KexiDBShortcutFile::fileName(); }
+
+ protected:
+};
+
+#if 0
+//! Loads and saves information for a sef of "shortcut to a connection" file containing
+//! connection information (i.e. KexiDBConnectionSet).
+//! This is implementation for handling .KEXIC files.
+//! The set is loaded from files found using
+//! KGlobal::dirs()->findAllResources("data", "kexi/connections/*.kexic").
+class KexiDBConnSetShortcutFiles
+{
+ public:
+ KexiDBConnSetShortcutFiles();
+
+ /*! Loads connection data into \a set. The set is cleared before loading.
+ \retuirn true on successful loading. */
+ static bool loadConnectionDataSet(KexiDBConnectionSet& set);
+
+ /*! Saves a set of connection data \a set to a shortcut files.
+ Existing files are overwritten with a new data.
+ \retuirn true on successful saving. */
+ static bool saveConnectionDataSet(const KexiDBConnectionSet& set);
+}
+#endif
+#endif
diff --git a/kexi/core/kexidialogbase.cpp b/kexi/core/kexidialogbase.cpp
new file mode 100644
index 00000000..2f94e661
--- /dev/null
+++ b/kexi/core/kexidialogbase.cpp
@@ -0,0 +1,661 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexidialogbase.h"
+
+#include "keximainwindow.h"
+#include "kexiviewbase.h"
+#include "kexicontexthelp_p.h"
+#include "kexipart.h"
+#include "kexistaticpart.h"
+#include "kexipartitem.h"
+#include "kexipartinfo.h"
+#include "kexiproject.h"
+
+#include <kexidb/connection.h>
+#include <kexidb/utils.h>
+#include <kexiutils/utils.h>
+
+#include <qwidgetstack.h>
+#include <qobjectlist.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+
+KexiDialogBase::KexiDialogBase(KexiMainWindow *parent, const QString &caption)
+ : KMdiChildView(caption, parent, "KexiDialogBase")
+ , KexiActionProxy(this, parent)
+ , m_isRegistered(false)
+ , m_origCaption(caption)
+ , m_schemaData(0)
+ , m_destroying(false)
+ , m_disableDirtyChanged(false)
+// , m_neverSaved(false)
+{
+ m_supportedViewModes = 0; //will be set by KexiPart
+ m_openedViewModes = 0;
+ m_currentViewMode = Kexi::NoViewMode; //no view available yet
+ m_parentWindow = parent;
+ m_creatingViewsMode = -1;
+
+ QVBoxLayout *lyr = new QVBoxLayout(this);
+ m_stack = new QWidgetStack(this, "stack");
+ lyr->addWidget(m_stack);
+
+#ifdef KEXI_NO_CTXT_HELP
+ m_contextHelpInfo=new KexiContextHelpInfo();
+#endif
+// m_instance=parent->instance();
+ m_id = -1;
+ m_item = 0;
+
+ hide(); //will be shown later
+}
+
+KexiDialogBase::~KexiDialogBase()
+{
+ m_destroying = true;
+}
+
+KexiViewBase *KexiDialogBase::selectedView() const
+{
+ if (m_destroying)
+ return 0;
+// return static_cast<KexiViewBase*>(m_stack->visibleWidget());
+ return static_cast<KexiViewBase*>( m_stack->widget(m_currentViewMode) );
+}
+
+KexiViewBase *KexiDialogBase::viewForMode(int mode) const
+{
+ return static_cast<KexiViewBase*>( m_stack->widget(mode) );
+}
+
+void KexiDialogBase::addView(KexiViewBase *view)
+{
+ addView(view,0);
+}
+
+void KexiDialogBase::addView(KexiViewBase *view, int mode)
+{
+ m_stack->addWidget(view, mode);
+// addActionProxyChild( view );
+
+ //set focus proxy inside this view
+ QWidget *ch = static_cast<QWidget*>(view->child( 0, "QWidget", false ));
+ if (ch)
+ view->setFocusProxy(ch);
+
+ m_openedViewModes |= mode;
+}
+
+void KexiDialogBase::removeView(int mode)
+{
+ KexiViewBase *view = viewForMode(mode);
+ if (view)
+ m_stack->removeWidget(view);
+
+ m_openedViewModes |= mode;
+ m_openedViewModes ^= mode;
+}
+
+QSize KexiDialogBase::minimumSizeHint() const
+{
+ KexiViewBase *v = selectedView();
+ if (!v)
+ return KMdiChildView::minimumSizeHint();
+ return v->minimumSizeHint() + QSize(0, mdiParent() ? mdiParent()->captionHeight() : 0);
+}
+
+QSize KexiDialogBase::sizeHint() const
+{
+ KexiViewBase *v = selectedView();
+ if (!v)
+ return KMdiChildView::sizeHint();
+ return v->preferredSizeHint( v->sizeHint() );
+}
+
+/*
+KInstance *KexiDialogBase::instance() {
+ return m_instance;
+}*/
+
+void KexiDialogBase::registerDialog() {
+ if (m_isRegistered)
+ return;
+ m_parentWindow->registerChild(this);
+ m_isRegistered=true;
+ if ( m_parentWindow->mdiMode() == KMdi::ToplevelMode ) {
+ m_parentWindow->addWindow( (KMdiChildView *)this, KMdi::Detach );
+ m_parentWindow->detachWindow((KMdiChildView *)this, true);
+ }
+ else
+ m_parentWindow->addWindow((KMdiChildView *)this);
+//later show();
+// m_parentWindow->activeWindowChanged(this);
+}
+
+bool KexiDialogBase::isRegistered(){
+ return m_isRegistered;
+}
+
+void KexiDialogBase::attachToGUIClient() {
+ if (!guiClient())
+ return;
+
+}
+
+void KexiDialogBase::detachFromGUIClient() {
+ if (!guiClient())
+ return;
+ //TODO
+}
+
+int KexiDialogBase::id() const
+{
+ return (partItem() && partItem()->identifier()>0) ? partItem()->identifier() : m_id;
+}
+
+void KexiDialogBase::setContextHelp(const QString& caption, const QString& text, const QString& iconName) {
+#ifdef KEXI_NO_CTXT_HELP
+ m_contextHelpInfo->caption=caption;
+ m_contextHelpInfo->text=text;
+ m_contextHelpInfo->text=iconName;
+ updateContextHelp();
+#endif
+}
+
+void KexiDialogBase::closeEvent( QCloseEvent * e )
+{
+ m_parentWindow->acceptPropertySetEditing();
+
+ //let any view send "closing" signal
+ QObjectList *list = m_stack->queryList( "KexiViewBase", 0, false, false);
+ KexiViewBase *view;
+ QObjectListIt it( *list );
+ for ( ;(view = static_cast<KexiViewBase*>(it.current()) ) != 0; ++it ) {
+ bool cancel = false;
+ emit view->closing(cancel);
+ if (cancel) {
+ e->ignore();
+ return;
+ }
+ }
+ delete list;
+ emit closing();
+ KMdiChildView::closeEvent(e);
+}
+
+#if 0
+//js removed
+bool KexiDialogBase::tryClose(bool dontSaveChanges)
+{
+ if (!dontSaveChanges && dirty()) {
+/*TODO if (KMessageBox::questionYesNo(this, "<b>"+i18n("Do you want save:")
+ +"<p>"+typeName+" \""+ item->name() + "\"?</b>",
+ 0, KStdGuiItem::yes(), KStdGuiItem::no(), ???????)==KMessageBox::No)
+ return false;*/
+ //js TODO: save data using saveChanges()
+ }
+ close(true);
+ return true;
+}
+#endif
+
+bool KexiDialogBase::dirty() const
+{
+ //look for "dirty" flag
+ int m = m_openedViewModes, mode = 1;
+ while (m>0) {
+ if (m & 1) {
+ if (static_cast<KexiViewBase*>(m_stack->widget(mode))->dirty())
+ return true;
+ }
+ m >>= 1;
+ mode <<= 1;
+ }
+ return false;
+/* KexiViewBase *v = m_newlySelectedView ? m_newlySelectedView : selectedView();
+ return v ? v->dirty() : false;*/
+}
+
+void KexiDialogBase::setDirty(bool dirty)
+{
+ m_disableDirtyChanged = true;
+ int m = m_openedViewModes, mode = 1;
+ while (m>0) {
+ if (m & 1) {
+ static_cast<KexiViewBase*>(m_stack->widget(mode))->setDirty(dirty);
+ }
+ m >>= 1;
+ mode <<= 1;
+ }
+ m_disableDirtyChanged = false;
+ dirtyChanged(m_viewThatRecentlySetDirtyFlag); //update
+}
+
+QString KexiDialogBase::itemIcon()
+{
+ if (!m_part || !m_part->info()) {
+ KexiViewBase *v = selectedView();
+ if (v) {//m_stack->visibleWidget() && m_stack->visibleWidget()->inherits("KexiViewBase")) {
+ return v->m_defaultIconName;
+ }
+ return QString::null;
+ }
+ return m_part->info()->itemIcon();
+}
+
+KexiPart::GUIClient* KexiDialogBase::guiClient() const
+{
+ if (!m_part || m_currentViewMode<1)
+ return 0;
+ return m_part->instanceGuiClient(m_currentViewMode);
+}
+
+KexiPart::GUIClient* KexiDialogBase::commonGUIClient() const
+{
+ if (!m_part)
+ return 0;
+ return m_part->instanceGuiClient(0);
+}
+
+bool KexiDialogBase::isDesignModePreloadedForTextModeHackUsed(int newViewMode) const
+{
+ return newViewMode==Kexi::TextViewMode
+ && !viewForMode(Kexi::DesignViewMode)
+ && supportsViewMode(Kexi::DesignViewMode);
+}
+
+tristate KexiDialogBase::switchToViewMode( int newViewMode, QMap<QString,QString>* staticObjectArgs,
+ bool& proposeOpeningInTextViewModeBecauseOfProblems)
+{
+ m_parentWindow->acceptPropertySetEditing();
+
+ const bool designModePreloadedForTextModeHack = isDesignModePreloadedForTextModeHackUsed(newViewMode);
+ tristate res = true;
+ if (designModePreloadedForTextModeHack) {
+ /* A HACK: open design BEFORE text mode: otherwise Query schema becames crazy */
+ bool _proposeOpeningInTextViewModeBecauseOfProblems = false; // used because even if opening the view failed,
+ // text view can be opened
+ res = switchToViewMode( Kexi::DesignViewMode, staticObjectArgs, _proposeOpeningInTextViewModeBecauseOfProblems);
+ if ((!res && !_proposeOpeningInTextViewModeBecauseOfProblems) || ~res)
+ return res;
+ }
+
+ kdDebug() << "KexiDialogBase::switchToViewMode()" << endl;
+ bool dontStore = false;
+ KexiViewBase *view = selectedView();
+
+ if (m_currentViewMode == newViewMode)
+ return true;
+ if (!supportsViewMode(newViewMode))
+ return false;
+
+ if (view) {
+ res = true;
+ if (!designModePreloadedForTextModeHack) {
+ res = view->beforeSwitchTo(newViewMode, dontStore);
+ }
+ if (~res || !res)
+ return res;
+ if (!dontStore && view->dirty()) {
+ res = m_parentWindow->saveObject(this, i18n("Design has been changed. "
+ "You must save it before switching to other view."));
+ if (~res || !res)
+ return res;
+// KMessageBox::questionYesNo(0, i18n("Design has been changed. You must save it before switching to other view."))
+// ==KMessageBox::No
+ }
+ }
+
+ //get view for viewMode
+ KexiViewBase *newView
+ = (m_stack->widget(newViewMode) && m_stack->widget(newViewMode)->inherits("KexiViewBase"))
+ ? static_cast<KexiViewBase*>(m_stack->widget(newViewMode)) : 0;
+ if (!newView) {
+ KexiUtils::setWaitCursor();
+ //ask the part to create view for the new mode
+ m_creatingViewsMode = newViewMode;
+ KexiPart::StaticPart *staticPart = dynamic_cast<KexiPart::StaticPart*>((KexiPart::Part*)m_part);
+ if (staticPart)
+ newView = staticPart->createView(m_stack, this, *m_item, newViewMode, staticObjectArgs);
+ else
+ newView = m_part->createView(m_stack, this, *m_item, newViewMode, staticObjectArgs);
+ KexiUtils::removeWaitCursor();
+ if (!newView) {
+ //js TODO error?
+ kdDebug() << "Switching to mode " << newViewMode << " failed. Previous mode "
+ << m_currentViewMode << " restored." << endl;
+ return false;
+ }
+ m_creatingViewsMode = -1;
+ addView(newView, newViewMode);
+ }
+ const int prevViewMode = m_currentViewMode;
+ res = true;
+ if (designModePreloadedForTextModeHack) {
+ m_currentViewMode = Kexi::NoViewMode; //SAFE?
+ }
+ res = newView->beforeSwitchTo(newViewMode, dontStore);
+ proposeOpeningInTextViewModeBecauseOfProblems = tempData()->proposeOpeningInTextViewModeBecauseOfProblems;
+ if (!res) {
+ removeView(newViewMode);
+ delete newView;
+ kdDebug() << "Switching to mode " << newViewMode << " failed. Previous mode "
+ << m_currentViewMode << " restored." << endl;
+ return false;
+ }
+ m_currentViewMode = newViewMode;
+ m_newlySelectedView = newView;
+ if (prevViewMode==Kexi::NoViewMode)
+ m_newlySelectedView->setDirty(false);
+
+ res = newView->afterSwitchFrom(
+ designModePreloadedForTextModeHack ? Kexi::NoViewMode : prevViewMode);
+ proposeOpeningInTextViewModeBecauseOfProblems = tempData()->proposeOpeningInTextViewModeBecauseOfProblems;
+ if (!res) {
+ removeView(newViewMode);
+ delete newView;
+ kdDebug() << "Switching to mode " << newViewMode << " failed. Previous mode "
+ << prevViewMode << " restored." << endl;
+ const Kexi::ObjectStatus status(*this);
+ setStatus(mainWin()->project()->dbConnection(),
+ i18n("Switching to other view failed (%1).").arg(Kexi::nameForViewMode(newViewMode)),"");
+ append( status );
+ m_currentViewMode = prevViewMode;
+ return false;
+ }
+ m_newlySelectedView = 0;
+ if (~res) {
+ m_currentViewMode = prevViewMode;
+ return cancelled;
+ }
+ if (view)
+ takeActionProxyChild( view ); //take current proxy child
+ addActionProxyChild( newView ); //new proxy child
+ m_stack->raiseWidget( newView );
+ newView->propertySetSwitched();
+ m_parentWindow->invalidateSharedActions( newView );
+ QTimer::singleShot(10, newView, SLOT(setFocus())); //newView->setFocus(); //js ok?
+// setFocus();
+ return true;
+}
+
+tristate KexiDialogBase::switchToViewMode( int newViewMode )
+{
+ bool dummy;
+ return switchToViewMode( newViewMode, 0, dummy );
+}
+
+void KexiDialogBase::setFocus()
+{
+ if (m_stack->visibleWidget()) {
+ if (m_stack->visibleWidget()->inherits("KexiViewBase"))
+ static_cast<KexiViewBase*>( m_stack->visibleWidget() )->setFocus();
+ else
+ m_stack->visibleWidget()->setFocus();
+ }
+ else {
+ KMdiChildView::setFocus();
+ }
+ activate();
+}
+
+KoProperty::Set*
+KexiDialogBase::propertySet()
+{
+ KexiViewBase *v = selectedView();
+ if (!v)
+ return 0;
+ return v->propertySet();
+}
+
+bool KexiDialogBase::eventFilter(QObject *obj, QEvent *e)
+{
+ if (KMdiChildView::eventFilter(obj, e))
+ return true;
+/* if (e->type()==QEvent::FocusIn) {
+ QWidget *w = m_parentWindow->activeWindow();
+ w=0;
+ }*/
+ if ((e->type()==QEvent::FocusIn && m_parentWindow->activeWindow()==this)
+ || e->type()==QEvent::MouseButtonPress) {
+ if (m_stack->visibleWidget() && KexiUtils::hasParent(m_stack->visibleWidget(), obj)) {
+ //pass the activation
+ activate();
+ }
+ }
+ return false;
+}
+
+void KexiDialogBase::dirtyChanged(KexiViewBase* view)
+{
+ if (m_disableDirtyChanged)
+ return;
+ m_viewThatRecentlySetDirtyFlag = dirty() ? view : 0;
+/* if (!dirty()) {
+ if (caption()!=m_origCaption)
+ KMdiChildView::setCaption(m_origCaption);
+ }
+ else {
+ if (caption()!=(m_origCaption+"*"))
+ KMdiChildView::setCaption(m_origCaption+"*");
+ }*/
+ updateCaption();
+ emit dirtyChanged(this);
+}
+
+/*QString KexiDialogBase::caption() const
+{
+ return m_origCaption;
+ if (dirty())
+ return KMdiChildView::caption()+;
+
+ return KMdiChildView::caption();
+}*/
+
+void KexiDialogBase::updateCaption()
+{
+ if (!m_item || !m_part || !m_origCaption.isEmpty())
+ return;
+// m_origCaption = c;
+ QString capt = m_item->name();
+ QString fullCapt = capt;
+ if (m_part)
+ fullCapt += (" : " + m_part->instanceCaption());
+ if (dirty()) {
+ KMdiChildView::setCaption(fullCapt+"*");
+ KMdiChildView::setTabCaption(capt+"*");
+ }
+ else {
+ KMdiChildView::setCaption(fullCapt);
+ KMdiChildView::setTabCaption(capt);
+ }
+}
+
+bool KexiDialogBase::neverSaved() const
+{
+ return m_item ? m_item->neverSaved() : true;
+}
+
+tristate KexiDialogBase::storeNewData()
+{
+ if (!neverSaved())
+ return false;
+ KexiViewBase *v = selectedView();
+ if (m_schemaData)
+ return false; //schema must not exist
+ if (!v)
+ return false;
+ //create schema object and assign information
+ KexiDB::SchemaData sdata(m_part->info()->projectPartID());
+ sdata.setName( m_item->name() );
+ sdata.setCaption( m_item->caption() );
+ sdata.setDescription( m_item->description() );
+
+ bool cancel = false;
+ m_schemaData = v->storeNewData(sdata, cancel);
+ if (cancel)
+ return cancelled;
+ if (!m_schemaData) {
+ setStatus(m_parentWindow->project()->dbConnection(), i18n("Saving object's definition failed."),"");
+ return false;
+ }
+
+ if (!part()->info()->isIdStoredInPartDatabase()) {
+ //this part's ID is not stored within kexi__parts:
+ KexiDB::TableSchema *ts = m_parentWindow->project()->dbConnection()->tableSchema("kexi__parts");
+ kdDebug() << "KexiDialogBase::storeNewData(): schema: " << ts << endl;
+ if (!ts)
+ return false;
+
+ //temp. hack: avoid problems with autonumber
+ // see http://bugs.kde.org/show_bug.cgi?id=89381
+ int p_id = part()->info()->projectPartID();
+
+ if (p_id<0) {
+ // Find first available custom part ID by taking the greatest
+ // existing custom ID (if it exists) and adding 1.
+ p_id = (int)KexiPart::UserObjectType;
+ tristate success = m_parentWindow->project()->dbConnection()->querySingleNumber(
+ "SELECT max(p_id) FROM kexi__parts", p_id);
+ if (!success) {
+ // Couldn't read part id's from the kexi__parts table
+ return false;
+ } else {
+ // Got a maximum part ID, or there were no parts
+ p_id = p_id + 1;
+ p_id = QMAX(p_id, (int)KexiPart::UserObjectType);
+ }
+ }
+
+ KexiDB::FieldList *fl = ts->subList("p_id", "p_name", "p_mime", "p_url");
+ kexidbg << "KexiDialogBase::storeNewData(): fieldlist: "
+ << (fl ? fl->debugString() : QString::null) << endl;
+ if (!fl)
+ return false;
+
+ kexidbg << part()->info()->ptr()->untranslatedGenericName() << endl;
+// QStringList sl = part()->info()->ptr()->propertyNames();
+// for (QStringList::ConstIterator it=sl.constBegin();it!=sl.constEnd();++it)
+// kexidbg << *it << " " << part()->info()->ptr()->property(*it).toString() << endl;
+ if (!m_parentWindow->project()->dbConnection()->insertRecord(
+ *fl,
+ QVariant(p_id),
+ QVariant(part()->info()->ptr()->untranslatedGenericName()),
+ QVariant(part()->info()->mimeType()), QVariant("http://www.koffice.org/kexi/" /*always ok?*/)))
+ return false;
+
+ kdDebug() << "KexiDialogBase::storeNewData(): insert success!" << endl;
+ part()->info()->setProjectPartID( p_id );
+ //(int) project()->dbConnection()->lastInsertedAutoIncValue("p_id", "kexi__parts"));
+ kdDebug() << "KexiDialogBase::storeNewData(): new id is: "
+ << part()->info()->projectPartID() << endl;
+
+ part()->info()->setIdStoredInPartDatabase(true);
+ }
+
+ /* Sets 'dirty' flag on every dialog's view. */
+ setDirty(false);
+// v->setDirty(false);
+ //new schema data has now ID updated to a unique value
+ //-assign that to item's identifier
+ m_item->setIdentifier( m_schemaData->id() );
+ m_parentWindow->project()->addStoredItem( part()->info(), m_item );
+
+ return true;
+}
+
+tristate KexiDialogBase::storeData(bool dontAsk)
+{
+ if (neverSaved())
+ return false;
+ KexiViewBase *v = selectedView();
+ if (!v)
+ return false;
+
+#define storeData_ERR \
+ setStatus(m_parentWindow->project()->dbConnection(), i18n("Saving object's data failed."),"");
+
+ //save changes using transaction
+ KexiDB::Transaction transaction = m_parentWindow->project()->dbConnection()->beginTransaction();
+ if (transaction.isNull()) {
+ storeData_ERR;
+ return false;
+ }
+ KexiDB::TransactionGuard tg(transaction);
+
+ const tristate res = v->storeData(dontAsk);
+ if (~res) //trans. will be cancelled
+ return res;
+ if (!res) {
+ storeData_ERR;
+ return res;
+ }
+ if (!tg.commit()) {
+ storeData_ERR;
+ return false;
+ }
+ /* Sets 'dirty' flag on every dialog's view. */
+ setDirty(false);
+// v->setDirty(false);
+ return true;
+}
+
+void KexiDialogBase::activate()
+{
+ KexiViewBase *v = selectedView();
+ //kdDebug() << "focusWidget(): " << focusWidget()->name() << endl;
+ if (KexiUtils::hasParent( v, KMdiChildView::focusedChildWidget()))//focusWidget()))
+ KMdiChildView::activate();
+ else {//ah, focused widget is not in this view, move focus:
+ if (v)
+ v->setFocus();
+ }
+ if (v)
+ v->updateActions(true);
+//js: not neeed?? m_parentWindow->invalidateSharedActions(this);
+}
+
+void KexiDialogBase::deactivate()
+{
+ KexiViewBase *v = selectedView();
+ if (v)
+ v->updateActions(false);
+}
+
+void KexiDialogBase::sendDetachedStateToCurrentView()
+{
+ KexiViewBase *v = selectedView();
+ if (v)
+ v->parentDialogDetached();
+}
+
+void KexiDialogBase::sendAttachedStateToCurrentView()
+{
+ KexiViewBase *v = selectedView();
+ if (v)
+ v->parentDialogAttached();
+}
+
+#include "kexidialogbase.moc"
+
diff --git a/kexi/core/kexidialogbase.h b/kexi/core/kexidialogbase.h
new file mode 100644
index 00000000..43dc1ff4
--- /dev/null
+++ b/kexi/core/kexidialogbase.h
@@ -0,0 +1,352 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIDIALOGBASE_H
+#define KEXIDIALOGBASE_H
+
+#include "kexipartguiclient.h"
+#include "kexiactionproxy.h"
+#include "kexi.h"
+#include "kexipart.h"
+
+#include <qguardedptr.h>
+
+#include <kmdichildview.h>
+#include <kxmlguiclient.h>
+
+class QWidgetStack;
+class KexiMainWindow;
+class KexiViewBase;
+class KActionCollection;
+class KexiContextHelpInfo;
+namespace KexiPart {
+ class Part;
+}
+
+namespace KoProperty {
+ class Set;
+}
+
+//! Privides temporary data shared between KexiDialogBase's views (KexiView's)
+/*! Designed for reimplementation, if needed. */
+class KEXICORE_EXPORT KexiDialogTempData : public QObject
+{
+ public:
+ KexiDialogTempData(QObject* parent)
+ : QObject(parent, "KexiDialogTempData")
+ , proposeOpeningInTextViewModeBecauseOfProblems(false)
+ {}
+ /*! Initially false, KexiPart::Part implementation can set this to true
+ on data loading (e.g. in loadSchemaData()), to indicate that TextView mode
+ could be used instead of DataView or DesignView, because there are problems
+ with opening object.
+
+ For example, in KexiQueryPart::loadSchemaData() query statement can be invalid,
+ and thus could not be displayed in DesignView mode or executed for DataView.
+ So, this flag is set to true and user is asked for confirmation for switching
+ to TextView (SQL Editor).
+
+ After switching to TextView, this flag is cleared.
+ */
+ bool proposeOpeningInTextViewModeBecauseOfProblems : 1;
+};
+
+//! Base class for child window of Kexi's main application window.
+/*! This class can contain a number of configurable views, switchable using toggle action.
+ It also automatically works as a proxy for shared (application-wide) actions.
+*/
+class KEXICORE_EXPORT KexiDialogBase :
+ public KMdiChildView,
+ public KexiActionProxy,
+ public Kexi::ObjectStatus
+{
+ Q_OBJECT
+
+ public:
+ KexiDialogBase(KexiMainWindow *parent, const QString &caption = QString::null);
+ virtual ~KexiDialogBase();
+
+ bool isRegistered();
+
+ //! \return currently selected view or 0 if there is no current view
+ KexiViewBase *selectedView() const;
+
+ /*! \return a view for a given \a mode or 0 if there's no such mode available (or opened).
+ This does not open mode if it's not opened. */
+ KexiViewBase *viewForMode(int mode) const;
+
+ //! Adds \a view for the dialog. It will be the _only_ view (of unspecified mode) for the dialog
+ void addView(KexiViewBase *view);
+
+ /*! \return main (top level) widget inside this dialog.
+ This widget is used for e.g. determining minimum size hint and size hint. */
+// virtual QWidget* mainWidget() = 0;
+
+ /*! reimplemented: minimum size hint is inherited from currently visible view. */
+ virtual QSize minimumSizeHint() const;
+
+ /*! reimplemented: size hint is inherited from currently visible view. */
+ virtual QSize sizeHint() const;
+
+ KexiMainWindow *mainWin() const { return m_parentWindow; }
+
+ //js todo: maybe remove this since it's often the same as partItem()->identifier()?:
+
+ /*! This method sets internal identifier for the dialog, but
+ if there is a part item associated with this dialog (see partItem()),
+ partItem()->identifier() will be is used as identifier, so this method is noop.
+ Thus, it's usable only for dialog types when no part item is assigned. */
+ void setId(int id) { m_id = id; }
+
+ /*! If there is a part item associated with this dialog (see partItem()),
+ partItem()->identifier() is returned, otherwise internal dialog's identifier
+ (previously set by setID()) is returned. */
+ int id() const;
+
+ //! \return Kexi part used to create this window
+ inline KexiPart::Part* part() const { return m_part; }
+
+ //! \return Kexi part item used to create this window
+ KexiPart::Item *partItem() const { return m_item; }
+
+ //! Kexi dialog's gui COMMON client.
+ //! It's obtained by querying part object for this dialog.
+ KexiPart::GUIClient* commonGUIClient() const;
+
+ //! Kexi dialog's gui client for currently selected view.
+ //! It's obtained by querying part object for this dialog.
+ KexiPart::GUIClient* guiClient() const;
+
+ /*! Tries to close the dialog. \return true if closing is accepted
+ (sometimes, user may not want to close the dialog by pressing cancel).
+ If \a dontSaveChanges if true, changes are not saved even if this dialog is dirty. */
+//js removed bool tryClose(bool dontSaveChanges);
+
+ /*! \return name of icon provided by part that created this dialog.
+ The name is used by KexiMainWindow to set/reset icon for this dialog. */
+ virtual QString itemIcon();
+
+ /*! \return true if this dialog supports switching to \a mode.
+ \a mode is one of Kexi::ViewMode enum elements.
+ The flags are used e.g. for testing by KexiMainWindow, if actions
+ of switching to given view mode is available.
+ This member is intialised in KexiPart that creates this KexiDialogBase object. */
+ bool supportsViewMode( int mode ) const { return m_supportedViewModes & mode; }
+
+ /*! \return current view mode for this dialog. */
+ int currentViewMode() const { return m_currentViewMode; }
+
+ /*! Switches this dialog to \a newViewMode.
+ \a viewMode is one of Kexi::ViewMode enum elements.
+ \return true for successful switching
+ True is returned also if user has cancelled switching
+ (rarely, but for any reason) - cancelled is returned.
+ */
+ tristate switchToViewMode( int newViewMode );
+
+ void setContextHelp(const QString& caption, const QString& text, const QString& iconName);
+
+ /*! Internal reimplementation. */
+ virtual bool eventFilter(QObject *obj, QEvent *e);
+
+ /*! Used by Main Window
+ \todo js: PROBABLY REMOVE THESE TWO?
+ */
+ virtual void attachToGUIClient();
+ virtual void detachFromGUIClient();
+
+ /*! True if contents (data) of the dialog is dirty and need to be saved
+ This may or not be used, depending if changes in the dialog
+ are saved immediately (e.g. like in datatableview) or saved by hand (by user)
+ (e.g. like in alter-table dialog).
+ \return true if at least on "dirty" flag is set for one of the dialog's view. */
+ bool dirty() const;
+
+ /*! \return a pointer to view that has recently set dirty flag.
+ This value is cleared when dirty flag is set to false (i.e. upon saving changes). */
+ KexiViewBase* viewThatRecentlySetDirtyFlag() const { return m_viewThatRecentlySetDirtyFlag; }
+
+ /*! \return true, if this dialog's data were never saved.
+ If it's true we're usually try to ask a user if the dialog's
+ data should be saved somewhere. After dialog construction,
+ "neverSaved" flag is set to appropriate value.
+ KexiPart::Item::neverSaved() is reused.
+ */
+ bool neverSaved() const;
+
+ /*! \return property set provided by a current view,
+ or NULL if there is no view set (or the view has no set assigned). */
+ KoProperty::Set *propertySet();
+
+ KexiDB::SchemaData* schemaData() const { return m_schemaData; }
+ /*! Reimpelmented: "*" is added if for 'dirty' dialog's data. */
+// QString caption() const;
+
+ /*! Used by KexiViewBase subclasses. \return temporary data shared between views */
+ KexiDialogTempData *tempData() const { return m_tempData; }
+
+// /*! Used by KexiViewBase subclasses. Sets temporary data shared between views. */
+// void setTempData( KexiDialogTempData* data ) { m_tempData = data; }
+
+ /*! Called primarily by KexiMainWindowImpl to activate dialog.
+ Selected view (if present) is also informed about activation. */
+ void activate();
+
+ /*! Called primarily by KexiMainWindowImpl to deactivate dialog.
+ Selected view (if present) is also informed about deactivation. */
+ void deactivate();
+
+ public slots:
+ virtual void setFocus();
+
+ void updateCaption();
+
+ /*! Internal. Called by KexiMainWindowImpl::saveObject().
+ Tells this dialog to save changes of the existing object
+ to the backend. If \a dontAsk is true, no question dialog will
+ be shown to the user. The default is false.
+ \sa storeNewData()
+ \return true on success, false on failure and cancelled when storing has been cancelled. */
+ tristate storeData(bool dontAsk = false);
+
+ /*! Internal. Called by KexiMainWindowImpl::saveObject().
+ Tells this dialog to create and store data of the new object
+ to the backend.
+ Object's schema data has been never stored,
+ so it is created automatically, using information obtained
+ form part item. On success, part item's ID is updated to new value,
+ and m_schemaData is set. \sa schemaData().
+ \return true on success, false on failure and cancelled when storing has been cancelled. */
+ tristate storeNewData();
+
+ /*! Reimplemented - we're informing the current view about performed detaching by calling
+ KexiViewBase::parentDialogDetached(), so the view can react on this event
+ (by default KexiViewBase::parentDialogDetached() does nothing, you can reimplement it). */
+ void sendDetachedStateToCurrentView();
+
+ /*! W're informing the current view about performed atttaching by calling
+ KexiViewBase::parentDialogAttached(), so the view can react on this event
+ (by default KexiViewBase::parentDialogAttached() does nothing, you can reimplement it). */
+ void sendAttachedStateToCurrentView();
+
+ signals:
+ void updateContextHelp();
+
+ //! emitted when the window is about to close
+ void closing();
+
+ /*! Emited to inform the world that 'dirty' flag changes.
+ Activated by KexiViewBase::setDirty(). */
+ void dirtyChanged(KexiDialogBase*);
+
+ protected slots:
+ /*! Sets 'dirty' flag on every dialog's view. */
+ void setDirty(bool dirty);
+
+ protected:
+ /*! Used by Part::openInstance(),
+ like switchToViewMode( int newViewMode ), but passed \a staticObjectArgs.
+ Only used for parts of class KexiPart::StaticPart. */
+ tristate switchToViewMode( int newViewMode, QMap<QString,QString>* staticObjectArgs,
+ bool& proposeOpeningInTextViewModeBecauseOfProblems);
+
+ void registerDialog();
+
+ virtual void closeEvent( QCloseEvent * e );
+
+ //! \internal
+ void addView(KexiViewBase *view, int mode);
+
+ //! \internal
+ void removeView(int mode);
+
+ int m_supportedViewModes;
+ int m_openedViewModes;
+ int m_currentViewMode;
+
+ inline QWidgetStack * stack() const { return m_stack; }
+
+ //! Used by \a view to inform the dialog about changing state of the "dirty" flag.
+ void dirtyChanged(KexiViewBase* view);
+#if 0
+ /*! Loads large string data \a dataString block (e.g. xml form's representation),
+ indexed with optional \a dataID, from the database backend.
+ \return true on success
+ \sa storeDataBlock(). */
+ bool loadDataBlock( QString &dataString, const QString& dataID = QString::null);
+
+ /*! Stores (potentially large) string data \a dataString, block (e.g. xml form's representation),
+ at the database backend. Block will be stored in "kexi__objectdata" table pointed by
+ this object's id and an optional \a dataID identifier.
+ If there is already such record in the table, it's simply overwritten.
+ \return true on success
+ */
+ bool storeDataBlock( const QString &dataString, const QString& dataID = QString::null );
+
+ /*! Removes (potentially large) string data (e.g. xml form's representation),
+ pointed by optional \a dataID, from the database backend.
+ \return true on success. Does not fail if the block doe not exists.
+ Note that if \a dataID is not specified, all data blocks for this dialog will be removed.
+ \sa storeDataBlock(). */
+ bool removeDataBlock( QString &dataString, const QString& dataID = QString::null);
+
+ /*! @internal
+ Used by KexiDialogBase::storeDataBlock() and by KexiViewBase::storeDataBlock().
+ */
+ bool storeDataBlock_internal( const QString &dataString, int o_id, const QString& dataID );
+#endif
+// void setError(const QString& message, const QString& details);
+
+ bool isDesignModePreloadedForTextModeHackUsed(int newViewMode) const;
+
+ private:
+ KexiMainWindow *m_parentWindow;
+ bool m_isRegistered;
+#ifdef KEXI_NO_CTXT_HELP
+ KexiContextHelpInfo *m_contextHelpInfo;
+#endif
+ int m_id;
+ QGuardedPtr<KexiPart::Part> m_part;
+ KexiPart::Item *m_item;
+ QWidgetStack *m_stack;
+ QString m_origCaption; //!< helper
+ KexiDB::SchemaData* m_schemaData;
+ QGuardedPtr<KexiViewBase> m_newlySelectedView; //!< Used in dirty(), temporary set in switchToViewMode()
+ //!< during view setup, when a new view is not yet raised.
+ //! Used in viewThatRecentlySetDirtyFlag(), modified in dirtyChanged().
+ QGuardedPtr<KexiViewBase> m_viewThatRecentlySetDirtyFlag;
+ QGuardedPtr<KexiDialogTempData> m_tempData; //!< temporary data shared between views
+
+ /*! Created view's mode - helper for switchToViewMode(),
+ KexiViewBase ctor uses that info. >0 values are useful. */
+ int m_creatingViewsMode;
+
+ bool m_destroying : 1; //!< true after entering to the dctor
+ bool m_disableDirtyChanged; //!< used in setDirty(), affects dirtyChanged()
+
+ friend class KexiMainWindow;
+// friend class KexiMainWindowImpl;
+ friend class KexiPart::Part;
+ friend class KexiInternalPart;
+ friend class KexiViewBase;
+};
+
+#endif
+
diff --git a/kexi/core/kexidragobjects.cpp b/kexi/core/kexidragobjects.cpp
new file mode 100644
index 00000000..5cddbca0
--- /dev/null
+++ b/kexi/core/kexidragobjects.cpp
@@ -0,0 +1,146 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexidragobjects.h"
+
+#include <qcstring.h>
+#include <qdatastream.h>
+#include <kdebug.h>
+
+/// implementation of KexiFieldDrag
+
+KexiFieldDrag::KexiFieldDrag(const QString& sourceMimeType, const QString& sourceName,
+ const QString& field, QWidget *parent, const char *name)
+ : QStoredDrag("kexi/field", parent, name)
+{
+ QByteArray data;
+ QDataStream stream1(data,IO_WriteOnly);
+ stream1 << sourceMimeType << sourceName << field;
+ setEncodedData(data);
+}
+
+KexiFieldDrag::KexiFieldDrag(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& fields, QWidget *parent, const char *name)
+ : QStoredDrag((fields.count() > 1) ? "kexi/fields" : "kexi/field", parent, name)
+{
+ QByteArray data;
+ QDataStream stream1(data,IO_WriteOnly);
+ if (fields.count() > 1)
+ stream1 << sourceMimeType << sourceName << fields;
+ else {
+ QString field;
+ if (fields.count() == 1)
+ field = fields.first();
+ else
+ kexidbg << "KexiFieldDrag::KexiFieldDrag(): fields list is empty!" << endl;
+ stream1 << sourceMimeType << sourceName << field;
+ }
+ setEncodedData(data);
+}
+
+KexiFieldDrag::~KexiFieldDrag()
+{
+}
+
+bool
+KexiFieldDrag::canDecodeSingle(QMimeSource *e)
+{
+ return e->provides("kexi/field");
+}
+
+bool
+KexiFieldDrag::canDecodeMultiple(QMimeSource *e)
+{
+ return e->provides("kexi/field") || e->provides("kexi/fields");
+}
+
+bool
+KexiFieldDrag::decodeSingle( QDropEvent* e, QString& sourceMimeType,
+ QString& sourceName, QString& field )
+{
+ QByteArray payload( e->data("kexi/field") );
+ if (payload.isEmpty())
+ return false;
+ e->accept();
+ QDataStream stream1(payload, IO_ReadOnly);
+ stream1 >> sourceMimeType;
+ stream1 >> sourceName;
+ stream1 >> field;
+// kdDebug() << "KexiFieldDrag::decode() decoded: " << sourceMimeType<<"/"<<sourceName<<"/"<<field << endl;
+ return true;
+}
+
+bool
+KexiFieldDrag::decodeMultiple( QDropEvent* e, QString& sourceMimeType,
+ QString& sourceName, QStringList& fields )
+{
+ QByteArray payload( e->data("kexi/fields") );
+ if (payload.isEmpty()) {//try single
+ QString field;
+ bool res = KexiFieldDrag::decodeSingle( e, sourceMimeType, sourceName, field );
+ if (!res)
+ return false;
+ fields.append(field);
+ return true;
+ }
+ e->accept();
+ QDataStream stream1(payload, IO_ReadOnly);
+ stream1 >> sourceMimeType;
+ stream1 >> sourceName;
+ stream1 >> fields;
+// kdDebug() << "KexiFieldDrag::decode() decoded: " << sourceMimeType<<"/"<<sourceName<<"/"<<fields << endl;
+ return true;
+}
+
+/// implementation of KexiDataProviderDrag
+
+KexiDataProviderDrag::KexiDataProviderDrag(const QString& sourceMimeType, const QString& sourceName,
+ QWidget *parent, const char *name)
+ : QStoredDrag("kexi/dataprovider", parent, name)
+{
+ QByteArray data;
+ QDataStream stream1(data,IO_WriteOnly);
+ stream1 << sourceMimeType << sourceName;
+ setEncodedData(data);
+}
+
+
+bool
+KexiDataProviderDrag::canDecode(QDragMoveEvent *e)
+{
+ return e->provides("kexi/dataprovider");
+}
+
+bool
+KexiDataProviderDrag::decode( QDropEvent* e, QString& sourceMimeType, QString& sourceName)
+{
+ QCString tmp;
+ QByteArray payload = e->data("kexidataprovider");
+ if(payload.size())
+ {
+ e->accept();
+ QDataStream stream1(payload, IO_ReadOnly);
+ stream1 >> sourceMimeType;
+ stream1 >> sourceName;
+// kdDebug() << "KexiDataProviderDrag::decode() decoded: " << sourceMimeType <<"/"<<sourceName<< endl;
+ return true;
+ }
+ return false;
+}
diff --git a/kexi/core/kexidragobjects.h b/kexi/core/kexidragobjects.h
new file mode 100644
index 00000000..9b7a42ec
--- /dev/null
+++ b/kexi/core/kexidragobjects.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXI_DRAGOBJECTS_H_
+#define KEXI_DRAGOBJECTS_H_
+
+#include <qdragobject.h>
+
+class QString;
+class QStringList;
+class QWidget;
+
+//! Drag object containing information about field(s).
+class KEXICORE_EXPORT KexiFieldDrag : public QStoredDrag
+{
+ public:
+ /*! Creates drag object for a single field \a field. */
+ KexiFieldDrag(const QString& sourceMimeType, const QString& sourceName,
+ const QString& field, QWidget *parent, const char *name);
+
+ /*! Creates drag object for multiple fields \a fields.
+ If there's less than two elements in the list, data is set up as for above ctor. */
+ KexiFieldDrag(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& field, QWidget *parent=0, const char *name=0);
+
+ ~KexiFieldDrag();
+
+ void addField(const QString& field);
+
+ /*! \return true if event \a e (of class QDragMoveEvent or QDropEvent)
+ can be decoded as "kexi/field" data */
+ static bool canDecodeSingle( QMimeSource* e );
+
+ /*! \return true if event \a e (of class QDragMoveEvent or QDropEvent)
+ can be decoded as "kexi/fields" data. If decoding of "kexi/field"
+ type is supported, decoding of "kexi/fields" is always supported.
+ */
+ static bool canDecodeMultiple( QMimeSource* e );
+
+ /*! Decodes data of single-field drag ("kexi/field" mime type) coming with event \a e.
+ Sets \a sourceMimeType, \a sourceName and \a field.
+ \return true on successful decoding (\a e will be accepted in such case). */
+ static bool decodeSingle( QDropEvent* e, QString& sourceMimeType,
+ QString& sourceName, QString& field );
+
+ /*! Decodes data of multiple-field drag ("kexi/fields" mime type) coming with event \a e.
+ Sets \a sourceMimeType, \a sourceName and \a fields. Also works with "kexi/field" data.
+ \return true on successful decoding (\a e will be accepted in such case). */
+ static bool decodeMultiple( QDropEvent* e, QString& sourceMimeType,
+ QString& sourceName, QStringList& fields );
+};
+
+class KEXICORE_EXPORT KexiDataProviderDrag : public QStoredDrag
+{
+ public:
+ KexiDataProviderDrag(const QString& sourceMimeType, const QString& sourceName,
+ QWidget *parent=0, const char *name=0);
+ ~KexiDataProviderDrag() { };
+
+ static bool canDecode( QDragMoveEvent* e);
+ static bool decode( QDropEvent* e, QString& sourceMimeType, QString& sourceName);
+
+};
+
+#endif
diff --git a/kexi/core/kexievents.cpp b/kexi/core/kexievents.cpp
new file mode 100644
index 00000000..2cafe2d3
--- /dev/null
+++ b/kexi/core/kexievents.cpp
@@ -0,0 +1,92 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ 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 "kexievents.h"
+
+Event::Event(QObject *sender, const QCString &signal,
+ QObject *receiver, const QCString &slot)
+{
+ m_sender = sender;
+ m_receiver = receiver;
+ m_slot = slot;
+ m_signal = signal;
+}
+
+Event::Event(QObject *sender, const QCString &signal,
+ const QCString &functionName)
+{
+ m_sender = sender;
+ m_signal = signal;
+ m_slot = functionName;
+}
+
+void
+EventList::addEvent(Event *event)
+{
+ if(event)
+ append(event);
+}
+
+void
+EventList::addEvent(QObject *sender, const QCString &signal, QObject *receiver, const QCString &slot)
+{
+ Event *ev = new Event(sender, signal, receiver, slot);
+ append(ev);
+}
+
+void
+EventList::addEvent(QObject *sender, const QCString &signal, const QCString &function)
+{
+ Event *ev = new Event(sender, signal, function);
+ append(ev);
+}
+
+void
+EventList::removeEvent(Event *event)
+{
+ if(!event) return;
+ remove(event);
+ delete event;
+}
+
+EventList*
+EventList::allEventsForObject(QObject *widget)
+{
+ if(!widget) return 0;
+
+ EventList *l = new EventList();
+ EventList::ConstIterator endIt = constEnd();
+ for(EventList::ConstIterator it = constBegin(); it != endIt; ++it) {
+ if( ((*it)->sender() == widget) || ( (*it)->receiver() == widget) )
+ l->addEvent(*it);
+ }
+
+ return l;
+}
+
+void
+EventList::removeAllEventsForObject(QObject *widget)
+{
+ EventList::ConstIterator endIt = constEnd();
+ for(EventList::ConstIterator it = constBegin(); it != endIt; ++it) {
+ if( ((*it)->sender() == widget) || ( (*it)->receiver() == widget) )
+ removeEvent(*it);
+ }
+}
+
diff --git a/kexi/core/kexievents.h b/kexi/core/kexievents.h
new file mode 100644
index 00000000..145ee68d
--- /dev/null
+++ b/kexi/core/kexievents.h
@@ -0,0 +1,100 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+
+ 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 KFORMDESIGNEREVENTS_H
+#define KFORMDESIGNEREVENTS_H
+
+#include <qvaluelist.h>
+#include <qguardedptr.h>
+
+class QDomNode;
+class QObject;
+
+//! A simple class to store events
+/*! There are three different types of events (an maybe more in the future):
+ * signal to slot: sender and receiver are both widgets.
+ * signal to user function: whenever the signal is emitted, a function in the form script is called.
+ * signal to action: the signal activates an application action (eg addNewRecord in Kexi)
+ (other :* global signal to user function: an application global signal (new window opened, etc.) calls a user script function)
+
+ \todo add aliases for slot()?? (eg actionName())
+ */
+class KEXICORE_EXPORT Event
+{
+ public:
+ Event(QObject *sender, const QCString &signal,
+ QObject *receiver, const QCString &slot);
+ Event(QObject *sender, const QCString &signal,
+ const QCString &functionName);
+ Event() : m_type(Slot) {;}
+ ~Event() {;}
+
+ enum { Slot=1000, UserFunction, Action }; //! Event types
+ int type() {return m_type; }
+ void setType(int type) { m_type = type; }
+
+ QObject* sender() const { return m_sender; }
+ QObject* receiver() const { return m_receiver; }
+ QCString signal() const { return m_signal; }
+ QCString slot() const { return m_slot; }
+
+ void setSender(QObject *o) { m_sender = o; }
+ void setReceiver(QObject *o) { m_receiver = o; }
+ void setSignal(const QCString &s) { m_signal = s; }
+ void setSlot(const QCString &s) { m_slot = s; }
+
+ protected:
+ QGuardedPtr<QObject> m_sender;
+ QCString m_signal;
+ QGuardedPtr<QObject> m_receiver;
+ QCString m_slot;
+ int m_type;
+};
+
+class KEXICORE_EXPORT EventList : protected QValueList<Event*>
+{
+ public:
+ EventList() {;}
+ ~EventList() {;}
+
+ /*! Adds an event in list. Other overload are available, so that
+ other classes don't have to use Event class in simple cases. */
+ void addEvent(Event *event);
+ void addEvent(QObject *sender, const QCString &signal, QObject *receiver, const QCString &slot);
+ void addEvent(QObject *sender, const QCString &signal, const QCString &action);
+ /*! Removes the Event \a event from the FormScript's list. */
+ void removeEvent(Event *event);
+
+ /*! \return A list of events related to widget \a name (ie where Event::sender()
+ or Event::receiver() == name). */
+ EventList* allEventsForObject(QObject *object);
+ /*! Replace all ocurrences of \a oldname with \a newName inside the list. */
+ //void renameWidget(const QCString &oldName, const QCString &newName);
+ /*! Removes all events related to widget \a name. Called eg when widget is destroyed. */
+ void removeAllEventsForObject(QObject *object);
+
+ // make some QValueList function accessible by other classes
+ QValueListConstIterator<Event*> constBegin() const { return QValueList<Event*>::constBegin(); }
+ QValueListConstIterator<Event*> constEnd() const { return QValueList<Event*>::constEnd(); }
+ bool isEmpty() const { return QValueList<Event*>::isEmpty(); }
+};
+
+
+#endif
+
diff --git a/kexi/core/kexiguimsghandler.cpp b/kexi/core/kexiguimsghandler.cpp
new file mode 100644
index 00000000..af5f3a6e
--- /dev/null
+++ b/kexi/core/kexiguimsghandler.cpp
@@ -0,0 +1,176 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiguimsghandler.h"
+
+#include "kexi.h"
+#include <kexidb/utils.h>
+#include <kexiutils/utils.h>
+
+#include <kmessagebox.h>
+#include <kdialogbase.h>
+
+KexiGUIMessageHandler::KexiGUIMessageHandler(QWidget *parent)
+: KexiDB::MessageHandler(parent)
+{
+}
+
+KexiGUIMessageHandler::~KexiGUIMessageHandler()
+{
+}
+
+/*virtual*/
+void
+KexiGUIMessageHandler::showErrorMessage(KexiDB::Object *obj,
+ const QString& msg)
+{
+ QString _msg(msg);
+ if (!obj) {
+ showErrorMessage(_msg);
+ return;
+ }
+ QString details;
+ KexiDB::getHTMLErrorMesage(obj, _msg, details);
+ showErrorMessage(_msg, details);
+}
+
+/*virtual*/
+void
+KexiGUIMessageHandler::showErrorMessage(const QString &title, const QString &details)
+{
+ showMessage(Error, title, details);
+}
+
+void
+KexiGUIMessageHandler::showSorryMessage(const QString &title, const QString &details)
+{
+ showMessage(Sorry, title, details);
+}
+
+void KexiGUIMessageHandler::showErrorMessage(const QString &msg, const QString &details,
+ KexiDB::Object *obj)
+{
+ QString _msg(msg);
+ if (!obj) {
+ showErrorMessage(_msg, details);
+ return;
+ }
+ QString _details(details);
+ KexiDB::getHTMLErrorMesage(obj, _msg, _details);
+ showErrorMessage(_msg, _details);
+}
+
+void
+KexiGUIMessageHandler::showErrorMessage(Kexi::ObjectStatus *status)
+{
+ showErrorMessage("", status);
+}
+
+void
+KexiGUIMessageHandler::showErrorMessage(const QString &message, Kexi::ObjectStatus *status)
+{
+ if (status && status->error()) {
+ QString msg(message);
+ if (msg.isEmpty() || msg==status->message) {
+ msg = status->message;
+ status->message = status->description;
+ status->description = "";
+ }
+ QString desc;
+ if (!status->message.isEmpty()) {
+ if (status->description.isEmpty()) {
+ desc = status->message;
+ } else {
+ msg += (QString("<br><br>") + status->message);
+ desc = status->description;
+ }
+ }
+ showErrorMessage(msg, desc, status->dbObject());
+ }
+ else {
+ showErrorMessage(message);
+ }
+ status->clearStatus();
+}
+
+void
+KexiGUIMessageHandler::showMessage(MessageType type,
+ const QString &title, const QString &details, const QString& dontShowAgainName)
+{
+ if (!m_enableMessages)
+ return;
+
+ //'wait' cursor is a nonsense now
+ KexiUtils::removeWaitCursor();
+
+ QString msg(title);
+ if (title.isEmpty())
+ msg = i18n("Unknown error");
+ msg = "<qt><p>"+msg+"</p>";
+ if (!details.isEmpty()) {
+ switch (type) {
+ case Error:
+ KMessageBox::detailedError(m_messageHandlerParentWidget, msg, details);
+ break;
+ case Warning:
+ showWarningContinueMessage(title, details, dontShowAgainName);
+ break;
+ default: //Sorry
+ KMessageBox::detailedSorry(m_messageHandlerParentWidget, msg, details);
+ }
+ }
+ else {
+ KMessageBox::messageBox(m_messageHandlerParentWidget,
+ type==Error ? KMessageBox::Error : KMessageBox::Sorry, msg);
+ }
+}
+
+void KexiGUIMessageHandler::showWarningContinueMessage(const QString &title, const QString &details,
+ const QString& dontShowAgainName)
+{
+ if (!KMessageBox::shouldBeShownContinue(dontShowAgainName))
+ return;
+ KDialogBase *dialog = new KDialogBase(
+ i18n("Warning"), KDialogBase::Yes, KDialogBase::Yes, KDialogBase::No,
+ m_messageHandlerParentWidget, "warningContinue", true, true, KStdGuiItem::cont() );
+ bool checkboxResult = false;
+ KMessageBox::createKMessageBox(dialog, QMessageBox::Warning,
+ title + (details.isEmpty() ? QString::null : (QString("\n")+details)), QStringList(),
+ dontShowAgainName.isEmpty() ? QString::null : i18n("Do not show this message again"),
+ &checkboxResult, 0);
+ if (checkboxResult)
+ KMessageBox::saveDontShowAgainContinue(dontShowAgainName);
+}
+
+int KexiGUIMessageHandler::askQuestion( const QString& message,
+ KMessageBox::DialogType dlgType, KMessageBox::ButtonCode defaultResult,
+ const KGuiItem &buttonYes,
+ const KGuiItem &buttonNo,
+ const QString &dontShowAskAgainName,
+ int options )
+{
+ Q_UNUSED(defaultResult);
+ if (KMessageBox::WarningContinueCancel == dlgType)
+ return KMessageBox::warningContinueCancel(m_messageHandlerParentWidget,
+ message, QString::null, buttonYes, dontShowAskAgainName, options);
+ else
+ return KMessageBox::messageBox(m_messageHandlerParentWidget,
+ dlgType, message, QString::null, buttonYes, buttonNo, dontShowAskAgainName, options);
+}
+
diff --git a/kexi/core/kexiguimsghandler.h b/kexi/core/kexiguimsghandler.h
new file mode 100644
index 00000000..6105f311
--- /dev/null
+++ b/kexi/core/kexiguimsghandler.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIGUIMSGHANDLER_H
+#define KEXIGUIMSGHANDLER_H
+
+#include <core/kexi.h>
+#include <kexidb/msghandler.h>
+
+class KEXICORE_EXPORT KexiGUIMessageHandler : public KexiDB::MessageHandler
+{
+ public:
+ KexiGUIMessageHandler(QWidget *parent = 0);
+ virtual ~KexiGUIMessageHandler();
+ virtual void showErrorMessage(const QString &title, const QString &details = QString::null);
+ virtual void showErrorMessage(KexiDB::Object *obj, const QString& msg = QString::null);
+
+ void showErrorMessage(const QString&,const QString&,KexiDB::Object *obj);
+ void showErrorMessage(Kexi::ObjectStatus *status);
+ void showErrorMessage(const QString &message, Kexi::ObjectStatus *status);
+
+ /*! Displays a "Sorry" message with \a title text and optional \a details. */
+ void showSorryMessage(const QString &title, const QString &details = QString::null);
+
+ /*! Displays a message of a type \a type, with \a title text and optional \a details.
+ \a dontShowAgainName can be specified to add "Do not show again" option if \a type is Warning. */
+ virtual void showMessage(MessageType type, const QString &title, const QString &details,
+ const QString& dontShowAgainName = QString::null);
+
+ /*! Displays a Warning message with \a title text and optional \a details
+ with "Continue" button instead "OK".
+ \a dontShowAgainName can be specified to add "Do not show again" option. */
+ virtual void showWarningContinueMessage(const QString &title, const QString &details = QString::null,
+ const QString& dontShowAgainName = QString::null);
+
+ /*! Interactively asks a question using KMessageBox.
+ See KexiDB::MessageHandler::askQuestion() for details. */
+ virtual int askQuestion( const QString& message,
+ KMessageBox::DialogType dlgType, KMessageBox::ButtonCode defaultResult,
+ const KGuiItem &buttonYes=KStdGuiItem::yes(),
+ const KGuiItem &buttonNo=KStdGuiItem::no(),
+ const QString &dontShowAskAgainName = QString::null,
+ int options = KMessageBox::Notify );
+};
+
+#endif
diff --git a/kexi/core/kexiinternalpart.cpp b/kexi/core/kexiinternalpart.cpp
new file mode 100644
index 00000000..fcbb8f17
--- /dev/null
+++ b/kexi/core/kexiinternalpart.cpp
@@ -0,0 +1,209 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiinternalpart.h"
+
+#include "kexidialogbase.h"
+#include "kexiviewbase.h"
+#include "keximainwindow.h"
+
+#include <qasciidict.h>
+#include <qdialog.h>
+
+#include <kdebug.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kexidb/msghandler.h>
+
+//! @internal
+class KexiInternalPartManager
+{
+ public:
+ KexiInternalPartManager()
+ : m_parts(101, false)
+ {
+ m_parts.setAutoDelete(false);
+ }
+
+ KexiInternalPart* findPart(KexiDB::MessageHandler *msgHdr, const char* partName)
+ {
+ KexiInternalPart *part = m_parts[partName];
+ if (!part) {
+ QCString fullname("kexihandler_");
+ fullname += QCString(partName).lower();
+ part = KParts::ComponentFactory::createInstanceFromLibrary<KexiInternalPart>(
+ fullname, 0, fullname);
+ if (!part) {
+ if (msgHdr)
+ msgHdr->showErrorMessage(i18n("Could not load \"%1\" plugin.").arg(partName));
+ }
+ else
+ m_parts.insert(partName, part);
+ }
+ return part;
+ }
+
+ private:
+
+ QAsciiDict<KexiInternalPart> m_parts;
+};
+
+KexiInternalPartManager internalPartManager;
+
+//----------------------------------------------
+
+KexiInternalPart::KexiInternalPart(QObject *parent, const char *name, const QStringList &)
+ : QObject(parent, name)
+ , m_uniqueDialog(true)
+ , m_cancelled(false)
+{
+}
+
+KexiInternalPart::~KexiInternalPart()
+{
+}
+
+//static
+const KexiInternalPart *
+KexiInternalPart::part(KexiDB::MessageHandler *msgHdr, const char* partName)
+{
+ return internalPartManager.findPart(msgHdr, partName);
+}
+
+//static
+QWidget* KexiInternalPart::createWidgetInstance(const char* partName,
+ const char* widgetClass, KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin,
+ QWidget *parent, const char *objName, QMap<QString,QString>* args)
+{
+ KexiInternalPart *part = internalPartManager.findPart(msgHdr, partName);
+ if (!part)
+ return 0; //fatal!
+ return part->createWidget(widgetClass, mainWin, parent, objName ? objName : partName, args);
+}
+
+KexiDialogBase* KexiInternalPart::findOrCreateKexiDialog(
+ KexiMainWindow* mainWin, const char *objName)
+{
+ if (m_uniqueDialog && !m_uniqueWidget.isNull())
+ return dynamic_cast<KexiDialogBase*>((QWidget*)m_uniqueWidget);
+// KexiDialogBase *dlg = createDialog(mainWin, objName);
+ KexiDialogBase * dlg = new KexiDialogBase(mainWin, "");
+ KexiViewBase *view = createView(mainWin, 0, objName);
+ if (!view)
+ return 0;
+
+// dlg->show();
+
+ if (m_uniqueDialog)
+ m_uniqueWidget = dlg; //recall unique!
+ dlg->addView(view);
+ dlg->setCaption( view->caption() );
+ dlg->setTabCaption( view->caption() );
+ dlg->resize(view->sizeHint());
+ dlg->setMinimumSize(view->minimumSizeHint().width(),view->minimumSizeHint().height());
+ dlg->setId( mainWin->generatePrivateID() );
+ dlg->registerDialog();
+ return dlg;
+}
+
+//static
+KexiDialogBase* KexiInternalPart::createKexiDialogInstance(
+ const char* partName,
+ KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin, const char *objName)
+{
+ KexiInternalPart *part = internalPartManager.findPart(msgHdr, partName);
+ if (!part) {
+ kdDebug() << "KexiInternalPart::createDialogInstance() !part" << endl;
+ return 0; //fatal!
+ }
+ return part->findOrCreateKexiDialog(mainWin, objName ? objName : partName);
+}
+
+//static
+QDialog* KexiInternalPart::createModalDialogInstance(const char* partName,
+ const char* dialogClass, KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin,
+ const char *objName, QMap<QString,QString>* args)
+{
+ KexiInternalPart *part = internalPartManager.findPart(msgHdr, partName);
+ if (!part) {
+ kdDebug() << "KexiInternalPart::createDialogInstance() !part" << endl;
+ return 0; //fatal!
+ }
+ QWidget *w;
+ if (part->uniqueDialog() && !part->m_uniqueWidget.isNull())
+ w = part->m_uniqueWidget;
+ else
+ w = part->createWidget(dialogClass, mainWin, mainWin, objName ? objName : partName, args);
+
+ if (dynamic_cast<QDialog*>(w)) {
+ if (part->uniqueDialog())
+ part->m_uniqueWidget = w;
+ return dynamic_cast<QDialog*>(w);
+ }
+ //sanity
+ if (! (part->uniqueDialog() && !part->m_uniqueWidget.isNull()))
+ delete w;
+ return 0;
+}
+
+//static
+bool KexiInternalPart::executeCommand(const char* partName,
+ KexiMainWindow* mainWin, const char* commandName, QMap<QString,QString>* args)
+{
+ KexiInternalPart *part = internalPartManager.findPart(0, partName);
+ if (!part) {
+ kdDebug() << "KexiInternalPart::createDialogInstance() !part" << endl;
+ return 0; //fatal!
+ }
+ return part->executeCommand(mainWin, commandName, args);
+}
+
+QWidget* KexiInternalPart::createWidget(const char* widgetClass, KexiMainWindow* mainWin,
+ QWidget * parent, const char * objName, QMap<QString,QString>* args)
+{
+ Q_UNUSED(widgetClass);
+ Q_UNUSED(mainWin);
+ Q_UNUSED(parent);
+ Q_UNUSED(objName);
+ Q_UNUSED(args);
+ return 0;
+}
+
+KexiViewBase* KexiInternalPart::createView(KexiMainWindow* mainWin, QWidget * parent,
+ const char * objName)
+{
+ Q_UNUSED(mainWin);
+ Q_UNUSED(parent);
+ Q_UNUSED(objName);
+ return 0;
+}
+
+bool KexiInternalPart::executeCommand(KexiMainWindow* mainWin, const char* commandName,
+ QMap<QString,QString>* args)
+{
+ Q_UNUSED(mainWin);
+ Q_UNUSED(commandName);
+ Q_UNUSED(args);
+ return false;
+}
+
+#include "kexiinternalpart.moc"
diff --git a/kexi/core/kexiinternalpart.h b/kexi/core/kexiinternalpart.h
new file mode 100644
index 00000000..232c3f84
--- /dev/null
+++ b/kexi/core/kexiinternalpart.h
@@ -0,0 +1,159 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIINTERNALPART_H
+#define KEXIINTERNALPART_H
+
+#include <qobject.h>
+#include <qguardedptr.h>
+#include <qvariant.h>
+
+class KexiMainWindow;
+class KexiDialogBase;
+class KexiViewBase;
+
+namespace KexiDB {
+ class MessageHandler;
+}
+
+class QWidget;
+
+/**
+ * @short A prototype for Kexi Internal Parts (plugins) implementation.
+ *
+ * Internal Kexi parts are parts that are not available for users, but loaded
+ * internally be application when needed. Example of such part is Relations Window.
+ * The internal part instance is unique and has no explicitly stored data.
+ * Parts may be able to create widgets or/and dialogs, depending on implementation
+ * (createWidgetInstance(), createDialogInstance()).
+ * Parts can have unique flag set for dialogs (true by default)
+ * - then a dialog created by createDialogInstance() is unique.
+ */
+class KEXICORE_EXPORT KexiInternalPart : public QObject
+{
+ Q_OBJECT
+
+ public:
+ KexiInternalPart(QObject *parent, const char *name, const QStringList &);
+ virtual ~KexiInternalPart();
+
+ KexiDialogBase *instance(KexiMainWindow *parent);
+
+ /*! Creates a new widget instance using part \a partName.
+ \a widgetClass is a pseudo class used in case when the part offers more
+ than one widget type.
+ \a msgHdr is a message handler for displaying error messages.
+ \a args is two-way optional argument: it can contain custom options used
+ on widget's creation. Depending on implementation, the created widget can write its
+ state (e.g. result or status information) back to this argument.
+ Created widget will have assigned \a parent widget and \a objName name. */
+ static QWidget* createWidgetInstance(const char* partName, const char* widgetClass,
+ KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin,
+ QWidget *parent, const char *objName = 0, QMap<QString,QString>* args = 0);
+
+ /*! For convenience. */
+ static QWidget* createWidgetInstance(const char* partName,
+ KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin,
+ QWidget *parent, const char *objName = 0, QMap<QString,QString>* args = 0)
+ { return createWidgetInstance(partName, 0, msgHdr, mainWin, parent, objName, args); }
+
+ /*! Creates a new dialog instance. If such instance already exists,
+ and is unique (see uniqueDialog()) it is just returned.
+ The part knows about destroying its dialog instance, (if it is uinque),
+ so on another call the dialog will be created again.
+ \a msgHdr is a message handler for displaying error messages.
+ The dialog is assigned to \a mainWin as its parent,
+ and \a objName name is set. */
+ static KexiDialogBase* createKexiDialogInstance(const char* partName,
+ KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin, const char *objName = 0);
+
+ /*! Creates a new modal dialog instance (QDialog or a subclass).
+ If such instance already exists, and is unique (see uniqueDialog())
+ it is just returned.
+ \a dialogClass is a pseudo class used in case when the part offers more
+ than one dialog type.
+ \a msgHdr is a message handler for displaying error messages.
+ \a args is two-way optional argument: it can contain custom options used
+ on widget's creation. Depending on implementation, the created dialog can write its
+ state (e.g. result or status information) back to this argument.
+ The part knows about destroying its dialog instance, (if it is uinque),
+ so on another call the dialog will be created again.
+ The dialog is assigned to \a mainWin as its parent,
+ and \a objName name is set. */
+ static QDialog* createModalDialogInstance(const char* partName,
+ const char* dialogClass, KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin,
+ const char *objName = 0, QMap<QString,QString>* args = 0);
+
+ /*! Adeded For convenience. */
+ static QDialog* createModalDialogInstance(const char* partName,
+ KexiDB::MessageHandler *msgHdr, KexiMainWindow* mainWin, const char *objName = 0,
+ QMap<QString,QString>* args = 0)
+ { return createModalDialogInstance(partName, 0, msgHdr, mainWin, objName, args); }
+
+ /*! Executes a command \a commandName (usually nonvisual) using part called \a partName.
+ The result can be put into the \a args. \return true on successful calling. */
+ static bool executeCommand(const char* partName,
+ KexiMainWindow* mainWin, const char* commandName, QMap<QString,QString>* args = 0);
+
+ /*! \return internal part of a name \a partName. Shouldn't be usable. */
+ static const KexiInternalPart* part(KexiDB::MessageHandler *msgHdr, const char* partName);
+
+ /*! \return true if the part can create only one (unique) dialog. */
+ inline bool uniqueDialog() const { return m_uniqueDialog; }
+
+ /*! \return true if the part creation has been cancelled (eg. by a user)
+ so it wasn't an error. Internal part's impelmentation should set it to true when needed.
+ False by default. */
+ inline bool cancelled() const { return m_cancelled; }
+
+ protected:
+ /*! Used internally */
+ KexiDialogBase *findOrCreateKexiDialog(KexiMainWindow* mainWin,
+ const char *objName);
+
+ /*! Reimplement this if your internal part has to return widgets
+ or QDialog objects. */
+ virtual QWidget *createWidget(const char* widgetClass, KexiMainWindow* mainWin,
+ QWidget * parent, const char * objName = 0, QMap<QString,QString>* args = 0);
+
+// //! Reimplement this if your internal part has to return dialogs
+// virtual KexiDialogBase *createDialog(KexiMainWindow* /*mainWin*/,
+// const char * /*objName*/ =0)
+// { return 0; }
+
+ /*! Reimplement this if your internal part has to return a view object. */
+ virtual KexiViewBase *createView(KexiMainWindow* mainWin, QWidget * parent,
+ const char *objName = 0);
+
+ /*! Reimplement this if your internal part has to execute a command \a commandName
+ (usually nonvisual). Arguments are put into \a args and the result can be put into the \a args.
+ \return true on successful calling. */
+ virtual bool executeCommand(KexiMainWindow* mainWin, const char* commandName,
+ QMap<QString,QString>* args = 0);
+
+ //! Unique dialog - we're using guarded ptr for the dialog so can know if it has been closed
+ QGuardedPtr<QWidget> m_uniqueWidget;
+
+ bool m_uniqueDialog : 1; //!< true if createDialogInstance() should return only one dialog
+
+ bool m_cancelled : 1; //!< Used in cancelled()
+};
+
+#endif
diff --git a/kexi/core/keximainwindow.cpp b/kexi/core/keximainwindow.cpp
new file mode 100644
index 00000000..bf66e638
--- /dev/null
+++ b/kexi/core/keximainwindow.cpp
@@ -0,0 +1,36 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "keximainwindow.h"
+
+#include <kdebug.h>
+
+KexiMainWindow::KexiMainWindow()
+ : KMdiMainFrm(0L, "keximainwindow")
+ , KexiSharedActionHost(this)
+{
+}
+
+KexiMainWindow::~KexiMainWindow()
+{
+}
+
+#include "keximainwindow.moc"
+
diff --git a/kexi/core/keximainwindow.h b/kexi/core/keximainwindow.h
new file mode 100644
index 00000000..ec1db633
--- /dev/null
+++ b/kexi/core/keximainwindow.h
@@ -0,0 +1,189 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIMAINWINDOW_H
+#define KEXIMAINWINDOW_H
+
+#include <qmap.h>
+#include <qintdict.h>
+
+#include <kmdimainfrm.h>
+#include <kexiutils/tristate.h>
+
+#include "kexisharedactionhost.h"
+#include "kexi.h"
+
+class KexiDialogBase;
+class KexiProject;
+namespace KexiPart {
+ class Item;
+}
+
+/**
+ * @short Kexi's main window interface
+ * This interface is implemented by KexiMainWindowImpl class.
+ * KexiMainWindow offers simple features what lowers cross-dependency (and also avoids
+ * circular dependencies between Kexi modules).
+ */
+class KEXICORE_EXPORT KexiMainWindow : public KMdiMainFrm, public KexiSharedActionHost
+{
+ Q_OBJECT
+ public:
+ //! Used by printActionForItem()
+ enum PrintActionType {
+ PrintItem,
+ PreviewItem,
+ PageSetupForItem
+ };
+
+ KexiMainWindow();
+ virtual ~KexiMainWindow();
+
+ //! Project data of currently opened project or NULL if no project here yet.
+ virtual KexiProject *project() = 0;
+
+ /*! Registers dialog \a dlg for watching and adds it to the main window's stack. */
+ virtual void registerChild(KexiDialogBase *dlg) = 0;
+
+ virtual QPopupMenu* findPopupMenu(const char *popupName) = 0;
+
+ /*! Generates ID for private "document" like Relations window.
+ Private IDs are negative numbers (while ID regular part instance's IDs are >0)
+ Private means that the object is not stored as-is in the project but is somewhat
+ generated and in most cases there is at most one unique instance document of such type (part).
+ To generate this ID, just app-wide internal counter is used. */
+ virtual int generatePrivateID() = 0;
+
+ /*! \return a list of all actions defined by application.
+ Not all of them are shared. Don't use plug these actions
+ in your windows by hand but user methods from KexiViewBase! */
+ virtual KActionPtrList allActions() const = 0;
+
+ /*! \return currently active dialog (window) od 0 if there is no active dialog. */
+ virtual KexiDialogBase* currentDialog() const = 0;
+
+ /*! \return true if this window is in the User Mode. */
+ virtual bool userMode() const = 0;
+
+ signals:
+ //! Emitted to make sure the project can be close.
+ //! Connect a slot here and set \a cancel to true to cancel the closing.
+ void acceptProjectClosingRequested(bool& cancel);
+
+ //! Emitted before closing the project (and destroying all it's data members).
+ //! You can do you cleanup of your structures here.
+ void beforeProjectClosing();
+
+ //! Emitted after closing the project.
+ void projectClosed();
+
+ public slots:
+ /*! Creates new object of type defined by \a info part info.
+ \a openingCancelled is set to true is opening has been cancelled.
+ \return true on success. */
+ virtual bool newObject( KexiPart::Info *info, bool& openingCancelled ) = 0;
+
+ //! Opens object pointed by \a item in a view \a viewMode
+ virtual KexiDialogBase * openObject(KexiPart::Item *item, int viewMode,
+ bool &openingCancelled, QMap<QString,QString>* staticObjectArgs = 0,
+ QString* errorMessage = 0) = 0;
+
+ //! For convenience
+ virtual KexiDialogBase * openObject(const QCString& mime, const QString& name,
+ int viewMode, bool &openingCancelled, QMap<QString,QString>* staticObjectArgs = 0) = 0;
+
+ /*! Closes the object for \a item.
+ \return true on success (closing can be dealyed though), false on failure and cancelled
+ if the object has "opening" job assigned. */
+ virtual tristate closeObject(KexiPart::Item* item) = 0;
+
+ /*! Called to accept property butter editing. */
+ virtual void acceptPropertySetEditing() = 0;
+
+ /*! Received information from active view that \a dlg has switched
+ its property set, so property editor contents should be reloaded.
+ If \a force is true, property editor's data is reloaded even
+ if the currently pointed property set is the same as before.
+ If \a preservePrevSelection is true and there was a property set
+ set before call, previously selected item will be preselected
+ in the editor (if found). */
+ virtual void propertySetSwitched(KexiDialogBase *dlg, bool force=false,
+ bool preservePrevSelection = true, const QCString& propertyToSelect = QCString()) = 0;
+
+ /*! Saves dialog's \a dlg data. If dialog's data is never saved,
+ user is asked for name and title, before saving (see getNewObjectInfo()).
+ \return true on successul saving or false on error.
+ If saving was cancelled by user, cancelled is returned.
+ \a messageWhenAskingForName is a i18n'ed text that will be visible
+ within name/caption dialog (see KexiNameDialog), which is popped
+ up for never saved objects. */
+ virtual tristate saveObject( KexiDialogBase *dlg,
+ const QString& messageWhenAskingForName = QString::null, bool dontAsk = false ) = 0;
+
+ /*! Closes dialog \a dlg. If dialog's data (see KexiDialoBase::dirty()) is unsaved,
+ used will be asked if saving should be perforemed.
+ \return true on successull closing or false on closing error.
+ If closing was cancelled by user, cancelled is returned. */
+ virtual tristate closeDialog(KexiDialogBase *dlg) = 0;
+
+ /*! Displays a dialog for entering object's name and title.
+ Used on new object saving.
+ \return true on successul closing or cancelled on cancel returned.
+ It's unlikely to have false returned here.
+ \a messageWhenAskingForName is a i18n'ed text that will be visible
+ within name/caption dialog (see KexiNameDialog).
+ If \a allowOverwriting is true, user will be asked for existing
+ object's overwriting, else it will be impossible to enter
+ a name of existing object.
+ You can check \a allowOverwriting after calling this method.
+ If it's true, user agreed on overwriting, if it's false, user picked
+ nonexisting name, so no overwrite will be needed. */
+ virtual tristate getNewObjectInfo( KexiPart::Item *partItem, KexiPart::Part *part,
+ bool& allowOverwriting, const QString& messageWhenAskingForName = QString::null ) = 0;
+
+ /*! Highlights object of mime \a mime and name \a name.
+ This can be done in the Project Navigator or so.
+ If a window for the object is opened (in any mode), it should be raised. */
+ virtual void highlightObject(const QCString& mime, const QCString& name) = 0;
+
+ //! Shows "print" dialog for \a item.
+ //! \return true on success.
+ virtual tristate printItem(KexiPart::Item* item) = 0;
+
+ //! Shows "print preview" dialog.
+ //! \return true on success.
+ virtual tristate printPreviewForItem(KexiPart::Item* item) = 0;
+
+ //! Shows "page setup" dialog for \a item.
+ //! \return true on success and cancelled when the action was cancelled.
+ virtual tristate showPageSetupForItem(KexiPart::Item* item) = 0;
+
+ /*! Executes custom action for the main window, usually provided by a plugin.
+ Also used by KexiFormEventAction. */
+ virtual tristate executeCustomActionForObject(KexiPart::Item* item, const QString& actionName) = 0;
+
+ protected slots:
+ virtual void slotObjectRenamed(const KexiPart::Item &item, const QCString& oldName) = 0;
+
+};
+
+
+#endif
+
diff --git a/kexi/core/kexipart.cpp b/kexi/core/kexipart.cpp
new file mode 100644
index 00000000..3f97e9c3
--- /dev/null
+++ b/kexi/core/kexipart.cpp
@@ -0,0 +1,452 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexipart.h"
+#include "kexipartinfo.h"
+#include "kexipartitem.h"
+#include "kexistaticpart.h"
+#include "kexidialogbase.h"
+#include "kexiviewbase.h"
+
+#include "kexipartguiclient.h"
+#include "keximainwindow.h"
+//#include "kexipartdatasource.h"
+#include "kexi.h"
+
+#include <kexidb/connection.h>
+#include <kexiutils/identifier.h>
+#include <kexiutils/utils.h>
+
+#include <qwidgetstack.h>
+
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+namespace KexiPart {
+//! @internal
+class PartPrivate
+{
+public:
+ PartPrivate()
+ : instanceActionsInitialized(false)
+ {
+ }
+
+ //! Helper, used in Part::openInstance()
+ tristate askForOpeningInTextMode(KexiDialogBase *dlg, KexiPart::Item &item,
+ int supportedViewModes, int viewMode)
+ {
+ if (viewMode != Kexi::TextViewMode
+ && supportedViewModes & Kexi::TextViewMode
+ && dlg->tempData()->proposeOpeningInTextViewModeBecauseOfProblems)
+ {
+ //ask
+ KexiUtils::WaitCursorRemover remover;
+ //! @todo use message handler for this to enable non-gui apps
+ QString singleStatusString( dlg->singleStatusString() );
+ if (!singleStatusString.isEmpty())
+ singleStatusString.prepend(QString("\n\n")+i18n("Details:")+" ");
+ if (KMessageBox::No==KMessageBox::questionYesNo(0,
+ ((viewMode == Kexi::DesignViewMode)
+ ? i18n("Object \"%1\" could not be opened in Design View.").arg(item.name())
+ : i18n("Object could not be opened in Data View."))+"\n"
+ + i18n("Do you want to open it in Text View?") + singleStatusString, 0,
+ KStdGuiItem::open(), KStdGuiItem::cancel()))
+ {
+ // dlg->close(); //this will destroy dlg
+ return false;
+ }
+ return true;
+ }
+ return cancelled;
+ }
+
+ bool instanceActionsInitialized : 1;
+};
+}
+
+//----------------------------------------------------------------
+
+using namespace KexiPart;
+
+Part::Part(QObject *parent, const char *name, const QStringList &)
+: QObject(parent, name)
+, m_guiClient(0)
+, m_registeredPartID(-1) //no registered ID by default
+, d(new PartPrivate())
+{
+ m_info = 0;
+ m_supportedViewModes = Kexi::DataViewMode | Kexi::DesignViewMode;
+ m_supportedUserViewModes = Kexi::DataViewMode;
+ m_mainWin = 0;
+ m_newObjectsAreDirty = false;
+}
+
+Part::Part(QObject* parent, StaticInfo *info)
+: QObject(parent, "StaticPart")
+, m_guiClient(0)
+, m_registeredPartID(-1) //no registered ID by default
+, d(new PartPrivate())
+{
+ m_info = info;
+ m_supportedViewModes = Kexi::DesignViewMode;
+ m_supportedUserViewModes = 0;
+ m_mainWin = 0;
+ m_newObjectsAreDirty = false;
+}
+
+Part::~Part()
+{
+ delete d;
+}
+
+void Part::createGUIClients(KexiMainWindow *win)
+{
+ m_mainWin = win;
+ if (!m_guiClient) {
+ //create part's gui client
+ m_guiClient = new GUIClient(m_mainWin, this, false, "part");
+
+ //default actions for part's gui client:
+ KAction *act = new KAction(m_names["instanceCaption"]+"...", info()->createItemIcon(), 0, this,
+ SLOT(slotCreate()), m_mainWin->actionCollection(),
+ KexiPart::nameForCreateAction(*info()));
+ act->plug( m_mainWin->findPopupMenu("insert") );
+// new KAction(m_names["instance"]+"...", info()->itemIcon(), 0, this,
+// SLOT(create()), m_guiClient->actionCollection(), (info()->objectName()+"part_create").latin1());
+ //let init specific actions for parts
+// initPartActions( m_guiClient->actionCollection() );
+ m_mainWin->guiFactory()->addClient(m_guiClient); //this client is added permanently
+
+ //create part instance's gui client
+// m_instanceGuiClient = new GUIClient(win, this, true);
+
+ //default actions for part instance's gui client:
+ //NONE
+ //let init specific actions for part instances
+ for (int mode = 1; mode <= 0x01000; mode <<= 1) {
+ if (m_supportedViewModes & mode) {
+ GUIClient *instanceGuiClient = new GUIClient(m_mainWin,
+ this, true, Kexi::nameForViewMode(mode).latin1());
+ m_instanceGuiClients.insert(mode, instanceGuiClient);
+// initInstanceActions( mode, instanceGuiClient->actionCollection() );
+ }
+ }
+ // also add an instance common for all modes (mode==0)
+ GUIClient *instanceGuiClient = new GUIClient(m_mainWin, this, true, "allViews");
+ m_instanceGuiClients.insert(Kexi::AllViewModes, instanceGuiClient);
+// initInstanceActions( Kexi::AllViewModes , instanceGuiClient->actionCollection() );
+
+//todo
+ initPartActions();
+// initActions();
+ }
+}
+
+KActionCollection* Part::actionCollectionForMode(int viewMode) const
+{
+ KXMLGUIClient *cli = m_instanceGuiClients[viewMode];
+ return cli ? cli->actionCollection() : 0;
+}
+
+KAction* Part::createSharedAction(int mode, const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name,
+ const char *subclassName)
+{
+ GUIClient *instanceGuiClient = m_instanceGuiClients[mode];
+ if (!instanceGuiClient) {
+ kdDebug() << "KexiPart::createSharedAction(): no gui client for mode " << mode << "!" << endl;
+ return 0;
+ }
+ return m_mainWin->createSharedAction(text, pix_name, cut, name,
+ instanceGuiClient->actionCollection(), subclassName);
+}
+
+KAction* Part::createSharedPartAction(const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name,
+ const char *subclassName)
+{
+ if (!m_guiClient)
+ return 0;
+ return m_mainWin->createSharedAction(text, pix_name, cut, name,
+ m_guiClient->actionCollection(), subclassName);
+}
+
+KAction* Part::createSharedToggleAction(int mode, const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name)
+{
+ return createSharedAction(mode, text, pix_name, cut, name, "KToggleAction");
+}
+
+KAction* Part::createSharedPartToggleAction(const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name)
+{
+ return createSharedPartAction(text, pix_name, cut, name, "KToggleAction");
+}
+
+/*KAction* Part::sharedAction(int mode, const char* name, const char *classname)
+{
+ GUIClient *instanceGuiClient = m_instanceGuiClients[mode];
+ if (!instanceGuiClient) {
+ kdDebug() << "KexiPart::createSharedAction(): no gui client for mode " << mode << "!" << endl;
+ return 0;
+ }
+ return instanceGuiClient->actionCollection()->action(name, classname);
+}
+
+KAction* Part::sharedPartAction(int mode, const char* name, const char *classname)
+{
+ if (!m_guiClient)
+ return 0;
+ return m_guiClient->actionCollection()->action(name, classname);
+}*/
+
+void Part::setActionAvailable(const char *action_name, bool avail)
+{
+ QIntDictIterator<GUIClient> it( m_instanceGuiClients );
+ for (;it.current();++it) {
+ KAction *act = it.current()->actionCollection()->action(action_name);
+ if (act) {
+ act->setEnabled(avail);
+ return;
+ }
+ }
+
+ m_mainWin->setActionAvailable(action_name, avail);
+}
+
+KexiDialogBase* Part::openInstance(KexiMainWindow *win, KexiPart::Item &item, int viewMode,
+ QMap<QString,QString>* staticObjectArgs)
+{
+ //now it's the time for creating instance actions
+ if (!d->instanceActionsInitialized) {
+ initInstanceActions();
+ d->instanceActionsInitialized = true;
+ }
+
+ m_status.clearStatus();
+// KexiDialogBase *dlg = createInstance(win,item,viewMode);
+// if (!dlg)
+// return 0;
+// QString capt = QString("%1 : %2").arg(item.name()).arg(instanceName());
+ KexiDialogBase *dlg = new KexiDialogBase(win);
+ dlg->m_supportedViewModes = m_supportedViewModes;
+// dlg->m_neverSaved = item.neverSaved();
+// dlg->m_currentViewMode = viewMode;
+ dlg->m_part = this;
+ dlg->m_item = &item;
+ dlg->updateCaption();
+
+ KexiDB::SchemaData sdata(m_info->projectPartID());
+ sdata.setName( item.name() );
+ sdata.setCaption( item.caption() );
+ sdata.setDescription( item.description() );
+
+/*! @todo js: apply settings for caption displaying method; there can be option for
+ - displaying item.caption() as caption, if not empty, without instanceName
+ - displaying the same as above in tabCaption (or not) */
+// dlg->setCaption( capt );
+// dlg->setTabCaption( item.name() );
+ dlg->setId(item.identifier()); //not needed, but we did it
+//moved down dlg->registerDialog();
+ dlg->setIcon( SmallIcon( dlg->itemIcon() ) );
+ if (dlg->mdiParent())
+ dlg->mdiParent()->setIcon( *dlg->icon() );
+// if (dlg->mainWidget())
+// dlg->mainWidget()->setIcon( *dlg->icon() );
+ dlg->stack()->setIcon( *dlg->icon() );
+ dlg->m_tempData = createTempData(dlg);
+
+ if (!item.neverSaved()) {
+ //we have to load schema data for this dialog
+ dlg->m_schemaData = loadSchemaData(dlg, sdata, viewMode);
+ if (!dlg->m_schemaData) {
+ //last chance:
+ if (false == d->askForOpeningInTextMode(dlg, item, dlg->m_supportedViewModes, viewMode)) {
+ delete dlg;
+ return 0;
+ }
+ viewMode = Kexi::TextViewMode;
+ dlg->m_schemaData = loadSchemaData(dlg, sdata, viewMode);
+ }
+ if (!dlg->m_schemaData) {
+ if (!m_status.error())
+ m_status = Kexi::ObjectStatus( dlg->mainWin()->project()->dbConnection(),
+ i18n("Could not load object's definition."), i18n("Object design may be corrupted."));
+ m_status.append(
+ Kexi::ObjectStatus(i18n("You can delete \"%1\" object and create it again.")
+ .arg(item.name()), QString::null) );
+
+ dlg->close();
+ delete dlg;
+ return 0;
+ }
+ }
+
+ bool switchingFailed = false;
+ bool dummy;
+ tristate res = dlg->switchToViewMode( viewMode, staticObjectArgs, dummy );
+ if (!res) {
+ tristate askForOpeningInTextModeRes
+ = d->askForOpeningInTextMode(dlg, item, dlg->m_supportedViewModes, viewMode);
+// if (viewMode==Kexi::DesignViewMode && dlg->isDesignModePreloadedForTextModeHackUsed(Kexi::TextViewMode))
+// askForOpeningInTextModeRes = cancelled; //do not try
+// else
+ if (true == askForOpeningInTextModeRes) {
+ delete dlg->m_schemaData; //old one
+ dlg->close();
+ delete dlg;
+ //try in text mode
+ return openInstance(win, item, Kexi::TextViewMode, staticObjectArgs);
+ }
+ else if (false == askForOpeningInTextModeRes) {
+ delete dlg->m_schemaData; //old one
+ dlg->close();
+ delete dlg;
+ return 0;
+ }
+ //dlg has an error info
+ switchingFailed = true;
+ }
+ if (~res)
+ switchingFailed = true;
+
+ if (switchingFailed) {
+ m_status = dlg->status();
+ dlg->close();
+ delete dlg;
+ return 0;
+ }
+ dlg->registerDialog(); //ok?
+ dlg->show();
+
+ if (dlg->mdiParent() && dlg->mdiParent()->state()==KMdiChildFrm::Normal) //only resize dialog if it is in normal state
+ dlg->resize(dlg->sizeHint());
+
+ dlg->setMinimumSize(dlg->minimumSizeHint().width(),dlg->minimumSizeHint().height());
+
+ //dirty only if it's a new object
+ if (dlg->selectedView())
+ dlg->selectedView()->setDirty( m_newObjectsAreDirty ? item.neverSaved() : false );
+
+ return dlg;
+}
+
+void Part::slotCreate()
+{
+ emit newObjectRequest( m_info );
+}
+
+KexiDB::SchemaData* Part::loadSchemaData(KexiDialogBase * /*dlg*/, const KexiDB::SchemaData& sdata,
+ int /*viewMode*/)
+{
+ KexiDB::SchemaData *new_schema = new KexiDB::SchemaData();
+ *new_schema = sdata;
+ return new_schema;
+}
+
+bool Part::loadDataBlock( KexiDialogBase *dlg, QString &dataString, const QString& dataID)
+{
+ if (!dlg->mainWin()->project()->dbConnection()->loadDataBlock( dlg->id(), dataString, dataID )) {
+ m_status = Kexi::ObjectStatus( dlg->mainWin()->project()->dbConnection(),
+ i18n("Could not load object's data."), i18n("Data identifier: \"%1\".").arg(dataID) );
+ m_status.append( *dlg );
+ return false;
+ }
+ return true;
+}
+
+void Part::initPartActions()
+{
+}
+
+void Part::initInstanceActions()
+{
+}
+
+bool Part::remove(KexiMainWindow *win, KexiPart::Item &item)
+{
+ if (!win || !win->project() || !win->project()->dbConnection())
+ return false;
+ KexiDB::Connection *conn = win->project()->dbConnection();
+ return conn->removeObject( item.identifier() );
+}
+
+KexiDialogTempData* Part::createTempData(KexiDialogBase* dialog)
+{
+ return new KexiDialogTempData(dialog);
+}
+
+QString Part::i18nMessage(const QCString& englishMessage, KexiDialogBase* dlg) const
+{
+ Q_UNUSED(dlg);
+ return QString(englishMessage).startsWith(":") ? QString::null : englishMessage;
+}
+
+void Part::setupCustomPropertyPanelTabs(KTabWidget *, KexiMainWindow*)
+{
+}
+
+QCString Part::instanceName() const
+{
+ // "instanceName" should be already valid identifier but we're using
+ // KexiUtils::string2Identifier() to be sure translators did it right.
+ return KexiUtils::string2Identifier(m_names["instanceName"]).lower().latin1();
+}
+
+QString Part::instanceCaption() const
+{
+ return m_names["instanceCaption"];
+}
+
+tristate Part::rename(KexiMainWindow *win, KexiPart::Item &item, const QString& newName)
+{
+ Q_UNUSED(win);
+ Q_UNUSED(item);
+ Q_UNUSED(newName);
+ return true;
+}
+
+//-------------------------------------------------------------------------
+
+
+GUIClient::GUIClient(KexiMainWindow *win, Part* part, bool partInstanceClient, const char* nameSuffix)
+ : QObject(part,
+ (part->info()->objectName()
+ + (nameSuffix ? QString(":%1").arg(nameSuffix) : QString())).latin1() )
+ , KXMLGUIClient(win)
+{
+ if(!win->project()->data()->userMode())
+ setXMLFile(QString::fromLatin1("kexi")+part->info()->objectName()
+ +"part"+(partInstanceClient?"inst":"")+"ui.rc");
+
+// new KAction(part->m_names["new"], part->info()->itemIcon(), 0, this,
+// SLOT(create()), actionCollection(), (part->info()->objectName()+"part_create").latin1());
+
+// new KAction(i18nInstanceName+"...", part->info()->itemIcon(), 0, this,
+// SLOT(create()), actionCollection(), (part->info()->objectName()+"part_create").latin1());
+
+// win->guiFactory()->addClient(this);
+}
+
+
+#include "kexipart.moc"
+
diff --git a/kexi/core/kexipart.h b/kexi/core/kexipart.h
new file mode 100644
index 00000000..4045c4c6
--- /dev/null
+++ b/kexi/core/kexipart.h
@@ -0,0 +1,333 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPART_H
+#define KEXIPART_H
+
+#include <qobject.h>
+#include <qmap.h>
+
+#include <kexiutils/tristate.h>
+#include "kexi.h"
+#include "keximainwindow.h"
+
+class KActionCollection;
+class KexiDialogBase;
+class KexiDialogTempData;
+class KexiViewBase;
+class KexiMainWindowImpl;
+class KAction;
+class KShortcut;
+class KTabWidget;
+
+namespace KexiPart
+{
+ class Info;
+ class Item;
+ class GUIClient;
+ class PartPrivate;
+ class StaticInfo;
+
+/*! Official (registered) type IDs for objects like table, query, form... */
+enum ObjectTypes {
+ TableObjectType = KexiDB::TableObjectType, //!< 1, like in KexiDB::ObjectTypes
+ QueryObjectType = KexiDB::QueryObjectType, //!< 2, like in KexiDB::ObjectTypes
+ FormObjectType = 3,
+ ReportObjectType = 4,
+ ScriptObjectType = 5,
+ WebObjectType = 6,
+ MacroObjectType = 7,
+ LastObjectType = 7, //ALWAYS UPDATE THIS
+
+ UserObjectType = 100 //!< external types
+};
+
+/**
+ * The main class for kexi frontend parts like tables, queries, forms and reports
+ */
+class KEXICORE_EXPORT Part : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /*! Constructor. */
+ Part(QObject *parent, const char *name, const QStringList &);
+ /*! Destructor. */
+ virtual ~Part();
+
+//! @todo make it protected, outside world should use KexiProject
+ /*! Try to execute the part. Implementations of this \a Part
+ are able to overwrite this method to offer execution.
+ \param item The \a KexiPart::Item that should be executed.
+ \param sender The sender QObject which likes to execute this \a Part or
+ NULL if there is no sender. The KFormDesigner uses this to pass
+ the actual widget (e.g. the button that was pressed).
+ \return true if execution was successfully else false.
+ */
+ virtual bool execute(KexiPart::Item* item, QObject* sender = 0) {
+ Q_UNUSED(item);
+ Q_UNUSED(sender);
+ return false;
+ }
+
+ /*! \return supported modes for dialogs created by this part, i.e. a combination
+ of Kexi::ViewMode enum elements.
+ Set this member in your KexiPart subclass' ctor, if you need to override the default value
+ that equals Kexi::DataViewMode | Kexi::DesignViewMode,
+ or Kexi::DesignViewMode in case of Kexi::PartStaticPart object.
+ This information is used to set supported view modes for every
+ KexiDialogBase-derived object created by this KexiPart. */
+ inline int supportedViewModes() const { return m_supportedViewModes; }
+
+ /*! \return supported modes for dialogs created by this part in "user mode", i.e. a combination
+ of Kexi::ViewMode enum elements.
+ Set this member in your KexiPart subclass' ctor, if you need to override the default value
+ that equals Kexi::DataViewMode. or 0 in case of Kexi::PartStaticPart object.
+ This information is used to set supported view modes for every
+ KexiDialogBase-derived object created by this KexiPart. */
+ inline int supportedUserViewModes() const { return m_supportedUserViewModes; }
+
+//! @todo make it protected, outside world should use KexiProject
+ /*! "Opens" an instance that the part provides, pointed by \a item in a mode \a viewMode.
+ \a viewMode is one of Kexi::ViewMode enum.
+ \a staticObjectArgs can be passed for static Kexi Parts. */
+ KexiDialogBase* openInstance(KexiMainWindow *win, KexiPart::Item &item,
+ int viewMode = Kexi::DataViewMode, QMap<QString,QString>* staticObjectArgs = 0);
+
+//! @todo make it protected, outside world should use KexiProject
+ /*! Removes any stored data pointed by \a item (example: table is dropped for table part).
+ From now this data is inaccesible, and \a item disappear.
+ You do not need to remove \a item, or remove object's schema stored in the database,
+ beacuse this will be done automatically by KexiProject after successful
+ call of this method. All object's data blocks are also automatically removed from database
+ (from "kexi__objectdata" table).
+ For this, a database connection associated with kexi project owned by \a win can be used.
+
+ Database transaction is started by KexiProject before calling this method,
+ and it will be rolled back if you return false here.
+ You shouldn't use by hand transactions here.
+
+ Default implementation just removes object from kexi__* system structures
+ at the database backend using KexiDB::Connection::removeObject(). */
+ virtual bool remove(KexiMainWindow *win, KexiPart::Item & item);
+
+ /*! Renames stored data pointed by \a item to \a newName
+ (example: table name is altered in the database).
+ For this, a database connection associated with kexi project owned by \a win can be used.
+ You do not need to change \a item, and change object's schema stored in the database,
+ beacuse this is automatically handled by KexiProject.
+
+ Database transaction is started by KexiProject before calling this method,
+ and it will be rolled back if you return false here.
+ You shouldn't use by hand transactions here.
+
+ Default implementation does nothing and returns true. */
+ virtual tristate rename(KexiMainWindow *win, KexiPart::Item &item, const QString& newName);
+
+ /*! Creates and returns a new temporary data for a dialog \a dialog.
+ This method is called on openInstance() once per dialog.
+ Reimplement this to return KexiDialogTempData subclass instance.
+ Default implemention just returns empty KexiDialogTempData object. */
+ virtual KexiDialogTempData* createTempData(KexiDialogBase* dialog);
+
+ /*! Creates a new view for mode \a viewMode, \a item and \a parent. The view will be
+ used inside \a dialog. */
+ virtual KexiViewBase* createView(QWidget *parent, KexiDialogBase* dialog,
+ KexiPart::Item &item, int viewMode = Kexi::DataViewMode, QMap<QString,QString>* staticObjectArgs = 0) = 0;
+
+ /*! i18n'd instance name usable for displaying in gui as object's name.
+ The name is valid identifier - contains latin1 lowercase characters only.
+ @todo move this to Info class when the name could be moved as localized property
+ to service's .desktop file. */
+ QCString instanceName() const;
+
+ /*! i18n'd instance name usable for displaying in gui as object's caption.
+ @todo move this to Info class when the name could be moved as localized property
+ to service's .desktop file. */
+ QString instanceCaption() const;
+
+ inline Info *info() const { return m_info; }
+
+ /*! \return part's GUI Client, so you can
+ create part-wide actions using this client. */
+ inline GUIClient *guiClient() const { return m_guiClient; }
+
+ /*! \return part's GUI Client, so you can
+ create instance-wide actions using this client. */
+ inline GUIClient *instanceGuiClient(int mode = 0) const
+ { return m_instanceGuiClients[mode]; }
+
+#if 0
+ /**
+ * @returns the datasource object of this part
+ * reeimplement it to make a part work as dataprovider ;)
+ */
+ virtual DataSource *dataSource() { return 0; }
+#endif
+
+ /*! \return action collection for mode \a viewMode. */
+ KActionCollection* actionCollectionForMode(int viewMode) const;
+
+ const Kexi::ObjectStatus& lastOperationStatus() const { return m_status; }
+
+ /*! \return i18n'd message translated from \a englishMessage.
+ This method is useful for messages like:
+ "<p>Table \"%1\" has been modified.</p>",
+ -- such messages can be accurately translated,
+ while this could not: "<p>%1 \"%2\" has been modified.</p>".
+ See implementation of this method in KexiTablePart to see
+ what strings are needed for translation.
+
+ Default implementation returns generic \a englishMessage.
+ In special cases, \a englishMessage can start with ":",
+ to indicate that empty string will be generated if
+ a part does not offer a message for such \a englishMessage.
+ This is used e.g. in KexiMainWindowImpl::closeDialog().
+ */
+ virtual QString i18nMessage(const QCString& englishMessage,
+ KexiDialogBase* dlg) const;
+
+ signals:
+ void newObjectRequest( KexiPart::Info *info );
+
+ protected slots:
+ void slotCreate();
+
+ protected:
+ //! Used by StaticPart
+ Part(QObject* parent, StaticInfo *info);
+
+// virtual KexiDialogBase* createInstance(KexiMainWindow *win, const KexiPart::Item &item, int viewMode = Kexi::DataViewMode) = 0;
+
+ //! Creates GUICLients for this part, attached to \a win
+ //! This method is called from KexiMainWindow
+ void createGUIClients(KexiMainWindow *win);
+
+#if 0
+ /*! For reimplementation. Create here all part actions (KAction or similar).
+ "Part action" is an action that is bound to given part, not for dialogs
+ created with this part, eg. "Open external project" action for Form part.
+ Default implementation does nothing.
+ */
+ virtual void initPartActions( KActionCollection * ) {};
+
+ /*! For reimplementation. You should here create all instance actions (KAction or similar)
+ for \a mode (this method called for every value given by Kexi::ViewMode enum,
+ and in special cases, in the future - for user-defined part-specific modes).
+ Actions should be bound to action collection \a col.
+ "Instance action" is an action that is bound to given dialog instance (created with a part),
+ for specific view. \a mo; eg. "Filter data" action for DataViewMode of Table part.
+ By creating actions here, you can ensure that after switching to other view mode (eg. from
+ Design view to Data view), appropriate actions will be switched/hidden.
+ \a mode equal Kexi::AllViewModes means that given actions will be available for
+ all supported views.
+ Default implementation does nothing.
+ */
+ virtual void initInstanceActions( int mode, KActionCollection *col ) {};
+#endif
+
+ virtual void initPartActions();
+ virtual void initInstanceActions();
+
+ virtual KexiDB::SchemaData* loadSchemaData(KexiDialogBase *dlg,
+ const KexiDB::SchemaData& sdata, int viewMode);
+
+ bool loadDataBlock( KexiDialogBase *dlg, QString &dataString, const QString& dataID = QString::null);
+
+ /*! Creates shared action for action collection declared
+ for 'instance actions' of this part.
+ See KexiSharedActionHost::createSharedAction() for details.
+ Pass desired KAction subclass with \a subclassName (e.g. "KToggleAction") to have
+ that subclass allocated instead just KAction (what is the default). */
+ KAction* createSharedAction(int mode, const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name,
+ const char *subclassName = 0);
+
+ /*! Convenience version of above method - creates shared toggle action. */
+ KAction* createSharedToggleAction(int mode, const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name);
+
+ /*! Creates shared action for action collection declared
+ for 'part actions' of this part.
+ See KexiSharedActionHost::createSharedAction() for details.
+ Pass desired KAction subclass with \a subclassName (e.g. "KToggleAction") to have
+ that subclass allocated instead just KAction (what is the default). */
+ KAction* createSharedPartAction(const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name,
+ const char *subclassName = 0);
+
+ /*! Convenience version of above method - creates shared toggle action
+ for 'part actions' of this part. */
+ KAction* createSharedPartToggleAction(const QString &text,
+ const QString &pix_name, const KShortcut &cut, const char *name);
+
+ void setActionAvailable(const char *action_name, bool avail);
+
+ inline void setInfo(Info *info) { m_info = info; }
+
+ /*! This method can be reimplemented to setup additional tabs
+ in the property editor panel. Default implementation does nothing.
+ This method is called whenever current dialog (KexiDialogBase) is switched and
+ type (mime type) of its contents differs from previous one.
+ For example, if a user switched from Table Designer to Form Designer,
+ additional tab containing Form Designer's object tree should be shown. */
+ virtual void setupCustomPropertyPanelTabs(KTabWidget *tab, KexiMainWindow* mainWin);
+
+ //! Set of i18n'd action names for, initialised on KexiPart::Part subclass ctor
+ //! The names are useful because the same action can have other name for each part
+ //! E.g. "New table" vs "New query" can have different forms for some languages...
+ QMap<QString,QString> m_names;
+
+ /*! Supported modes for dialogs created by this part.
+ @see supportedViewModes() */
+ int m_supportedViewModes;
+
+ /*! Supported modes for dialogs created by this part in "user mode".
+ The default is Kexi::DataViewMode. It is altered in classes like KexiSimplePrintingPart.
+ @see supportedUserViewModes() */
+ int m_supportedUserViewModes;
+
+ Info *m_info;
+ GUIClient *m_guiClient;
+ QIntDict<GUIClient> m_instanceGuiClients;
+ KexiMainWindow* m_mainWin;
+ Kexi::ObjectStatus m_status;
+
+ /*! If you're implementing a new part, set this to value >0 in your ctor
+ if you have well known (ie registered ID) for your part.
+ So far, table, query, form, report and script part have defined their IDs
+ (see KexiPart::ObjectTypes). */
+ int m_registeredPartID;
+
+ /*! True if newwly created, unsaved objects are dirty. False by default.
+ You can change it in your subclass' constructor. */
+ bool m_newObjectsAreDirty : 1;
+
+ PartPrivate *d;
+
+ friend class Manager;
+ friend class ::KexiMainWindow;
+ friend class ::KexiMainWindowImpl;
+ friend class GUIClient;
+};
+
+}
+
+#endif
diff --git a/kexi/core/kexipartdatasource.cpp b/kexi/core/kexipartdatasource.cpp
new file mode 100644
index 00000000..f3268594
--- /dev/null
+++ b/kexi/core/kexipartdatasource.cpp
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.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 "kexipartdatasource.h"
+#include "kexipart.h"
+
+namespace KexiPart {
+
+class DataSourcePrivate
+{
+ public:
+ DataSourcePrivate() {}
+ ~DataSourcePrivate() {}
+ Part *part;
+};
+
+}
+
+using namespace KexiPart;
+
+DataSource::DataSource(Part *part)
+ : d(new DataSourcePrivate())
+{
+ d->part = part;
+}
+
+DataSource::~DataSource()
+{
+ delete d;
+}
+
+Part* DataSource::part() const { return d->part; }
+
diff --git a/kexi/core/kexipartdatasource.h b/kexi/core/kexipartdatasource.h
new file mode 100644
index 00000000..e7ce9a96
--- /dev/null
+++ b/kexi/core/kexipartdatasource.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.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 KEXIPARTDATASOURCE_H
+#define KEXIPARTDATASOURCE_H
+
+class KexiProject;
+namespace KexiDB
+{
+ class FieldList;
+ class Cursor;
+}
+
+namespace KexiPart
+{
+ class DataSourcePrivate;
+ class Item;
+ class Part;
+
+/**
+ * this class provides a datasource framework for e.g. tables and queries
+ * using this framework one can query for
+ * - a list of datasources
+ * - the fileds in datasources
+ * - variables (e.g. query variables)
+ */
+class KEXICORE_EXPORT DataSource
+{
+ public:
+ DataSource(Part *part);
+ virtual ~DataSource();
+
+ /**
+ * @returns a list of fileds for the datasource
+ * @arg id is the document id for the source
+ */
+ virtual KexiDB::FieldList *fields(KexiProject *project, const KexiPart::Item &i)=0;
+
+ /**
+ * @returns the cursor
+ */
+ virtual KexiDB::Cursor *cursor(KexiProject *project, const KexiPart::Item &i, bool buffer)=0;
+
+ /**
+ * @returns the part providing this datasource
+ */
+ Part *part() const;
+
+ private:
+ DataSourcePrivate *d;
+};
+
+}
+
+#endif
+
diff --git a/kexi/core/kexipartguiclient.h b/kexi/core/kexipartguiclient.h
new file mode 100644
index 00000000..bb0d16ea
--- /dev/null
+++ b/kexi/core/kexipartguiclient.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPARTGUICL_H
+#define KEXIPARTGUICL_H
+
+#include "kexipart.h"
+
+#include <qobject.h>
+
+#include <kxmlguiclient.h>
+
+class KexiMainWindow;
+class KexiDialogBase;
+
+namespace KexiPart
+{
+
+/** @internal A GUI Client used by KexiPart::Part objects within KexiMainWindow
+*/
+class GUIClient : public QObject, public KXMLGUIClient
+{
+ public:
+ virtual ~GUIClient() {};
+
+ inline Part *part() { return static_cast<Part*>(QObject::parent()); }
+
+ protected:
+ /*! Creates a new GUI Client. If \a partInstanceClient is true, the part will be
+ used as "instance" client, otherwise it will be defined per-view.
+ \a nameSuffix is used in constructing client's name (only useful for debugging purposes). */
+ GUIClient(KexiMainWindow *win, Part* part, bool partInstanceClient, const char* nameSuffix);
+
+ friend class Part;
+};
+
+}
+
+#endif
+
diff --git a/kexi/core/kexipartinfo.cpp b/kexi/core/kexipartinfo.cpp
new file mode 100644
index 00000000..22f7cc55
--- /dev/null
+++ b/kexi/core/kexipartinfo.cpp
@@ -0,0 +1,133 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexipartinfo_p.h"
+
+#include <kexidb/global.h>
+
+using namespace KexiPart;
+
+Info::Private::Private(const KService::Ptr& aPtr)
+ : ptr(aPtr)
+ , groupName(aPtr->name())
+ , mimeType(aPtr->property("X-Kexi-TypeMime").toCString())
+ , itemIcon(aPtr->property("X-Kexi-ItemIcon").toString())
+ , objectName(aPtr->property("X-Kexi-TypeName").toString())
+ , broken(false)
+ , idStoredInPartDatabase(false)
+{
+ QVariant val = ptr->property("X-Kexi-NoObject");
+ isVisibleInNavigator = val.isValid() ? (val.toInt() != 1) : true;
+
+//! @todo (js)..... now it's hardcoded!
+ if(objectName == "table")
+ projectPartID = KexiDB::TableObjectType;
+ else if(objectName == "query")
+ projectPartID = KexiDB::QueryObjectType;
+// else if(objectName == "html")
+// m_projectPartID = KexiDB::WebObjectType;
+ else
+ projectPartID = -1; //TODO!!
+}
+
+Info::Private::Private()
+ : projectPartID(-1) //OK?
+ , broken(false)
+ , isVisibleInNavigator(false)
+ , idStoredInPartDatabase(false)
+{
+}
+
+//------------------------------
+
+Info::Info(KService::Ptr ptr)
+ : d(new Private(ptr))
+{
+}
+
+Info::Info()
+ : d(new Private())
+{
+}
+
+Info::~Info()
+{
+ delete d;
+}
+
+QString Info::groupName() const { return d->groupName; }
+
+QCString Info::mimeType() const { return d->mimeType; }
+
+QString Info::itemIcon() const { return d->itemIcon; }
+
+QString Info::createItemIcon() const { return d->itemIcon+"_newobj"; }
+
+QString Info::objectName() const { return d->objectName; }
+
+KService::Ptr Info::ptr() const { return d->ptr; }
+
+bool Info::isBroken() const { return d->broken; }
+
+bool Info::isVisibleInNavigator() const { return d->isVisibleInNavigator; }
+
+int Info::projectPartID() const { return d->projectPartID; }
+
+void Info::setProjectPartID(int id) { d->projectPartID=id; }
+
+void Info::setBroken(bool broken, const QString& errorMessage)
+{ d->broken = broken; d->errorMessage = errorMessage; }
+
+QString Info::errorMessage() const { return d->errorMessage; }
+
+void Info::setIdStoredInPartDatabase(bool set)
+{
+ d->idStoredInPartDatabase = set;
+}
+
+bool Info::isIdStoredInPartDatabase() const
+{
+ return d->idStoredInPartDatabase;
+}
+
+bool Info::isDataExportSupported() const
+{
+ QVariant val = d->ptr ? d->ptr->property("X-Kexi-SupportsDataExport") : QVariant();
+ return val.isValid() ? val.toBool() : false;
+}
+
+bool Info::isPrintingSupported() const
+{
+ QVariant val = d->ptr ? d->ptr->property("X-Kexi-SupportsPrinting") : QVariant();
+ return val.isValid() ? val.toBool() : false;
+}
+
+bool Info::isExecuteSupported() const
+{
+ QVariant val = d->ptr ? d->ptr->property("X-Kexi-SupportsExecution") : QVariant();
+ return val.isValid() ? val.toBool() : false;
+}
+
+//--------------
+
+QCString KexiPart::nameForCreateAction(const Info& info)
+{
+ return (info.objectName()+"part_create").latin1();
+}
diff --git a/kexi/core/kexipartinfo.h b/kexi/core/kexipartinfo.h
new file mode 100644
index 00000000..43cf5b87
--- /dev/null
+++ b/kexi/core/kexipartinfo.h
@@ -0,0 +1,160 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPARTINFO_H
+#define KEXIPARTINFO_H
+
+#include "kexipartmanager.h"
+
+class KexiMainWindowImpl;
+class KexiProject;
+class KexiDialogBase;
+
+namespace KexiPart
+{
+
+ class Manager;
+ class Item;
+ class Part;
+
+/**
+ * @short Information about a Kexi Part (plugin).
+ */
+class KEXICORE_EXPORT Info
+{
+ public:
+ Info(KService::Ptr service);
+ ~Info();
+
+ /**
+ * @return a i18n'ed group name e.g. "Tables"
+ */
+ QString groupName() const;
+
+ /**
+ * @return the internal mime type of this part
+ */
+ QCString mimeType() const;
+
+// /**
+// * @return the icon for groups
+// */
+// inline QString groupIcon() const { return m_groupIcon; }
+
+ /**
+ * @return the icon for a item
+ */
+ QString itemIcon() const;
+
+ /**
+ * @return the icon for a item
+ */
+ QString createItemIcon() const;
+
+ /**
+ * @return the object name associated with this part (e.g. "table")
+ */
+ QString objectName() const;
+
+ /**
+ * @return the project-part-id
+ */
+ int projectPartID() const;
+
+ /**
+ * @return the KService::Ptr associated with this part
+ */
+ KService::Ptr ptr() const;
+
+ /**
+ * @return true if loading was tried but failed
+ */
+ bool isBroken() const;
+
+ /**
+ * \return true if the part should be visible in the Project Navigator (as a folder).
+ */
+ bool isVisibleInNavigator() const;
+
+ /**
+ * \return true if the part supports data exporting.
+ */
+ bool isDataExportSupported() const;
+
+ /**
+ * \return true if the part supports data printing.
+ */
+ bool isPrintingSupported() const;
+
+ /**
+ * \return true if the part supports execution. This is as
+ * example the case for the Macro and the Scripting plugins.
+ */
+ bool isExecuteSupported() const;
+
+ protected:
+ /**
+ * Used in StaticInfo
+ */
+ Info();
+
+ friend class Manager;
+ friend class ::KexiProject;
+ friend class ::KexiMainWindowImpl;
+ friend class ::KexiDialogBase;
+
+ /**
+ * Sets the project-part-id.
+ */
+ void setProjectPartID(int id);
+
+ /**
+ * Sets the broken flag and error message.
+ * Most likely to be called by @ref KexiPart::Manager
+ */
+ void setBroken(bool broken, const QString& errorMessage);
+
+ /**
+ * \return i18n'd error message set by setBroken().
+ */
+ QString errorMessage() const;
+
+ void setIdStoredInPartDatabase(bool set);
+
+ /**
+ * \return true if ID of the part is stored in project's database
+ * false by default. This flag is updated in Manager::checkProject()
+ * and set to true on first successful execution of KexiDialogBase::storeNewData()
+ * @internal
+ */
+ bool isIdStoredInPartDatabase() const;
+
+ class Private;
+ Private *d;
+};
+
+/*! \return "create" KAction's name for part defined by \a info.
+ The result is like "tablepart_create". Used in Part::createGUIClients()
+ and KexiBrowser. */
+KEXICORE_EXPORT QCString nameForCreateAction(const Info& info);
+
+}
+
+#endif
diff --git a/kexi/core/kexipartinfo_p.h b/kexi/core/kexipartinfo_p.h
new file mode 100644
index 00000000..5904ff97
--- /dev/null
+++ b/kexi/core/kexipartinfo_p.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPROJECTPARTITEM_P_H
+#define KEXIPROJECTPARTITEM_P_H
+
+#include "kexipartinfo.h"
+#include <kservice.h>
+
+namespace KexiPart
+{
+//! @internal
+class Info::Private
+{
+ public:
+ Private(const KService::Ptr& aPtr);
+
+ //! used in StaticItem class
+ Private();
+
+ KService::Ptr ptr;
+ QString errorMessage;
+ QString groupName;
+ QCString mimeType;
+ QString itemIcon;
+ QString objectName;
+ int projectPartID;
+ bool broken : 1;
+ bool isVisibleInNavigator : 1;
+ bool idStoredInPartDatabase : 1;
+};
+}
+
+#endif
diff --git a/kexi/core/kexipartitem.cpp b/kexi/core/kexipartitem.cpp
new file mode 100644
index 00000000..4ef77783
--- /dev/null
+++ b/kexi/core/kexipartitem.cpp
@@ -0,0 +1,33 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+
+ 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 "kexipartitem.h"
+
+using namespace KexiPart;
+
+Item::Item()
+ : m_id(0) //- null
+ , m_neverSaved(false)
+{
+}
+
+Item::~Item()
+{
+}
+
diff --git a/kexi/core/kexipartitem.h b/kexi/core/kexipartitem.h
new file mode 100644
index 00000000..46eebf47
--- /dev/null
+++ b/kexi/core/kexipartitem.h
@@ -0,0 +1,117 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPROJECTPARTITEM_H
+#define KEXIPROJECTPARTITEM_H
+
+#include <qobject.h>
+#include <qintdict.h>
+#include <qptrlist.h>
+
+namespace KexiDB
+{
+ class Connection;
+}
+
+namespace KexiPart
+{
+
+class Info;
+
+/*!
+ @short Information about a single object that can be instantiated using Kexi Part
+
+ KexiPart::Item stores:
+ - identifier ident (low-level name, for example: table name)
+ - mime type name, eg. "kexi/table"
+ - caption (visible, i18n'd hight level name, eg. table or query title)
+*/
+class KEXICORE_EXPORT Item
+{
+ public:
+
+ Item();
+ ~Item();
+
+ int identifier() const { return m_id; }
+ void setIdentifier(int id) { m_id = id; }
+
+ QCString mimeType() const { return m_mime; }
+ void setMimeType(const QCString &mime) { m_mime = mime; }
+
+ QString name() const { return m_name; }
+ void setName(const QString &name) { m_name = name; }
+
+ QString caption() const { return m_caption; }
+ void setCaption(const QString &c) { m_caption = c; }
+
+ QString description() const { return m_desc; }
+ void setDescription(const QString &d) { m_desc = d; }
+
+ /*! \return "neverSaved" flag for this item what mean
+ that is used when new item is created in-memory-only,
+ so we need to indicate for KexiProject about that state.
+ By default this flag is false.
+ Used by KexiMainWindowImpl::newObject(). */
+ bool neverSaved() const { return m_neverSaved; }
+
+ /*! \sa neverSaved().
+ Used by KexiMainWindowImpl::newObject(). */
+ void setNeverSaved(bool set) { m_neverSaved = set; }
+
+ bool isNull() const { return m_id==0; }
+
+ //! \return caption if not empty, else returns name.
+ inline QString captionOrName() const { return m_caption.isEmpty() ? m_name : m_caption; }
+
+ private:
+ QCString m_mime;
+ QString m_name;
+ QString m_caption;
+ QString m_desc;
+ int m_id;
+ bool m_neverSaved : 1;
+};
+
+typedef QIntDict<KexiPart::Item> ItemDict;
+typedef QIntDictIterator<KexiPart::Item> ItemDictIterator;
+typedef QPtrListIterator<KexiPart::Item> ItemListIterator;
+
+/*!
+ @short Part item list with reimplemented compareItems() method.
+
+ Such a list is returend by KexiProject::getSortedItems(KexiPart::ItemList& list, KexiPart::Info *i);
+ so you can call sort() on the list to sort it by item name.
+*/
+class KEXICORE_EXPORT ItemList : public QPtrList<KexiPart::Item> {
+ public:
+ ItemList() {}
+ protected:
+ virtual int compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 ) {
+ return QString::compare(
+ static_cast<KexiPart::Item*>(item1)->name(),
+ static_cast<KexiPart::Item*>(item2)->name());
+ }
+};
+
+}
+
+#endif
+
diff --git a/kexi/core/kexipartmanager.cpp b/kexi/core/kexipartmanager.cpp
new file mode 100644
index 00000000..8525c2d7
--- /dev/null
+++ b/kexi/core/kexipartmanager.cpp
@@ -0,0 +1,280 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 <klibloader.h>
+#include <ktrader.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kparts/componentfactory.h>
+
+#include "kexipartmanager.h"
+#include "kexipart.h"
+#include "kexipartinfo.h"
+#include "kexistaticpart.h"
+#include "kexi_version.h"
+
+#include <kexidb/connection.h>
+#include <kexidb/cursor.h>
+
+using namespace KexiPart;
+
+Manager::Manager(QObject *parent)
+ : QObject(parent)
+{
+ m_lookupDone = false;
+ m_partlist.setAutoDelete(true);
+ m_partsByMime.setAutoDelete(false);
+ m_parts.setAutoDelete(false);//KApp will remove parts
+ m_nextTempProjectPartID = -1;
+}
+
+void
+Manager::lookup()
+{
+//js: TODO: allow refreshing!!!! (will need calling removeClient() by Part objects)
+ if (m_lookupDone)
+ return;
+ m_lookupDone = true;
+ m_partlist.clear();
+ m_partsByMime.clear();
+ m_parts.clear();
+ KTrader::OfferList tlist = KTrader::self()->query("Kexi/Handler",
+ "[X-Kexi-PartVersion] == " + QString::number(KEXI_PART_VERSION));
+
+ KConfig conf("kexirc", true);
+ conf.setGroup("Parts");
+ QStringList sl_order = QStringList::split( ",", conf.readEntry("Order") );//we'll set parts in defined order
+ const int size = QMAX( tlist.count(), sl_order.count() );
+ QPtrVector<KService> ordered( size*2 );
+ int offset = size; //we will insert not described parts from #offset
+
+ //compute order
+ for(KTrader::OfferList::ConstIterator it(tlist.constBegin()); it != tlist.constEnd(); ++it)
+ {
+ KService::Ptr ptr = (*it);
+ QCString mime = ptr->property("X-Kexi-TypeMime").toCString();
+ kdDebug() << "Manager::lookup(): " << mime << endl;
+//<TEMP>: disable some parts if needed
+ if (!Kexi::tempShowForms() && mime=="kexi/form")
+ continue;
+ if (!Kexi::tempShowReports() && mime=="kexi/report")
+ continue;
+ if (!Kexi::tempShowMacros() && mime=="kexi/macro")
+ continue;
+ if (!Kexi::tempShowScripts() && mime=="kexi/script")
+ continue;
+//</TEMP>
+ int idx = sl_order.findIndex( ptr->library() );
+ if (idx!=-1)
+ ordered.insert(idx, ptr);
+ else //add to end
+ ordered.insert(offset++, ptr);
+ }
+ //fill final list using computed order
+ for (int i = 0; i< (int)ordered.size(); i++) {
+ KService::Ptr ptr = ordered[i];
+ if (ptr) {
+ Info *info = new Info(ptr);
+ info->setProjectPartID(m_nextTempProjectPartID--); // temp. part id are -1, -2, and so on,
+ // to avoid duplicates
+ if (!info->mimeType().isEmpty()) {
+ m_partsByMime.insert(info->mimeType(), info);
+ kdDebug() << "Manager::lookup(): inserting info to " << info->mimeType() << endl;
+ }
+ m_partlist.append(info);
+ }
+ }
+}
+
+Manager::~Manager()
+{
+}
+
+Part *
+Manager::part(Info *i)
+{
+ clearError();
+ if(!i)
+ return 0;
+
+// kdDebug() << "Manager::part( id = " << i->projectPartID() << " )" << endl;
+
+ if (i->isBroken()) {
+ setError(i->errorMessage());
+ return 0;
+ }
+
+ Part *p = m_parts[i->projectPartID()];
+
+ if(!p) {
+// kdDebug() << "Manager::part().." << endl;
+ int error=0;
+ p = KParts::ComponentFactory::createInstanceFromService<Part>(i->ptr(), this,
+ QString(i->objectName()+"_part").latin1(), QStringList(), &error);
+ if(!p) {
+ kdDebug() << "Manager::part(): failed :( (ERROR #" << error << ")" << endl;
+ kdDebug() << " " << KLibLoader::self()->lastErrorMessage() << endl;
+ i->setBroken(true, i18n("Error while loading plugin \"%1\"").arg(i->objectName()));
+ setError(i->errorMessage());
+ return 0;
+ }
+ if (p->m_registeredPartID>0) {
+ i->setProjectPartID( p->m_registeredPartID );
+ }
+
+ p->setInfo(i);
+ m_parts.insert(i->projectPartID(),p);
+ emit partLoaded(p);
+ }
+ else {
+// kdDebug() << "Manager::part(): cached: " << i->groupName() << endl;
+ }
+
+// kdDebug() << "Manager::part(): fine!" << endl;
+ return p;
+}
+
+#if 0
+void
+Manager::unloadPart(Info *i)
+{
+ m_parts.setAutoDelete(true);
+ m_parts.remove(i->projectPartID());
+ m_parts.setAutoDelete(false);
+/* if (!p)
+ return;
+ m_partsByMime.take(i->mime());
+ m_partlist.removeRef(p);*/
+}
+
+void
+Manager::unloadAllParts()
+{
+// m_partsByMime.clear();
+ m_parts.setAutoDelete(true);
+ m_parts.clear();
+ m_parts.setAutoDelete(false);
+// m_partlist.clear();
+}
+#endif
+
+/*void
+Manager::removeClients( KexiMainWindow *win )
+{
+ if (!win)
+ return;
+ QIntDictIterator<Part> it(m_parts);
+ for (;i.current();++it) {
+ i.current()->removeClient(win->guiFactory());
+ }
+}*/
+
+Part *
+Manager::partForMimeType(const QString &mimeType)
+{
+ return mimeType.isEmpty() ? 0 : part(m_partsByMime[mimeType.latin1()]);
+}
+
+Info *
+Manager::infoForMimeType(const QString &mimeType)
+{
+ Info *i = mimeType.isEmpty() ? 0 : m_partsByMime[mimeType.latin1()];
+ if (i)
+ return i;
+ setError(i18n("No plugin for mime type \"%1\"").arg(mimeType));
+ return 0;
+}
+
+
+bool
+Manager::checkProject(KexiDB::Connection *conn)
+{
+ clearError();
+// QString errmsg = i18n("Invalid project contents.");
+
+//TODO: catch errors!
+ if(!conn->isDatabaseUsed()) {
+ setError(conn);
+ return false;
+ }
+
+ KexiDB::Cursor *cursor = conn->executeQuery("SELECT * FROM kexi__parts");//, KexiDB::Cursor::Buffered);
+ if(!cursor) {
+ setError(conn);
+ return false;
+ }
+
+// int id=0;
+// QStringList parts_found;
+ for(cursor->moveFirst(); !cursor->eof(); cursor->moveNext())
+ {
+// id++;
+ Info *i = infoForMimeType(cursor->value(2).toCString());
+ if(!i)
+ {
+ Missing m;
+ m.name = cursor->value(1).toString();
+ m.mime = cursor->value(2).toCString();
+ m.url = cursor->value(3).toString();
+
+ m_missing.append(m);
+ }
+ else
+ {
+ i->setProjectPartID(cursor->value(0).toInt());
+ i->setIdStoredInPartDatabase(true);
+// parts_found+=cursor->value(2).toString();
+ }
+ }
+
+ conn->deleteCursor(cursor);
+
+#if 0 //js: moved to Connection::createDatabase()
+ //add missing default part entries
+ KexiDB::TableSchema *ts = conn->tableSchema("kexi__parts");
+ if (!ts)
+ return false;
+ KexiDB::FieldList *fl = ts->subList("p_id", "p_name", "p_mime", "p_url");
+ if (!fl)
+ return false;
+ if (!parts_found.contains("kexi/table")) {
+ if (!conn->insertRecord(*fl, QVariant(1), QVariant("Tables"), QVariant("kexi/table"), QVariant("http://")))
+ return false;
+ }
+ if (!parts_found.contains("kexi/query")) {
+ if (!conn->insertRecord(*fl, QVariant(2), QVariant("Queries"), QVariant("kexi/query"), QVariant("http://")))
+ return false;
+ }
+#endif
+ return true;
+}
+
+void Manager::insertStaticPart(StaticPart* part)
+{
+ if (!part)
+ return;
+ part->info()->setProjectPartID(m_nextTempProjectPartID--); // temp. part id are -1, -2, and so on,
+ m_partlist.append(part->info());
+ if (!part->info()->mimeType().isEmpty())
+ m_partsByMime.insert(part->info()->mimeType(), part->info());
+ m_parts.insert(part->info()->projectPartID(), part);
+}
+
+#include "kexipartmanager.moc"
diff --git a/kexi/core/kexipartmanager.h b/kexi/core/kexipartmanager.h
new file mode 100644
index 00000000..1756e965
--- /dev/null
+++ b/kexi/core/kexipartmanager.h
@@ -0,0 +1,141 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPARTMANAGER_H
+#define KEXIPARTMANAGER_H
+
+#include <qobject.h>
+#include <qdict.h>
+#include <qasciidict.h>
+#include <qintdict.h>
+#include <qvaluelist.h>
+#include <qptrlist.h>
+
+#include <kservice.h>
+
+#include <kexidb/object.h>
+
+//#include "kexipartdatasource.h"
+
+namespace KexiDB
+{
+ class Connection;
+}
+
+namespace KexiPart
+{
+ class Info;
+ class Part;
+ class StaticPart;
+
+ struct Missing
+ {
+ QString name;
+ QCString mime;
+ QString url;
+ };
+
+ typedef QAsciiDict<Info> PartInfoDict;
+ typedef QDictIterator<Info> PartInfoDictIterator;
+ typedef QValueList<Missing> MissingList;
+ typedef QPtrList<Info> PartInfoList;
+ typedef QPtrListIterator<Info> PartInfoListIterator;
+ typedef QIntDict<Part> PartDict;
+// typedef QPtrList<DataSource> DataSourceList;
+
+/**
+ * @short KexiPart's manager: looks up and instantiates them
+ *
+ * It dlopens them when needed, they aren't dlopened at startup is not necessary.
+ */
+class KEXICORE_EXPORT Manager : public QObject, public KexiDB::Object
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * creates an empty instance
+ */
+ Manager(QObject *parent = 0);
+ ~Manager();
+
+ /**
+ * queries ktrader and creates a list of available parts
+ */
+ void lookup();
+
+ /**
+ * \return a part object for specified mime type. Dlopens a part using KexiPart::Info
+ * if needed. Return 0 if loading failed.
+ */
+ Part *partForMimeType(const QString& mimeTypt);
+
+ /**
+ * \return a part object for specified info. Dlopens a part using KexiPart::Info
+ * if needed. Return 0 if loading failed.
+ */
+ Part *part(Info *);
+
+ /**
+ * \return the info for a corresponding internal mime
+ */
+ Info *infoForMimeType(const QString& mimeType);
+
+ /**
+ * checks project's kexi__part table
+ * and checks if all parts used in a project are available locally
+ *
+ * use @ref missingParts() to get a list of missing parts
+ */
+ bool checkProject(KexiDB::Connection *conn);
+
+ /**
+ * @returns parts metioned in the project meta tables but not available locally
+ */
+ MissingList missingParts() const { return m_missing; }
+
+
+ /**
+ * @returns a list of the available KexiParts in well-defined order
+ */
+ PartInfoList *partInfoList() { return &m_partlist; }
+
+ signals:
+ void partLoaded(KexiPart::Part*);
+
+ protected:
+ //! Used by StaticPart
+ void insertStaticPart(KexiPart::StaticPart* part);
+
+ private:
+ PartDict m_parts;
+ PartInfoList m_partlist;
+ PartInfoDict m_partsByMime;
+ MissingList m_missing;
+ int m_nextTempProjectPartID;
+ bool m_lookupDone : 1;
+
+ friend class StaticPart;
+};
+
+}
+
+#endif
+
diff --git a/kexi/core/kexiproject.cpp b/kexi/core/kexiproject.cpp
new file mode 100644
index 00000000..741fb67a
--- /dev/null
+++ b/kexi/core/kexiproject.cpp
@@ -0,0 +1,1023 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 <qfile.h>
+#include <qapplication.h>
+#include <qdom.h>
+
+#include <kmimetype.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kexiutils/identifier.h>
+
+#include <kexidb/connection.h>
+#include <kexidb/cursor.h>
+#include <kexidb/driver.h>
+#include <kexidb/drivermanager.h>
+#include <kexidb/utils.h>
+#include <kexidb/parser/parser.h>
+#include <kexidb/msghandler.h>
+#include <kexidb/dbproperties.h>
+#include <kexiutils/utils.h>
+
+#include "kexiproject.h"
+#include "kexipartmanager.h"
+#include "kexipartitem.h"
+#include "kexipartinfo.h"
+#include "kexipart.h"
+#include "kexidialogbase.h"
+#include "kexi.h"
+#include "keximainwindow.h"
+#include "kexiblobbuffer.h"
+#include "kexiguimsghandler.h"
+
+#include <assert.h>
+
+class KexiProject::Private
+{
+ public:
+ Private()
+ : data(0)
+ , itemDictsCache(199)
+ , unstoredItems(199)
+ , tempPartItemID_Counter(-1)
+ , sqlParser(0)
+ , versionMajor(0)
+ , versionMinor(0)
+ {
+ itemDictsCache.setAutoDelete(true);
+ unstoredItems.setAutoDelete(true);
+ }
+ ~Private() {
+ delete data;
+ data=0;
+ delete sqlParser;
+ }
+
+ QGuardedPtr<KexiDB::Connection> connection;
+ QGuardedPtr<KexiProjectData> data;
+
+ QString error_title;
+
+ //! a cache for item() method, indexed by project part's ids
+ QIntDict<KexiPart::ItemDict> itemDictsCache;
+
+ QPtrDict<KexiPart::Item> unstoredItems;
+ int tempPartItemID_Counter; //!< helper for getting unique
+ //!< temporary identifiers for unstored items
+ KexiDB::Parser* sqlParser;
+
+ int versionMajor;
+ int versionMinor;
+};
+
+//---------------------------
+
+/*
+ Helper for setting temporary error title.
+class KexiProject::ErrorTitle
+{
+ public:
+ ErrorTitle(KexiProject* p, const QString& msg = QString::null)
+ : prj(p)
+ , prev_err_title(p->m_error_title)
+ {
+ p->m_error_title = msg;
+ }
+ ~ErrorTitle()
+ {
+ prj->m_error_title = prev_err_title;
+ }
+ KexiProject* prj;
+ QString prev_err_title;
+};*/
+
+KexiProject::KexiProject(KexiProjectData *pdata, KexiDB::MessageHandler* handler)
+ : QObject(), Object(handler)
+ , d(new Private())
+{
+ d->data = pdata;
+//! @todo partmanager is outside project, so can be initialised just once:
+ Kexi::partManager().lookup();
+}
+
+KexiProject::KexiProject(KexiProjectData *pdata, KexiDB::MessageHandler* handler,
+ KexiDB::Connection* conn)
+ : QObject(), Object(handler)
+ , d(new Private())
+{
+ d->data = pdata;
+ if (d->data->connectionData() == d->connection->data())
+ d->connection = conn;
+ else
+ kdWarning() << "KexiProject::KexiProject(): passed connection's data ("
+ << conn->data()->serverInfoString() << ") is not compatible with project's conn. data ("
+ << d->data->connectionData()->serverInfoString() << ")" << endl;
+//! @todo partmanager is outside project, so can be initialised just once:
+ Kexi::partManager().lookup();
+}
+
+KexiProject::~KexiProject()
+{
+ closeConnection();
+ delete d;
+}
+
+KexiDB::Connection *KexiProject::dbConnection() const
+{
+ return d->connection;
+}
+
+KexiProjectData* KexiProject::data() const
+{
+ return d->data;
+}
+
+int KexiProject::versionMajor() const
+{
+ return d->versionMajor;
+}
+
+int KexiProject::versionMinor() const
+{
+ return d->versionMinor;
+}
+
+tristate
+KexiProject::open(bool &incompatibleWithKexi)
+{
+ return openInternal(&incompatibleWithKexi);
+}
+
+tristate
+KexiProject::open()
+{
+ return openInternal(0);
+}
+
+tristate
+KexiProject::openInternal(bool *incompatibleWithKexi)
+{
+ if (incompatibleWithKexi)
+ *incompatibleWithKexi = false;
+ kdDebug() << "KexiProject::open(): " << d->data->databaseName() <<" "<< d->data->connectionData()->driverName << endl;
+ KexiDB::MessageTitle et(this,
+ i18n("Could not open project \"%1\".").arg(d->data->databaseName()));
+
+ if (!createConnection()) {
+ kdDebug() << "KexiProject::open(): !createConnection()" << endl;
+ return false;
+ }
+ bool cancel = false;
+ KexiGUIMessageHandler msgHandler;
+ if (!d->connection->useDatabase(d->data->databaseName(), true, &cancel, &msgHandler))
+ {
+ if (cancel) {
+ return cancelled;
+ }
+ kdDebug() << "KexiProject::open(): !d->connection->useDatabase() "
+ << d->data->databaseName() <<" "<< d->data->connectionData()->driverName << endl;
+
+ if (d->connection->errorNum() == ERR_NO_DB_PROPERTY) {
+//<temp>
+//! @todo this is temporary workaround as we have no import driver for SQLite
+ if (/*supported?*/ !d->data->connectionData()->driverName.lower().startsWith("sqlite")) {
+//</temp>
+ if (incompatibleWithKexi)
+ *incompatibleWithKexi = true;
+ }
+ else
+ setError(d->connection);
+ closeConnection();
+ return false;
+ }
+
+ setError(d->connection);
+ closeConnection();
+ return false;
+ }
+
+ if (!initProject())
+ return false;
+
+ return createInternalStructures(/*insideTransaction*/true);
+}
+
+tristate
+KexiProject::create(bool forceOverwrite)
+{
+ KexiDB::MessageTitle et(this,
+ i18n("Could not create project \"%1\".").arg(d->data->databaseName()));
+
+ if (!createConnection())
+ return false;
+ if (!checkWritable())
+ return false;
+ if (d->connection->databaseExists( d->data->databaseName() )) {
+ if (!forceOverwrite)
+ return cancelled;
+ if (!d->connection->dropDatabase( d->data->databaseName() )) {
+ setError(d->connection);
+ closeConnection();
+ return false;
+ }
+ kdDebug() << "--- DB '" << d->data->databaseName() << "' dropped ---"<< endl;
+ }
+ if (!d->connection->createDatabase( d->data->databaseName() )) {
+ setError(d->connection);
+ closeConnection();
+ return false;
+ }
+ kdDebug() << "--- DB '" << d->data->databaseName() << "' created ---"<< endl;
+ // and now: open
+ if (!d->connection->useDatabase(d->data->databaseName()))
+ {
+ kdDebug() << "--- DB '" << d->data->databaseName() << "' USE ERROR ---"<< endl;
+ setError(d->connection);
+ closeConnection();
+ return false;
+ }
+ kdDebug() << "--- DB '" << d->data->databaseName() << "' used ---"<< endl;
+
+ //<add some data>
+ KexiDB::Transaction trans = d->connection->beginTransaction();
+ if (trans.isNull())
+ return false;
+
+ if (!createInternalStructures(/*!insideTransaction*/false))
+ return false;
+
+ //add some metadata
+//! @todo put more props. todo - creator, created date, etc. (also to KexiProjectData)
+ KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
+ if (!props.setValue("kexiproject_major_ver", d->versionMajor)
+ || !props.setCaption("kexiproject_major_ver", i18n("Project major version"))
+ || !props.setValue("kexiproject_minor_ver", d->versionMinor)
+ || !props.setCaption("kexiproject_minor_ver", i18n("Project minor version"))
+ || !props.setValue("project_caption", d->data->caption())
+ || !props.setCaption("project_caption", i18n("Project caption"))
+ || !props.setValue("project_desc", d->data->description())
+ || !props.setCaption("project_desc", i18n("Project description")) )
+ return false;
+
+/* KexiDB::TableSchema *t_db = d->connection->tableSchema("kexi__db");
+ //caption:
+ if (!t_db)
+ return false;
+
+ if (!KexiDB::replaceRow(*d->connection, t_db, "db_property", "project_caption",
+ "db_value", QVariant( d->data->caption() ), KexiDB::Field::Text)
+ || !KexiDB::replaceRow(*d->connection, t_db, "db_property", "project_desc",
+ "db_value", QVariant( d->data->description() ), KexiDB::Field::Text) )
+ return false;
+*/
+ if (trans.active() && !d->connection->commitTransaction(trans))
+ return false;
+ //</add some data>
+
+ return initProject();
+}
+
+bool KexiProject::createInternalStructures(bool insideTransaction)
+{
+ KexiDB::TransactionGuard tg;
+ if (insideTransaction) {
+ tg.setTransaction( d->connection->beginTransaction() );
+ if (tg.transaction().isNull())
+ return false;
+ }
+
+ //Get information about kexiproject version.
+ //kexiproject version is a version of data layer above kexidb layer.
+ KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
+ bool ok;
+ int storedMajorVersion = props.value("kexiproject_major_ver").toInt(&ok);
+ if (!ok)
+ storedMajorVersion = 0;
+ int storedMinorVersion = props.value("kexiproject_minor_ver").toInt(&ok);
+ if (!ok)
+ storedMinorVersion = 1;
+
+ bool containsKexi__blobsTable = d->connection->drv_containsTable("kexi__blobs");
+ int dummy;
+ bool contains_o_folder_id = containsKexi__blobsTable && true == d->connection->querySingleNumber(
+ "SELECT COUNT(o_folder_id) FROM kexi__blobs", dummy, 0, false/*addLimitTo1*/);
+ bool add_folder_id_column = false;
+
+//! @todo what about read-only db access?
+ if (storedMajorVersion<=0) {
+ d->versionMajor = KEXIPROJECT_VERSION_MAJOR;
+ d->versionMinor = KEXIPROJECT_VERSION_MINOR;
+ //For compatibility for projects created before Kexi 1.0 beta 1:
+ //1. no kexiproject_major_ver and kexiproject_minor_ver -> add them
+ if (!d->connection->isReadOnly()) {
+ if (!props.setValue("kexiproject_major_ver", d->versionMajor)
+ || !props.setCaption("kexiproject_major_ver", i18n("Project major version"))
+ || !props.setValue("kexiproject_minor_ver", d->versionMinor)
+ || !props.setCaption("kexiproject_minor_ver", i18n("Project minor version")) ) {
+ return false;
+ }
+ }
+
+ if (containsKexi__blobsTable) {
+//! @todo what to do for readonly connections? Should we alter kexi__blobs in memory?
+ if (!d->connection->isReadOnly()) {
+ if (!contains_o_folder_id) {
+ add_folder_id_column = true;
+ }
+ }
+ }
+ }
+ if (storedMajorVersion!=d->versionMajor || storedMajorVersion!=d->versionMinor) {
+ //! @todo version differs: should we change something?
+ d->versionMajor = storedMajorVersion;
+ d->versionMinor = storedMinorVersion;
+ }
+
+ KexiDB::InternalTableSchema *t_blobs = new KexiDB::InternalTableSchema("kexi__blobs");
+ t_blobs->addField( new KexiDB::Field("o_id", KexiDB::Field::Integer,
+ KexiDB::Field::PrimaryKey | KexiDB::Field::AutoInc, KexiDB::Field::Unsigned) )
+ .addField( new KexiDB::Field("o_data", KexiDB::Field::BLOB) )
+ .addField( new KexiDB::Field("o_name", KexiDB::Field::Text ) )
+ .addField( new KexiDB::Field("o_caption", KexiDB::Field::Text ) )
+ .addField( new KexiDB::Field("o_mime", KexiDB::Field::Text, KexiDB::Field::NotNull) )
+ .addField( new KexiDB::Field("o_folder_id",
+ KexiDB::Field::Integer, 0, KexiDB::Field::Unsigned) //references kexi__gallery_folders.f_id
+ //If null, the BLOB only points to virtual "All" folder
+ //WILL BE USED in Kexi >=2.0
+ );
+
+ //*** create global BLOB container, if not present
+ if (containsKexi__blobsTable) {
+ //! just insert this schema
+ d->connection->insertInternalTableSchema(t_blobs);
+ if (add_folder_id_column && !d->connection->isReadOnly()) {
+ // 2. "kexi__blobs" table contains no "o_folder_id" column -> add it
+ // (by copying table to avoid data loss)
+ KexiDB::TableSchema *kexi__blobsCopy = new KexiDB::TableSchema( *t_blobs );
+ kexi__blobsCopy->setName("kexi__blobs__copy");
+ if (!d->connection->drv_createTable( *kexi__blobsCopy )) {
+ delete kexi__blobsCopy;
+ delete t_blobs;
+ return false;
+ }
+ // 2.1 copy data (insert 0's into o_folder_id column)
+ if (!d->connection->executeSQL(
+ QString::fromLatin1("INSERT INTO kexi__blobs (o_data, o_name, o_caption, o_mime, o_folder_id) "
+ "SELECT o_data, o_name, o_caption, o_mime, 0 FROM kexi__blobs") )
+ // 2.2 remove the original kexi__blobs
+ || !d->connection->executeSQL(QString::fromLatin1("DROP TABLE kexi__blobs")) //lowlevel
+ // 2.3 rename the copy back into kexi__blobs
+ || !d->connection->drv_alterTableName(*kexi__blobsCopy, "kexi__blobs")
+ )
+ {
+ //(no need to drop the copy, ROLLBACK will drop it)
+ delete kexi__blobsCopy;
+ delete t_blobs;
+ return false;
+ }
+ delete kexi__blobsCopy; //not needed - physically renamed to kexi_blobs
+ }
+ }
+ else {
+// if (!d->connection->createTable( t_blobs, false/*!replaceExisting*/ )) {
+ if (!d->connection->isReadOnly()) {
+ if (!d->connection->createTable( t_blobs, true/*replaceExisting*/ )) {
+ delete t_blobs;
+ return false;
+ }
+ }
+ }
+
+ //Store default part infos.
+ //Infos for other parts (forms, reports...) are created on demand in KexiDialogBase::storeNewData()
+ KexiDB::InternalTableSchema *t_parts = new KexiDB::InternalTableSchema("kexi__parts"); //newKexiDBSystemTableSchema("kexi__parts");
+ t_parts->addField(
+ new KexiDB::Field("p_id", KexiDB::Field::Integer, KexiDB::Field::PrimaryKey | KexiDB::Field::AutoInc, KexiDB::Field::Unsigned)
+ )
+ .addField( new KexiDB::Field("p_name", KexiDB::Field::Text) )
+ .addField( new KexiDB::Field("p_mime", KexiDB::Field::Text ) )
+ .addField( new KexiDB::Field("p_url", KexiDB::Field::Text ) );
+
+ bool containsKexi__partsTable = d->connection->drv_containsTable("kexi__parts");
+ bool partsTableOk = true;
+ if (containsKexi__partsTable) {
+ //! just insert this schema
+ d->connection->insertInternalTableSchema(t_parts);
+ }
+ else {
+ if (!d->connection->isReadOnly()) {
+ partsTableOk = d->connection->createTable( t_parts, true/*replaceExisting*/ );
+
+ KexiDB::FieldList *fl = t_parts->subList("p_id", "p_name", "p_mime", "p_url");
+ if (partsTableOk)
+ partsTableOk = d->connection->insertRecord(*fl, QVariant(1), QVariant("Tables"),
+ QVariant("kexi/table"), QVariant("http://koffice.org/kexi/"));
+
+ if (partsTableOk)
+ partsTableOk = d->connection->insertRecord(*fl, QVariant(2), QVariant("Queries"),
+ QVariant("kexi/query"), QVariant("http://koffice.org/kexi/"));
+ }
+ }
+
+ if (!partsTableOk) {
+ delete t_parts;
+ return false;
+ }
+
+ if (insideTransaction) {
+ if (tg.transaction().active() && !tg.commit())
+ return false;
+ }
+ return true;
+}
+
+bool
+KexiProject::createConnection()
+{
+ if (d->connection)
+ return true;
+
+ clearError();
+// closeConnection();//for sanity
+ KexiDB::MessageTitle et(this);
+
+ KexiDB::Driver *driver = Kexi::driverManager().driver(d->data->connectionData()->driverName);
+ if(!driver) {
+ setError(&Kexi::driverManager());
+ return false;
+ }
+
+ int connectionOptions = 0;
+ if (d->data->isReadOnly())
+ connectionOptions |= KexiDB::Driver::ReadOnlyConnection;
+ d->connection = driver->createConnection(*d->data->connectionData(), connectionOptions);
+ if (!d->connection)
+ {
+ kdDebug() << "KexiProject::open(): uuups failed " << driver->errorMsg() << endl;
+ setError(driver);
+ return false;
+ }
+
+ if (!d->connection->connect())
+ {
+ setError(d->connection);
+ kdDebug() << "KexiProject::createConnection(): error connecting: " << (d->connection ? d->connection->errorMsg() : QString::null) << endl;
+ closeConnection();
+ return false;
+ }
+
+ //re-init BLOB buffer
+//! @todo won't work for subsequent connection
+ KexiBLOBBuffer::setConnection(d->connection);
+ return true;
+}
+
+
+bool
+KexiProject::closeConnection()
+{
+ if (!d->connection)
+ return true;
+
+ if (!d->connection->disconnect()) {
+ setError(d->connection);
+ return false;
+ }
+
+ delete d->connection; //this will also clear connection for BLOB buffer
+ d->connection = 0;
+ return true;
+}
+
+bool
+KexiProject::initProject()
+{
+// emit dbAvailable();
+ kdDebug() << "KexiProject::open(): checking project parts..." << endl;
+
+ if (!Kexi::partManager().checkProject(d->connection)) {
+ setError(Kexi::partManager().error() ? (KexiDB::Object*)&Kexi::partManager() : (KexiDB::Connection*)d->connection);
+ return false;
+ }
+
+// !@todo put more props. todo - creator, created date, etc. (also to KexiProjectData)
+ KexiDB::DatabaseProperties &props = d->connection->databaseProperties();
+ QString str( props.value("project_caption").toString() );
+ if (!str.isEmpty())
+ d->data->setCaption( str );
+ str = props.value("project_desc").toString();
+ if (!str.isEmpty())
+ d->data->setDescription( str );
+/* KexiDB::RowData data;
+ QString sql = "select db_value from kexi__db where db_property='%1'";
+ if (d->connection->querySingleRecord( sql.arg("project_caption"), data ) && !data[0].toString().isEmpty())
+ d->data->setCaption(data[0].toString());
+ if (d->connection->querySingleRecord( sql.arg("project_desc"), data) && !data[0].toString().isEmpty())
+ d->data->setDescription(data[0].toString());*/
+
+ return true;
+}
+
+bool
+KexiProject::isConnected()
+{
+ if(d->connection && d->connection->isDatabaseUsed())
+ return true;
+
+ return false;
+}
+
+KexiPart::ItemDict*
+KexiProject::items(KexiPart::Info *i)
+{
+ kdDebug() << "KexiProject::items()" << endl;
+ if(!i || !isConnected())
+ return 0;
+
+ //trying in cache...
+ KexiPart::ItemDict *dict = d->itemDictsCache[ i->projectPartID() ];
+ if (dict)
+ return dict;
+ //retrieve:
+ KexiDB::Cursor *cursor = d->connection->executeQuery(
+ "SELECT o_id, o_name, o_caption FROM kexi__objects WHERE o_type = "
+ + QString::number(i->projectPartID()));//, KexiDB::Cursor::Buffered);
+// kdDebug() << "KexiProject::items(): cursor handle is:" << cursor << endl;
+ if(!cursor)
+ return 0;
+
+ dict = new KexiPart::ItemDict(1009);
+ dict->setAutoDelete(true);
+
+ for(cursor->moveFirst(); !cursor->eof(); cursor->moveNext())
+ {
+ KexiPart::Item *it = new KexiPart::Item();
+ bool ok;
+ int ident = cursor->value(0).toInt(&ok);
+ QString objName( cursor->value(1).toString() );
+
+ if ( ok && (ident>0) && !d->connection->isInternalTableSchema(objName)
+ && KexiUtils::isIdentifier(objName) )
+ {
+ it->setIdentifier(ident);
+ it->setMimeType(i->mimeType()); //js: may be not null???
+ it->setName(objName);
+ it->setCaption(cursor->value(2).toString());
+ }
+ dict->insert(it->identifier(), it);
+// kdDebug() << "KexiProject::items(): ITEM ADDED == "<<objName <<" id="<<ident<<endl;
+ }
+
+ d->connection->deleteCursor(cursor);
+// kdDebug() << "KexiProject::items(): end with count " << dict->count() << endl;
+ d->itemDictsCache.insert( i->projectPartID(), dict );
+ return dict;
+}
+
+KexiPart::ItemDict*
+KexiProject::itemsForMimeType(const QCString &mimeType)
+{
+ KexiPart::Info *info = Kexi::partManager().infoForMimeType(mimeType);
+ return items(info);
+}
+
+void
+KexiProject::getSortedItems(KexiPart::ItemList& list, KexiPart::Info *i)
+{
+ list.clear();
+ KexiPart::ItemDict* dict = items(i);
+ if (!dict)
+ return;
+ for (KexiPart::ItemDictIterator it(*dict); it.current(); ++it)
+ list.append(it.current());
+}
+
+void
+KexiProject::getSortedItemsForMimeType(KexiPart::ItemList& list, const QCString &mimeType)
+{
+ KexiPart::Info *info = Kexi::partManager().infoForMimeType(mimeType);
+ getSortedItems(list, info);
+}
+
+void
+KexiProject::addStoredItem(KexiPart::Info *info, KexiPart::Item *item)
+{
+ if (!info || !item)
+ return;
+ KexiPart::ItemDict *dict = items(info);
+ item->setNeverSaved( false );
+ d->unstoredItems.take(item); //no longer unstored
+ dict->insert( item->identifier(), item );
+ //let's update e.g. navigator
+ emit newItemStored(*item);
+}
+
+KexiPart::Item*
+KexiProject::itemForMimeType(const QCString &mimeType, const QString &name)
+{
+ KexiPart::ItemDict *dict = itemsForMimeType(mimeType);
+ if (!dict)
+ return 0;
+ const QString l_name = name.lower();
+ for (KexiPart::ItemDictIterator it( *dict ); it.current(); ++it) {
+ if (it.current()->name().lower()==l_name)
+ return it.current();
+ }
+ return 0;
+}
+
+KexiPart::Item*
+KexiProject::item(KexiPart::Info *i, const QString &name)
+{
+ KexiPart::ItemDict *dict = items(i);
+ if (!dict)
+ return 0;
+ const QString l_name = name.lower();
+ for (KexiPart::ItemDictIterator it( *dict ); it.current(); ++it) {
+ if (it.current()->name().lower()==l_name)
+ return it.current();
+ }
+ return 0;
+}
+
+KexiPart::Item*
+KexiProject::item(int identifier)
+{
+ KexiPart::ItemDict *dict;
+ for (QIntDictIterator<KexiPart::ItemDict> it(d->itemDictsCache); (dict = it.current()); ++it) {
+ KexiPart::Item *item = dict->find(identifier);
+ if (item)
+ return item;
+ }
+ return 0;
+}
+
+/*void KexiProject::clearMsg()
+{
+ clearError();
+// d->error_title=QString::null;
+}
+
+void KexiProject::setError(int code, const QString &msg )
+{
+ Object::setError(code, msg);
+ if (Object::error())
+ ERRMSG(d->error_title, this);
+// emit error(d->error_title, this);
+}
+
+
+void KexiProject::setError( const QString &msg )
+{
+ Object::setError(msg);
+ if (Object::error())
+ ERRMSG(d->error_title, this);
+// emit error(d->error_title, this);
+}
+
+void KexiProject::setError( KexiDB::Object *obj )
+{
+ if (!obj)
+ return;
+ Object::setError(obj);
+ if (Object::error())
+ ERRMSG(d->error_title, obj);
+// emit error(d->error_title, obj);
+}
+
+void KexiProject::setError(const QString &msg, const QString &desc)
+{
+ Object::setError(msg); //ok?
+ ERRMSG(msg, desc); //not KexiDB-related
+// emit error(msg, desc); //not KexiDB-related
+}
+*/
+
+KexiPart::Part *KexiProject::findPartFor(KexiPart::Item& item)
+{
+ clearError();
+ KexiDB::MessageTitle et(this);
+ KexiPart::Part *part = Kexi::partManager().partForMimeType(item.mimeType());
+ if (!part)
+ setError(&Kexi::partManager());
+ return part;
+}
+
+KexiDialogBase* KexiProject::openObject(KexiMainWindow *wnd, KexiPart::Item& item,
+ int viewMode, QMap<QString,QString>* staticObjectArgs)
+{
+ clearError();
+ if (viewMode!=Kexi::DataViewMode && data()->userMode())
+ return 0;
+
+ KexiDB::MessageTitle et(this);
+ KexiPart::Part *part = findPartFor(item);
+ if (!part)
+ return 0;
+ KexiDialogBase *dlg = part->openInstance(wnd, item, viewMode, staticObjectArgs);
+ if (!dlg) {
+ if (part->lastOperationStatus().error())
+ setError(i18n("Opening object \"%1\" failed.").arg(item.name())+"<br>"
+ +part->lastOperationStatus().message,
+ part->lastOperationStatus().description);
+ return 0;
+ }
+ return dlg;
+}
+
+KexiDialogBase* KexiProject::openObject(KexiMainWindow *wnd, const QCString &mimeType,
+ const QString& name, int viewMode)
+{
+ KexiPart::Item *it = itemForMimeType(mimeType, name);
+ return it ? openObject(wnd, *it, viewMode) : 0;
+}
+
+bool KexiProject::checkWritable()
+{
+ if (!d->connection->isReadOnly())
+ return true;
+ setError(i18n("This project is opened as read only."));
+ return false;
+}
+
+bool KexiProject::removeObject(KexiMainWindow *wnd, KexiPart::Item& item)
+{
+ clearError();
+ if (data()->userMode())
+ return false;
+
+ KexiDB::MessageTitle et(this);
+ if (!checkWritable())
+ return false;
+ KexiPart::Part *part = findPartFor(item);
+ if (!part)
+ return false;
+ if (!item.neverSaved() && !part->remove(wnd, item)) {
+ //js TODO check for errors
+ return false;
+ }
+ if (!item.neverSaved()) {
+ KexiDB::TransactionGuard tg( *d->connection );
+ if (!tg.transaction().active()) {
+ setError(d->connection);
+ return false;
+ }
+ if (!d->connection->removeObject( item.identifier() )) {
+ setError(d->connection);
+ return false;
+ }
+ if (!tg.commit()) {
+ setError(d->connection);
+ return false;
+ }
+ }
+ emit itemRemoved(item);
+
+ //now: remove this item from cache
+ if (part->info()) {
+ KexiPart::ItemDict *dict = d->itemDictsCache[ part->info()->projectPartID() ];
+ if (!(dict && dict->remove( item.identifier() )))
+ d->unstoredItems.remove(&item);//remove temp.
+ }
+ return true;
+}
+
+bool KexiProject::renameObject( KexiMainWindow *wnd, KexiPart::Item& item, const QString& _newName )
+{
+ clearError();
+ if (data()->userMode())
+ return 0;
+
+ KexiUtils::WaitCursor wait;
+ QString newName = _newName.stripWhiteSpace();
+ {
+ KexiDB::MessageTitle et(this);
+ if (newName.isEmpty()) {
+ setError( i18n("Could not set empty name for this object.") );
+ return false;
+ }
+ if (this->itemForMimeType(item.mimeType(), newName)!=0) {
+ setError( i18n("Could not use this name. Object with name \"%1\" already exists.")
+ .arg(newName) );
+ return false;
+ }
+ }
+
+ KexiDB::MessageTitle et(this,
+ i18n("Could not rename object \"%1\".").arg(item.name()) );
+ if (!checkWritable())
+ return false;
+ KexiPart::Part *part = findPartFor(item);
+ if (!part)
+ return false;
+ KexiDB::TransactionGuard tg( *d->connection );
+ if (!tg.transaction().active()) {
+ setError(d->connection);
+ return false;
+ }
+ if (!part->rename(wnd, item, newName)) {
+ setError(part->lastOperationStatus().message, part->lastOperationStatus().description);
+ return false;
+ }
+ if (!d->connection->executeSQL( "update kexi__objects set o_name="
+ + d->connection->driver()->valueToSQL( KexiDB::Field::Text, newName )
+ + " where o_id=" + QString::number(item.identifier()) )) {
+ setError(d->connection);
+ return false;
+ }
+ if (!tg.commit()) {
+ setError(d->connection);
+ return false;
+ }
+ QCString oldName( item.name().latin1() );
+ item.setName( newName );
+ emit itemRenamed(item, oldName);
+ return true;
+}
+
+KexiPart::Item* KexiProject::createPartItem(KexiPart::Info *info, const QString& suggestedCaption)
+{
+ clearError();
+ if (data()->userMode())
+ return 0;
+
+ KexiDB::MessageTitle et(this);
+ KexiPart::Part *part = Kexi::partManager().part(info);
+ if (!part) {
+ setError(&Kexi::partManager());
+ return 0;
+ }
+
+ KexiPart::ItemDict *dict = items(info);
+
+ //find new, unique default name for this item
+ int n;
+ QString new_name;
+ QString base_name;
+ if (suggestedCaption.isEmpty()) {
+ n = 1;
+ base_name = part->instanceName();
+ }
+ else {
+ n = 0; //means: try not to add 'n'
+ base_name = KexiUtils::string2Identifier(suggestedCaption).lower();
+ }
+ base_name = KexiUtils::string2Identifier(base_name).lower();
+ KexiPart::ItemDictIterator it(*dict);
+ QPtrDictIterator<KexiPart::Item> itUnstored(d->unstoredItems);
+ do {
+ new_name = base_name;
+ if (n>=1)
+ new_name += QString::number(n);
+ for (it.toFirst(); it.current(); ++it) {
+ if (it.current()->name().lower()==new_name)
+ break;
+ }
+ if ( it.current() ) {
+ n++;
+ continue; //stored exists!
+ }
+ for (itUnstored.toFirst(); itUnstored.current(); ++itUnstored) {
+ if (itUnstored.current()->name().lower()==new_name)
+ break;
+ }
+ if ( !itUnstored.current() )
+ break; //unstored doesn't exist
+ n++;
+ } while (n<1000/*sanity*/);
+
+ if (n>=1000)
+ return 0;
+
+ QString new_caption( suggestedCaption.isEmpty() ? part->instanceCaption() : suggestedCaption);
+ if (n>=1)
+ new_caption += QString::number(n);
+
+ KexiPart::Item *item = new KexiPart::Item();
+ item->setIdentifier( --d->tempPartItemID_Counter );//temporary
+ item->setMimeType(info->mimeType());
+ item->setName(new_name);
+ item->setCaption(new_caption);
+ item->setNeverSaved(true);
+ d->unstoredItems.insert(item, item);
+ return item;
+}
+
+KexiPart::Item* KexiProject::createPartItem(KexiPart::Part *part, const QString& suggestedCaption)
+{
+ return createPartItem(part->info(), suggestedCaption);
+}
+
+void KexiProject::deleteUnstoredItem(KexiPart::Item *item)
+{
+ if (!item)
+ return;
+ d->unstoredItems.remove(item);
+}
+
+KexiDB::Parser* KexiProject::sqlParser()
+{
+ if (!d->sqlParser) {
+ if (!d->connection)
+ return 0;
+ d->sqlParser = new KexiDB::Parser(d->connection);
+ }
+ return d->sqlParser;
+}
+
+static const QString warningNoUndo = i18n("Warning: entire project's data will be removed.");
+
+/*static*/
+KexiProject*
+KexiProject::createBlankProject(bool &cancelled, KexiProjectData* data,
+ KexiDB::MessageHandler* handler)
+{
+ cancelled = false;
+ KexiProject *prj = new KexiProject( new KexiProjectData(*data), handler );
+
+ tristate res = prj->create(false);
+ if (~res) {
+//! @todo move to KexiMessageHandler
+ if (KMessageBox::Yes != KMessageBox::warningYesNo(0, "<qt>"+i18n(
+ "The project %1 already exists.\n"
+ "Do you want to replace it with a new, blank one?")
+ .arg(prj->data()->infoString())+"\n"+warningNoUndo+"</qt>",
+ QString::null, KGuiItem(i18n("Replace")), KStdGuiItem::cancel() ))
+//todo add serverInfoString() for server-based prj
+ {
+ delete prj;
+ cancelled = true;
+ return 0;
+ }
+ res = prj->create(true/*overwrite*/);
+ }
+ if (res != true) {
+ delete prj;
+ return 0;
+ }
+ kdDebug() << "KexiProject::createBlankProject(): new project created --- " << endl;
+//todo? Kexi::recentProjects().addProjectData( data );
+
+ return prj;
+}
+
+/*static*/
+tristate KexiProject::dropProject(KexiProjectData* data,
+ KexiDB::MessageHandler* handler, bool dontAsk)
+{
+ if (!dontAsk && KMessageBox::Yes != KMessageBox::warningYesNo(0,
+ i18n("Do you want to drop the project \"%1\"?").arg(data->objectName())+"\n"+warningNoUndo ))
+ return cancelled;
+
+ KexiProject prj( new KexiProjectData(*data), handler );
+ if (!prj.open())
+ return false;
+
+ if (prj.dbConnection()->isReadOnly()) {
+ handler->showErrorMessage(
+ i18n("Could not drop this project. Database connection for this project has been opened as read only."));
+ return false;
+ }
+
+ return prj.dbConnection()->dropDatabase();
+}
+
+/*void KexiProject::reloadPartItem( KexiDialogBase* dialog )
+{
+ if (!dialog)
+ return;
+
+ KexiPart::Item* item = dialog->partItem();
+
+ if (dialog || !d->connection->setQuerySchemaObsolete( queryName ))
+ return;
+ KexiPart::Info *partInfo = Kexi::partManager().infoForMimeType("kexi/query");
+ if (!partInfo)
+ return; //err?
+ item(partInfo, queryName);
+ if (!item)
+ return; //err?
+ emit itemSetO
+
+}*/
+
+#include "kexiproject.moc"
diff --git a/kexi/core/kexiproject.h b/kexi/core/kexiproject.h
new file mode 100644
index 00000000..1128ffe4
--- /dev/null
+++ b/kexi/core/kexiproject.h
@@ -0,0 +1,334 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPROJECT_H
+#define KEXIPROJECT_H
+
+#include <qobject.h>
+#include <qintdict.h>
+#include <qptrdict.h>
+#include <qguardedptr.h>
+
+#include <kexiutils/tristate.h>
+#include <kexidb/object.h>
+#include "kexiprojectdata.h"
+#include "kexipartitem.h"
+#include "kexi.h"
+
+/*! KexiProject implementation version.
+ It is altered after every change:
+ - major number is increased after KexiProject storage format change,
+ - minor is increased after adding binary-incompatible change.
+ Use KexiProject::versionMajor() and KexiProject::versionMinor() to get real project's version.
+*/
+
+#define KEXIPROJECT_VERSION_MAJOR 1
+#define KEXIPROJECT_VERSION_MINOR 0
+
+namespace KexiDB
+{
+ class DriverManager;
+ class Driver;
+ class Connection;
+ class Parser;
+}
+
+namespace KexiPart
+{
+ class Part;
+ class Info;
+}
+
+class KexiMainWindow;
+class KexiDialogBase;
+
+/**
+ * @short A project's main controller.
+ * It also contains connection data,
+ * current file state, etc.
+ */
+class KEXICORE_EXPORT KexiProject : public QObject, public KexiDB::Object
+{
+ Q_OBJECT
+
+ public:
+ /*! Constructor 1. Creates a new object using \a pdata.
+ \a pdata which will be then owned by KexiProject object.
+ \a handler can be provided to receive error messages during
+ entire KexiProject object's lifetime. */
+ KexiProject(KexiProjectData* pdata, KexiDB::MessageHandler* handler = 0);
+
+ /*! Constructor 2. Like above but sets predefined connections \a conn.
+ The connection should be created using the same connection data
+ as pdata->connectionData(). The connection will become owned by created KexiProject
+ object, so do not destroy it. */
+ KexiProject(KexiProjectData *pdata, KexiDB::MessageHandler* handler,
+ KexiDB::Connection* conn);
+
+// KexiProject(KexiDB::ConnectionData *cdata);
+
+ ~KexiProject();
+
+ /*! \return major version of KexiProject object.
+ This information is retrieved from database when existing project is opened. */
+ int versionMajor() const;
+
+ /*! \return minor version of KexiProject object.
+ @see versionMajor() */
+ int versionMinor() const;
+
+ /*! Opens existing project using project data.
+ \return true on success */
+ tristate open();
+
+ /*! Like open().
+ \return true on success.
+ Additional \a incompatibleWithKexi, is set to false on failure when
+ connection for the project was successfully started bu the project
+ is probably not compatible with Kexi - no valid "kexidb_major_ver"
+ value in "kexi__db" table.
+ This is often the case for native server-based databases.
+ If so, Kexi application can propose importing the database
+ or linking it to parent project (the latter isn't yet implemented).
+ For other types of errors the variable is set to true. */
+ tristate open(bool &incompatibleWithKexi);
+
+ /*! Creates new, empty project using project data.
+ If \a forceOverwrite is true, existing database project is silently overwritten.
+ Connection is created (accessible then with KexiProject::dbConnection()).
+
+ Since KexiProject inherits KexiDB::Object, it is possible to get error message
+ and other information on error.
+
+ \return true on success, false on failure, and cancelled when database exists
+ but \a forceOverwrite is false. */
+ tristate create(bool forceOverwrite = false);
+
+ /*! \return true if there was error during last operation on the object. */
+ bool error() const { return KexiDB::Object::error(); }
+
+ /**
+ * @return true if a we are connected to a database
+ */
+ bool isConnected();
+
+ /**
+ * @return all items of a type \a i in this project
+ */
+ KexiPart::ItemDict* items(KexiPart::Info *i);
+
+ /**
+ * @return all items of a type \a mime in this project
+ * It is a convenience function.
+ */
+ KexiPart::ItemDict* itemsForMimeType(const QCString &mimeType);
+
+ /**
+ * Puts a list of items of a type \a i in this project into \a list.
+ * You can then sort this list using ItemList::sort().
+ */
+ void getSortedItems(KexiPart::ItemList& list, KexiPart::Info *i);
+
+ /**
+ * Puts a sorted list of items of a type \a mimeType in this project into \a list.
+ * You can then sort this list using ItemList::sort().
+ */
+ void getSortedItemsForMimeType(KexiPart::ItemList& list, const QCString &mimeType);
+
+ /**
+ * @return item of type \a mime and name \a name
+ */
+ KexiPart::Item* itemForMimeType(const QCString &mimeType, const QString &name);
+
+ /**
+ * @return item of type \a i and name \a name
+ */
+ KexiPart::Item* item(KexiPart::Info *i, const QString &name);
+
+ /**
+ * @return item for \a identifier
+ */
+ KexiPart::Item* item(int identifier);
+
+ /**
+ * @return the database connection associated with this project
+ */
+ KexiDB::Connection *dbConnection() const;
+
+ /**
+ * @return the project's data
+ */
+ KexiProjectData *data() const;
+
+ /*! Opens object pointed by \a item in a view \a viewMode.
+ \a staticObjectArgs can be passed for static object
+ (only works when part for this item is of type KexiPart::StaticPart) */
+ KexiDialogBase* openObject(KexiMainWindow *wnd, KexiPart::Item& item,
+ int viewMode = Kexi::DataViewMode, QMap<QString,QString>* staticObjectArgs = 0);
+
+ //! For convenience
+ KexiDialogBase* openObject(KexiMainWindow *wnd, const QCString &mimeType,
+ const QString& name, int viewMode = Kexi::DataViewMode);
+
+ /*! Remove a part instance pointed by \a item.
+ \return true on success. */
+ bool removeObject(KexiMainWindow *wnd, KexiPart::Item& item);
+
+ /*! Renames a part instance pointed by \a item to a new name \a newName.
+ \return true on success. */
+ bool renameObject(KexiMainWindow *wnd, KexiPart::Item& item, const QString& newName);
+
+ /*! Creates part item for given part \a info.
+ Newly item will not be saved to the backend but stored in memory only
+ (owned by project), and marked as "neverSaved" (see KexiPart::Item::neverSaved()).
+ The item will have assigned a new unique caption like e.g. "Table15",
+ and unique name like "table15", but no specific identifier
+ (because id will be assigned on creation at the backend side).
+
+ If \a suggestedCaption is not empty, it will be set as a caption
+ (with number suffix, to avoid duplicated, e.g. "employees7"
+ for "employees" sugested name). Name will be then built based
+ on this caption using KexiUtils::string2Identifier().
+
+ This method is used before creating new object.
+ \return newly created part item or NULL on any error. */
+ KexiPart::Item* createPartItem(KexiPart::Info *info,
+ const QString& suggestedCaption = QString::null );
+
+ //! Added for convenience.
+ KexiPart::Item* createPartItem(KexiPart::Part *part,
+ const QString& suggestedCaption = QString::null);
+
+ /*! Adds item \a item after it is succesfully stored as an instance of part
+ pointed by \a info. Also clears 'neverSaved' flag if \a item.
+ Used by KexiDialogBase::storeNewData().
+ @internal */
+ void addStoredItem(KexiPart::Info *info, KexiPart::Item *item);
+
+ /*! removes \a item from internal dictionaries. The item is destroyed
+ after successful removal.
+ Used to delete an unstored part item previusly created with createPartItem(). */
+ void deleteUnstoredItem(KexiPart::Item *item);
+
+#if 0 //remove?
+ /*! Creates object using data provided by \a dlg dialog.
+ Dialog's \a item (KexiDialog::partItem()) must not be stored
+ (KexiPart::Item::neverStored()==false) and created
+ by KexiProject::createPartItem().
+ Identifier of the item will be updated to a final value
+ (stored in the backend), because previously there was temporary one set.
+ \return true for successfully created object or false on any error. */
+ bool createObject(KexiDialogBase *dlg);
+#endif
+
+ KexiDB::Parser* sqlParser();
+
+ /*! Shows dialog for creating new blank project,
+ ans creates one. Dialog is not shown if option for automatic creation
+ is checked or Kexi::startupHandler().projectData() was provided from command line.
+ \a cancelled is set to true if creation has been cancelled (e.g. user answered
+ no when asked for database overwriting, etc.
+ \return true if database was created, false on error or when cancel was pressed */
+ static KexiProject* createBlankProject(bool &cancelled, KexiProjectData* data,
+ KexiDB::MessageHandler* handler = 0);
+
+ /*! Drops project described by \a data. \return true on success.
+ Use with care: Any KexiProject objects allocated for this project will become invalid! */
+ static tristate dropProject(KexiProjectData* data,
+ KexiDB::MessageHandler* handler, bool dontAsk = false);
+
+ /*! @see KexiDB::Connection::setQuerySchemaObsolete( const QString& queryName ) */
+// void setQuerySchemaObsolete( const QString& queryName );
+
+// /** used to emit objectCreated() signal */
+// void emitObjectCreated(const QCString &mime, const QCString& name) { emit objectCreated(mime, name); }
+// void emitTableCreated(KexiDB::TableSchema& schema) { emit tableCreated(schema); }
+
+ protected:
+ /*! Creates connection using project data.
+ The connection will be readonly if data()->isReadOnly().
+ \return true on success, otherwise false and appropriate error is set. */
+ bool createConnection();
+
+ bool closeConnection();
+
+ bool initProject();
+
+ //! Used in open() and open(bool&).
+ tristate openInternal(bool *incompatibleWithKexi);
+
+ /*! Kexi itself can define a number of internal database objects (mostly data structures),
+ usually tables for it's own purposes.
+ Even while at KexiDB library level, such "system" tables, like "kexi__objects", "kexi__objectdata"
+ are created automatically on database project creation, this is not enough: there are objects
+ needed specifically for Kexi but not for other applications utilizing KexiDB library.
+ Example table created here for now is "kexi__blobs".
+
+ This method is called on create() and open(): creates necessary objects
+ if they are not yet existing. This especially allows to create to create these objects
+ (on open) within a project made with previous Kexi version not supporting
+ all currently defined structurtes. We're trying to be here as much backward compatible as possible.
+ For this purpose, here's the complete list of currently created objects:
+ - "kexi__blobs" - a table containing BLOBs data that can be accessed globally at Kexi projects
+ from within any database-aware view (table views, forms, reports, etc.)
+
+ @param insideTransaction Embed entire creation process inside a transaction
+
+ \return true on successful object's creation. Objects are created only once, they are not overwritten.
+ */
+ bool createInternalStructures(bool insideTransaction);
+
+ /*! \return Kexi part for \a item. */
+ KexiPart::Part *findPartFor(KexiPart::Item& item);
+
+ signals:
+ /** signal emitted on error */
+ void error(const QString &title, KexiDB::Object *obj);
+
+ /** signal emitted on error (not KexiDB-related) */
+ void error(const QString &msg, const QString &desc);
+
+ /** New \a item has been stored. */
+ void newItemStored(KexiPart::Item& item);
+
+ /** instance pointed by \a item is removed */
+ void itemRemoved(const KexiPart::Item &item);
+
+ /** instance pointed by \a item is renamed */
+ void itemRenamed(const KexiPart::Item &item, const QCString& oldName);
+
+// /** new table \a schema created */
+// void tableCreated(KexiDB::TableSchema& schema);
+// /** New object of mimetype \a mime and \a name has been created. */
+// void objectCreated(const QCString &mime, const QCString& name);
+
+ protected:
+ /*! Checks whether the project's connection is read-only.
+ If so, error message is set and false is returned. */
+ bool checkWritable();
+
+ class Private;
+ Private *d;
+
+ friend class KexiMainWindowImpl;
+};
+
+
+#endif
diff --git a/kexi/core/kexiprojectconnectiondata.cpp b/kexi/core/kexiprojectconnectiondata.cpp
new file mode 100644
index 00000000..6a73342f
--- /dev/null
+++ b/kexi/core/kexiprojectconnectiondata.cpp
@@ -0,0 +1,152 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.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 <sys/types.h>
+#include <unistd.h>
+
+#include <qdom.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kio/netaccess.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <kexidb/connectiondata.h>
+#include <kexidb/drivermanager.h>
+#include "kexiprojectconnectiondata.h"
+
+KexiProjectConnectionData::KexiProjectConnectionData(): KexiDB::ConnectionData()
+{
+}
+
+KexiProjectConnectionData::KexiProjectConnectionData(const QString& driverName, const QString& databaseName, const QString &host,
+ unsigned short int rport, const QString& user, const QString &pass, const QString& file):KexiDB::ConnectionData()
+{
+ m_driverName=driverName;
+ m_databaseName=databaseName;
+ hostName=host;
+ port=rport;
+ userName=user;
+ password=pass;
+ setFileName(file);
+}
+
+KexiProjectConnectionData::KexiProjectConnectionData(const QString &driverName, const QString &fileName)
+ : KexiDB::ConnectionData()
+{
+ m_driverName=driverName;
+ setFileName(fileName);
+}
+
+const QString &
+KexiProjectConnectionData::generateTmpName()
+{
+ return QString::null;
+}
+
+KexiProjectConnectionData*
+KexiProjectConnectionData::loadInfo(QDomElement &rootElement)
+{
+ QDomElement engineElement = rootElement.namedItem("engine").toElement();
+ QDomElement hostElement = rootElement.namedItem("host").toElement();
+ QDomElement portElement = rootElement.namedItem("port").toElement();
+ QDomElement nameElement = rootElement.namedItem("name").toElement();
+ QDomElement userElement = rootElement.namedItem("user").toElement();
+ QDomElement passElement = rootElement.namedItem("password").toElement();
+ QDomElement persElement = rootElement.namedItem("persistant").toElement();
+ QDomElement encodingElement = rootElement.namedItem("encoding").toElement();
+
+ KexiProjectConnectionData *tmp=new KexiProjectConnectionData(
+ engineElement.text(), nameElement.text(),hostElement.text(),portElement.text().toInt(),
+ userElement.text(),passElement.text(),"");
+
+ return tmp;
+}
+
+void KexiProjectConnectionData::setDriverName(const QString &driverName) {
+ m_driverName=driverName;
+}
+
+void KexiProjectConnectionData::setDatabaseName(const QString &databaseName) {
+ m_databaseName=databaseName;
+}
+
+QString KexiProjectConnectionData::driverName() const {
+ return m_driverName;
+}
+
+QString KexiProjectConnectionData::databaseName() const {
+ return m_databaseName;
+}
+
+
+void
+KexiProjectConnectionData::writeInfo(QDomDocument &domDoc)
+{
+ QDomElement connectionElement = domDoc.createElement("KexiDBConnection");
+ domDoc.documentElement().appendChild(connectionElement);
+
+//DB ENGINE
+ QDomElement engineElement = domDoc.createElement("engine");
+ connectionElement.appendChild(engineElement);
+
+ QDomText tEngine = domDoc.createTextNode(m_driverName);
+ engineElement.appendChild(tEngine);
+
+//HOST
+ QDomElement hostElement = domDoc.createElement("host");
+ connectionElement.appendChild(hostElement);
+
+ QDomText tHost = domDoc.createTextNode(hostName);
+ hostElement.appendChild(tHost);
+
+//DATABASE NAME
+ QDomElement nameElement = domDoc.createElement("name");
+ connectionElement.appendChild(nameElement);
+
+ QDomText tName = domDoc.createTextNode(m_databaseName);
+ nameElement.appendChild(tName);
+
+//USER
+ QDomElement userElement = domDoc.createElement("user");
+ connectionElement.appendChild(userElement);
+
+ QDomText tUser = domDoc.createTextNode(userName);
+ userElement.appendChild(tUser);
+
+//PASSWORD STUFF
+ QDomElement passElement = domDoc.createElement("password");
+ connectionElement.appendChild(passElement);
+
+ QDomText tPass=domDoc.createTextNode(password);
+ passElement.appendChild(tPass);
+
+}
+
+
+
+KexiProjectConnectionData::~KexiProjectConnectionData()
+{
+}
diff --git a/kexi/core/kexiprojectconnectiondata.h b/kexi/core/kexiprojectconnectiondata.h
new file mode 100644
index 00000000..04ff40ff
--- /dev/null
+++ b/kexi/core/kexiprojectconnectiondata.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.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 KEXIPROJECTCONNECTIONDATA_H
+#define KEXIPROJECTCONNECTIONDATA_H
+
+#include <kexidb/connectiondata.h>
+
+class QDomElement;
+class QDomDocument;
+class KoStore;
+/**
+ * This class aims to provide
+ * methods to store/load database settings
+ * especially for file based engines. Extends KexiDB::ConnectionData with
+ * additional information (selected driver name and database name)
+ * that allows fully-automatic reconnect eg. on next application startup.
+ */
+
+class KEXICORE_EXPORT KexiProjectConnectionData:public KexiDB::ConnectionData
+{
+ public:
+
+ KexiProjectConnectionData();
+
+ KexiProjectConnectionData(const QString& driverName, const QString& databaseName, const QString &hostName, unsigned short int port,
+ const QString& userName, const QString &password, const QString& fileName);
+
+ /**
+ * connect to a embedded database
+ */
+ KexiProjectConnectionData(const QString &driverName, const QString &fileName=QString::null);
+
+ ~KexiProjectConnectionData();
+
+ static const QString &generateTmpName();
+
+ static KexiProjectConnectionData* loadInfo(QDomElement &e);
+ void writeInfo(QDomDocument &doc);
+
+ void setDriverName(const QString &driverName);
+ void setDatabaseName(const QString &databaseName);
+
+ QString driverName() const;
+ QString databaseName() const;
+
+ private:
+ QString m_driverName;
+ QString m_databaseName;
+
+};
+
+#endif
diff --git a/kexi/core/kexiprojectdata.cpp b/kexi/core/kexiprojectdata.cpp
new file mode 100644
index 00000000..68966a11
--- /dev/null
+++ b/kexi/core/kexiprojectdata.cpp
@@ -0,0 +1,176 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 <sys/types.h>
+#include <unistd.h>
+
+#include <qdom.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kio/netaccess.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <kexidb/drivermanager.h>
+#include "kexiprojectdata.h"
+
+
+//! @internal
+class KexiProjectDataPrivate
+{
+public:
+ KexiProjectDataPrivate()
+ : userMode(false)
+ , readOnly(false)
+ {}
+
+ KexiDB::ConnectionData connData;
+ QDateTime lastOpened;
+ bool userMode : 1;
+ bool readOnly : 1;
+};
+
+//---------------------------------------
+
+KexiProjectData::KexiProjectData()
+ : QObject(0, "KexiProjectData")
+ , KexiDB::SchemaData()
+ , formatVersion(0)
+ , d( new KexiProjectDataPrivate() )
+{
+}
+
+KexiProjectData::KexiProjectData(
+ const KexiDB::ConnectionData &cdata, const QString& dbname, const QString& caption )
+ : QObject(0, "KexiProjectData")
+ , KexiDB::SchemaData()
+ , formatVersion(0)
+ , d( new KexiProjectDataPrivate() )
+{
+ d->connData = cdata;
+ setDatabaseName(dbname);
+ setCaption(caption);
+}
+
+KexiProjectData::KexiProjectData( const KexiProjectData& pdata )
+ : QObject(0, "KexiProjectData"), KexiDB::SchemaData()
+ , d( 0 )
+{
+ *this = pdata;
+ autoopenObjects = pdata.autoopenObjects;
+/*
+ d->connData = *pdata.connectionData();
+ setDatabaseName(pdata.databaseName());
+ setCaption(pdata.caption());*/
+}
+
+KexiProjectData::~KexiProjectData()
+{
+ delete d;
+}
+
+KexiProjectData& KexiProjectData::operator=(const KexiProjectData& pdata)
+{
+ delete d; //this is old
+ static_cast<KexiDB::SchemaData&>(*this) = static_cast<const KexiDB::SchemaData&>(pdata);
+ //deep copy
+ d = new KexiProjectDataPrivate();
+ *d = *pdata.d;
+// d->connData = *pdata.constConnectionData();
+// setDatabaseName(pdata.databaseName());
+// setCaption(pdata.caption());
+// setDescription(pdata.description());
+ return *this;
+}
+
+KexiDB::ConnectionData* KexiProjectData::connectionData()
+{
+ return &d->connData;
+}
+
+const KexiDB::ConnectionData* KexiProjectData::constConnectionData() const
+{
+ return &d->connData;
+}
+
+QString KexiProjectData::databaseName() const
+{
+ return KexiDB::SchemaData::name();
+}
+
+void KexiProjectData::setDatabaseName(const QString& dbName)
+{
+ KexiDB::SchemaData::setName(dbName);
+}
+
+bool KexiProjectData::userMode() const
+{
+ return d->userMode;
+}
+
+QDateTime KexiProjectData::lastOpened() const
+{
+ return d->lastOpened;
+}
+
+void KexiProjectData::setLastOpened(const QDateTime& lastOpened)
+{
+ d->lastOpened=lastOpened;
+
+}
+QString KexiProjectData::description() const
+{
+ return KexiDB::SchemaData::description();
+}
+
+void KexiProjectData::setDescription(const QString& desc)
+{
+ return KexiDB::SchemaData::setDescription(desc);
+}
+
+QString KexiProjectData::infoString(bool nobr) const
+{
+ if (constConnectionData()->fileName().isEmpty()) {
+ //server-based
+ return QString(nobr ? "<nobr>" : "") + QString("\"%1\"").arg(databaseName()) + (nobr ? "</nobr>" : "")
+ + (nobr ? " <nobr>" : " ") + i18n("database connection", "(connection %1)")
+ .arg(constConnectionData()->serverInfoString()) + (nobr ? "</nobr>" : "");
+ }
+ //file-based
+ return QString(nobr ? "<nobr>" : "")
+ + QString("\"%1\"").arg(constConnectionData()->fileName()) + (nobr ? "</nobr>" : "");
+}
+
+void KexiProjectData::setReadOnly(bool set)
+{
+ d->readOnly = set;
+}
+
+bool KexiProjectData::isReadOnly() const
+{
+ return d->readOnly;
+}
+
diff --git a/kexi/core/kexiprojectdata.h b/kexi/core/kexiprojectdata.h
new file mode 100644
index 00000000..b4fc99d3
--- /dev/null
+++ b/kexi/core/kexiprojectdata.h
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPROJECTDATA_H
+#define KEXIPROJECTDATA_H
+
+#include <kexidb/connectiondata.h>
+#include <kexidb/schemadata.h>
+
+#include <qdatetime.h>
+
+class KexiProjectDataPrivate;
+
+/** @short Kexi project core data member
+
+ Contains:
+ - project name
+ - database name
+ - connection data
+ - date and time of last opening
+*/
+class KEXICORE_EXPORT KexiProjectData : public QObject, public KexiDB::SchemaData
+{
+ public:
+ typedef QPtrList<KexiProjectData> List;
+ typedef QMap<QCString,QString> ObjectInfo;
+
+ KexiProjectData();
+
+ KexiProjectData( const KexiDB::ConnectionData &cdata,
+ const QString& dbname = QString::null, const QString& caption = QString::null );
+
+ /*! Constructs a copy of \a pdata */
+ KexiProjectData( const KexiProjectData& pdata );
+
+ ~KexiProjectData();
+
+ KexiProjectData& operator=(const KexiProjectData& pdata);
+
+ /*! \return true if there is the User Mode set in internal
+ project settings. */
+ bool userMode() const;
+
+ KexiDB::ConnectionData* connectionData();
+
+ const KexiDB::ConnectionData* constConnectionData() const;
+
+ /*! \return database name.
+ In fact, this is the same as KexiDB::SchemaData::name() */
+ QString databaseName() const;
+ void setDatabaseName(const QString& dbName);
+
+ /*! \return user-visible string better describing the project than just databaseName().
+ For server-based projects returns i18n'd string:
+ "<project name>" (connection: user\@server:port).
+ For file-based projects returns project's filename.
+ If \a nobr is true, \<nobr\> tags are added around '(connection: user\@server:port)'
+ (useful for displaying in message boxes). */
+ QString infoString(bool nobr = true) const;
+
+ QDateTime lastOpened() const;
+ void setLastOpened(const QDateTime& lastOpened);
+
+ QString description() const;
+ void setDescription(const QString& desc);
+
+ /*! If \a set is true, sets readonly flag for this data, so any connection opened for the project will
+ be readonly. Change this flag before using this data in KexiProject instance,
+ otherwise you will need to reopen the project. */
+ void setReadOnly(bool set);
+
+ /*! \return readonly flag. False by default.
+ @see setReadOnly() */
+ bool isReadOnly() const;
+
+ /*! objects to open on startup (come from command line "-open" option)
+ It's public for convenience */
+ QValueList<ObjectInfo> autoopenObjects;
+
+ /*! @internal
+ Format version used when saving the data to a shortcut file.
+ This is set to 0 by default what means KexiDBShortcutFile_version should be used on saving.
+ If KexiDBShortcutFile was used to create this KexiProjectData object,
+ the version information is be retrieved from the file. */
+ uint formatVersion;
+
+ private:
+ KexiProjectDataPrivate *d;
+};
+
+#endif
diff --git a/kexi/core/kexiprojectset.cpp b/kexi/core/kexiprojectset.cpp
new file mode 100644
index 00000000..51e804dd
--- /dev/null
+++ b/kexi/core/kexiprojectset.cpp
@@ -0,0 +1,112 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiprojectset.h"
+#include "kexi.h"
+
+#include <kexidb/driver.h>
+#include <kexidb/connection.h>
+#include <kexidb/msghandler.h>
+
+#include <kdebug.h>
+
+//#define ERRMSG(a1, a2)
+// { if (m_msgHandler) m_msgHandler->showErrorMessage(a1, a2); }
+
+//! @internal
+class KexiProjectSetPrivate
+{
+public:
+ KexiProjectSetPrivate()
+ {
+// list.setAutoDelete(true);
+ }
+ KexiProjectData::List list;
+// KexiDB::MessageHandler* msgHandler;
+};
+
+KexiProjectSet::KexiProjectSet(KexiDB::MessageHandler* handler)
+: KexiDB::Object(handler)
+, d(new KexiProjectSetPrivate())
+{
+}
+
+KexiProjectSet::KexiProjectSet(KexiDB::ConnectionData &conndata,
+ KexiDB::MessageHandler* handler)
+: KexiDB::Object(handler)
+, d(new KexiProjectSetPrivate())
+{
+ KexiDB::Driver *drv = Kexi::driverManager().driver(conndata.driverName);
+ if (!drv) {
+ setError(&Kexi::driverManager());
+ return;
+ }
+ KexiDB::Connection *conn = drv->createConnection(conndata);
+ if (!conn) {
+ setError(drv);
+ return;
+ }
+ if (!conn->connect()) {
+ setError(conn);
+ delete conn;
+ return;
+ }
+ QStringList dbnames = conn->databaseNames(false/*skip system*/);
+// kexidbg << dbnames.count() << endl;
+ if (conn->error()) {
+ setError(conn);
+ delete conn;
+ return;
+ }
+ delete conn;
+ conn = 0;
+ for (QStringList::ConstIterator it = dbnames.constBegin(); it!=dbnames.constEnd(); ++it) {
+ // project's caption is just the same as database name - nothing better is available
+ KexiProjectData *pdata = new KexiProjectData(conndata, *it, *it);
+ d->list.append( pdata );
+ }
+ clearError();
+}
+
+
+KexiProjectSet::~KexiProjectSet()
+{
+ delete d;
+}
+
+void KexiProjectSet::addProjectData(KexiProjectData *data)
+{
+ d->list.append(data);
+}
+
+KexiProjectData::List KexiProjectSet::list() const
+{
+ return d->list;
+}
+
+KexiProjectData* KexiProjectSet::findProject(const QString &dbName) const
+{
+ const QString _dbName = dbName.lower();
+ QPtrListIterator<KexiProjectData> it( d->list );
+ for (;it.current();++it) {
+ if (it.current()->databaseName().lower()==_dbName)
+ return it.current();
+ }
+ return 0;
+}
diff --git a/kexi/core/kexiprojectset.h b/kexi/core/kexiprojectset.h
new file mode 100644
index 00000000..af251722
--- /dev/null
+++ b/kexi/core/kexiprojectset.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIPROJECTSET_H
+#define KEXIPROJECTSET_H
+
+#include <kexidb/connectiondata.h>
+#include <kexidb/object.h>
+
+#include "kexiprojectdata.h"
+
+class KexiProjectSetPrivate;
+namespace KexiDB {
+ class MessageHandler;
+}
+
+/*! @short Stores information about multiple kexi project-data items */
+class KEXICORE_EXPORT KexiProjectSet : public KexiDB::Object
+{
+ public:
+
+ /*! Creates empty project set. Use addProjectData to add a project data.
+ \a handler can be provided to receive error messages. */
+ KexiProjectSet(KexiDB::MessageHandler* handler = 0);
+
+ /*! Creates project set filled with all projects found using \a conndata.
+ There may be error during project list retrieving - use appropriate
+ KexiDB::Object::error(), and similar methods to get error message.
+ \a handler can be provided to receive error messages. */
+ KexiProjectSet(KexiDB::ConnectionData &conndata,
+ KexiDB::MessageHandler* handler = 0);
+
+ ~KexiProjectSet();
+
+ /*! Adds \a data as project data.
+ \a data will be owned by this object. */
+ void addProjectData(KexiProjectData *data);
+
+ //! \return list object
+ KexiProjectData::List list() const;
+
+ //! Case insensitive lookup.
+ //! \return project data for databased \a dbName or NULL if not found
+ KexiProjectData* findProject(const QString &dbName) const;
+
+ private:
+ KexiProjectSetPrivate *d;
+};
+
+#endif // KEXINEWDBCONNDIALOG_H
+
diff --git a/kexi/core/kexisearchandreplaceiface.cpp b/kexi/core/kexisearchandreplaceiface.cpp
new file mode 100644
index 00000000..0c533d93
--- /dev/null
+++ b/kexi/core/kexisearchandreplaceiface.cpp
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexisearchandreplaceiface.h"
+
+KexiSearchAndReplaceViewInterface::KexiSearchAndReplaceViewInterface()
+{
+}
+
+KexiSearchAndReplaceViewInterface::~KexiSearchAndReplaceViewInterface()
+{
+}
+
+//-----------------------------------------------------------------------
+
+KexiSearchAndReplaceViewInterface::Options::Options()
+ : columnNumber(AllColumns)
+ , textMatching(MatchAnyPartOfField)
+ , searchDirection(DefaultSearchDirection)
+ , caseSensitive(false)
+ , wholeWordsOnly(false)
+ , promptOnReplace(true)
+{
+}
+
diff --git a/kexi/core/kexisearchandreplaceiface.h b/kexi/core/kexisearchandreplaceiface.h
new file mode 100644
index 00000000..f17d8358
--- /dev/null
+++ b/kexi/core/kexisearchandreplaceiface.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KexiSearchAndReplaceViewInterface_H
+#define KexiSearchAndReplaceViewInterface_H
+
+#include <kexiutils/tristate.h>
+#include <qstring.h>
+class QVariant;
+class QStringList;
+
+//! @short An interface used by Kexi views (KexiViewBase) supporting search/replace features
+class KEXICORE_EXPORT KexiSearchAndReplaceViewInterface
+{
+ public:
+ KexiSearchAndReplaceViewInterface();
+ virtual ~KexiSearchAndReplaceViewInterface();
+
+ //! @short Specifies options for find and replace operations.
+ /*! A GUI for setting these options is provided by KexiFindDialog class. */
+ class KEXICORE_EXPORT Options {
+ public:
+ Options();
+
+ //! Special values for columnNumber.
+ enum SpecialLookInValue {
+ AllColumns = -1, //!< "all columns" (the default)
+ CurrentColumn = -2 //!< "current column"
+ };
+ //! Column number to look in, AllColumns means "all columns" (the default)
+ //! and CurrentColumn means "current column".
+ int columnNumber;
+
+ //! Specifies possible options for text matching
+ enum TextMatching {
+ MatchAnyPartOfField = 0, //!< Matched text can be any part of field (the default)
+ MatchWholeField = 1, //!< Matched text must be the whole field
+ MatchStartOfField = 2 //!< Matched text must be at the start of field
+ };
+
+ //! Specifies possible options for text matching
+ TextMatching textMatching;
+
+ //! Specifies search direction
+ enum SearchDirection {
+ SearchUp = 0, //!< Search up (previous) from the current position
+ SearchDown = 1, //!< Search down (next) from the current position (the default)
+ SearchAllRows = 2, //!< Search from the first to the last row
+ DefaultSearchDirection = SearchDown //! Used to mark the default
+ };
+
+ //! Specifies search direction
+ SearchDirection searchDirection;
+
+ //! True for searching is case-sensitive (false by default)
+ bool caseSensitive : 1;
+
+ //! True for searching for whole words only (false by default)
+ bool wholeWordsOnly : 1;
+
+ //! True if question should be displayed before every replacement made (true by default)
+ bool promptOnReplace : 1;
+ };
+
+ /*! Sets up data for find/replace dialog, based on view's data model.
+ \a columnNames should contain column name, \a columnCaptions should contain column captions,
+ and \a currentColumnName should beset to current column's name.
+ Implementation should set up values and return true if find/replace dialog should be filled. */
+ virtual bool setupFindAndReplace(QStringList& columnNames, QStringList& columnCaptions,
+ QString& currentColumnName) = 0;
+
+ /*! Finds \a valueToFind within the view.
+ \a options are used to control the process. Selection is moved to found value.
+ \return true if value has been found, false if value has not been found,
+ and cancelled if there is nothing to find or there is no data to search in.
+ If \a next is true, "find next" is performed, else "find previous" is performed. */
+ virtual tristate find(const QVariant& valueToFind,
+ const KexiSearchAndReplaceViewInterface::Options& options, bool next) = 0;
+
+ /*! Finds \a valueToFind within the view and replaces with \a replacement
+ \a options are used to control the process.
+ \return true if value has been found and replaced, false if value
+ has not been found and replaced, and cancelled if there is nothing
+ to find or there is no data to search in or the data is read only.
+ If \a replaceAll is true, all found values are replaced. */
+ virtual tristate findNextAndReplace(const QVariant& valueToFind, const QVariant& replacement,
+ const KexiSearchAndReplaceViewInterface::Options& options, bool replaceAll) = 0;
+};
+
+#endif
diff --git a/kexi/core/kexisharedactionhost.cpp b/kexi/core/kexisharedactionhost.cpp
new file mode 100644
index 00000000..11ab94db
--- /dev/null
+++ b/kexi/core/kexisharedactionhost.cpp
@@ -0,0 +1,291 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexisharedactionhost.h"
+#include "kexisharedactionhost_p.h"
+#include "kexiactionproxy.h"
+#include "kexidialogbase.h"
+
+#include <kexiutils/utils.h>
+
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kdebug.h>
+
+KexiSharedActionHostPrivate::KexiSharedActionHostPrivate(KexiSharedActionHost *h)
+: QObject(0,"KexiSharedActionHostPrivate")
+, actionProxies(401)
+, actionMapper( this )
+, volatileActions(401)
+, enablers(401, false)
+, host(h)
+{
+ volatileActions.setAutoDelete(true);
+ connect(&actionMapper, SIGNAL(mapped(const QString &)), this, SLOT(slotAction(const QString &)));
+}
+
+void KexiSharedActionHostPrivate::slotAction(const QString& act_id)
+{
+ QWidget *w = host->focusWindow(); //focusWidget();
+// while (w && !w->inherits("KexiDialogBase") && !w->inherits("KexiDockBase"))
+// w = w->parentWidget();
+
+ KexiActionProxy *proxy = w ? actionProxies[ w ] : 0;
+
+ if (!proxy || !proxy->activateSharedAction(act_id.latin1())) {
+ //also try to find previous enabler
+ w = enablers[act_id.latin1()];
+ if (!w)
+ return;
+ proxy = actionProxies[ w ];
+ if (!proxy)
+ return;
+ proxy->activateSharedAction(act_id.latin1());
+ }
+}
+
+//--------------------------------------------------
+
+//! dummy host to avoid crashes
+KexiSharedActionHost KexiSharedActionHost_dummy = KexiSharedActionHost(0);
+
+//! default host
+KexiSharedActionHost* KexiSharedActionHost_defaultHost = &KexiSharedActionHost_dummy;
+
+KexiSharedActionHost& KexiSharedActionHost::defaultHost()
+{
+ return *KexiSharedActionHost_defaultHost;
+}
+
+void KexiSharedActionHost::setAsDefaultHost()
+{
+ KexiSharedActionHost_defaultHost = this;
+}
+
+//--------------------------------------------------
+
+KexiSharedActionHost::KexiSharedActionHost(KMainWindow* mainWin)
+: d( new KexiSharedActionHostPrivate(this) )
+{
+ d->mainWin = mainWin;
+}
+
+KexiSharedActionHost::~KexiSharedActionHost()
+{
+ if (KexiSharedActionHost_defaultHost == this) {
+ //default host is destroyed! - restore dummy
+ KexiSharedActionHost_defaultHost = &KexiSharedActionHost_dummy;
+ }
+ delete d;
+ d=0; //! to let takeActionProxyFor() know that we are almost dead :)
+}
+
+void KexiSharedActionHost::setActionAvailable(const char *action_name, bool avail)
+{
+ KAction *act = d->mainWin->actionCollection()->action(action_name);
+ if (act) {
+ act->setEnabled(avail);
+ }
+}
+
+void KexiSharedActionHost::updateActionAvailable(const char *action_name, bool avail, QObject *obj)
+{
+/*test if (qstrcmp(action_name, "tablepart_toggle_pkey")==0) {
+ kdDebug() << "tablepart_toggle_pkey" << endl;
+ }*/
+ if (!d)
+ return; //sanity
+ QWidget *fw = d->mainWin->focusWidget();
+ while (fw && obj!=fw)
+ fw = fw->parentWidget();
+ if (!fw)
+ return;
+
+ setActionAvailable(action_name, avail);
+ if (avail) {
+ d->enablers.replace(action_name, fw);
+ }
+ else {
+ d->enablers.take(action_name);
+ }
+}
+
+void KexiSharedActionHost::plugActionProxy(KexiActionProxy *proxy)
+{
+// kdDebug() << "KexiSharedActionHost::plugActionProxy():" << proxy->receiver()->name() << endl;
+ d->actionProxies.insert( proxy->receiver(), proxy );
+}
+
+KMainWindow* KexiSharedActionHost::mainWindow() const
+{
+ return d->mainWin;
+}
+
+void KexiSharedActionHost::invalidateSharedActions(QObject *o)
+{
+ if (!d)
+ return;
+ bool insideDialogBase = o && (o->inherits("KexiDialogBase") || 0!=KexiUtils::findParent<KexiDialogBase>(o, "KexiDialogBase"));
+
+ KexiActionProxy *p = o ? d->actionProxies[ o ] : 0;
+ for (KActionPtrList::ConstIterator it=d->sharedActions.constBegin(); it!=d->sharedActions.constEnd(); ++it) {
+// setActionAvailable((*it)->name(),p && p->isAvailable((*it)->name()));
+ KAction *a = *it;
+ if (!insideDialogBase && d->mainWin->actionCollection()!=a->parentCollection()) {
+ //o is not KexiDialogBase or its child:
+ // only invalidate action if it comes from mainwindow's KActionCollection
+ // (thus part-actions are untouched when the focus is e.g. in the Property Editor)
+ continue;
+ }
+ const bool avail = p && p->isAvailable(a->name());
+ KexiVolatileActionData *va = d->volatileActions[ a ];
+ if (va != 0) {
+ if (p && p->isSupported(a->name())) {
+ QPtrList<KAction> actions_list;
+ actions_list.append( a );
+ if (!va->plugged) {
+ va->plugged=true;
+ // d->mainWin->unplugActionList( a->name() );
+ d->mainWin->plugActionList( a->name(), actions_list );
+ }
+ }
+ else {
+ if (va->plugged) {
+ va->plugged=false;
+ d->mainWin->unplugActionList( a->name() );
+ }
+ }
+ }
+// a->setEnabled(p && p->isAvailable(a->name()));
+ a->setEnabled(avail);
+// kdDebug() << "Action " << a->name() << (avail ? " enabled." : " disabled.") << endl;
+ }
+}
+
+KexiActionProxy* KexiSharedActionHost::actionProxyFor(QObject *o) const
+{
+ return d->actionProxies[ o ];
+}
+
+KexiActionProxy* KexiSharedActionHost::takeActionProxyFor(QObject *o)
+{
+ if (d)
+ return d->actionProxies.take( o );
+ return 0;
+}
+
+bool KexiSharedActionHost::acceptsSharedActions(QObject *)
+{
+ return false;
+}
+
+QWidget* KexiSharedActionHost::focusWindow()
+{
+ QWidget *fw;
+ if (dynamic_cast<KMdiMainFrm*>(d->mainWin)) {
+ fw = dynamic_cast<KMdiMainFrm*>(d->mainWin)->activeWindow();
+ }
+ else {
+ QWidget *aw = qApp->activeWindow();
+ if (!aw)
+ aw = d->mainWin;
+ fw = aw->focusWidget();
+ }
+ while (fw && !acceptsSharedActions(fw))
+ fw = fw->parentWidget();
+ return fw;
+}
+
+KAction* KexiSharedActionHost::createSharedActionInternal( KAction *action )
+{
+ QObject::connect(action,SIGNAL(activated()), &d->actionMapper, SLOT(map()));
+ d->actionMapper.setMapping(action, action->name());
+ d->sharedActions.append( action );
+ return action;
+}
+
+KActionPtrList KexiSharedActionHost::sharedActions() const
+{
+ return d->sharedActions;
+}
+
+/*class KexiAction : public KAction
+{
+ public:
+ KexiAction(const QString &text, const QIconSet &pix,
+ const KShortcut &cut, const QObject *receiver,
+ const char *slot, KActionCollection *parent, const char *name)
+ : KAction(text,pix,cut,receiver,slot,parent,name)
+ {
+ }
+
+ QPtrDict<QWidget> unplugged;
+};*/
+
+KAction* KexiSharedActionHost::createSharedAction(const QString &text, const QString &pix_name,
+ const KShortcut &cut, const char *name, KActionCollection* col, const char *subclassName)
+{
+ if (subclassName==0)
+ return createSharedActionInternal(
+ new KAction(text, pix_name,
+ cut, 0/*receiver*/, 0/*slot*/, col ? col : d->mainWin->actionCollection(), name)
+ );
+ else if (qstricmp(subclassName,"KToggleAction")==0)
+ return createSharedActionInternal(
+ new KToggleAction(text, pix_name,
+ cut, 0/*receiver*/, 0/*slot*/, col ? col : d->mainWin->actionCollection(), name)
+ );
+ else if (qstricmp(subclassName,"KActionMenu")==0)
+ return createSharedActionInternal(
+ new KActionMenu(text, pix_name, col ? col : d->mainWin->actionCollection(), name)
+ );
+//TODO: more KAction subclasses
+
+ return 0;
+}
+
+KAction* KexiSharedActionHost::createSharedAction( KStdAction::StdAction id, const char *name,
+ KActionCollection* col)
+{
+ return createSharedActionInternal(
+ KStdAction::create( id, name, 0/*receiver*/, 0/*slot*/, col ? col : d->mainWin->actionCollection() )
+ );
+}
+
+KAction* KexiSharedActionHost::createSharedAction(const KGuiItem& guiItem, const KShortcut &cut,
+ const char *name, KActionCollection* col)
+{
+ return createSharedActionInternal(
+ new KAction(guiItem, cut, 0/*receiver*/, 0/*slot*/,
+ col ? col : d->mainWin->actionCollection(), name));
+}
+
+void KexiSharedActionHost::setActionVolatile( KAction *a, bool set )
+{
+ if (!set) {
+ d->volatileActions.remove( a );
+ return;
+ }
+ if (d->volatileActions[ a ])
+ return;
+ d->volatileActions.insert( a, new KexiVolatileActionData() );
+}
+
+#include "kexisharedactionhost_p.moc"
+
diff --git a/kexi/core/kexisharedactionhost.h b/kexi/core/kexisharedactionhost.h
new file mode 100644
index 00000000..abb960bf
--- /dev/null
+++ b/kexi/core/kexisharedactionhost.h
@@ -0,0 +1,165 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXISHAREDACTIONHOST_H
+#define KEXISHAREDACTIONHOST_H
+
+#include <qguardedptr.h>
+#include <qasciidict.h>
+#include <qobject.h>
+#include <qpair.h>
+
+#include <kstdaction.h>
+#include <kaction.h>
+
+class KShortcut;
+class KGuiItem;
+class KMainWindow;
+class KexiActionProxy;
+class KexiSharedActionHostPrivate;
+
+namespace KexiPart {
+ class Part;
+}
+
+//! Acts as application-wide host that offers shared actions.
+/*!
+ You can inherit this class together with KMainWindow (or any KMainWindow).
+ Call setAsDefaultHost() to make the host default for all shared actions that have
+ not explicitly specified host.
+
+ For example how all this is done, see KexiMainWindow implementation.
+
+ \sa KexiActionProxy, KexiMainWindow
+*/
+
+class KEXICORE_EXPORT KexiSharedActionHost
+{
+ public:
+
+ /*! Constructs host for main window \a mainWin. */
+ KexiSharedActionHost(KMainWindow* mainWin);
+
+ virtual ~KexiSharedActionHost();
+
+ /*! \return true if \a w can accept shared actions.
+ This method is used by focusWindow() to look up widgets hierarchy
+ for widget that can accept shared actions.
+ Default implementation always returns false.
+ You can reimplement it e.g. like in KexiMainWindowImpl::acceptsSharedActions():
+ \code
+ return o->inherits("KexiDialogBase") || o->inherits("KexiViewBase");
+ \endcode
+ */
+ virtual bool acceptsSharedActions(QObject *o);
+
+ /*! \return window widget that is currently focused (using QWidget::focusWidget())
+ and matches acceptsSharedActions(). If focused widget does not match,
+ it's parent, grandparent, and so on is checked. If all this fails,
+ or no widget has focus, NULL is returned.
+ Also works if currently focused window is detached (as in KMDI).
+ */
+ QWidget* focusWindow();
+
+ /*! Sets this host as default shared actions host. */
+ void setAsDefaultHost();
+
+ /*! \return default shared actions host, used when no host
+ is explicitly specified for shared actions.
+ There can be exactly one deault shared actions host. */
+ static KexiSharedActionHost& defaultHost();
+
+ /*! \return shared actions list. */
+ KActionPtrList sharedActions() const;
+
+ /*! PROTOTYPE, DO NOT USE YET */
+ void setActionVolatile( KAction *a, bool set );
+
+
+ protected:
+
+ /*! Invalidates all shared actions declared using createSharedAction().
+ Any shared action will be enabled if \a o (typically: a child window or a dock window)
+ has this action plugged _and_ it is available (i.e. enabled).
+ Otherwise the action is disabled.
+
+ If \a o is not KexiDialogBase or its child,
+ actions are only invalidated if these come from mainwindow's KActionCollection
+ (thus part-actions are untouched when the focus is e.g. in the Property Editor.
+
+ Call this method when it is known that some actions need invalidation
+ (e.g. when new window is activated). See how it is used in KexiMainWindowImpl.
+ */
+ virtual void invalidateSharedActions(QObject *o);
+
+ void setActionAvailable(const char *action_name, bool avail);
+
+ /*! Plugs shared actions proxy \a proxy for this host. */
+ void plugActionProxy(KexiActionProxy *proxy);
+
+ /*! Updates availability of action \a action_name for object \a obj.
+ Object is mainly the window. */
+ void updateActionAvailable(const char *action_name, bool avail, QObject *obj);
+
+ /*! \return main window for which this host is defined. */
+ KMainWindow* mainWindow() const;
+
+ /*! Creates shared action using \a text, \a pix_name pixmap, shortcut \a cut,
+ optional \a name. You can pass your own action collection as \a col.
+ If \a col action collection is null, main window's action will be used.
+ Pass desired KAction subclass with \a subclassName (e.g. "KToggleAction") to have
+ that subclass allocated instead just KAction (what is the default).
+ Created action's data is owned by the main window. */
+ KAction* createSharedAction(const QString &text, const QString &pix_name,
+ const KShortcut &cut, const char *name, KActionCollection* col = 0,
+ const char *subclassName = 0);
+
+ /*! Like above - creates shared action, but from standard action identified by \a id.
+ Action's data is owned by the main window. */
+ KAction* createSharedAction( KStdAction::StdAction id, const char *name,
+ KActionCollection* col = 0);
+
+ /*! Creates shared action with name \a name and shortcut \a cut
+ by copying all properties of \a guiItem.
+ If \a col action collection is null, main window's action will be used. */
+ KAction* createSharedAction(const KGuiItem& guiItem, const KShortcut &cut, const char *name,
+ KActionCollection* col = 0);
+
+ /*! \return action proxy for object \a o, or NULL if this object has
+ no plugged shared actions. */
+ KexiActionProxy* actionProxyFor(QObject *o) const;
+
+ /*! Like actionProxyFor(), but takes the proxy from the host completely.
+ This is called by KExiActionProxy on its destruction. */
+ KexiActionProxy* takeActionProxyFor(QObject *o);
+
+ private:
+ /*! Helper function for createSharedAction(). */
+ KAction* createSharedActionInternal( KAction *action );
+
+ KexiSharedActionHostPrivate *d;
+
+ friend class KexiActionProxy;
+ friend class KexiPart::Part;
+ friend class KexiViewBase;
+ friend class KexiDialogBase;
+};
+
+#endif
+
diff --git a/kexi/core/kexisharedactionhost_p.h b/kexi/core/kexisharedactionhost_p.h
new file mode 100644
index 00000000..f56db586
--- /dev/null
+++ b/kexi/core/kexisharedactionhost_p.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXISHAREDACTIONHOST_P_H
+#define KEXISHAREDACTIONHOST_P_H
+
+#include <qobject.h>
+#include <qptrdict.h>
+#include <qsignalmapper.h>
+
+#include <kmainwindow.h>
+
+#include "kexiactionproxy.h"
+
+class KexiSharedActionHost;
+
+class KexiVolatileActionData
+{
+ public:
+ KexiVolatileActionData() { plugged=false; }
+// KAction *kaction;
+ bool plugged : 1;
+};
+
+//! @internal
+class KEXICORE_EXPORT KexiSharedActionHostPrivate : public QObject
+{
+ Q_OBJECT
+
+ public:
+ KexiSharedActionHostPrivate(KexiSharedActionHost *h);
+
+ public slots:
+ void slotAction(const QString& act_id);
+
+ public:
+ QPtrDict<KexiActionProxy> actionProxies;
+ KMainWindow *mainWin;
+ KActionPtrList sharedActions;
+ QSignalMapper actionMapper;
+ QPtrDict<KexiVolatileActionData> volatileActions;
+ QAsciiDict<QWidget> enablers;
+
+ KexiSharedActionHost *host;
+};
+
+#endif
+
diff --git a/kexi/core/kexistartupdata.cpp b/kexi/core/kexistartupdata.cpp
new file mode 100644
index 00000000..301ebdbd
--- /dev/null
+++ b/kexi/core/kexistartupdata.cpp
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexistartupdata.h"
+#include "kexi.h"
+
+#include <kexidb/driver.h>
+#include <kexidb/drivermanager.h>
+
+#include <qfileinfo.h>
+#include <qcstring.h>
+
+KexiStartupData::KexiStartupData()
+ : m_projectData(0)
+ , m_action(KexiStartupData::DoNothing)
+ , m_forcedUserMode(false)
+ , m_forcedDesignMode(false)
+ , m_isProjectNavigatorVisible(false)
+// , m_createDB(false)
+// , m_dropDB(false)
+// , m_alsoOpenDB(false)
+{
+}
+
+KexiStartupData::~KexiStartupData()
+{
+}
+
+KexiProjectData *KexiStartupData::projectData() const
+{
+ return m_projectData;
+}
+
+KexiStartupData::Action KexiStartupData::action() const
+{
+ return m_action;
+}
+
+bool KexiStartupData::forcedUserMode() const
+{
+ return m_forcedUserMode;
+}
+
+bool KexiStartupData::forcedDesignMode() const
+{
+ return m_forcedDesignMode;
+}
+
+bool KexiStartupData::isProjectNavigatorVisible() const
+{
+ if (m_forcedUserMode && !m_forcedDesignMode)
+ return m_isProjectNavigatorVisible;
+ return true;
+}
+
+KexiStartupData::Import KexiStartupData::importActionData() const
+{
+ return m_importActionData;
+}
+
+KexiStartupData::Import::Import()
+{
+}
+
+KexiStartupData::Import::operator bool() const
+{
+ return !fileName.isEmpty() && !mimeType.isEmpty();
+}
diff --git a/kexi/core/kexistartupdata.h b/kexi/core/kexistartupdata.h
new file mode 100644
index 00000000..71999bcb
--- /dev/null
+++ b/kexi/core/kexistartupdata.h
@@ -0,0 +1,90 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXI_STARTUPDATA_H
+#define KEXI_STARTUPDATA_H
+
+#include <qstring.h>
+
+class KexiProjectData;
+
+//! Startup data used for storing results of startup operations in Kexi.
+//! @see KexiStartupHandler
+class KEXICORE_EXPORT KexiStartupData
+{
+ public:
+ typedef enum Action {
+ DoNothing,
+ CreateBlankProject,
+ CreateFromTemplate,
+ OpenProject,
+ ImportProject,
+ Exit
+ };
+
+ /*! Data required to perform import action.
+ It is set by KexiStartupHandler::detectActionForFile()
+ if a need for project/data importing has been detected. */
+ class KEXICORE_EXPORT Import
+ {
+ public:
+ Import();
+ operator bool() const;
+ QString fileName;
+ QString mimeType;
+ };
+
+ KexiStartupData();
+ virtual ~KexiStartupData();
+
+ virtual bool init() { return true; };
+
+ Action action() const;
+
+ //! \return project data of a project that should be opened (for action()==OpenProject)
+ KexiProjectData *projectData() const;
+
+ //! \return import action's data needed to perform import (for action()==ImportProject)
+ KexiStartupData::Import importActionData() const;
+
+ /*! \return true is the Design Mode is forced for this project.
+ Used on startup (by --design-mode comman line switch). */
+ bool forcedDesignMode() const;
+
+ /*! \return true is the User Mode is forced for this project.
+ Used on startup (by --user-mode comman line switch).
+ By default this is false. */
+ bool forcedUserMode() const;
+
+ /*! \return true if the Project Navigator should be visible even if User Mode is on. */
+ bool isProjectNavigatorVisible() const;
+
+ protected:
+ KexiProjectData *m_projectData;
+ Action m_action;
+ KexiStartupData::Import m_importActionData;
+ bool m_forcedUserMode : 1;
+ bool m_forcedDesignMode : 1;
+ bool m_isProjectNavigatorVisible : 1;
+ bool m_createDB : 1;
+ bool m_dropDB : 1;
+ bool m_alsoOpenDB : 1;
+};
+
+#endif
diff --git a/kexi/core/kexistaticpart.cpp b/kexi/core/kexistaticpart.cpp
new file mode 100644
index 00000000..c7e323e1
--- /dev/null
+++ b/kexi/core/kexistaticpart.cpp
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexistaticpart.h"
+#include "kexipartinfo_p.h"
+#include "kexipartitem.h"
+#include "kexi.h"
+
+using namespace KexiPart;
+
+//------------------------------
+
+StaticInfo::StaticInfo(const QCString& mimeType, const QString& itemIcon, const QString& objectName)
+ : Info()
+{
+ d->mimeType = mimeType;
+ d->itemIcon = itemIcon;
+ d->objectName = objectName;
+}
+
+StaticInfo::~StaticInfo()
+{
+}
+
+//------------------------------
+
+StaticPart::StaticPart(const QCString& mimeType, const QString& itemIcon, const QString& objectName)
+ : Part(&Kexi::partManager(), new StaticInfo(mimeType, itemIcon, objectName))
+{
+ Kexi::partManager().insertStaticPart(this);
+}
+
+StaticPart::~StaticPart()
+{
+}
+
+KexiViewBase* StaticPart::createView(QWidget *parent, KexiDialogBase* dialog,
+ KexiPart::Item &item, int viewMode)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(dialog);
+ Q_UNUSED(item);
+ Q_UNUSED(viewMode);
+ //unused
+ return 0;
+}
diff --git a/kexi/core/kexistaticpart.h b/kexi/core/kexistaticpart.h
new file mode 100644
index 00000000..fe127fe4
--- /dev/null
+++ b/kexi/core/kexistaticpart.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2003,2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXISTATICPART_H
+#define KEXISTATICPART_H
+
+#include "kexipart.h"
+#include "kexipartinfo.h"
+
+namespace KexiPart
+{
+
+/**
+ * @short Information about a static Kexi Part (plugin).
+ */
+class KEXICORE_EXPORT StaticInfo : public Info
+{
+ public:
+ StaticInfo(const QCString& mimeType, const QString& itemIcon, const QString& objectName);
+ ~StaticInfo();
+
+ protected:
+};
+
+/**
+ * @short Static Kexi Part (plugin).
+ */
+class KEXICORE_EXPORT StaticPart : public Part
+{
+ public:
+ StaticPart(const QCString& mimeType, const QString& itemIcon, const QString& objectName);
+ virtual ~StaticPart();
+
+ /*! Creates a new view for mode \a viewMode, \a item and \a parent. The view will be
+ used inside \a dialog. \a args arguments can be passed. */
+ virtual KexiViewBase* createView(QWidget *parent, KexiDialogBase* dialog,
+ KexiPart::Item &item, int viewMode, QMap<QString,QString>* args) = 0;
+
+ protected:
+ //! unused by static parts
+ KexiViewBase* createView(QWidget *parent, KexiDialogBase* dialog,
+ KexiPart::Item &item, int viewMode = Kexi::DataViewMode);
+};
+
+}
+
+#endif
diff --git a/kexi/core/kexitabledesignerinterface.cpp b/kexi/core/kexitabledesignerinterface.cpp
new file mode 100644
index 00000000..9d6e1dc0
--- /dev/null
+++ b/kexi/core/kexitabledesignerinterface.cpp
@@ -0,0 +1,28 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexitabledesignerinterface.h"
+
+KexiTableDesignerInterface::KexiTableDesignerInterface()
+{
+}
+
+KexiTableDesignerInterface::~KexiTableDesignerInterface()
+{
+}
diff --git a/kexi/core/kexitabledesignerinterface.h b/kexi/core/kexitabledesignerinterface.h
new file mode 100644
index 00000000..60d7d0c7
--- /dev/null
+++ b/kexi/core/kexitabledesignerinterface.h
@@ -0,0 +1,104 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXITABLEDESIGNERINTERFACE_H
+#define KEXITABLEDESIGNERINTERFACE_H
+
+#include <koproperty/property.h>
+#include <kexiutils/tristate.h>
+
+namespace KoProperty {
+ class Set;
+}
+
+//! Interface for main Table Designer's commands
+/*! This interface has been specified to enable invoking Table Designer's commands
+ at application's level. This is used in the "altertable" test suite, available in
+ kexi/tests/altertable Kexi source code directory.
+ KexiTableDesignerInterface is implemented by KexiTableDesignerView, so it's enough
+ to use dynamic_cast:
+ \code
+ KexiDialogBase *dlg = KexiMainWindowImpl::self()->currentDialog();
+ if (dlg) {
+ KexiTableDesignerInterface* designerIface
+ = dynamic_cast<KexiTableDesignerInterface*>( dlg->selectedView() );
+ if (designerIface) {
+ //for example, delete row #3
+ designerIface->deleteRow( 3, true );
+ }
+ }
+ \endcode
+ Methods of KexiTableDesignerInterface are also used by classes of KexiTableDesignerCommands
+ namespace (KCommand derivatives) for implementing commands execution and unexecution.
+
+ All the methods contain addCommand argument. Set if to true to get the command added
+ to the undo/redo buffer, what will look like real user's action. This is also needed
+ to poperly generate arguments for commiting the "alter table" operation.
+*/
+class KEXICORE_EXPORT KexiTableDesignerInterface
+{
+ public:
+ KexiTableDesignerInterface();
+
+ virtual ~KexiTableDesignerInterface();
+
+ /*! Clears field information entered for row.
+ This is performed by removing values from caption and data type columns. */
+ virtual void clearRow(int row, bool addCommand = false) = 0;
+
+ /*! Inserts a new field with \a caption for \a row.
+ Property set is also created.
+ Existing field will be overwritten, so use insertEmptyRow()
+ is you want to move subsequent fields down. */
+ virtual void insertField(int row, const QString& caption, bool addCommand = false) = 0;
+
+ /*! Inserts a new \a field for \a row.
+ Property set is also created. \a set will be deeply-copied into the new set.
+ Existing field will be overwritten, so use insertEmptyRow()
+ is you want to move subsequent fields down. */
+ virtual void insertField(int row, KoProperty::Set& set, bool addCommand = false) = 0;
+
+ /*! Inserts a new empty row at position \a row. */
+ virtual void insertEmptyRow( int row, bool addCommand = false ) = 0;
+
+ /*! Deletes \a row from the table view. Property set is also deleted.
+ All the subsequent fields are moved up. */
+ virtual void deleteRow( int row, bool addCommand = false ) = 0;
+
+ /*! Changes property \a propertyName to \a newValue for a field pointed by \a fieldUID.
+ If \a listData is not NULL and not empty, a deep copy of it is passed to Property::setListData().
+ If \a listData \a nlist if not NULL but empty, Property::setListData(0) is called. */
+ virtual void changeFieldPropertyForRow( int fieldUID, const QCString& propertyName,
+ const QVariant& newValue, KoProperty::Property::ListData* const listData = 0,
+ bool addCommand = false ) = 0;
+
+ /*! Creates temporary table for the current design and returns debug string for it. */
+ virtual QString debugStringForCurrentTableSchema(tristate& result) = 0;
+
+ /*! Simulates execution of alter table, and puts debug into \a debugTarget.
+ A case when debugTarget is not 0 is true for the alter table test suite. */
+ virtual tristate simulateAlterTableExecution(QString *debugTarget) = 0;
+
+ /*! Real execution of the Alter Table. For debugging of the real alter table.
+ \return true on success, false on failure and cancelled if user has cancelled
+ execution. */
+ virtual tristate executeRealAlterTable() = 0;
+};
+
+#endif
diff --git a/kexi/core/kexitemplateloader.cpp b/kexi/core/kexitemplateloader.cpp
new file mode 100644
index 00000000..489d5f51
--- /dev/null
+++ b/kexi/core/kexitemplateloader.cpp
@@ -0,0 +1,112 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexitemplateloader.h"
+
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include <qdir.h>
+
+//static
+KexiTemplateInfo::List KexiTemplateLoader::loadListInfo()
+{
+ KexiTemplateInfo::List list;
+ const QString subdir = QString(kapp->instanceName()) + "/templates";
+ QString lang( KGlobal::locale()->language() );
+ QStringList dirs( kapp->dirs()->findDirs("data", subdir) );
+ while (true) {
+ foreach( QStringList::ConstIterator, it, dirs) {
+ QDir dir((*it)+lang);
+ if (!dir.exists())
+ continue;
+ if (!dir.isReadable()) {
+ kdWarning() << "KexiTemplateLoader::loadListInfo() \"" << dir.absPath() << "\" not readable!" << endl;
+ continue;
+ }
+ const QStringList templateDirs( dir.entryList(QDir::Dirs, QDir::Name) );
+ const QString absDirPath( dir.absPath() + '/' );
+ foreach(QStringList::ConstIterator, templateIt, templateDirs) {
+ if ((*templateIt)=="." || (*templateIt==".."))
+ continue;
+ KexiTemplateInfo info = KexiTemplateLoader::loadInfo( absDirPath + *templateIt );
+ if (!info.name.isEmpty())
+ list.append( info );
+ }
+ }
+ if (lang != "en" && list.isEmpty()) //not found for current locale, try "en"
+ lang = "en";
+ else
+ break;
+ }
+ return list;
+}
+
+//static
+KexiTemplateInfo KexiTemplateLoader::loadInfo(const QString& directory)
+{
+ QDir dir(directory);
+ if (!dir.isReadable()) {
+ kdWarning() << "KexiTemplateLoader::loadInfo() \""
+ << directory << "\" not readable!" << endl;
+ return KexiTemplateInfo();
+ }
+ if (!QFileInfo(directory+"/info.txt").isReadable())
+ return KexiTemplateInfo();
+ KConfig infoTxt(directory+"/info.txt", true/*readonly*/, false/*local*/);
+ KexiTemplateInfo info;
+ info.name = infoTxt.readEntry("Name");
+ if (info.name.isEmpty()) {
+ kdWarning() << "KexiTemplateLoader::loadInfo() \"" << (directory+"/info.txt") << "\" contains no \"name\" field" << endl;
+ return KexiTemplateInfo();
+ }
+ const QStringList templateFiles( dir.entryList("*.kexi", QDir::Files|QDir::Readable, QDir::Name) );
+ if (templateFiles.isEmpty()) {
+ kdWarning() << "KexiTemplateLoader::loadInfo() no readable .kexi template file found in \"" << directory << "\"" << endl;
+ return KexiTemplateInfo();
+ }
+ info.filename = directory+"/"+templateFiles.first();
+ info.description = infoTxt.readEntry("Description");
+ const QString iconFileName( infoTxt.readEntry("Icon") );
+ if (!iconFileName.isEmpty())
+ info.icon = QPixmap(directory+'/'+iconFileName);
+ if (info.icon.isNull())
+ info.icon = DesktopIcon("kexiproject_sqlite"); //default
+ QStringList autoopenObjectsString = infoTxt.readListEntry("AutoOpenObjects");
+ foreach( QStringList::ConstIterator, it, autoopenObjectsString) {
+ KexiProjectData::ObjectInfo autoopenObject;
+ QStringList autoopenObjectNameSplitted( QStringList::split(':', *it) );
+ if (autoopenObjectNameSplitted.count()>1) {
+ autoopenObject["type"] = autoopenObjectNameSplitted[0];
+ autoopenObject["name"] = autoopenObjectNameSplitted[1];
+ }
+ else {
+ autoopenObject["type"] = "table";
+ autoopenObject["name"] = autoopenObjectNameSplitted[0];
+ }
+ autoopenObject["action"] = "open";
+ info.autoopenObjects.append( autoopenObject );
+ }
+ return info;
+}
diff --git a/kexi/core/kexitemplateloader.h b/kexi/core/kexitemplateloader.h
new file mode 100644
index 00000000..131eda31
--- /dev/null
+++ b/kexi/core/kexitemplateloader.h
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXI_TEMPLLOADER_H
+#define KEXI_TEMPLLOADER_H
+
+#include <qpixmap.h>
+#include "kexiprojectdata.h"
+
+//! A structure providing information about single kexi database template file
+struct KEXICORE_EXPORT KexiTemplateInfo
+{
+ typedef QValueList<KexiTemplateInfo> List;
+
+ QString filename, name, description;
+ QPixmap icon;
+ QValueList<KexiProjectData::ObjectInfo> autoopenObjects;
+};
+
+//! Handles retrieving information about templates
+class KEXICORE_EXPORT KexiTemplateLoader
+{
+ public:
+ static KexiTemplateInfo::List loadListInfo();
+ static KexiTemplateInfo loadInfo(const QString& directory);
+};
+
+#endif
diff --git a/kexi/core/kexitextmsghandler.cpp b/kexi/core/kexitextmsghandler.cpp
new file mode 100644
index 00000000..a75c7eb3
--- /dev/null
+++ b/kexi/core/kexitextmsghandler.cpp
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexitextmsghandler.h"
+
+#include "kexi.h"
+#include <kexidb/utils.h>
+#include <kexiutils/utils.h>
+
+KexiTextMessageHandler::KexiTextMessageHandler(QString &messageTarget, QString &detailsTarget)
+ : KexiGUIMessageHandler(0)
+ , m_messageTarget(&messageTarget)
+ , m_detailsTarget(&detailsTarget)
+{
+ *m_messageTarget = QString::null;
+ *m_detailsTarget = QString::null;
+}
+
+KexiTextMessageHandler::~KexiTextMessageHandler()
+{
+}
+
+void
+KexiTextMessageHandler::showMessage(MessageType type,
+ const QString &title, const QString &details)
+{
+ Q_UNUSED(type);
+ if (!m_enableMessages)
+ return;
+
+ //'wait' cursor is a nonsense now
+ KexiUtils::removeWaitCursor();
+
+ QString msg(title);
+ if (title.isEmpty())
+ msg = i18n("Unknown error");
+ msg = "<qt><p>"+msg+"</p>";
+ *m_messageTarget = msg;
+ *m_detailsTarget = details;
+}
+
diff --git a/kexi/core/kexitextmsghandler.h b/kexi/core/kexitextmsghandler.h
new file mode 100644
index 00000000..74463cc7
--- /dev/null
+++ b/kexi/core/kexitextmsghandler.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXITXTMSGHANDLER_H
+#define KEXITXTMSGHANDLER_H
+
+#include "kexiguimsghandler.h"
+
+//! @short A wrapper that redirects messages to a string variables instead of displaying them.
+//! See KexiTextMessageHandler constructor for details.
+class KEXICORE_EXPORT KexiTextMessageHandler : public KexiGUIMessageHandler
+{
+ public:
+ KexiTextMessageHandler(QString &messageTarget, QString &detailsTarget);
+ virtual ~KexiTextMessageHandler();
+ virtual void showMessage(MessageType type, const QString &title, const QString &details);
+
+ QString *m_messageTarget, *m_detailsTarget;
+};
+
+#endif
diff --git a/kexi/core/kexiuseraction.cpp b/kexi/core/kexiuseraction.cpp
new file mode 100644
index 00000000..eb521de5
--- /dev/null
+++ b/kexi/core/kexiuseraction.cpp
@@ -0,0 +1,108 @@
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kshortcut.h>
+
+#include <kexidb/cursor.h>
+
+#include "kexipart.h"
+#include "kexipartmanager.h"
+
+#include "kexiproject.h"
+#include "keximainwindow.h"
+#include "kexiuseraction.h"
+
+KexiUserAction::KexiUserAction(KexiMainWindow *win, KActionCollection *parent, const QString &name, const QString &text, const QString &pixmap)
+ : KAction(text, pixmap, KShortcut::null(), this, SLOT(execute()), parent, name.latin1())
+{
+ m_win = win;
+ m_method = 0;
+ connect(this, SIGNAL(activated()), this, SLOT(execute()));
+}
+
+void
+KexiUserAction::setMethod(int method, Arguments args)
+{
+ m_method = method;
+ m_args = args;
+}
+
+void
+KexiUserAction::execute()
+{
+ kdDebug() << "KexiUserAction::execute(): " << KexiUserActionMethod::methodName(m_method) << endl;
+
+ switch(m_method)
+ {
+ case OpenObject: //open a project object
+ {
+ //get partinfo
+ KexiPart::Info *i = Kexi::partManager().infoForMimeType(m_args[0].toString().latin1());
+ if (!i) {
+ KMessageBox::error(m_win, i18n("Specified part does not exist"));
+ return;
+ }
+
+ Kexi::partManager().part(i); //load part if doesn't exists
+ KexiPart::Item *item = m_win->project()->item(i, m_args[1].toString());
+ bool openingCancelled;
+ if(!m_win->openObject(item, Kexi::DataViewMode, openingCancelled) && !openingCancelled) {
+ KMessageBox::error(m_win, i18n("Specified document could not be opened."));
+ return;
+ }
+ if (openingCancelled)
+ return;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+KexiUserAction *
+KexiUserAction::fromCurrentRecord(KexiMainWindow *context, KActionCollection *parent, KexiDB::Cursor *c)
+{
+ if(!c || c->bof() || c->eof())
+ return 0;
+
+ KexiUserAction *a = new KexiUserAction(context, parent, c->value(1).toString(), c->value(2).toString(), c->value(3).toString());
+ QString args = c->value(5).toString();
+ bool quote = false;
+
+ Arguments arg;
+ QString tmp;
+ const int len = args.length();
+ for(int i=0; i < len; i++)
+ {
+ if(args[i] == '"') // if current char is quoted unqote or other way round
+ {
+ quote = !quote;
+ }
+ else if(args[i] == ',' && !quote) //if item end add tmp to argumentstack and strip quotes if nessesery
+ {
+ if(tmp.left(1)=="\"" && tmp.right(1)=="\"")
+ tmp = tmp.mid(1, tmp.length()-2);
+
+ arg.append(QVariant(tmp));
+ tmp = "";
+ }
+ else //else simply add char to tmp
+ {
+ tmp += args[i];
+ }
+ }
+
+ if(tmp.left(1)=="\"" && tmp.right(1)=="\"")
+ tmp = tmp.mid(1, tmp.length()-2);
+
+ arg.append(QVariant(tmp));
+
+ a->setMethod(c->value(4).toInt(), arg);
+ return a;
+}
+
+KexiUserAction::~KexiUserAction()
+{
+}
+
+#include "kexiuseraction.moc"
+
diff --git a/kexi/core/kexiuseraction.h b/kexi/core/kexiuseraction.h
new file mode 100644
index 00000000..822220f0
--- /dev/null
+++ b/kexi/core/kexiuseraction.h
@@ -0,0 +1,81 @@
+#ifndef KEXIUSERACTION_H
+#define KEXIUSERACTION_H
+
+#include <kaction.h>
+
+#include "kexiuseractionmethod.h"
+
+namespace KexiDB
+{
+ class Cursor;
+}
+class KexiMainWindow;
+typedef QValueVector<QVariant> Arguments;
+
+/*! action that can be defined by a user for a special scope e.g. main, form ...
+ the actions can have some predefined \ref Methods which are described in \ref KexiUserActionMethod
+ e.g. OpenObject, ExecuteScript ... those methods take different arguments also described in \ref KexiUserActionMethod
+*/
+class KEXICORE_EXPORT KexiUserAction : public KAction
+{
+ Q_OBJECT
+
+ public:
+ /*! bytecode of available methods */
+ enum Methods
+ {
+ MethodNone = 0,
+ OpenObject = 1,
+ CloseObject = 2,
+ DeleteObject = 3,
+ ExecuteScript = 4,
+ ExitKexi = 5,
+
+ LastMethod = 6 //use the last integer here... so we can stop iteration
+ };
+
+ /*! argument types */
+ enum ArgTypes
+ {
+ String = 0,
+ Integer = 1,
+ Bool = 2,
+ KexiPart = 3,
+ KexiItem = 4
+ };
+
+ /*! constructs an action
+ \note methods are associated using setMethod()
+ */
+ KexiUserAction(KexiMainWindow *context, KActionCollection *parent, const QString &name, const QString &text, const QString &pixmap);
+ ~KexiUserAction();
+
+ /*! sets execution information associated with this action this will mostly look like
+ \code
+ KexiUserAction *action = new KexiUserAction(...);
+ Arguments arg;
+ arg.append(QVariant("kexi/form"));
+ arg.append(QVariant("main"));
+ action->setMethod(KexiUserAction::OpenAction, arg);
+ \endcode
+ */
+ void setMethod(int method, Arguments args);
+
+ /*! creates a KexiUserAction from current record in \a c
+ mostly needed for creation from kexi__useractions table */
+ static KexiUserAction *fromCurrentRecord(KexiMainWindow *context, KActionCollection *parent, KexiDB::Cursor *c);
+
+ protected slots:
+ /*! actually executes the associated method
+ \note KexiUserAction automatically connects KAction::activated() to KexiUserAction::execute()
+ */
+ void execute();
+
+ private:
+ KexiMainWindow *m_win;
+ int m_method;
+ Arguments m_args;
+};
+
+#endif
+
diff --git a/kexi/core/kexiuseractionmethod.cpp b/kexi/core/kexiuseractionmethod.cpp
new file mode 100644
index 00000000..a2ec2914
--- /dev/null
+++ b/kexi/core/kexiuseractionmethod.cpp
@@ -0,0 +1,32 @@
+#include <klocale.h>
+
+#include "kexiuseraction.h"
+#include "kexiuseractionmethod.h"
+
+KexiUserActionMethod::KexiUserActionMethod(int method, ArgTypes types, ArgNames names)
+{
+ m_method = method;
+ m_types = types;
+ m_names = names;
+}
+
+QString
+KexiUserActionMethod::methodName(int method)
+{
+ switch(method)
+ {
+ case KexiUserAction::OpenObject:
+ return i18n("Open Object");
+ case KexiUserAction::CloseObject:
+ return i18n("Close Object");
+ case KexiUserAction::DeleteObject:
+ return i18n("Delete Object");
+ case KexiUserAction::ExecuteScript:
+ return i18n("Execute Script");
+ case KexiUserAction::ExitKexi:
+ return i18n("Exit Main Application");
+ default:
+ return QString::null;
+ }
+}
+
diff --git a/kexi/core/kexiuseractionmethod.h b/kexi/core/kexiuseractionmethod.h
new file mode 100644
index 00000000..5bfae22c
--- /dev/null
+++ b/kexi/core/kexiuseractionmethod.h
@@ -0,0 +1,42 @@
+#ifndef KEXIUSERACTIONMETHOD_H
+#define KEXIUSERACTIONMETHOD_H
+
+#include <qvaluevector.h>
+#include <qstring.h>
+#include <qvariant.h>
+
+typedef QValueVector<int> ArgTypes;
+typedef QValueVector<QString> ArgNames;
+
+/*! describes a UserActionCommand */
+class KEXICORE_EXPORT KexiUserActionMethod
+{
+ public:
+ /*! constructs a UserActionCommand describtion */
+ KexiUserActionMethod(int method, ArgTypes types, ArgNames names);
+
+ /*! \return method id of this method */
+ int method() { return m_method; }
+
+ /*! \return argument type information of this method */
+ ArgTypes types() { return m_types; }
+
+ /*! \return i18n argument names of this method */
+ ArgNames names() { return m_names; }
+
+
+
+ /*! \return i18n method name for \a method */
+ static QString methodName(int method);
+
+ /*! \return an i18n string for \a type */
+ static QString typeName(int type);
+
+ private:
+ int m_method;
+ ArgTypes m_types;
+ ArgNames m_names;
+};
+
+#endif
+
diff --git a/kexi/core/kexiviewbase.cpp b/kexi/core/kexiviewbase.cpp
new file mode 100644
index 00000000..1696f502
--- /dev/null
+++ b/kexi/core/kexiviewbase.cpp
@@ -0,0 +1,328 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexiviewbase.h"
+
+#include "keximainwindow.h"
+#include "kexidialogbase.h"
+#include "kexiproject.h"
+#include <koproperty/set.h>
+
+#include <kexidb/connection.h>
+#include <kexidb/utils.h>
+#include <kexiutils/utils.h>
+
+#include <kdebug.h>
+
+KexiViewBase::KexiViewBase(KexiMainWindow *mainWin, QWidget *parent, const char *name)
+ : QWidget(parent, name)
+ , KexiActionProxy(this, mainWin)
+ , m_mainWin(mainWin)
+ , m_viewWidget(0)
+ , m_parentView(0)
+ , m_newlyAssignedID(-1)
+ , m_viewMode(0) //unknown!
+ , m_dirty(false)
+{
+ QWidget *wi=this;
+ while ((wi = wi->parentWidget()) && !wi->inherits("KexiDialogBase"))
+ ;
+ m_dialog = (wi && wi->inherits("KexiDialogBase")) ? static_cast<KexiDialogBase*>(wi) : 0;
+ if (m_dialog) {
+ //init view mode number for this view (obtained from dialog where this view is created)
+ if (m_dialog->supportsViewMode(m_dialog->m_creatingViewsMode))
+ m_viewMode = m_dialog->m_creatingViewsMode;
+ }
+
+ installEventFilter(this);
+}
+
+KexiViewBase::~KexiViewBase()
+{
+}
+
+KexiPart::Part* KexiViewBase::part() const
+{
+ return m_dialog ? m_dialog->part() : 0;
+}
+
+tristate KexiViewBase::beforeSwitchTo(int /* mode */, bool & /*dontStore*/)
+{
+ return true;
+}
+
+tristate KexiViewBase::afterSwitchFrom(int /* mode */)
+{
+ return true;
+}
+
+QSize KexiViewBase::preferredSizeHint(const QSize& otherSize)
+{
+ KexiDialogBase* dlg = parentDialog();
+ if (dlg && dlg->mdiParent()) {
+ QRect r = dlg->mdiParent()->mdiAreaContentsRect();
+ return otherSize.boundedTo( QSize(
+ r.width() - 10,
+ r.height() - dlg->mdiParent()->captionHeight() - dlg->pos().y() - 10
+ ) );
+ }
+ return otherSize;
+}
+
+void KexiViewBase::closeEvent( QCloseEvent * e )
+{
+ bool cancel = false;
+ emit closing(cancel);
+ if (cancel) {
+ e->ignore();
+ return;
+ }
+ QWidget::closeEvent(e);
+}
+
+KoProperty::Set *KexiViewBase::propertySet()
+{
+ return 0;
+}
+
+void KexiViewBase::propertySetSwitched()
+{
+ if (parentDialog())
+ m_mainWin->propertySetSwitched( parentDialog(), false );
+}
+
+void KexiViewBase::propertySetReloaded(bool preservePrevSelection, const QCString& propertyToSelect)
+{
+ if (parentDialog())
+ m_mainWin->propertySetSwitched( parentDialog(), true, preservePrevSelection, propertyToSelect );
+}
+
+void KexiViewBase::setDirty(bool set)
+{
+/* if (m_dirty == set) {//no change here
+ if (m_dialog) {
+ // however, it's a change from dialog perspective
+ if (m_dialog->dirty()!=set)
+ m_dialog->dirtyChanged();
+ }
+ return;
+ }*/
+ const bool changed = (m_dirty != set);
+ m_dirty = set;
+ m_dirty = dirty();
+// if (m_dirty!=set)//eventually didn't change
+// return;
+ if (m_parentView) {
+ m_parentView->setDirty(m_dirty);
+ }
+ else {
+ if (changed && m_dialog)
+ m_dialog->dirtyChanged(this);
+ }
+}
+
+/*bool KexiViewBase::saveData()
+{
+ //TODO....
+
+ //finally:
+ setDirty(false);
+ return true;
+}*/
+
+KexiDB::SchemaData* KexiViewBase::storeNewData(const KexiDB::SchemaData& sdata, bool & /*cancel*/)
+{
+ KexiDB::SchemaData *new_schema = new KexiDB::SchemaData();
+ *new_schema = sdata;
+
+ if (!m_mainWin->project()->dbConnection()
+ ->storeObjectSchemaData( *new_schema, true ))
+ {
+ delete new_schema;
+ new_schema=0;
+ }
+ m_newlyAssignedID = new_schema->id();
+ return new_schema;
+}
+
+tristate KexiViewBase::storeData(bool dontAsk)
+{
+ Q_UNUSED(dontAsk);
+ if (!m_dialog || !m_dialog->schemaData())
+ return false;
+ if (!m_mainWin->project()->dbConnection()
+ ->storeObjectSchemaData( *m_dialog->schemaData(), false /*existing object*/ ))
+ {
+ return false;
+ }
+ setDirty(false);
+ return true;
+}
+
+bool KexiViewBase::loadDataBlock( QString &dataString, const QString& dataID, bool canBeEmpty )
+{
+ if (!m_dialog)
+ return false;
+ const tristate res = m_mainWin->project()->dbConnection()->loadDataBlock(m_dialog->id(), dataString, dataID);
+ if (canBeEmpty && ~res) {
+ dataString = QString::null;
+ return true;
+ }
+ return res == true;
+}
+
+bool KexiViewBase::storeDataBlock( const QString &dataString, const QString &dataID )
+{
+ if (!m_dialog)
+ return false;
+ int effectiveID;
+ if (m_newlyAssignedID>0) {//ID not yet stored within dialog, but we've got ID here
+ effectiveID = m_newlyAssignedID;
+ m_newlyAssignedID = -1;
+ }
+ else
+ effectiveID = m_dialog->id();
+
+ return effectiveID>0
+ && m_mainWin->project()->dbConnection()->storeDataBlock(effectiveID, dataString, dataID);
+}
+
+bool KexiViewBase::removeDataBlock( const QString& dataID )
+{
+ if (!m_dialog)
+ return false;
+ return m_mainWin->project()->dbConnection()->removeDataBlock(m_dialog->id(), dataID);
+}
+
+bool KexiViewBase::eventFilter( QObject *o, QEvent *e )
+{
+ if (e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut) {// && o->inherits("QWidget")) {
+// //hp==true if currently focused widget is a child of this table view
+// const bool hp = Kexi::hasParent( static_cast<QWidget*>(o), focusWidget());
+// kexidbg << "KexiViewBase::eventFilter(): " << o->name() << " " << e->type() << endl;
+ if (KexiUtils::hasParent( this, static_cast<QWidget*>(o))) {
+ if (e->type()==QEvent::FocusOut && focusWidget() && !KexiUtils::hasParent( this, focusWidget())) {
+ //focus out: when currently focused widget is not a parent of this view
+ emit focus(false);
+ } else if (e->type()==QEvent::FocusIn) {
+ emit focus(true);
+ }
+ if (e->type()==QEvent::FocusOut) { // && focusWidget() && Kexi::hasParent( this, focusWidget())) { // && focusWidget()->inherits("KexiViewBase")) {
+// kdDebug() << focusWidget()->className() << " " << focusWidget()->name()<< endl;
+// kdDebug() << o->className() << " " << o->name()<< endl;
+ KexiViewBase *v = KexiUtils::findParent<KexiViewBase>(o, "KexiViewBase") ;
+// QWidget *www=v->focusWidget();
+ if (v) {
+ while (v->m_parentView)
+ v = v->m_parentView;
+ if (KexiUtils::hasParent( this, static_cast<QWidget*>(v->focusWidget()) ))
+ v->m_lastFocusedChildBeforeFocusOut = static_cast<QWidget*>(v->focusWidget());
+// v->m_lastFocusedChildBeforeFocusOut = static_cast<QWidget*>(o); //focusWidget();
+ }
+ }
+
+ if (e->type()==QEvent::FocusIn && m_actionProxyParent) {
+ m_actionProxyParent->m_focusedChild = this;
+ }
+// m_mainWin->invalidateSharedActions(this);
+ }
+ }
+ return false;
+}
+
+void KexiViewBase::setViewWidget(QWidget* w, bool focusProxy)
+{
+ if (m_viewWidget == w)
+ return;
+ if (m_viewWidget) {
+ m_viewWidget->removeEventFilter(this);
+ }
+ m_viewWidget = w;
+ if (m_viewWidget) {
+ m_viewWidget->installEventFilter(this);
+ if (focusProxy)
+ setFocusProxy(m_viewWidget); //js: ok?
+ }
+}
+
+void KexiViewBase::addChildView( KexiViewBase* childView )
+{
+ m_children.append( childView );
+ addActionProxyChild( childView );
+ childView->m_parentView = this;
+// if (m_parentView)
+// childView->installEventFilter(m_parentView);
+ childView->installEventFilter(this);
+
+}
+
+void KexiViewBase::setFocus()
+{
+ if (!m_lastFocusedChildBeforeFocusOut.isNull()) {
+// kdDebug() << "FOCUS: " << m_lastFocusedChildBeforeFocusOut->className() << " " << m_lastFocusedChildBeforeFocusOut->name()<< endl;
+ QWidget *w = m_lastFocusedChildBeforeFocusOut;
+ m_lastFocusedChildBeforeFocusOut = 0;
+ w->setFocus();
+ }
+ else {
+ if (hasFocus())
+ setFocusInternal();
+ else
+ setFocusInternal();
+ }
+ m_mainWin->invalidateSharedActions(this);
+}
+
+KAction* KexiViewBase::sharedAction( const char *action_name )
+{
+ if (part()) {
+ KActionCollection *ac;
+ if ( (ac = part()->actionCollectionForMode( viewMode() )) ) {
+ KAction* a = ac->action( action_name );
+ if (a)
+ return a;
+ }
+ }
+ return KexiActionProxy::sharedAction(action_name);
+}
+
+void KexiViewBase::setAvailable(const char* action_name, bool set)
+{
+ if (part()) {
+ KActionCollection *ac;
+ KAction* a;
+ if ( (ac = part()->actionCollectionForMode( viewMode() )) && (a = ac->action( action_name )) ) {
+ a->setEnabled(set);
+//why? return;
+ }
+ }
+ KexiActionProxy::setAvailable(action_name, set);
+}
+
+void KexiViewBase::updateActions(bool activated)
+{
+ //do nothing here
+ //do the same for children :)
+ for (QPtrListIterator<KexiViewBase> it(m_children); it.current(); ++it) {
+ it.current()->updateActions(activated);
+ }
+}
+
+#include "kexiviewbase.moc"
+
diff --git a/kexi/core/kexiviewbase.h b/kexi/core/kexiviewbase.h
new file mode 100644
index 00000000..18cd056d
--- /dev/null
+++ b/kexi/core/kexiviewbase.h
@@ -0,0 +1,280 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 KEXIVIEWBASE_H
+#define KEXIVIEWBASE_H
+
+#include <qwidget.h>
+
+#include "kexiactionproxy.h"
+
+class KexiMainWindow;
+class KexiDialogBase;
+
+namespace KoProperty {
+ class Set;
+}
+
+namespace KexiDB {
+ class SchemaData;
+}
+
+//! Base class for single view embeddable of in KexiDialogBase.
+/*! This class automatically works as a proxy for shared (application-wide) actions.
+ KexiViewBase has 'dirty' flag to indicate that view's data has changed.
+ This flag's state is reused by KexiDialogBase object that contain the view.
+ KexiViewBase objects can be also nested, using addChildView(): any actions and 'dirty' flag
+ are transmited to parent view in this case.
+
+ KexiViewBase objects are usually allocated within KexiDialogBase objects by implementing
+ KexiPart::createView() method. See query or table part code for examples.
+
+ KexiViewBase object can be also allocated without attaching it KexiDialogBase,
+ especially withinn dock window. see KexiMainWindowImpl::initNavigator() to see example
+ how KexiBrowser does this.
+*/
+class KEXICORE_EXPORT KexiViewBase : public QWidget, public KexiActionProxy
+{
+ Q_OBJECT
+
+ public:
+ KexiViewBase(KexiMainWindow *mainWin, QWidget *parent, const char *name = 0);
+ virtual ~KexiViewBase();
+
+ //! \return kexi main window that contain this view
+ inline KexiMainWindow *mainWin() const { return m_mainWin; }
+
+ //! \return parent KexiDialogBase that contains this view, or 0 if no dialog contain this view
+ KexiDialogBase* parentDialog() const { return m_dialog; }
+
+ /*! Added for convenience.
+ \return KexiPart object that was used to create this view (with a dialog)
+ or 0 if this view is not created using KexiPart. \sa parentDialog() */
+ KexiPart::Part* part() const;
+
+ /*! \return preferred size hint, that can be used to resize the view.
+ It is computed using maximum of (a) \a otherSize and (b) current KMDI dock area's size,
+ so the view won't exceed this maximum size. The method is used e.g. in KexiDialogBase::sizeHint().
+ If you reimplement this method, do not forget to return value of
+ yoursize.boundedTo( KexiViewBase::preferredSizeHint(otherSize) ). */
+ virtual QSize preferredSizeHint(const QSize& otherSize);
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+ void addChildView( KexiViewBase* childView );
+
+ /*! True if contents (data) of the view is dirty and need to be saved
+ This may or not be used, depending if changes in the dialog
+ are saved immediately (e.g. like in datatableview) or saved by hand (by user)
+ (e.g. like in alter-table dialog).
+ "Dirty" flag is reused by KexiDialogBase::dirty().
+ Default implementation just uses internal m_dirty flag, that is false by default.
+ Reimplement this if you e.g. want reuse other "dirty"
+ flag from internal structures that may be changed. */
+ virtual bool dirty() const { return m_dirty; }
+
+ /*! \return the view mode for this view. */
+ int viewMode() const { return m_viewMode; }
+
+ /*! Reimpelmented from KexiActionProxy.
+ \return shared action with name \a action_name for this view.
+ If there's no such action declared in Kexi Part (part()),
+ global shared action is returned (if exists). */
+ virtual KAction* sharedAction( const char *action_name );
+
+ /*! Enables or disables shared action declared in Kexi Part (part()).
+ If there's no such action, global shared action is enabled or disabled (if exists). */
+ virtual void setAvailable(const char* action_name, bool set);
+
+ public slots:
+ virtual void setFocus();
+
+ /*! Call this in your view's implementation whenever current property set
+ (returned by propertySet()) is switched to other,
+ so property editor contents need to be completely replaced. */
+ virtual void propertySetSwitched();
+
+ /*! Sets dirty flag on or off. It the flag changes,
+ dirty(bool) signal is emitted by parent dialog (KexiDialog),
+ to inform the world about that. If this view has a parent view, setDirty()
+ is called also on parent view.
+ Always use this function to update 'dirty' flag information. */
+ void setDirty(bool set);
+
+ /*! Equal to setDirty(true). */
+ void setDirty() { setDirty(true); }
+
+ signals:
+ //! emitted when the view is about to close
+ void closing(bool& cancel);
+
+ void focus(bool in);
+
+ protected:
+ /*! called by KexiDialogBase::switchToViewMode() right before dialog is switched to new mode
+ By default does nothing. Reimplement this if you need to do something
+ before switching to this view.
+ \return true if you accept or false if a error occupied and view shouldn't change
+ If there is no error but switching should be just cancelled
+ (probably after showing some info messages), you need to return cancelled.
+ Set \a dontStore to true (it's false by default) if you want to avoid data storing
+ by storeData() or storeNewData(). */
+ virtual tristate beforeSwitchTo(int mode, bool &dontStore);
+
+ /*! called by KexiDialogBase::switchToViewMode() right after dialog is switched to new mode
+ By default does nothing. Reimplement this if you need to do something
+ after switching to this view.
+ \return true if you accept or false if a error occupied and view shouldn't change
+ If there is no error but switching should be just cancelled
+ (probably after showing some info messages), you need to return cancelled. */
+ virtual tristate afterSwitchFrom(int mode);
+
+ virtual void closeEvent( QCloseEvent * e );
+
+ /*! \return a property set for this view. For reimplementation. By default returns NULL. */
+ virtual KoProperty::Set *propertySet();
+
+ /*! Call this in your view's implementation whenever current property set
+ is changed that few properties are now visible and/or few other are invisible,
+ so property editor operating on this property set should be completely reloaded.
+ If \a preservePrevSelection is true and there was a property set
+ assigned before call, previously selected item will be preselected
+ in the editor (if found). */
+ void propertySetReloaded(bool preservePrevSelection = false, const QCString& propertyToSelect = QCString());
+
+ /*! Tells this dialog to create and store data of the new object
+ pointed by \a sdata on the backend.
+ Called by KexiDialogBase::storeNewData().
+ Default implementation:
+ - makes a deep copy of \a sdata
+ - stores object schema data \a sdata in 'kexi__objects' internal table
+ using Connection::storeObjectSchemaData().
+ Reimpelment this for your needs.
+ Requirements:
+ - deep copy of \a sdata should be made
+ - schema data should be created at the backend
+ (by calling KexiViewBase::storeNewData(const KexiDB::SchemaData& sdata)),
+ or using Connection::storeObjectSchemaData() or more specialized
+ method. For example, KexiAlterTableDialog
+ uses Connection::createTable(TableSchema) for this
+ (tableschema is SchemaData subclass) to store more information than
+ just a schem adata. You should use such subclasses if needed.
+ Should return newly created schema data object on success.
+ In this case, do not store schema object yourself (make deep copy if needed). */
+ virtual KexiDB::SchemaData* storeNewData(const KexiDB::SchemaData& sdata, bool &cancel);
+
+ /*! Loads large string data \a dataString block (e.g. xml form's representation),
+ indexed with optional \a dataID, from the database backend.
+ If \a canBeEmpty is true and there is no data block for dataID, true is returned
+ and \a dataString is set to null string. The default is false.
+ \return true on success
+ \sa storeDataBlock(). */
+ bool loadDataBlock( QString &dataString, const QString& dataID = QString::null, bool canBeEmpty = false );
+
+ /*! Tells this view to store data changes on the backend.
+ Called by KexiDialogBase::storeData().
+ Default implementation:
+ - makes a deep copy of \a sdata
+ - stores object schema data \a sdata in 'kexi__objects' internal table
+ using Connection::storeObjectSchemaData().
+ If \a dontAsk is true, no question dialog will
+ be shown to the user. The default is false.
+
+ Reimpelment this for your needs. Should return true on success
+ or cancelled when the task should be cancelled.
+ \sa storeNewData() */
+ virtual tristate storeData(bool dontAsk = false);
+
+ /*! Stores (potentially large) string data \a dataString, block (e.g. xml form's representation),
+ at the database backend. Block will be stored in "kexi__objectdata" table pointed by
+ this object's id and an optional \a dataID identifier.
+
+ If dialog's id is not available (KexiDialogBase::id()),
+ then ID that was just created in storeNewData() is used
+ (see description of m_newlyAssignedID member).
+ If there is already such record in the table, it's simply overwritten.
+ \return true on success
+ */
+ bool storeDataBlock( const QString &dataString, const QString &dataID = QString::null );
+
+ /*! Removes (potentially large) string data (e.g. xml form's representation),
+ pointed by optional \a dataID, from the database backend.
+ \return true on success. Does not fail if the block doe not exists.
+ Note that if \a dataID is not specified, all data blocks for this view will be removed.
+ \sa storeDataBlock(). */
+ bool removeDataBlock( const QString& dataID = QString::null);
+
+ void setViewWidget(QWidget* w, bool focusProxy = false);
+
+ /*! Updates actions (e.g. availability). Reimplement it, if needed (you must
+ call superclass impelmentation at the end!).
+ This implementation does nothing for this view but calls updateActions()
+ for every child-view of this view.
+ called by KexiDialogBase on dialog's activation (\a activated is true)
+ or deactivation. */
+ virtual void updateActions(bool activated);
+
+ virtual void setFocusInternal() { QWidget::setFocus(); }
+
+ /*! Allows to react on parent dialog's detaching (only for KMDI's ChildFrame mode)
+ - it is called by KexiDialogBase::youAreDetached().
+ Default implementation does nothing.
+ Implement it if you want to perform some appropriate actions. */
+ virtual void parentDialogDetached() {};
+
+ /*! Allows to react on parent dialog's attaching (only for KMDI's ChildFrame mode)
+ - it is called by KexiDialogBase::youAreAttached().
+ Default implementation does nothing.
+ Implement it if you want to perform some appropriate actions. */
+ virtual void parentDialogAttached() {};
+
+ QString m_defaultIconName;
+
+ KexiMainWindow *m_mainWin;
+
+ KexiDialogBase *m_dialog;
+
+ QWidget *m_viewWidget;
+
+ KexiViewBase *m_parentView;
+
+ QGuardedPtr<QWidget> m_lastFocusedChildBeforeFocusOut;
+
+ private:
+ /*! Member set to newly assigned object's ID in storeNewData()
+ and used in storeDataBlock(). This is needed because usually,
+ storeDataBlock() can be called from storeNewData() and in this case
+ dialog has not yet assigned valid identifier (it has just negative temp. number).
+ \sa KexiDialogBase::id()
+ */
+ int m_newlyAssignedID;
+
+ /*! Mode for this view. Initialized by KexiDialogBase::switchToViewMode().
+ Can be useful when single class is used for more than one view (e.g. KexiDBForm). */
+ int m_viewMode;
+
+ QPtrList<KexiViewBase> m_children;
+
+ bool m_dirty : 1;
+
+ friend class KexiDialogBase;
+};
+
+#endif
+