summaryrefslogtreecommitdiffstats
path: root/kexi/plugins/forms
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/plugins/forms
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/plugins/forms')
-rw-r--r--kexi/plugins/forms/Makefile.am56
-rw-r--r--kexi/plugins/forms/kexiactionselectiondialog.cpp724
-rw-r--r--kexi/plugins/forms/kexiactionselectiondialog.h71
-rw-r--r--kexi/plugins/forms/kexiactionselectiondialog_p.h51
-rw-r--r--kexi/plugins/forms/kexidataawarewidgetinfo.cpp43
-rw-r--r--kexi/plugins/forms/kexidataawarewidgetinfo.h44
-rw-r--r--kexi/plugins/forms/kexidataprovider.cpp315
-rw-r--r--kexi/plugins/forms/kexidataprovider.h95
-rw-r--r--kexi/plugins/forms/kexidatasourcepage.cpp471
-rw-r--r--kexi/plugins/forms/kexidatasourcepage.h112
-rw-r--r--kexi/plugins/forms/kexidbfactory.cpp713
-rw-r--r--kexi/plugins/forms/kexidbfactory.h74
-rw-r--r--kexi/plugins/forms/kexidbtextwidgetinterface.cpp71
-rw-r--r--kexi/plugins/forms/kexidbtextwidgetinterface.h53
-rw-r--r--kexi/plugins/forms/kexiformdataiteminterface.cpp68
-rw-r--r--kexi/plugins/forms/kexiformdataiteminterface.h145
-rw-r--r--kexi/plugins/forms/kexiformeventhandler.cpp188
-rw-r--r--kexi/plugins/forms/kexiformeventhandler.h101
-rw-r--r--kexi/plugins/forms/kexiformhandler.desktop115
-rw-r--r--kexi/plugins/forms/kexiformmanager.cpp235
-rw-r--r--kexi/plugins/forms/kexiformmanager.h87
-rw-r--r--kexi/plugins/forms/kexiformpart.cpp550
-rw-r--r--kexi/plugins/forms/kexiformpart.h108
-rw-r--r--kexi/plugins/forms/kexiformpartinstui.rc77
-rw-r--r--kexi/plugins/forms/kexiformpartui.rc10
-rw-r--r--kexi/plugins/forms/kexiforms.cpp25
-rw-r--r--kexi/plugins/forms/kexiformscrollview.cpp587
-rw-r--r--kexi/plugins/forms/kexiformscrollview.h297
-rw-r--r--kexi/plugins/forms/kexiformview.cpp1278
-rw-r--r--kexi/plugins/forms/kexiformview.h231
-rw-r--r--kexi/plugins/forms/kformdesigner_kexidbfactory.desktop55
-rw-r--r--kexi/plugins/forms/widgets/Makefile.am28
-rw-r--r--kexi/plugins/forms/widgets/kexidbautofield.cpp846
-rw-r--r--kexi/plugins/forms/widgets/kexidbautofield.h210
-rw-r--r--kexi/plugins/forms/widgets/kexidbcheckbox.cpp175
-rw-r--r--kexi/plugins/forms/widgets/kexidbcheckbox.h99
-rw-r--r--kexi/plugins/forms/widgets/kexidbcombobox.cpp550
-rw-r--r--kexi/plugins/forms/widgets/kexidbcombobox.h181
-rw-r--r--kexi/plugins/forms/widgets/kexidbdateedit.cpp230
-rw-r--r--kexi/plugins/forms/widgets/kexidbdateedit.h118
-rw-r--r--kexi/plugins/forms/widgets/kexidbdatetimeedit.cpp243
-rw-r--r--kexi/plugins/forms/widgets/kexidbdatetimeedit.h106
-rw-r--r--kexi/plugins/forms/widgets/kexidbdoublespinbox.cpp113
-rw-r--r--kexi/plugins/forms/widgets/kexidbdoublespinbox.h79
-rw-r--r--kexi/plugins/forms/widgets/kexidbform.cpp714
-rw-r--r--kexi/plugins/forms/widgets/kexidbform.h139
-rw-r--r--kexi/plugins/forms/widgets/kexidbimagebox.cpp870
-rw-r--r--kexi/plugins/forms/widgets/kexidbimagebox.h275
-rw-r--r--kexi/plugins/forms/widgets/kexidbintspinbox.cpp114
-rw-r--r--kexi/plugins/forms/widgets/kexidbintspinbox.h80
-rw-r--r--kexi/plugins/forms/widgets/kexidblabel.cpp650
-rw-r--r--kexi/plugins/forms/widgets/kexidblabel.h140
-rw-r--r--kexi/plugins/forms/widgets/kexidblineedit.cpp417
-rw-r--r--kexi/plugins/forms/widgets/kexidblineedit.h170
-rw-r--r--kexi/plugins/forms/widgets/kexidbsubform.cpp131
-rw-r--r--kexi/plugins/forms/widgets/kexidbsubform.h52
-rw-r--r--kexi/plugins/forms/widgets/kexidbtextedit.cpp209
-rw-r--r--kexi/plugins/forms/widgets/kexidbtextedit.h113
-rw-r--r--kexi/plugins/forms/widgets/kexidbtimeedit.cpp156
-rw-r--r--kexi/plugins/forms/widgets/kexidbtimeedit.h87
-rw-r--r--kexi/plugins/forms/widgets/kexidbutils.cpp99
-rw-r--r--kexi/plugins/forms/widgets/kexidbutils.h71
-rw-r--r--kexi/plugins/forms/widgets/kexiframe.cpp77
-rw-r--r--kexi/plugins/forms/widgets/kexiframe.h84
-rw-r--r--kexi/plugins/forms/widgets/kexiframeutils_p.cpp232
-rw-r--r--kexi/plugins/forms/widgets/kexipushbutton.cpp32
-rw-r--r--kexi/plugins/forms/widgets/kexipushbutton.h55
67 files changed, 14995 insertions, 0 deletions
diff --git a/kexi/plugins/forms/Makefile.am b/kexi/plugins/forms/Makefile.am
new file mode 100644
index 00000000..e01b4f6c
--- /dev/null
+++ b/kexi/plugins/forms/Makefile.am
@@ -0,0 +1,56 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = kexihandler_form.la kformdesigner_kexidbwidgets.la
+
+kexihandler_form_la_SOURCES = kexiforms.cpp
+
+kexihandler_form_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module -no-undefined
+kexihandler_form_la_LIBADD = $(top_builddir)/kexi/core/libkexicore.la \
+ $(top_builddir)/kexi/widget/utils/libkexiguiutils.la \
+ $(top_builddir)/kexi/widget/tableview/libkexidatatable.la \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ $(top_builddir)/kexi/formeditor/libkformdesigner.la \
+ $(top_builddir)/lib/koproperty/libkoproperty.la \
+ ./libkexiformutils.la
+
+kformdesigner_kexidbwidgets_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module -no-undefined
+kformdesigner_kexidbwidgets_la_SOURCES = kexidbfactory.cpp
+kformdesigner_kexidbwidgets_la_LIBADD = $(top_builddir)/kexi/formeditor/libkformdesigner.la \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ ./libkexiformutils.la
+
+lib_LTLIBRARIES = libkexiformutils.la
+libkexiformutils_la_SOURCES = kexiformdataiteminterface.cpp kexidataawarewidgetinfo.cpp \
+ kexidataprovider.cpp kexiformscrollview.cpp kexiformeventhandler.cpp \
+ kexidbtextwidgetinterface.cpp kexiactionselectiondialog.cpp kexiformmanager.cpp \
+ kexidatasourcepage.cpp kexiformpart.cpp kexiformview.cpp
+libkexiformutils_la_LDFLAGS = $(all_libraries) $(VER_INFO) -no-undefined
+libkexiformutils_la_LIBADD = $(top_builddir)/kexi/core/libkexicore.la \
+ $(top_builddir)/kexi/widget/libkexiextendedwidgets.la \
+ $(top_builddir)/kexi/formeditor/libkformdesigner.la \
+ $(top_builddir)/kexi/plugins/forms/widgets/libkexiformutilswidgets.la
+
+kformdesignerservicesdir=$(kde_servicesdir)/kformdesigner
+kformdesignerservices_DATA=kformdesigner_kexidbfactory.desktop
+
+servicesdir=$(kde_servicesdir)/kexi
+services_DATA=kexiformhandler.desktop
+
+rcdir = $(kde_datadir)/kexi
+rc_DATA = kexiformpartui.rc kexiformpartinstui.rc
+
+SUBDIRS = widgets .
+
+INCLUDES= -I$(top_srcdir)/kexi/core -I$(top_srcdir)/kexi \
+ -I$(top_srcdir)/kexi/widget/utils \
+ -I$(top_srcdir)/kexi/widget \
+ -I$(top_srcdir)/kexi/formeditor \
+ -I$(top_srcdir)/lib -I$(top_srcdir)/lib/koproperty -I$(top_srcdir)/lib/kofficecore \
+ -I$(top_srcdir)/kexi/widget/tableview/private \
+ -I$(top_srcdir)/kexi/widget/tableview $(all_includes)
+
+METASOURCES = AUTO
+
+include ../Makefile.common
+noinst_HEADERS = kexidataprovider.h kexidbfactory.h \
+ kexiformpart.h kexiformscrollview.h kexiformview.h \ No newline at end of file
diff --git a/kexi/plugins/forms/kexiactionselectiondialog.cpp b/kexi/plugins/forms/kexiactionselectiondialog.cpp
new file mode 100644
index 00000000..26b4a9a6
--- /dev/null
+++ b/kexi/plugins/forms/kexiactionselectiondialog.cpp
@@ -0,0 +1,724 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-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 "kexiactionselectiondialog.h"
+#include "kexiactionselectiondialog_p.h"
+
+#include <keximainwindow.h>
+#include <kexipartitem.h>
+#include <kexiproject.h>
+#include <kexipartinfo.h>
+#include <kexipart.h>
+#include <kexiactioncategories.h>
+
+#include <klistview.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kstdguiitem.h>
+#include <kpushbutton.h>
+
+#include <qbitmap.h>
+#include <qlabel.h>
+#include <qheader.h>
+#include <qvbox.h>
+#include <qtooltip.h>
+#include <qwidgetstack.h>
+
+#include <widget/utils/klistviewitemtemplate.h>
+#include <widget/kexibrowser.h>
+#include <widget/kexibrowseritem.h>
+#include <kexiutils/utils.h>
+
+typedef KListViewItemTemplate<QString> ActionSelectorDialogListItemBase;
+
+class ActionSelectorDialogListItem : public ActionSelectorDialogListItemBase
+{
+public:
+ ActionSelectorDialogListItem(const QString& data, QListView *parent, QString label1)
+ : ActionSelectorDialogListItemBase(data, parent, label1)
+ , fifoSorting(true)
+ {
+ m_sortKey.sprintf("%2.2d", parent->childCount());
+ }
+
+ ActionSelectorDialogListItem(const QString& data, QListViewItem *parent, QString label1)
+ : ActionSelectorDialogListItemBase(data, parent, label1)
+ , fifoSorting(true)
+ {
+ m_sortKey.sprintf("%2.2d", parent->childCount());
+ }
+
+ virtual QString key( int column, bool ascending ) const
+ {
+ return fifoSorting ? m_sortKey : ActionSelectorDialogListItemBase::key(column, ascending);
+ }
+
+ bool fifoSorting : 1;
+
+protected:
+ QString m_sortKey;
+};
+
+//---------------------------------------
+
+ActionsListViewBase::ActionsListViewBase(QWidget* parent)
+ : KListView(parent)
+{
+ setResizeMode(QListView::AllColumns);
+ addColumn("");
+ header()->hide();
+ setColumnWidthMode(0, QListView::Maximum);
+ setAllColumnsShowFocus(true);
+ setTooltipColumn(0);
+}
+
+ActionsListViewBase::~ActionsListViewBase()
+{
+}
+
+QListViewItem *ActionsListViewBase::itemForAction(const QString& actionName)
+{
+ for (QListViewItemIterator it(this); it.current(); ++it) {
+ ActionSelectorDialogListItem* item = dynamic_cast<ActionSelectorDialogListItem*>(it.current());
+ if (item && item->data == actionName)
+ return item;
+ }
+ return 0;
+}
+
+void ActionsListViewBase::selectAction(const QString& actionName)
+{
+ QListViewItem *item = itemForAction(actionName);
+ if (item) {
+ setSelected(item, true);
+ ensureItemVisible(firstChild());
+ ensureItemVisible(selectedItem());
+ }
+}
+
+//---------------------------------------
+
+KActionsListViewBase::KActionsListViewBase(QWidget* parent, KexiMainWindow* mainWin)
+ : ActionsListViewBase(parent)
+ , m_mainWin(mainWin)
+{
+}
+
+KActionsListViewBase::~KActionsListViewBase() {}
+
+void KActionsListViewBase::init()
+{
+ setSorting(0);
+ const QPixmap noIcon( KexiUtils::emptyIcon(KIcon::Small) );
+ KActionPtrList sharedActions( m_mainWin->allActions() );
+ const Kexi::ActionCategories *acat = Kexi::actionCategories();
+ foreach (KActionPtrList::ConstIterator, it, sharedActions) {
+// kdDebug() << (*it)->name() << " " << (*it)->text() << endl;
+ //! @todo group actions
+ //! @todo: store KAction* here?
+ const int actionCategories = acat->actionCategories((*it)->name());
+ if (actionCategories==-1) {
+ kexipluginswarn << "KActionsListViewBase(): no category declared for action \""
+ << (*it)->name() << "\"! Fix this!" << endl;
+ continue;
+ }
+ if (!isActionVisible((*it)->name(), actionCategories))
+ continue;
+ ActionSelectorDialogListItem *pitem = new ActionSelectorDialogListItem((*it)->name(),
+ this, (*it)->toolTip().isEmpty() ? (*it)->text().replace("&", "") : (*it)->toolTip() );
+ pitem->fifoSorting = false; //alpha sort
+ pitem->setPixmap( 0, (*it)->iconSet( KIcon::Small, 16 ).pixmap( QIconSet::Small, QIconSet::Active ) );
+ if (!pitem->pixmap(0) || pitem->pixmap(0)->isNull())
+ pitem->setPixmap( 0, noIcon );
+ }
+}
+
+//---------------------------------------
+
+//! @internal Used to display KActions (in column 2)
+class KActionsListView : public KActionsListViewBase
+{
+public:
+ KActionsListView(QWidget* parent, KexiMainWindow* mainWin)
+ : KActionsListViewBase(parent, mainWin)
+ {
+ }
+ virtual ~KActionsListView() {}
+
+ virtual bool isActionVisible(const char* actionName, int actionCategories) const {
+ Q_UNUSED(actionName);
+ return actionCategories & Kexi::GlobalActionCategory;
+ }
+};
+
+//! @internal Used to display KActions (in column 2)
+class CurrentFormActionsListView : public KActionsListViewBase
+{
+public:
+ CurrentFormActionsListView(QWidget* parent, KexiMainWindow* mainWin)
+ : KActionsListViewBase(parent, mainWin)
+ {
+ }
+ virtual ~CurrentFormActionsListView() {}
+
+ virtual bool isActionVisible(const char* actionName, int actionCategories) const {
+ return actionCategories & Kexi::WindowActionCategory
+ && Kexi::actionCategories()->actionSupportsObjectType(actionName, KexiPart::FormObjectType);
+ }
+};
+
+//! @internal a list view displaying action categories user can select from (column 1)
+class ActionCategoriesListView : public ActionsListViewBase
+{
+public:
+ ActionCategoriesListView(QWidget* parent) //, KexiProject& project)
+ : ActionsListViewBase(parent)
+ {
+ QListViewItem *item = new ActionSelectorDialogListItem("noaction", this, i18n("No action") );
+ const QPixmap noIcon( KexiUtils::emptyIcon(KIcon::Small) );
+ item->setPixmap(0, noIcon);
+ item = new ActionSelectorDialogListItem("kaction", this, i18n("Application actions") );
+ item->setPixmap(0, SmallIcon("form_action"));
+
+ KexiPart::PartInfoList *pl = Kexi::partManager().partInfoList();
+ for (KexiPart::Info *info = pl->first(); info; info = pl->next()) {
+ KexiPart::Part *part = Kexi::partManager().part(info);
+ if (!info->isVisibleInNavigator() || !part)
+ continue;
+ item = new KexiBrowserItem(this, info);
+ item->setText(0, part->instanceCaption());
+ }
+ QListViewItem *formItem = itemForAction("form");
+ if (formItem) {
+ item = new ActionSelectorDialogListItem("currentForm", formItem,
+ i18n("Current form's actions", "Current"));
+ }
+ adjustColumn(0);
+ setMinimumWidth( columnWidth(0) + 6 );
+ }
+
+ ~ActionCategoriesListView()
+ {
+ }
+
+ //! \return item for action \a actionName, reimplemented to support KexiBrowserItem items
+ virtual QListViewItem *itemForAction(const QString& actionName)
+ {
+ for (QListViewItemIterator it(this); it.current(); ++it) {
+ //simple case
+ ActionSelectorDialogListItem* item = dynamic_cast<ActionSelectorDialogListItem*>(it.current());
+ if (item) {
+ if (item->data == actionName)
+ return it.current();
+ continue;
+ }
+ KexiBrowserItem* bitem = dynamic_cast<KexiBrowserItem*>(it.current());
+ if (bitem) {
+ if (bitem->info()->objectName() == actionName)
+ return it.current();
+ }
+ }
+ return 0;
+ }
+};
+
+//! @internal Used to display list of actions available to executing (column 3)
+class ActionToExecuteListView : public ActionsListViewBase
+{
+ public:
+ ActionToExecuteListView(QWidget* parent)
+ : ActionsListViewBase(parent)
+ {
+ }
+
+ ~ActionToExecuteListView()
+ {
+ }
+
+ //! Updates actions
+ void showActionsForMimeType(const QString& mimeType) {
+ if (m_currentMimeType == mimeType)
+ return;
+ m_currentMimeType = mimeType;
+ clear();
+ KexiPart::Part *part = Kexi::partManager().partForMimeType( m_currentMimeType );
+ if (!part)
+ return;
+ int supportedViewModes = part->supportedViewModes();
+ ActionSelectorDialogListItem *item;
+ const QPixmap noIcon( KexiUtils::emptyIcon(KIcon::Small) );
+ if (supportedViewModes & Kexi::DataViewMode) {
+ item = new ActionSelectorDialogListItem("open", this, i18n("Open in Data View"));
+ item->setPixmap(0, SmallIcon("fileopen"));
+ }
+ if (part->info()->isExecuteSupported()) {
+ item = new ActionSelectorDialogListItem("execute", this, i18n("Execute"));
+ item->setPixmap(0, SmallIcon("player_play"));
+ }
+ if (part->info()->isPrintingSupported()) {
+ ActionSelectorDialogListItem *printItem = new ActionSelectorDialogListItem(
+ "print", this, i18n("Print"));
+ printItem->setPixmap(0, SmallIcon("fileprint"));
+ KAction *a = KStdAction::printPreview(0, 0, 0);
+ item = new ActionSelectorDialogListItem("printPreview", printItem,
+ a->text().replace("&", "").replace("...", ""));
+ item->setPixmap(0, SmallIcon(a->icon()));
+ delete a;
+ item = new ActionSelectorDialogListItem("pageSetup", printItem, i18n("Show Page Setup"));
+ item->setPixmap(0, noIcon);
+ setOpen(printItem, true);
+ printItem->setExpandable(false);
+ }
+ if (part->info()->isDataExportSupported()) {
+ ActionSelectorDialogListItem *exportItem = new ActionSelectorDialogListItem(
+ "exportToCSV", this,
+ i18n("Note: use multiple rows if needed", "Export to File\nAs Data Table"));
+ exportItem->setMultiLinesEnabled(true);
+ exportItem->setPixmap(0, SmallIcon("table"));
+ item = new ActionSelectorDialogListItem("copyToClipboardAsCSV",
+ exportItem,
+ i18n("Note: use multiple rows if needed", "Copy to Clipboard\nAs Data Table"));
+ item->setPixmap(0, SmallIcon("table"));
+ item->setMultiLinesEnabled(true);
+ setOpen(exportItem, true);
+ exportItem->setExpandable(false);
+ }
+ item = new ActionSelectorDialogListItem("new", this, i18n("Create New Object"));
+ item->setPixmap(0, SmallIcon("filenew"));
+ if (supportedViewModes & Kexi::DesignViewMode) {
+ item = new ActionSelectorDialogListItem("design", this, i18n("Open in Design View"));
+ item->setPixmap(0, SmallIcon("edit"));
+ }
+ if (supportedViewModes & Kexi::TextViewMode) {
+ item = new ActionSelectorDialogListItem("editText", this, i18n("Open in Text View"));
+ item->setPixmap(0, noIcon);
+ }
+ item = new ActionSelectorDialogListItem("close", this, i18n("Close View"));
+ item->setPixmap(0, SmallIcon("fileclose"));
+ updateWidth();
+ }
+
+ void updateWidth()
+ {
+ adjustColumn(0);
+ setMinimumWidth( columnWidth(0) );
+ }
+
+ QString m_currentMimeType;
+};
+
+//-------------------------------------
+
+//! @internal
+class KexiActionSelectionDialog::KexiActionSelectionDialogPrivate
+{
+public:
+ KexiActionSelectionDialogPrivate()
+ : kactionPageWidget(0), kactionListView(0), objectsListView(0)
+ , currentFormActionsPageWidget(0)
+ , currentFormActionsListView(0)
+ , secondAnd3rdColumnMainWidget(0)
+ , hideActionToExecuteListView(false)
+ {
+ }
+
+ void raiseWidget(QWidget *w)
+ {
+ secondAnd3rdColumnStack->raiseWidget( w );
+ selectActionToBeExecutedLbl->setBuddy(w);
+ }
+
+ void updateSelectActionToBeExecutedMessage(const QString& actionType)
+ {
+ QString msg;
+ if (actionType=="noaction")
+ msg = QString::null;
+ // hardcoded, but it's not that bad
+ else if (actionType=="macro")
+ msg = i18n("&Select macro to be executed after clicking \"%1\" button:").arg(actionWidgetName);
+ else if (actionType=="script")
+ msg = i18n("&Select script to be executed after clicking \"%1\" button:").arg(actionWidgetName);
+ //default: table/query/form/report...
+ else
+ msg = i18n("&Select object to be opened after clicking \"%1\" button:").arg(actionWidgetName);
+ selectActionToBeExecutedLbl->setText(msg);
+ }
+
+ // changes 3rd column visibility
+ void setActionToExecuteSectionVisible(bool visible, bool force = false)
+ {
+ if (!force && hideActionToExecuteListView != visible)
+ return;
+ hideActionToExecuteListView = !visible;
+ actionToExecuteListView->hide();
+ actionToExecuteLbl->hide();
+ actionToExecuteListView->show();
+ actionToExecuteLbl->show();
+ }
+
+ KexiMainWindow* mainWin;
+ QString actionWidgetName;
+ ActionCategoriesListView* actionCategoriesListView; //!< for column #1
+ QWidget *kactionPageWidget;
+ KActionsListView* kactionListView; //!< for column #2
+ KexiBrowser* objectsListView; //!< for column #2
+ QWidget *currentFormActionsPageWidget; //!< for column #2
+ CurrentFormActionsListView* currentFormActionsListView; //!< for column #2
+ QWidget *emptyWidget;
+ QLabel* selectActionToBeExecutedLbl;
+ ActionToExecuteListView* actionToExecuteListView;
+ QLabel *actionToExecuteLbl;
+ QWidget *secondAnd3rdColumnMainWidget;
+ QGridLayout *glyr;
+ QGridLayout *secondAnd3rdColumnGrLyr;
+ QWidgetStack *secondAnd3rdColumnStack, *secondColumnStack;
+ bool hideActionToExecuteListView;
+};
+
+//-------------------------------------
+
+KexiActionSelectionDialog::KexiActionSelectionDialog(KexiMainWindow* mainWin, QWidget *parent,
+ const KexiFormEventAction::ActionData& action, const QCString& actionWidgetName)
+ : KDialogBase(parent, "actionSelectorDialog", true, i18n("Assigning Action to Command Button"),
+ KDialogBase::Ok | KDialogBase::Cancel )
+ , d( new KexiActionSelectionDialogPrivate() )
+{
+ d->mainWin = mainWin;
+ d->actionWidgetName = actionWidgetName;
+ setButtonOK( KGuiItem(i18n("Assign action", "&Assign"), "button_ok", i18n("Assign action")) );
+
+ QWidget *mainWidget = new QWidget( this );
+ mainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ setMainWidget(mainWidget);
+
+/* lbl 1
+ +------------+ +-------------------------------+
+ | | | [a] |
+ | 1st column | | +----------- + +------------+ |
+ | | | | 2nd column | | 3rd column | |
+ | | | + + + + |
+ | | | +------------+ +------------+ |
+ +------------+ +-------------------------------+
+ \______________________________________________/
+ glyr
+ [a]- QWidgetStack *secondAnd3rdColumnStack,
+ - for displaying KActions, the stack contains d->kactionPageWidget QWidget
+ - for displaying objects, the stack contains secondAnd3rdColumnMainWidget QWidget and QGridLayout *secondAnd3rdColumnGrLyr
+ - kactionPageWidget contains only a QVBoxLayout and label+kactionListView
+*/
+ d->glyr = new QGridLayout(mainWidget, 2, 2, KDialog::marginHint(), KDialog::spacingHint());
+ d->glyr->setRowStretch(1, 1);
+
+ // 1st column: action types
+ d->actionCategoriesListView = new ActionCategoriesListView(mainWidget);
+ d->actionCategoriesListView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ d->glyr->addWidget(d->actionCategoriesListView, 1, 0);
+ connect( d->actionCategoriesListView, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotActionCategorySelected(QListViewItem*)));
+
+ QLabel *lbl = new QLabel(d->actionCategoriesListView, i18n("Action category:"), mainWidget);
+ lbl->setMinimumHeight(lbl->fontMetrics().height()*2);
+ lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ lbl->setAlignment(Qt::AlignTop|Qt::AlignLeft|Qt::WordBreak);
+ d->glyr->addWidget(lbl, 0, 0, Qt::AlignTop|Qt::AlignLeft);
+
+ // widget stack for 2nd and 3rd column
+ d->secondAnd3rdColumnStack = new QWidgetStack(mainWidget);
+ d->secondAnd3rdColumnStack->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ d->glyr->addMultiCellWidget(d->secondAnd3rdColumnStack, 0, 1, 1, 1);//, Qt::AlignTop|Qt::AlignLeft);
+
+ d->secondAnd3rdColumnMainWidget = new QWidget(d->secondAnd3rdColumnStack);
+ d->secondAnd3rdColumnMainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ d->secondAnd3rdColumnGrLyr = new QGridLayout(d->secondAnd3rdColumnMainWidget, 2, 2, 0, KDialog::spacingHint());
+ d->secondAnd3rdColumnGrLyr->setRowStretch(1, 2);
+ d->secondAnd3rdColumnStack->addWidget(d->secondAnd3rdColumnMainWidget);
+
+ // 2nd column: list of actions/objects
+ d->objectsListView = new KexiBrowser(d->secondAnd3rdColumnMainWidget, d->mainWin, 0/*features*/);
+ d->secondAnd3rdColumnGrLyr->addWidget(d->objectsListView, 1, 0);
+ connect(d->objectsListView, SIGNAL(selectionChanged(KexiPart::Item*)),
+ this, SLOT(slotItemForOpeningOrExecutingSelected(KexiPart::Item*)));
+
+ d->selectActionToBeExecutedLbl = new QLabel(d->secondAnd3rdColumnMainWidget);
+ d->selectActionToBeExecutedLbl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ d->selectActionToBeExecutedLbl->setAlignment(Qt::AlignTop|Qt::AlignLeft|Qt::WordBreak);
+ d->selectActionToBeExecutedLbl->setMinimumHeight(d->selectActionToBeExecutedLbl->fontMetrics().height()*2);
+ d->secondAnd3rdColumnGrLyr->addWidget(d->selectActionToBeExecutedLbl, 0, 0, Qt::AlignTop|Qt::AlignLeft);
+
+ d->emptyWidget = new QWidget(d->secondAnd3rdColumnStack);
+ d->secondAnd3rdColumnStack->addWidget(d->emptyWidget);
+
+ // 3rd column: actions to execute
+ d->actionToExecuteListView = new ActionToExecuteListView(d->secondAnd3rdColumnMainWidget);
+ d->actionToExecuteListView->installEventFilter(this); //to be able to disable painting
+ d->actionToExecuteListView->viewport()->installEventFilter(this); //to be able to disable painting
+ d->actionToExecuteListView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ connect(d->actionToExecuteListView, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotActionToExecuteItemExecuted(QListViewItem*)));
+ connect(d->actionToExecuteListView, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotActionToExecuteItemSelected(QListViewItem*)));
+ d->secondAnd3rdColumnGrLyr->addWidget(d->actionToExecuteListView, 1, 1);
+
+ d->actionToExecuteLbl = new QLabel(d->actionToExecuteListView,
+ i18n("Action to execute:"), d->secondAnd3rdColumnMainWidget);
+ d->actionToExecuteLbl->installEventFilter(this); //to be able to disable painting
+ d->actionToExecuteLbl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ d->actionToExecuteLbl->setAlignment(Qt::AlignTop|Qt::AlignLeft|Qt::WordBreak);
+ d->secondAnd3rdColumnGrLyr->addWidget(d->actionToExecuteLbl, 0, 1, Qt::AlignTop|Qt::AlignLeft);
+
+ // temporary show all sections to avoid resizing the dialog in the future
+ d->actionCategoriesListView->selectAction("table");
+ d->setActionToExecuteSectionVisible(true);
+ adjustSize();
+ resize(QMAX(700, width()), QMAX(450, height()));
+ d->actionToExecuteListView->updateWidth();
+
+ bool ok;
+ QString actionType, actionArg;
+ KexiPart::Info* partInfo = action.decodeString(actionType, actionArg, ok);
+ if (ok) {
+ d->actionCategoriesListView->selectAction(actionType);
+ if (actionType=="kaction") {
+ d->kactionListView->selectAction(actionArg);
+ d->kactionListView->setFocus();
+ }
+ else if (actionType=="currentForm") {
+ d->currentFormActionsListView->selectAction(actionArg);
+ d->currentFormActionsListView->setFocus();
+ }
+ else if (partInfo
+ && Kexi::partManager().part(partInfo)) // We use the Part Manager
+ // to determine whether the Kexi-plugin is installed and whether we like to show
+ // it in our list of actions.
+ {
+ KexiPart::Item *item = d->mainWin->project()->item(partInfo, actionArg);
+ if (d->objectsListView && item) {
+ d->objectsListView->selectItem(*item);
+ QString actionOption( action.option );
+ if (actionOption.isEmpty())
+ actionOption = "open"; // for backward compatibility
+ d->actionToExecuteListView->selectAction(actionOption);
+ d->objectsListView->setFocus();
+ }
+ }
+ }
+ else {//invalid assignment or 'noaction'
+ d->actionCategoriesListView->selectAction("noaction");
+ d->actionCategoriesListView->setFocus();
+ }
+}
+
+KexiActionSelectionDialog::~KexiActionSelectionDialog()
+{
+ delete d;
+}
+
+void KexiActionSelectionDialog::slotKActionItemExecuted(QListViewItem*)
+{
+ accept();
+}
+
+void KexiActionSelectionDialog::slotKActionItemSelected(QListViewItem*)
+{
+ d->setActionToExecuteSectionVisible(false);
+ updateOKButtonStatus();
+}
+
+void KexiActionSelectionDialog::slotCurrentFormActionItemExecuted(QListViewItem*)
+{
+ accept();
+}
+
+void KexiActionSelectionDialog::slotCurrentFormActionItemSelected(QListViewItem*)
+{
+ d->setActionToExecuteSectionVisible(false);
+ updateOKButtonStatus();
+}
+
+void KexiActionSelectionDialog::slotItemForOpeningOrExecutingSelected(KexiPart::Item* item)
+{
+ d->setActionToExecuteSectionVisible(item);
+}
+
+void KexiActionSelectionDialog::slotActionToExecuteItemExecuted(QListViewItem* item)
+{
+ if (!item)
+ return;
+ ActionSelectorDialogListItemBase *listItem = dynamic_cast<ActionSelectorDialogListItemBase*>(item);
+ if (listItem && !listItem->data.isEmpty())
+ accept();
+}
+
+void KexiActionSelectionDialog::slotActionToExecuteItemSelected(QListViewItem*)
+{
+ updateOKButtonStatus();
+}
+
+void KexiActionSelectionDialog::slotActionCategorySelected(QListViewItem* item)
+{
+ ActionSelectorDialogListItem *simpleItem = dynamic_cast<ActionSelectorDialogListItem*>(item);
+ // simple case: part-less item, e.g. kaction:
+ if (simpleItem) {
+ d->updateSelectActionToBeExecutedMessage(simpleItem->data);
+ QString selectActionToBeExecutedMsg(
+ i18n("&Select action to be executed after clicking \"%1\" button:")); // msg for a label
+ if (simpleItem->data == "kaction") {
+ if (!d->kactionPageWidget) {
+ //create lbl+list view with a vlayout
+ d->kactionPageWidget = new QWidget();
+ d->kactionPageWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ QVBoxLayout *vlyr = new QVBoxLayout(d->kactionPageWidget, 0, KDialog::spacingHint());
+ d->kactionListView = new KActionsListView(d->kactionPageWidget, d->mainWin);
+ d->kactionListView->init();
+ QLabel *lbl = new QLabel(d->kactionListView, selectActionToBeExecutedMsg.arg(d->actionWidgetName),
+ d->kactionPageWidget);
+ lbl->setAlignment(Qt::AlignTop|Qt::AlignLeft|Qt::WordBreak);
+ lbl->setMinimumHeight(lbl->fontMetrics().height()*2);
+ vlyr->addWidget(lbl);
+ vlyr->addWidget(d->kactionListView);
+ d->secondAnd3rdColumnStack->addWidget(d->kactionPageWidget);
+ connect(d->kactionListView, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotKActionItemExecuted(QListViewItem*)));
+ connect( d->kactionListView, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotKActionItemSelected(QListViewItem*)));
+ }
+ d->setActionToExecuteSectionVisible(false);
+ d->raiseWidget(d->kactionPageWidget);
+ slotKActionItemSelected(d->kactionListView->selectedItem()); //to refresh column #3
+ }
+ else if (simpleItem->data == "currentForm") {
+ if (!d->currentFormActionsPageWidget) {
+ //create lbl+list view with a vlayout
+ d->currentFormActionsPageWidget = new QWidget();
+ d->currentFormActionsPageWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ QVBoxLayout *vlyr = new QVBoxLayout(d->currentFormActionsPageWidget, 0, KDialog::spacingHint());
+ d->currentFormActionsListView = new CurrentFormActionsListView(
+ d->currentFormActionsPageWidget, d->mainWin);
+ d->currentFormActionsListView->init();
+ QLabel *lbl = new QLabel(d->currentFormActionsListView,
+ selectActionToBeExecutedMsg.arg(d->actionWidgetName), d->currentFormActionsPageWidget);
+ lbl->setAlignment(Qt::AlignTop|Qt::AlignLeft|Qt::WordBreak);
+ lbl->setMinimumHeight(lbl->fontMetrics().height()*2);
+ vlyr->addWidget(lbl);
+ vlyr->addWidget(d->currentFormActionsListView);
+ d->secondAnd3rdColumnStack->addWidget(d->currentFormActionsPageWidget);
+ connect(d->currentFormActionsListView, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotCurrentFormActionItemExecuted(QListViewItem*)));
+ connect( d->currentFormActionsListView, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotCurrentFormActionItemSelected(QListViewItem*)));
+ }
+ d->setActionToExecuteSectionVisible(false);
+ d->raiseWidget(d->currentFormActionsPageWidget);
+ slotCurrentFormActionItemSelected(d->currentFormActionsListView->selectedItem()); //to refresh column #3
+ }
+ else if (simpleItem->data == "noaction") {
+ d->raiseWidget(d->emptyWidget);
+ d->objectsListView->clearSelection();
+ //hide column #3
+ d->setActionToExecuteSectionVisible(false);
+ }
+ d->actionCategoriesListView->update();
+ updateOKButtonStatus();
+ return;
+ }
+ // other case
+ KexiBrowserItem* browserItem = dynamic_cast<KexiBrowserItem*>(item);
+ if (browserItem) {
+ d->updateSelectActionToBeExecutedMessage(browserItem->info()->objectName());
+ if (d->objectsListView->itemsMimeType().latin1()!=browserItem->info()->mimeType()) {
+ d->objectsListView->setProject(d->mainWin->project(), browserItem->info()->mimeType());
+ d->actionToExecuteListView->showActionsForMimeType( browserItem->info()->mimeType() );
+ d->setActionToExecuteSectionVisible(false);
+ }
+ if (d->secondAnd3rdColumnStack->visibleWidget()!=d->secondAnd3rdColumnMainWidget) {
+ d->raiseWidget( d->secondAnd3rdColumnMainWidget );
+ d->objectsListView->clearSelection();
+ d->setActionToExecuteSectionVisible(false, true);
+ }
+ else
+ d->raiseWidget( d->secondAnd3rdColumnMainWidget );
+ }
+ d->actionCategoriesListView->update();
+ updateOKButtonStatus();
+}
+
+KexiMainWindow* KexiActionSelectionDialog::mainWin() const
+{
+ return d->mainWin;
+}
+
+KexiFormEventAction::ActionData KexiActionSelectionDialog::currentAction() const
+{
+ KexiFormEventAction::ActionData data;
+ ActionSelectorDialogListItem *simpleItem = dynamic_cast<ActionSelectorDialogListItem*>(
+ d->actionCategoriesListView->selectedItem());
+ // simple case: part-less item, e.g. kaction:
+ if (simpleItem) {
+ if (simpleItem->data == "kaction") {
+ if (d->kactionListView->selectedItem()) {
+ data.string = QString("kaction:")
+ + dynamic_cast<ActionSelectorDialogListItem*>( d->kactionListView->selectedItem() )->data;
+ return data;
+ }
+ }
+ else if (simpleItem->data == "currentForm") {
+ if (d->currentFormActionsListView->selectedItem()) {
+ data.string = QString("currentForm:")
+ + dynamic_cast<ActionSelectorDialogListItem*>(
+ d->currentFormActionsListView->selectedItem() )->data;
+ return data;
+ }
+ }
+ }
+ KexiBrowserItem* browserItem = dynamic_cast<KexiBrowserItem*>( d->actionCategoriesListView->selectedItem() );
+ if (browserItem) {
+ ActionSelectorDialogListItem *actionToExecute = dynamic_cast<ActionSelectorDialogListItem*>(
+ d->actionToExecuteListView->selectedItem());
+ if (d->objectsListView && actionToExecute && !actionToExecute->data.isEmpty()) {
+ KexiPart::Item* partItem = d->objectsListView->selectedPartItem();
+ KexiPart::Info* partInfo = partItem ? Kexi::partManager().infoForMimeType( partItem->mimeType() ) : 0;
+ if (partInfo) {
+ // opening or executing: table:name, query:name, form:name, macro:name, script:name, etc.
+ data.string = QString("%1:%2").arg(partInfo->objectName()).arg(partItem->name());
+ data.option = actionToExecute->data;
+ return data;
+ }
+ }
+ }
+ return data; // No Action
+}
+
+void KexiActionSelectionDialog::updateOKButtonStatus()
+{
+ QPushButton *btn = actionButton(Ok);
+ ActionSelectorDialogListItem *simpleItem = dynamic_cast<ActionSelectorDialogListItem*>(
+ d->actionCategoriesListView->selectedItem());
+ btn->setEnabled( (simpleItem && simpleItem->data == "noaction") || !currentAction().isEmpty() );
+}
+
+bool KexiActionSelectionDialog::eventFilter(QObject *o, QEvent *e)
+{
+ if (d->hideActionToExecuteListView)
+ return true;
+ return KDialogBase::eventFilter(o, e);
+}
+
+#include "kexiactionselectiondialog.moc"
+#include "kexiactionselectiondialog_p.moc"
diff --git a/kexi/plugins/forms/kexiactionselectiondialog.h b/kexi/plugins/forms/kexiactionselectiondialog.h
new file mode 100644
index 00000000..6b6a896b
--- /dev/null
+++ b/kexi/plugins/forms/kexiactionselectiondialog.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-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 KEXIACTIONSELECTIONDIALOG_H
+#define KEXIACTIONSELECTIONDIALOG_H
+
+#include <kdialogbase.h>
+#include "kexiformeventhandler.h"
+
+class KexiMainWindow;
+class KListView;
+namespace KexiPart {
+ class Item;
+}
+
+//! @short A dialog for selecting an action to be executed for a form's command button
+/*! Available actions are:
+ - application's global actions like "edit->copy" (KAction-based)
+ - opening/printing/executing of selected object (table/query/form/script/macrto, etc.)
+*/
+class KEXIFORMUTILS_EXPORT KexiActionSelectionDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ KexiActionSelectionDialog(KexiMainWindow* mainWin, QWidget *parent,
+ const KexiFormEventAction::ActionData& action, const QCString& actionWidgetName);
+ ~KexiActionSelectionDialog();
+
+ /*! \return selected action data or empty action if dialog has been rejected
+ or "No action" has been selected. */
+ KexiFormEventAction::ActionData currentAction() const;
+
+ //! \return the \a KexiMainWindow instance.
+ KexiMainWindow* mainWin() const;
+
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+ protected slots:
+ void slotActionCategorySelected(QListViewItem* item);
+ void slotKActionItemExecuted(QListViewItem*);
+ void slotKActionItemSelected(QListViewItem*);
+ void slotActionToExecuteItemExecuted(QListViewItem* item);
+ void slotActionToExecuteItemSelected(QListViewItem*);
+ void slotCurrentFormActionItemExecuted(QListViewItem*);
+ void slotCurrentFormActionItemSelected(QListViewItem*);
+ void slotItemForOpeningOrExecutingSelected(KexiPart::Item* item);
+
+ protected:
+ void updateOKButtonStatus();
+
+ class KexiActionSelectionDialogPrivate;
+ KexiActionSelectionDialogPrivate* d;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexiactionselectiondialog_p.h b/kexi/plugins/forms/kexiactionselectiondialog_p.h
new file mode 100644
index 00000000..51f5c369
--- /dev/null
+++ b/kexi/plugins/forms/kexiactionselectiondialog_p.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-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 KEXIACTIONSELECTIONDIALOG_P_H
+#define KEXIACTIONSELECTIONDIALOG_P_H
+
+#include <klistview.h>
+
+//! @internal
+class ActionsListViewBase : public KListView
+{
+ public:
+ ActionsListViewBase(QWidget* parent);
+ virtual ~ActionsListViewBase();
+
+ //! \return item for action \a actionName
+ virtual QListViewItem *itemForAction(const QString& actionName);
+ void selectAction(const QString& actionName);
+};
+
+//! @internal Used by KActionsListView and CurrentFormActionsListView (in column 2)
+class KActionsListViewBase : public ActionsListViewBase
+{
+ Q_OBJECT
+ public:
+ KActionsListViewBase(QWidget* parent, KexiMainWindow* mainWin);
+ virtual ~KActionsListViewBase();
+ void init();
+ virtual bool isActionVisible(const char* actionName, int actionCategories) const = 0;
+
+ protected:
+ KexiMainWindow* m_mainWin;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexidataawarewidgetinfo.cpp b/kexi/plugins/forms/kexidataawarewidgetinfo.cpp
new file mode 100644
index 00000000..a6033c70
--- /dev/null
+++ b/kexi/plugins/forms/kexidataawarewidgetinfo.cpp
@@ -0,0 +1,43 @@
+/* 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 "kexidataawarewidgetinfo.h"
+
+KexiDataAwareWidgetInfo::KexiDataAwareWidgetInfo(KFormDesigner::WidgetFactory *f)
+ : KFormDesigner::WidgetInfo(f)
+{
+ init();
+}
+
+KexiDataAwareWidgetInfo::KexiDataAwareWidgetInfo(KFormDesigner::WidgetFactory *f,
+ const char* parentFactoryName, const char* inheritedClassName)
+ : KFormDesigner::WidgetInfo(f, parentFactoryName, inheritedClassName)
+{
+ init();
+}
+
+KexiDataAwareWidgetInfo::~KexiDataAwareWidgetInfo()
+{
+}
+
+void KexiDataAwareWidgetInfo::init()
+{
+ setAutoSyncForProperty( "dataSource", false );
+ setAutoSyncForProperty( "dataSourceMimeType", false );
+}
diff --git a/kexi/plugins/forms/kexidataawarewidgetinfo.h b/kexi/plugins/forms/kexidataawarewidgetinfo.h
new file mode 100644
index 00000000..41e67d85
--- /dev/null
+++ b/kexi/plugins/forms/kexidataawarewidgetinfo.h
@@ -0,0 +1,44 @@
+/* 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 KEXIDATAAWAREWIDGETINFO_H
+#define KEXIDATAAWAREWIDGETINFO_H
+
+#include <formeditor/widgetfactory.h>
+
+//! A widget info for data-aware widgets
+/*! Used within factories just like KFormDesigner::WidgetInfo,
+ but also predefines specific behaviour,
+ e.g. sets autoSync flag to false for "dataSource" property.
+*/
+class KEXIFORMUTILS_EXPORT KexiDataAwareWidgetInfo : public KFormDesigner::WidgetInfo
+{
+ public:
+ KexiDataAwareWidgetInfo(KFormDesigner::WidgetFactory *f);
+
+ KexiDataAwareWidgetInfo(KFormDesigner::WidgetFactory *f,
+ const char* parentFactoryName, const char* inheritedClassName = 0);
+
+ virtual ~KexiDataAwareWidgetInfo();
+
+ protected:
+ void init();
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexidataprovider.cpp b/kexi/plugins/forms/kexidataprovider.cpp
new file mode 100644
index 00000000..6706f838
--- /dev/null
+++ b/kexi/plugins/forms/kexidataprovider.cpp
@@ -0,0 +1,315 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-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 "kexidataprovider.h"
+
+#include <qwidget.h>
+#include <qobjectlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <widget/tableview/kexitableitem.h>
+#include <widget/tableview/kexitableviewdata.h>
+#include <widget/tableview/kexicomboboxbase.h>
+#include <kexidb/queryschema.h>
+#include <kexiutils/utils.h>
+
+#include "widgets/kexidbform.h"
+
+KexiFormDataProvider::KexiFormDataProvider()
+ : KexiDataItemChangesListener()
+ , m_mainWidget(0)
+ , m_duplicatedItems(0)
+ , m_disableFillDuplicatedDataItems(false)
+{
+}
+
+KexiFormDataProvider::~KexiFormDataProvider()
+{
+ delete m_duplicatedItems;
+}
+
+void KexiFormDataProvider::setMainDataSourceWidget(QWidget* mainWidget)
+{
+ m_mainWidget = mainWidget;
+ m_dataItems.clear();
+ m_usedDataSources.clear();
+ m_fieldNumbersForDataItems.clear();
+ if (!m_mainWidget)
+ return;
+
+ //find widgets whose will work as data items
+ QObjectList *l = m_mainWidget->queryList( "QWidget" );
+ QObjectListIt it( *l );
+ QObject *obj;
+ QDict<char> tmpSources;
+ for ( ; (obj = it.current()) != 0; ++it ) {
+ KexiFormDataItemInterface* const formDataItem = dynamic_cast<KexiFormDataItemInterface*>(obj);
+ if (!formDataItem)
+ continue;
+ if (formDataItem->parentInterface()) //item with parent interface: collect parent instead...
+ continue;
+#if 0 //! @todo reenable when subform is moved to KexiDBForm
+ KexiDBForm *dbForm = KexiUtils::findParent<KexiDBForm>(obj, "KexiDBForm"); //form's surface...
+ if (dbForm!=m_mainWidget) //only set data for this form's data items
+ continue;
+#else
+ //tmp: reject widgets within subforms
+ if (KexiUtils::findParent<KexiDBForm>(obj, "KexiDBSubForm"))
+ continue;
+#endif
+ QString dataSource( formDataItem->dataSource().lower() );
+ if (dataSource.isEmpty())
+ continue;
+ kexipluginsdbg << obj->name() << endl;
+ m_dataItems.append( formDataItem );
+ formDataItem->installListener( this );
+ tmpSources.replace( dataSource, (char*)1 );
+ }
+ delete l;
+ //now we've got a set (unique list) of field names in tmpSources
+ //remember it in m_usedDataSources
+ for (QDictIterator<char> it(tmpSources); it.current(); ++it) {
+ m_usedDataSources += it.currentKey();
+ }
+}
+
+void KexiFormDataProvider::fillDataItems(KexiTableItem& row, bool cursorAtNewRow)
+{
+ kexipluginsdbg << "KexiFormDataProvider::fillDataItems() cnt=" << row.count() << endl;
+ for (KexiFormDataItemInterfaceToIntMap::ConstIterator it = m_fieldNumbersForDataItems.constBegin();
+ it!=m_fieldNumbersForDataItems.constEnd(); ++it)
+ {
+ KexiFormDataItemInterface *itemIface = it.key();
+ if (!itemIface->columnInfo()) {
+ kexipluginsdbg << "KexiFormDataProvider::fillDataItems(): itemIface->columnInfo() == 0" << endl;
+ continue;
+ }
+ //1. Is this a value with a combo box (lookup)?
+ int indexForVisibleLookupValue = itemIface->columnInfo()->indexForVisibleLookupValue();
+ if (indexForVisibleLookupValue<0 && indexForVisibleLookupValue>=(int)row.count()) //sanity
+ indexForVisibleLookupValue = -1; //no
+ const QVariant value(row.at(it.data()));
+ QVariant visibleLookupValue;
+ if (indexForVisibleLookupValue!=-1 && (int)row.size()>indexForVisibleLookupValue)
+ visibleLookupValue = row.at(indexForVisibleLookupValue);
+ kexipluginsdbg << "fill data of '" << itemIface->dataSource() << "' at idx=" << it.data()
+ << " data=" << value << (indexForVisibleLookupValue!=-1
+ ? QString(" SPECIAL: indexForVisibleLookupValue=%1 visibleValue=%2")
+ .arg(indexForVisibleLookupValue).arg(visibleLookupValue.toString())
+ : QString::null)
+ << endl;
+ const bool displayDefaultValue = cursorAtNewRow && (value.isNull() && visibleLookupValue.isNull())
+ && !itemIface->columnInfo()->field->defaultValue().isNull()
+ && !itemIface->columnInfo()->field->isAutoIncrement(); //no value to set but there is default value defined
+ itemIface->setValue(
+ displayDefaultValue ? itemIface->columnInfo()->field->defaultValue() : value,
+ QVariant(), /*add*/
+ /*!remove old*/false,
+ indexForVisibleLookupValue==-1 ? 0 : &visibleLookupValue //pass visible value if available
+ );
+ // now disable/enable "display default value" if needed (do it after setValue(), before setValue() turns it off)
+ if (itemIface->hasDisplayedDefaultValue() != displayDefaultValue)
+ itemIface->setDisplayDefaultValue( dynamic_cast<QWidget*>(itemIface), displayDefaultValue );
+ }
+}
+
+void KexiFormDataProvider::fillDuplicatedDataItems(
+ KexiFormDataItemInterface* item, const QVariant& value)
+{
+ if (m_disableFillDuplicatedDataItems)
+ return;
+ if (!m_duplicatedItems) {
+ //build (once) a set of duplicated data items (having the same fields assigned)
+ //so we can later check if an item is duplicated with a cost of o(1)
+ QMap<KexiDB::Field*,int> tmpDuplicatedItems;
+ QMapIterator<KexiDB::Field*,int> it_dup;
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ if (!it.current()->columnInfo() || !it.current()->columnInfo()->field)
+ continue;
+ kdDebug() << " ** " << it.current()->columnInfo()->field->name() << endl;
+ it_dup = tmpDuplicatedItems.find( it.current()->columnInfo()->field );
+ uint count;
+ if (it_dup==tmpDuplicatedItems.end())
+ count = 0;
+ else
+ count = it_dup.data();
+ tmpDuplicatedItems.insert( it.current()->columnInfo()->field, ++count );
+ }
+ m_duplicatedItems = new QPtrDict<char>(101);
+ for (it_dup = tmpDuplicatedItems.begin(); it_dup!=tmpDuplicatedItems.end(); ++it_dup) {
+ if (it_dup.data() > 1) {
+ m_duplicatedItems->insert( it_dup.key(), (char*)1 );
+ kexipluginsdbg << "duplicated item: " << static_cast<KexiDB::Field*>(it_dup.key())->name()
+ << " (" << it_dup.data() << " times)" << endl;
+ }
+ }
+ }
+ if (item->columnInfo() && m_duplicatedItems->find( item->columnInfo()->field )) {
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ if (it.current()!=item && item->columnInfo()->field == it.current()->columnInfo()->field) {
+ kexipluginsdbg << "- setting a copy of value for item '"
+ << dynamic_cast<QObject*>(it.current())->name() << "' == " << value << endl;
+ it.current()->setValue( value );
+ }
+ }
+ }
+}
+
+void KexiFormDataProvider::valueChanged(KexiDataItemInterface* item)
+{
+ Q_UNUSED( item );
+}
+
+bool KexiFormDataProvider::cursorAtNewRow() const
+{
+ return false;
+}
+
+void KexiFormDataProvider::invalidateDataSources( const QDict<char>& invalidSources,
+ KexiDB::QuerySchema* query)
+{
+ //fill m_fieldNumbersForDataItems mapping from data item to field number
+ //(needed for fillDataItems)
+ KexiDB::QueryColumnInfo::Vector fieldsExpanded;
+// uint dataFieldsCount; // == fieldsExpanded.count() if query is available or else == m_dataItems.count()
+
+ if (query) {
+ fieldsExpanded = query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields );
+// dataFieldsCount = fieldsExpanded.count();
+ QMap<KexiDB::QueryColumnInfo*,int> columnsOrder( query->columnsOrder() );
+ for (QMapConstIterator<KexiDB::QueryColumnInfo*,int> it = columnsOrder.constBegin(); it!=columnsOrder.constEnd(); ++it) {
+ kexipluginsdbg << "query->columnsOrder()[ " << it.key()->field->name() << " ] = " << it.data() << endl;
+ }
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ KexiFormDataItemInterface *item = it.current();
+ KexiDB::QueryColumnInfo* ci = query->columnInfo( it.current()->dataSource() );
+ int index = ci ? columnsOrder[ ci ] : -1;
+ kexipluginsdbg << "query->columnsOrder()[ " << (ci ? ci->field->name() : "") << " ] = " << index
+ << " (dataSource: " << item->dataSource() << ", name=" << dynamic_cast<QObject*>(item)->name() << ")" << endl;
+ if (index!=-1 && !m_fieldNumbersForDataItems[ item ])
+ m_fieldNumbersForDataItems.insert( item, index );
+ //todo
+ //WRONG: not only used data sources can be fetched!
+ // m_fieldNumbersForDataItems.insert( it.current(),
+ // m_usedDataSources.findIndex(it.current()->dataSource().lower()) );
+ }
+ }
+ else {//!query
+// dataFieldsCount = m_dataItems.count();
+ }
+
+#if 0 //moved down
+ //in 'newIndices' let's collect new indices for every data source
+ foreach(QValueList<uint>::ConstIterator, it, invalidSources) {
+ //all previous indices have corresponding data source
+// for (; i < (*it); i++) {
+// newIndices[i] = number++;
+ //kexipluginsdbg << "invalidateDataSources(): " << i << " -> " << number-1 << endl;
+// }
+ //this index have no corresponding data source
+// newIndices[i]=-1;
+ KexiFormDataItemInterface *item = m_dataItems.at( *it );
+ if (item)
+ item->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
+ m_dataItems.remove(*it);
+ kexipluginsdbg << "invalidateDataSources(): " << (*it) << " -> " << -1 << endl;
+// i++;
+ }
+#endif
+ //fill remaining part of the vector
+// for (; i < dataFieldsCount; i++) { //m_dataItems.count(); i++) {
+ //newIndices[i] = number++;
+ //kexipluginsdbg << "invalidateDataSources(): " << i << " -> " << number-1 << endl;
+ //}
+
+#if 0
+ //recreate m_fieldNumbersForDataItems and mark widgets with invalid data sources
+ KexiFormDataItemInterfaceToIntMap newFieldNumbersForDataItems;
+ foreach(KexiFormDataItemInterfaceToIntMap::ConstIterator, it, m_fieldNumbersForDataItems) {
+ bool ok;
+ const int newIndex = newIndices.at( it.data(), &ok );
+ if (ok && newIndex!=-1) {
+ kexipluginsdbg << "invalidateDataSources(): " << it.key()->dataSource() << ": " << it.data() << " -> " << newIndex << endl;
+ newFieldNumbersForDataItems.replace(it.key(), newIndex);
+ }
+ else {
+ kexipluginsdbg << "invalidateDataSources(): removing " << it.key()->dataSource() << endl;
+ m_dataItems.remove(it.key());
+ it.key()->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
+ }
+ }
+#endif
+// m_fieldNumbersForDataItems = newFieldNumbersForDataItems;
+
+ //update data sources set (some of them may be removed)
+ QDict<char> tmpUsedDataSources(1013);
+
+ if (query)
+ query->debug();
+
+ //if (query && m_dataItems.count()!=query->fieldCount()) {
+ // kdWarning() << "KexiFormDataProvider::invalidateDataSources(): m_dataItems.count()!=query->fieldCount() ("
+ // << m_dataItems.count() << "," << query->fieldCount() << ")" << endl;
+ //}
+ //i = 0;
+ m_disableFillDuplicatedDataItems = true; // temporary disable fillDuplicatedDataItems()
+ // because setColumnInfo() can activate it
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current();) {
+ KexiFormDataItemInterface * item = it.current();
+ if (invalidSources[ item->dataSource().lower() ]) {
+ item->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
+ m_dataItems.remove(item);
+ continue;
+ }
+ uint fieldNumber = m_fieldNumbersForDataItems[ item ];
+ if (query) {
+ KexiDB::QueryColumnInfo *ci = fieldsExpanded[fieldNumber];
+ item->setColumnInfo(ci);
+ kexipluginsdbg << "- item=" << dynamic_cast<QObject*>(item)->name()
+ << " dataSource=" << item->dataSource()
+ << " field=" << ci->field->name() << endl;
+ const int indexForVisibleLookupValue = ci->indexForVisibleLookupValue();
+ if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)fieldsExpanded.count()) {
+ //there's lookup column defined: set visible column as well
+ KexiDB::QueryColumnInfo *visibleColumnInfo = fieldsExpanded[ indexForVisibleLookupValue ];
+ if (visibleColumnInfo) {
+ item->setVisibleColumnInfo( visibleColumnInfo );
+ if (dynamic_cast<KexiComboBoxBase*>(item) && m_mainWidget
+ && dynamic_cast<KexiComboBoxBase*>(item)->internalEditor())
+ {
+ // m_mainWidget (dbform) should filter the (just created using setVisibleColumnInfo())
+ // combo box' internal editor (actually, only if the combo is in 'editable' mode)
+ dynamic_cast<KexiComboBoxBase*>(item)->internalEditor()->installEventFilter(m_mainWidget);
+ }
+ kexipluginsdbg << " ALSO SET visibleColumn=" << visibleColumnInfo->debugString()
+ << "\n at position " << indexForVisibleLookupValue << endl;
+ }
+ }
+ }
+ tmpUsedDataSources.replace( item->dataSource().lower(), (char*)1 );
+ ++it;
+ }
+ m_disableFillDuplicatedDataItems = false;
+ m_usedDataSources.clear();
+ foreach_list(QDictIterator<char>, it, tmpUsedDataSources) {
+ m_usedDataSources += it.currentKey();
+ }
+}
diff --git a/kexi/plugins/forms/kexidataprovider.h b/kexi/plugins/forms/kexidataprovider.h
new file mode 100644
index 00000000..64019842
--- /dev/null
+++ b/kexi/plugins/forms/kexidataprovider.h
@@ -0,0 +1,95 @@
+/* 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 KEXIFORMDATAPROVIDER_H
+#define KEXIFORMDATAPROVIDER_H
+
+#include "kexiformdataiteminterface.h"
+#include <qptrdict.h>
+#include <qdict.h>
+
+class KexiTableItem;
+namespace KexiDB {
+ class QuerySchema;
+}
+
+//! @short The KexiFormDataProvider class is a data provider for Kexi Forms
+/*! This provider collects data-aware widgets using setMainWidget().
+ Then, usedDataSources() unique list of required field names is available.
+ On every call of fillDataItems() method, the provider will fill data items
+ with appropriate data from a database cursor.
+
+ Field names are collected effectively, so eg. having widgets using data sources:
+ ("name", "surname", "surname", "name") - "name" and "surname" repeated - will only
+ return ("name", "surname") list, so the cursor's query can be simplified
+ and thus more effective.
+*/
+class KEXIFORMUTILS_EXPORT KexiFormDataProvider : public KexiDataItemChangesListener
+{
+ public:
+ KexiFormDataProvider();
+ virtual ~KexiFormDataProvider();
+
+ /*! sets \a mainWidget to be a main widget for this data provider.
+ Also find widgets whose will work as data items
+ (all of them must implement KexiFormDataItemInterface), so these could be
+ filled with data on demand. */
+ void setMainDataSourceWidget(QWidget* mainWidget);
+
+ QStringList usedDataSources() const { return m_usedDataSources; }
+
+ //unused QPtrList<KexiFormDataItemInterface>& dataItems() { return m_dataItems; }
+
+ /*! Fills data items with appropriate data fetched from \a cursor.
+ \a newRowEditing == true means that we are at new (not yet inserted) database row. */
+ void fillDataItems(KexiTableItem& row, bool cursorAtNewRow);
+
+ /*! Implementation for KexiDataItemChangesListener.
+ Reaction for change of \a item. Does nothing here. */
+ virtual void valueChanged(KexiDataItemInterface* item);
+
+ /*! Implementation for KexiDataItemChangesListener.
+ Implement this to return information whether we're currently at new row or now.
+ This can be used e.g. by data-aware widgets to determine if "(autonumber)"
+ label should be displayed. Returns false here. */
+ virtual bool cursorAtNewRow() const;
+
+ /*! Invalidates data sources collected by this provided.
+ \a invalidSources is the set of data sources that should
+ be omitted for fillDataItems().
+ Used by KexiFormView::initDataSource(). */
+ void invalidateDataSources( const QDict<char>& invalidSources,
+ KexiDB::QuerySchema* query = 0 );
+
+ /*! Fills the same data provided by \a value to every data item (other than \a item)
+ having the same data source as \a item. This method is called immediately when
+ \a value is changed, so duplicated data items are quickly updated. */
+ void fillDuplicatedDataItems(KexiFormDataItemInterface* item, const QVariant& value);
+
+ protected:
+ QWidget *m_mainWidget;
+ QPtrDict<char> *m_duplicatedItems;
+ typedef QMap<KexiFormDataItemInterface*,uint> KexiFormDataItemInterfaceToIntMap;
+ QPtrList<KexiFormDataItemInterface> m_dataItems;
+ QStringList m_usedDataSources;
+ KexiFormDataItemInterfaceToIntMap m_fieldNumbersForDataItems;
+ bool m_disableFillDuplicatedDataItems : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexidatasourcepage.cpp b/kexi/plugins/forms/kexidatasourcepage.cpp
new file mode 100644
index 00000000..6c0de830
--- /dev/null
+++ b/kexi/plugins/forms/kexidatasourcepage.cpp
@@ -0,0 +1,471 @@
+/* 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 "kexidatasourcepage.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qheader.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <ktoolbarbutton.h>
+#include <kdebug.h>
+#include <kpopupmenu.h>
+
+#include <widget/kexipropertyeditorview.h>
+#include <widget/kexidatasourcecombobox.h>
+#include <widget/kexifieldlistview.h>
+#include <widget/kexifieldcombobox.h>
+#include <widget/kexismalltoolbutton.h>
+#include <kexidb/connection.h>
+#include <kexiproject.h>
+
+#include <formeditor/commands.h>
+
+#include <koproperty/property.h>
+#include <koproperty/utils.h>
+
+KexiDataSourcePage::KexiDataSourcePage(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+ , m_insideClearDataSourceSelection(false)
+{
+ QVBoxLayout *vlyr = new QVBoxLayout(this);
+ m_objectInfoLabel = new KexiObjectInfoLabel(this, "KexiObjectInfoLabel");
+ vlyr->addWidget(m_objectInfoLabel);
+
+ m_noDataSourceAvailableSingleText = i18n("No data source could be assigned for this widget.");
+ m_noDataSourceAvailableMultiText = i18n("No data source could be assigned for multiple widgets.");
+
+ vlyr->addSpacing(8);
+
+ //Section 1: Form's/Widget's Data Source
+ KoProperty::GroupContainer *container = new KoProperty::GroupContainer(i18n("Data Source"), this);
+ vlyr->addWidget(container);
+
+ QWidget *contents = new QWidget(container);
+ container->setContents(contents);
+ QVBoxLayout *contentsVlyr = new QVBoxLayout(contents);
+
+ m_noDataSourceAvailableLabel = new QLabel(m_noDataSourceAvailableSingleText, contents);
+ m_noDataSourceAvailableLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ m_noDataSourceAvailableLabel->setMargin(2);
+ m_noDataSourceAvailableLabel->setAlignment(Qt::WordBreak | Qt::AlignBottom | Qt::AlignLeft);
+ contentsVlyr->addWidget(m_noDataSourceAvailableLabel);
+
+ //-Widget's Data Source
+ QHBoxLayout *hlyr = new QHBoxLayout(contentsVlyr);
+#if 0
+//! @todo unhide this when expression work
+// m_widgetDSLabel = new QLabel(i18n("Table Field, Query Field or Expression", "Source field or expression:"), this);
+#else
+ m_widgetDSLabel = new QLabel(i18n("Table Field or Query Field", "Widget's data source:"), contents);
+#endif
+ m_widgetDSLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ m_widgetDSLabel->setMargin(2);
+ m_widgetDSLabel->setMinimumHeight(IconSize(KIcon::Small)+4);
+ m_widgetDSLabel->setAlignment(AlignLeft|AlignBottom);
+ hlyr->addWidget(m_widgetDSLabel);
+
+ m_clearWidgetDSButton = new KexiSmallToolButton(contents, QString::null, "clear_left", "clearWidgetDSButton");
+ m_clearWidgetDSButton->setMinimumHeight(m_widgetDSLabel->minimumHeight());
+ QToolTip::add(m_clearWidgetDSButton, i18n("Clear widget's data source"));
+ hlyr->addWidget(m_clearWidgetDSButton);
+ connect(m_clearWidgetDSButton, SIGNAL(clicked()), this, SLOT(clearWidgetDataSourceSelection()));
+
+ m_sourceFieldCombo = new KexiFieldComboBox(contents, "sourceFieldCombo");
+ m_widgetDSLabel->setBuddy(m_sourceFieldCombo);
+ contentsVlyr->addWidget(m_sourceFieldCombo);
+
+/* m_dataSourceSeparator = new QFrame(contents);
+ m_dataSourceSeparator->setFrameShape(QFrame::HLine);
+ m_dataSourceSeparator->setFrameShadow(QFrame::Sunken);
+ contentsVlyr->addWidget(m_dataSourceSeparator);*/
+
+ contentsVlyr->addSpacing(8);
+
+ //- Form's Data Source
+ hlyr = new QHBoxLayout(contentsVlyr);
+ m_dataSourceLabel = new QLabel(i18n("Form's data source:"), contents);
+ m_dataSourceLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ m_dataSourceLabel->setMargin(2);
+ m_dataSourceLabel->setMinimumHeight(IconSize(KIcon::Small)+4);
+ m_dataSourceLabel->setAlignment(AlignLeft|AlignBottom);
+ hlyr->addWidget(m_dataSourceLabel);
+
+ m_gotoButton = new KexiSmallToolButton(contents, QString::null, "goto", "gotoButton");
+ m_gotoButton->setMinimumHeight(m_dataSourceLabel->minimumHeight());
+ QToolTip::add(m_gotoButton, i18n("Go to selected form's data source"));
+ hlyr->addWidget(m_gotoButton);
+ connect(m_gotoButton, SIGNAL(clicked()), this, SLOT(slotGotoSelected()));
+
+ m_clearDSButton = new KexiSmallToolButton(contents, QString::null, "clear_left", "clearDSButton");
+ m_clearDSButton->setMinimumHeight(m_dataSourceLabel->minimumHeight());
+ QToolTip::add(m_clearDSButton, i18n("Clear form's data source"));
+ hlyr->addWidget(m_clearDSButton);
+ connect(m_clearDSButton, SIGNAL(clicked()), this, SLOT(clearDataSourceSelection()));
+
+ m_dataSourceCombo = new KexiDataSourceComboBox(contents, "dataSourceCombo");
+ m_dataSourceLabel->setBuddy(m_dataSourceCombo);
+ contentsVlyr->addWidget(m_dataSourceCombo);
+
+#ifdef KEXI_NO_AUTOFIELD_WIDGET
+ m_availableFieldsLabel = 0;
+ m_addField = 0;
+// m_fieldListView = 0;
+ vlyr->addStretch();
+#else
+ vlyr->addSpacing(fontMetrics().height());
+/* QFrame *separator = new QFrame(this);
+ separator->setFrameShape(QFrame::HLine);
+ separator->setFrameShadow(QFrame::Sunken);
+ vlyr->addWidget(separator);*/
+/*
+ KPopupTitle *title = new KPopupTitle(this);
+ title->setTitle(i18n("Inserting fields"));
+ vlyr->addWidget(title);
+ vlyr->addSpacing(4);*/
+
+
+ //2. Inserting fields
+ container = new KoProperty::GroupContainer(i18n("Inserting Fields"), this);
+ vlyr->addWidget(container, 1);
+
+ //helper info
+//! @todo allow to hide such helpers by adding global option
+ contents = new QWidget(container);
+ container->setContents(contents);
+ contentsVlyr = new QVBoxLayout(contents);
+ hlyr = new QHBoxLayout(contentsVlyr);
+ m_mousePointerLabel = new QLabel(contents);
+ hlyr->addWidget(m_mousePointerLabel);
+ m_mousePointerLabel->setPixmap( SmallIcon("mouse_pointer") );
+ m_mousePointerLabel->setFixedWidth( m_mousePointerLabel->pixmap() ? m_mousePointerLabel->pixmap()->width() : 0);
+ m_availableFieldsDescriptionLabel = new QLabel(
+ i18n("Select fields from the list below and drag them onto a form or click the \"Insert\" button"), contents);
+ m_availableFieldsDescriptionLabel->setAlignment( Qt::AlignAuto | Qt::WordBreak );
+ hlyr->addWidget(m_availableFieldsDescriptionLabel);
+
+ //Available Fields
+ contentsVlyr->addSpacing(4);
+ hlyr = new QHBoxLayout(contentsVlyr);
+ m_availableFieldsLabel = new QLabel(i18n("Available fields:"), contents);
+ m_availableFieldsLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ m_availableFieldsLabel->setMargin(2);
+ m_availableFieldsLabel->setMinimumHeight(IconSize(KIcon::Small));
+ hlyr->addWidget(m_availableFieldsLabel);
+
+ m_addField = new KexiSmallToolButton(contents, i18n("Insert selected field into form", "Insert"),
+ "add_field", "addFieldButton");
+ m_addField->setMinimumHeight(m_availableFieldsLabel->minimumHeight());
+// m_addField->setTextPosition(QToolButton::Right);
+ m_addField->setFocusPolicy(StrongFocus);
+ QToolTip::add(m_addField, i18n("Insert selected fields into form"));
+ hlyr->addWidget(m_addField);
+ connect(m_addField, SIGNAL(clicked()), this, SLOT(slotInsertSelectedFields()));
+
+ m_fieldListView = new KexiFieldListView(contents, "fieldListView",
+ KexiFieldListView::ShowDataTypes | KexiFieldListView::AllowMultiSelection );
+ m_fieldListView->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
+ m_availableFieldsLabel->setBuddy(m_fieldListView);
+ contentsVlyr->addWidget(m_fieldListView, 1);
+ connect(m_fieldListView, SIGNAL(selectionChanged()), this, SLOT(slotFieldListViewSelectionChanged()));
+ connect(m_fieldListView, SIGNAL(fieldDoubleClicked(const QString&, const QString&, const QString&)),
+ this, SLOT(slotFieldDoubleClicked(const QString&, const QString&, const QString&)));
+#endif
+
+ vlyr->addStretch(1);
+
+ connect(m_dataSourceCombo, SIGNAL(textChanged(const QString &)), this, SLOT(slotDataSourceTextChanged(const QString &)));
+ connect(m_dataSourceCombo, SIGNAL(dataSourceChanged()), this, SLOT(slotDataSourceChanged()));
+ connect(m_sourceFieldCombo, SIGNAL(selected()), this, SLOT(slotFieldSelected()));
+
+ clearDataSourceSelection();
+ slotFieldListViewSelectionChanged();
+}
+
+KexiDataSourcePage::~KexiDataSourcePage()
+{
+}
+
+void KexiDataSourcePage::setProject(KexiProject *prj)
+{
+ m_sourceFieldCombo->setProject(prj);
+ m_dataSourceCombo->setProject(prj);
+}
+
+void KexiDataSourcePage::clearDataSourceSelection(bool alsoClearComboBox)
+{
+ if (m_insideClearDataSourceSelection)
+ return;
+ m_insideClearDataSourceSelection = true;
+ if (alsoClearComboBox && !m_dataSourceCombo->selectedName().isEmpty())
+ m_dataSourceCombo->setDataSource("", "");
+// if (!m_dataSourceCombo->currentText().isEmpty()) {
+// m_dataSourceCombo->setCurrentText("");
+// emit m_dataSourceCombo->dataSourceSelected();
+// }
+ m_clearDSButton->setEnabled(false);
+ m_gotoButton->setEnabled(false);
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ m_addField->setEnabled(false);
+ m_fieldListView->clear();
+#endif
+ m_insideClearDataSourceSelection = false;
+}
+
+void KexiDataSourcePage::clearWidgetDataSourceSelection()
+{
+ if (!m_sourceFieldCombo->currentText().isEmpty()) {
+ m_sourceFieldCombo->setCurrentText("");
+ m_sourceFieldCombo->setFieldOrExpression(QString::null);
+ slotFieldSelected();
+ }
+ m_clearWidgetDSButton->setEnabled(false);
+}
+
+void KexiDataSourcePage::slotGotoSelected()
+{
+ QCString mime = m_dataSourceCombo->selectedMimeType().latin1();
+ if (mime=="kexi/table" || mime=="kexi/query") {
+ if (m_dataSourceCombo->isSelectionValid())
+ emit jumpToObjectRequested(mime, m_dataSourceCombo->selectedName().latin1());
+ }
+}
+
+void KexiDataSourcePage::slotInsertSelectedFields()
+{
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ QStringList selectedFieldNames(m_fieldListView->selectedFieldNames());
+ if (selectedFieldNames.isEmpty())
+ return;
+
+ emit insertAutoFields(m_fieldListView->schema()->table() ? "kexi/table" : "kexi/query",
+ m_fieldListView->schema()->name(), selectedFieldNames);
+#endif
+}
+
+void KexiDataSourcePage::slotFieldDoubleClicked(const QString& sourceMimeType, const QString& sourceName,
+ const QString& fieldName)
+{
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ QStringList selectedFields;
+ selectedFields.append(fieldName);
+ emit insertAutoFields(sourceMimeType, sourceName, selectedFields);
+#endif
+}
+
+void KexiDataSourcePage::slotDataSourceTextChanged(const QString & string)
+{
+ Q_UNUSED(string);
+ const bool enable = m_dataSourceCombo->isSelectionValid(); //!string.isEmpty() && m_dataSourceCombo->selectedName() == string.latin1();
+ if (!enable) {
+ clearDataSourceSelection( m_dataSourceCombo->selectedName().isEmpty()/*alsoClearComboBox*/ );
+ }
+ updateSourceFieldWidgetsAvailability();
+/*#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ m_fieldListView->setEnabled(enable);
+// m_addField->setEnabled(enable);
+ m_availableFieldsLabel->setEnabled(enable);
+#endif*/
+}
+
+void KexiDataSourcePage::slotDataSourceChanged()
+{
+ if (!m_dataSourceCombo->project())
+ return;
+ QCString mime = m_dataSourceCombo->selectedMimeType().latin1();
+ bool dataSourceFound = false;
+ QCString name = m_dataSourceCombo->selectedName().latin1();
+ if ((mime=="kexi/table" || mime=="kexi/query") && m_dataSourceCombo->isSelectionValid()) {
+ KexiDB::TableOrQuerySchema *tableOrQuery = new KexiDB::TableOrQuerySchema(
+ m_dataSourceCombo->project()->dbConnection(), name, mime=="kexi/table");
+ if (tableOrQuery->table() || tableOrQuery->query()) {
+#ifdef KEXI_NO_AUTOFIELD_WIDGET
+ m_tableOrQuerySchema = tableOrQuery;
+#else
+ m_fieldListView->setSchema( tableOrQuery );
+#endif
+ dataSourceFound = true;
+ m_sourceFieldCombo->setTableOrQuery(name, mime=="kexi/table");
+ }
+ else {
+ delete tableOrQuery;
+ }
+ }
+ if (!dataSourceFound) {
+ m_sourceFieldCombo->setTableOrQuery("", true);
+ }
+ //if (m_sourceFieldCombo->hasFocus())
+// m_dataSourceCombo->setFocus();
+ m_clearDSButton->setEnabled(dataSourceFound);
+ m_gotoButton->setEnabled(dataSourceFound);
+ if (dataSourceFound) {
+ slotFieldListViewSelectionChanged();
+ } else {
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ m_addField->setEnabled(false);
+#endif
+ }
+ updateSourceFieldWidgetsAvailability();
+ emit formDataSourceChanged(mime, name);
+}
+
+void KexiDataSourcePage::slotFieldSelected()
+{
+ KexiDB::Field::Type dataType = KexiDB::Field::InvalidType;
+#ifdef KEXI_NO_AUTOFIELD_WIDGET
+ KexiDB::Field *field = m_tableOrQuerySchema->field( m_sourceFieldCombo->fieldOrExpression() ); //temp
+#else
+//! @todo this should also work for expressions
+ KexiDB::Field *field = m_fieldListView->schema()->field( m_sourceFieldCombo->fieldOrExpression() );
+#endif
+ if (field)
+ dataType = field->type();
+
+ m_clearWidgetDSButton->setEnabled( !m_sourceFieldCombo->fieldOrExpression().isEmpty() );
+
+ emit dataSourceFieldOrExpressionChanged(
+ m_sourceFieldCombo->fieldOrExpression(),
+ m_sourceFieldCombo->fieldOrExpressionCaption(),
+ dataType
+ );
+}
+
+void KexiDataSourcePage::setDataSource(const QCString& mimeType, const QCString& name)
+{
+ m_dataSourceCombo->setDataSource(mimeType, name);
+}
+
+void KexiDataSourcePage::assignPropertySet(KoProperty::Set* propertySet)
+{
+ QCString objectName;
+ if (propertySet && propertySet->contains("name"))
+ objectName = (*propertySet)["name"].value().toCString();
+ if (!objectName.isEmpty() && objectName == m_currentObjectName)
+ return; //the same object
+ m_currentObjectName = objectName;
+
+ QCString objectClassName;
+ if (propertySet && propertySet->contains("this:className"))
+ objectClassName = (*propertySet)["this:className"].value().toCString();
+/*moved if (propertySet) {
+ QCString iconName;
+ QString objectClassString;
+ if (propertySet->contains("this:iconName"))
+ iconName = (*propertySet)["this:iconName"].value().toCString();
+ if (propertySet->contains("this:classString"))
+ objectClassString = (*propertySet)["this:classString"].value().toString();
+ m_objectInfoLabel->setObjectName(objectName);
+ m_objectInfoLabel->setObjectClassIcon(iconName);
+ m_objectInfoLabel->setObjectClassName(objectClassString);
+ if (propertySet->contains("this:className"))
+ objectClassName = (*propertySet)["this:className"].value().toCString();
+ }*/
+ KexiPropertyEditorView::updateInfoLabelForPropertySet(
+ m_objectInfoLabel, propertySet);
+
+ const bool isForm = objectClassName=="KexiDBForm";
+// kdDebug() << "objectClassName=" << objectClassName << endl;
+// {
+/* //this is top level form's surface: data source means table or query
+ QCString dataSourceMimeType, dataSource;
+ if (buffer->hasProperty("dataSourceMimeType"))
+ dataSourceMimeType = (*buffer)["dataSourceMimeType"].value().toCString();
+ if (buffer->hasProperty("dataSource"))
+ dataSource = (*buffer)["dataSource"].value().toCString();
+ m_dataSourceCombo->setDataSource(dataSourceMimeType, dataSource);*/
+// }
+// else {
+
+ const bool multipleSelection = objectClassName=="special:multiple";
+ const bool hasDataSourceProperty = propertySet && propertySet->contains("dataSource") && !multipleSelection;
+
+ if (!isForm) {
+ //this is a widget
+ QCString dataSource;
+ if (hasDataSourceProperty) {
+ if (propertySet)
+ dataSource = (*propertySet)["dataSource"].value().toCString();
+ m_noDataSourceAvailableLabel->hide();
+ m_sourceFieldCombo->setFieldOrExpression(dataSource);
+ m_sourceFieldCombo->setEnabled(true);
+ m_clearWidgetDSButton->setEnabled(!m_sourceFieldCombo->currentText().isEmpty());
+ m_widgetDSLabel->show();
+ m_clearWidgetDSButton->show();
+ m_sourceFieldCombo->show();
+// m_dataSourceSeparator->hide();
+ updateSourceFieldWidgetsAvailability();
+ }
+ }
+
+ if (isForm) {
+ m_noDataSourceAvailableLabel->hide();
+// m_dataSourceSeparator->hide();
+ }
+ else if (!hasDataSourceProperty) {
+ if (multipleSelection)
+ m_noDataSourceAvailableLabel->setText(m_noDataSourceAvailableMultiText);
+ else
+ m_noDataSourceAvailableLabel->setText(m_noDataSourceAvailableSingleText);
+ m_noDataSourceAvailableLabel->show();
+// m_dataSourceSeparator->show();
+ //make 'No data source could be assigned' label's height the same as the 'source field' combo+label
+ m_noDataSourceAvailableLabel->setMinimumHeight(m_widgetDSLabel->height()
+ + m_sourceFieldCombo->height()/*-m_dataSourceSeparator->height()*/);
+ m_sourceFieldCombo->setCurrentText("");
+ }
+
+ if (isForm || !hasDataSourceProperty) {
+ //no source field can be set
+ m_widgetDSLabel->hide();
+ m_clearWidgetDSButton->hide();
+ m_sourceFieldCombo->hide();
+ }
+}
+
+void KexiDataSourcePage::slotFieldListViewSelectionChanged()
+{
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ //update "add field" button's state
+ for (QListViewItemIterator it(m_fieldListView); it.current(); ++it) {
+ if (it.current()->isSelected()) {
+ m_addField->setEnabled(true);
+ return;
+ }
+ }
+ m_addField->setEnabled(false);
+#endif
+}
+
+void KexiDataSourcePage::updateSourceFieldWidgetsAvailability()
+{
+ const bool hasDataSource = m_dataSourceCombo->isSelectionValid(); //!m_dataSourceCombo->selectedName().isEmpty();
+ m_sourceFieldCombo->setEnabled( hasDataSource );
+ m_widgetDSLabel->setEnabled( hasDataSource );
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ m_fieldListView->setEnabled( hasDataSource );
+ m_availableFieldsLabel->setEnabled( hasDataSource );
+ m_mousePointerLabel->setEnabled( hasDataSource );
+ m_availableFieldsDescriptionLabel->setEnabled( hasDataSource );
+#endif
+}
+
+#include "kexidatasourcepage.moc"
diff --git a/kexi/plugins/forms/kexidatasourcepage.h b/kexi/plugins/forms/kexidatasourcepage.h
new file mode 100644
index 00000000..0f113aa7
--- /dev/null
+++ b/kexi/plugins/forms/kexidatasourcepage.h
@@ -0,0 +1,112 @@
+/* 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 KEXIDATASOURCEPAGE_H
+#define KEXIDATASOURCEPAGE_H
+
+#include <qwidget.h>
+#include <kexidb/field.h>
+#include <kexidb/utils.h>
+#include <koproperty/set.h>
+
+class KCommand;
+class KexiObjectInfoLabel;
+class KexiDataSourceComboBox;
+class KexiFieldComboBox;
+class KexiFieldListView;
+class KexiProject;
+class QToolButton;
+class QLabel;
+class QFrame;
+
+//! A page within form designer's property tabbed pane, providing data source editor
+class KEXIFORMUTILS_EXPORT KexiDataSourcePage : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ KexiDataSourcePage(QWidget *parent, const char *name = 0);
+ virtual ~KexiDataSourcePage();
+
+ KexiDataSourceComboBox* dataSourceCombo() const { return m_dataSourceCombo; }
+ KexiObjectInfoLabel* objectInfoLabel() const { return m_objectInfoLabel; }
+
+ public slots:
+ void setProject(KexiProject *prj);
+ void clearDataSourceSelection(bool alsoClearComboBox = true);
+ void clearWidgetDataSourceSelection();
+
+ //! Sets data source of a currently selected form.
+ //! This is performed on form initialization and on activating.
+ void setDataSource(const QCString& mimeType, const QCString& name);
+
+ //! Receives a pointer to a new property \a set (from KexiFormView::managerPropertyChanged())
+ void assignPropertySet(KoProperty::Set* propertySet);
+
+ signals:
+ //! Signal emitted when helper button 'go to selected data source' is clicked.
+ void jumpToObjectRequested(const QCString& mime, const QCString& name);
+
+ //! Signal emitted when form's data source has been changed. It's connected to the Form Manager.
+ void formDataSourceChanged(const QCString& mime, const QCString& name);
+
+ /*! Signal emitted when current widget's data source (field/expression)
+ has been changed. It's connected to the Form Manager.
+ \a caption for this field is also provided (e.g. AutoField form widget use it) */
+ void dataSourceFieldOrExpressionChanged(const QString& string, const QString& caption,
+ KexiDB::Field::Type type);
+
+ /*! Signal emitted when 'insert fields' button has been clicked */
+ void insertAutoFields(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& fields);
+
+ protected slots:
+ void slotDataSourceTextChanged(const QString & string);
+ void slotDataSourceChanged();
+ void slotFieldSelected();
+ void slotGotoSelected();
+ void slotInsertSelectedFields();
+ void slotFieldListViewSelectionChanged();
+ void slotFieldDoubleClicked(const QString& sourceMimeType, const QString& sourceName,
+ const QString& fieldName);
+
+ protected:
+ void updateSourceFieldWidgetsAvailability();
+
+ KexiFieldComboBox *m_sourceFieldCombo;
+ KexiObjectInfoLabel *m_objectInfoLabel;
+ KexiDataSourceComboBox* m_dataSourceCombo;
+ QLabel *m_dataSourceLabel, *m_noDataSourceAvailableLabel,
+ *m_widgetDSLabel, *m_availableFieldsLabel,
+ *m_mousePointerLabel, *m_availableFieldsDescriptionLabel;
+ QToolButton *m_clearWidgetDSButton, *m_clearDSButton, *m_gotoButton, *m_addField;
+ QFrame *m_dataSourceSeparator;
+ QString m_noDataSourceAvailableSingleText, m_noDataSourceAvailableMultiText;
+ bool m_insideClearDataSourceSelection : 1;
+#ifdef KEXI_NO_AUTOFIELD_WIDGET
+ KexiDB::TableOrQuerySchema *m_tableOrQuerySchema; //!< temp.
+#else
+ KexiFieldListView* m_fieldListView;
+#endif
+
+ //! Used only in assignPropertySet() to check whether we already have the set assigned
+ QCString m_currentObjectName;
+ //QGuardedPtr<KoProperty::Set> m_propertySet;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexidbfactory.cpp b/kexi/plugins/forms/kexidbfactory.cpp
new file mode 100644
index 00000000..4ab05d76
--- /dev/null
+++ b/kexi/plugins/forms/kexidbfactory.cpp
@@ -0,0 +1,713 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ 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 <qpopupmenu.h>
+#include <qscrollview.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qstyle.h>
+
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kactioncollection.h>
+#include <kstdaction.h>
+
+#include <formeditor/container.h>
+#include <formeditor/form.h>
+#include <formeditor/formIO.h>
+#include <formeditor/formmanager.h>
+#include <formeditor/objecttree.h>
+#include <formeditor/utils.h>
+#include <kexidb/utils.h>
+#include <kexidb/connection.h>
+#include <kexipart.h>
+#include <formeditor/widgetlibrary.h>
+#include <kexigradientwidget.h>
+#include <keximainwindow.h>
+#include <kexiutils/utils.h>
+#include <widget/kexicustompropertyfactory.h>
+#include <widget/utils/kexicontextmenuutils.h>
+
+#include "kexiformview.h"
+#include "widgets/kexidbautofield.h"
+#include "widgets/kexidbcheckbox.h"
+#include "widgets/kexidbimagebox.h"
+//#include "widgets/kexidbdoublespinbox.h"
+//#include "widgets/kexidbintspinbox.h"
+#include "widgets/kexiframe.h"
+#include "widgets/kexidblabel.h"
+#include "widgets/kexidblineedit.h"
+#include "widgets/kexidbtextedit.h"
+#include "widgets/kexidbcombobox.h"
+#include "widgets/kexipushbutton.h"
+#include "widgets/kexidbform.h"
+#include "widgets/kexidbsubform.h"
+#include "kexidataawarewidgetinfo.h"
+
+#include "kexidbfactory.h"
+#include <core/kexi.h>
+
+
+//////////////////////////////////////////
+
+KexiDBFactory::KexiDBFactory(QObject *parent, const char *name, const QStringList &)
+ : KFormDesigner::WidgetFactory(parent, name)
+{
+ KFormDesigner::WidgetInfo *wi;
+ wi = new KexiDataAwareWidgetInfo(this);
+ wi->setPixmap("form");
+ wi->setClassName("KexiDBForm");
+ wi->setName(i18n("Form"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "form"));
+ wi->setDescription(i18n("A data-aware form widget"));
+ addClass(wi);
+
+#ifndef KEXI_NO_SUBFORM
+ wi = new KexiDataAwareWidgetInfo(this);
+ wi->setPixmap("subform");
+ wi->setClassName("KexiDBSubForm");
+ wi->addAlternateClassName("KexiSubForm", true/*override*/); //older
+ wi->setName(i18n("Sub Form"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "subForm"));
+ wi->setDescription(i18n("A form widget included in another Form"));
+ wi->setAutoSyncForProperty( "formName", false );
+ addClass(wi);
+#endif
+
+ // inherited
+ wi = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KLineEdit");
+ wi->setPixmap("lineedit");
+ wi->setClassName("KexiDBLineEdit");
+ wi->addAlternateClassName("QLineEdit", true/*override*/);
+ wi->addAlternateClassName("KLineEdit", true/*override*/);
+ wi->setIncludeFileName("klineedit.h");
+ wi->setName(i18n("Text Box"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "textBox"));
+ wi->setDescription(i18n("A widget for entering and displaying text"));
+ addClass(wi);
+
+ // inherited
+ wi = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KTextEdit");
+ wi->setPixmap("textedit");
+ wi->setClassName("KexiDBTextEdit");
+ wi->addAlternateClassName("QTextEdit", true/*override*/);
+ wi->addAlternateClassName("KTextEdit", true/*override*/);
+ wi->setIncludeFileName("ktextedit.h");
+ wi->setName(i18n("Text Editor"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "textEditor"));
+ wi->setDescription(i18n("A multiline text editor"));
+ addClass(wi);
+
+ wi = new KFormDesigner::WidgetInfo(
+ this, "containers", "QFrame" /*we're inheriting to get i18n'd strings already translated there*/);
+ wi->setPixmap("frame");
+ wi->setClassName("KexiFrame");
+ wi->addAlternateClassName("QFrame", true/*override*/);
+ wi->setName(i18n("Frame"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "frame"));
+ wi->setDescription(i18n("A simple frame widget"));
+ addClass(wi);
+
+ wi = new KexiDataAwareWidgetInfo(
+ this, "stdwidgets", "QLabel" /*we're inheriting to get i18n'd strings already translated there*/);
+ wi->setPixmap("label");
+ wi->setClassName("KexiDBLabel");
+ wi->addAlternateClassName("QLabel", true/*override*/);
+ wi->addAlternateClassName("KexiLabel", true/*override*/); //older
+ wi->setName(i18n("Text Label", "Label"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "label"));
+ wi->setDescription(i18n("A widget for displaying text"));
+ addClass(wi);
+
+#ifndef KEXI_NO_IMAGEBOX_WIDGET
+ wi = new KexiDataAwareWidgetInfo(
+ this, "stdwidgets", "KexiPictureLabel" /*we're inheriting to get i18n'd strings already translated there*/);
+ wi->setPixmap("pixmaplabel");
+ wi->setClassName("KexiDBImageBox");
+ wi->addAlternateClassName("KexiPictureLabel", true/*override*/);
+ wi->addAlternateClassName("KexiImageBox", true/*override*/); //older
+ wi->setName(i18n("Image Box"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "image"));
+ wi->setDescription(i18n("A widget for displaying images"));
+// wi->setCustomTypeForProperty("pixmapData", KexiCustomPropertyFactory::PixmapData);
+ wi->setCustomTypeForProperty("pixmapId", KexiCustomPropertyFactory::PixmapId);
+ addClass(wi);
+
+ setInternalProperty("KexiDBImageBox", "dontStartEditingOnInserting", "1");
+// setInternalProperty("KexiDBImageBox", "forceShowAdvancedProperty:pixmap", "1");
+#endif
+
+#ifdef KEXI_DB_COMBOBOX_WIDGET
+ wi = new KexiDataAwareWidgetInfo(
+ this, "stdwidgets", "KComboBox" /*we're inheriting to get i18n'd strings already translated there*/);
+ wi->setPixmap("combo");
+ wi->setClassName("KexiDBComboBox");
+ wi->addAlternateClassName("KComboBox", true/*override*/);
+ wi->setName(i18n("Combo Box"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "comboBox"));
+ wi->setDescription(i18n("A combo box widget"));
+ addClass(wi);
+#endif
+
+ wi = new KexiDataAwareWidgetInfo(this, "stdwidgets", "QCheckBox");
+ wi->setPixmap("check");
+ wi->setClassName("KexiDBCheckBox");
+ wi->addAlternateClassName("QCheckBox", true/*override*/);
+ wi->setName(i18n("Check Box"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "checkBox"));
+ wi->setDescription(i18n("A check box with text label"));
+ addClass(wi);
+
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ wi = new KexiDataAwareWidgetInfo(this);
+ wi->setPixmap("autofield");
+ wi->setClassName("KexiDBAutoField");
+ wi->addAlternateClassName("KexiDBFieldEdit", true/*override*/); //older
+ wi->setName(i18n("Auto Field"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters", "autoField"));
+ wi->setDescription(i18n("A widget containing an automatically selected editor "
+ "and a label to edit the value of a database field of any type."));
+ addClass(wi);
+#endif
+
+/*
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ KexiDataAwareWidgetInfo *wDate = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KDateWidget");
+#else
+ KexiDataAwareWidgetInfo *wDate = new KexiDataAwareWidgetInfo(this, "stdwidgets", "QDateEdit");
+#endif
+ wDate->setPixmap("dateedit");
+ wDate->setClassName("KexiDBDateEdit");
+ wDate->addAlternateClassName("QDateEdit", true);//override
+ wDate->addAlternateClassName("KDateWidget", true);//override
+ wDate->setName(i18n("Date Widget"));
+ wDate->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "dateWidget"));
+ wDate->setDescription(i18n("A widget to input and display a date"));
+ addClass(wDate);
+
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ KexiDataAwareWidgetInfo *wTime = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KTimeWidget");
+#else
+ KexiDataAwareWidgetInfo *wTime = new KexiDataAwareWidgetInfo(this, "stdwidgets", "QTimeEdit");
+#endif
+ wTime->setPixmap("timeedit");
+ wTime->setClassName("KexiDBTimeEdit");
+ wTime->addAlternateClassName("QTimeEdit", true);//override
+ wTime->addAlternateClassName("KTimeWidget", true);//override
+ wTime->setName(i18n("Time Widget"));
+ wTime->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "timeWidget"));
+ wTime->setDescription(i18n("A widget to input and display a time"));
+ addClass(wTime);
+
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,9)
+ KexiDataAwareWidgetInfo *wDateTime = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KDateTimeWidget");
+#else
+ KexiDataAwareWidgetInfo *wDateTime = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KDateTimeWidget");
+#endif
+ wDateTime->setPixmap("datetimeedit");
+ wDateTime->setClassName("KexiDBDateTimeEdit");
+ wDateTime->addAlternateClassName("QDateTimeEdit", true);//override
+ wDateTime->addAlternateClassName("KDateTimeWidget", true);//override
+ wDateTime->setName(i18n("Date/Time Widget"));
+ wDateTime->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "dateTimeWidget"));
+ wDateTime->setDescription(i18n("A widget to input and display a date and time"));
+ addClass(wDateTime);
+*/
+
+/* KexiDataAwareWidgetInfo *wIntSpinBox = new KexiDataAwareWidgetInfo(this, "stdwidgets", "KIntSpinBox");
+ wIntSpinBox->setPixmap("spin");
+ wIntSpinBox->setClassName("KexiDBIntSpinBox");
+ wIntSpinBox->addAlternateClassName("QSpinBox", true);
+ wIntSpinBox->addAlternateClassName("KIntSpinBox", true);
+ wIntSpinBox->setName(i18n("Integer Number Spin Box"));
+ wIntSpinBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "intSpinBox"));
+ wIntSpinBox->setDescription(i18n("A spin box widget to input and display integer numbers"));
+ addClass(wIntSpinBox);
+
+ KexiDataAwareWidgetInfo *wDoubleSpinBox = new KexiDataAwareWidgetInfo(this, "stdwidgets");
+ wDoubleSpinBox->setPixmap("spin");
+ wDoubleSpinBox->setClassName("KexiDBDoubleSpinBox");
+ wDoubleSpinBox->addAlternateClassName("KDoubleSpinBox", true);
+ wDoubleSpinBox->setName(i18n("Floating-point Number Spin Box"));
+ wDoubleSpinBox->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. It must _not_ contain white spaces and non latin1 characters.", "dblSpinBox"));
+ wDoubleSpinBox->setDescription(i18n("A spin box widget to input and display floating-point numbers"));
+ addClass(wDoubleSpinBox);*/
+
+ // inherited
+ wi = new KFormDesigner::WidgetInfo(
+ this, "stdwidgets", "KPushButton");
+ wi->addAlternateClassName("KexiPushButton");
+ wi->setName(i18n("Command Button"));
+ wi->setNamePrefix(
+ i18n("Widget name. This string will be used to name widgets of this class. "
+ "It must _not_ contain white spaces and non latin1 characters.", "button"));
+ wi->setDescription(i18n("A command button to execute actions"));
+ addClass(wi);
+
+ m_propDesc["dataSource"] = i18n("Data Source");
+ m_propDesc["formName"] = i18n("Form Name");
+ m_propDesc["onClickAction"] = i18n("On Click");
+ m_propDesc["onClickActionOption"] = i18n("On Click Option");
+ m_propDesc["autoTabStops"] = i18n("Auto Tab Order");
+ m_propDesc["shadowEnabled"] = i18n("Shadow Enabled");
+ m_propDesc["on"] = i18n("On: button", "On");
+
+ m_propDesc["widgetType"] = i18n("Editor Type");
+ //for autofield's type: inherit i18n from KexiDB
+ m_propValDesc["Auto"] = i18n("AutoField editor's type", "Auto");
+ m_propValDesc["Text"] = KexiDB::Field::typeName(KexiDB::Field::Text);
+ m_propValDesc["Integer"] = KexiDB::Field::typeName(KexiDB::Field::Integer);
+ m_propValDesc["Double"] = KexiDB::Field::typeName(KexiDB::Field::Double);
+ m_propValDesc["Boolean"] = KexiDB::Field::typeName(KexiDB::Field::Boolean);
+ m_propValDesc["Date"] = KexiDB::Field::typeName(KexiDB::Field::Date);
+ m_propValDesc["Time"] = KexiDB::Field::typeName(KexiDB::Field::Time);
+ m_propValDesc["DateTime"] = KexiDB::Field::typeName(KexiDB::Field::DateTime);
+ m_propValDesc["MultiLineText"] = i18n("AutoField editor's type", "Multiline Text");
+ m_propValDesc["ComboBox"] = i18n("AutoField editor's type", "Drop-Down List");
+ m_propValDesc["Image"] = i18n("AutoField editor's type", "Image");
+
+// m_propDesc["labelCaption"] = i18n("Label Text");
+ m_propDesc["autoCaption"] = i18n("Auto Label");
+ m_propDesc["foregroundLabelColor"] = i18n("Label Text Color");
+ m_propDesc["backgroundLabelColor"] = i18n("(a property name, keep the text narrow!)",
+ "Label Background\nColor");
+
+ m_propDesc["labelPosition"] = i18n("Label Position");
+ m_propValDesc["Left"] = i18n("Label Position", "Left");
+ m_propValDesc["Top"] = i18n("Label Position", "Top");
+ m_propValDesc["NoLabel"] = i18n("Label Position", "No Label");
+
+ m_propDesc["sizeInternal"] = i18n("Size");
+// m_propDesc["pixmap"] = i18n("Image");
+ m_propDesc["pixmapId"] = i18n("Image");
+ m_propDesc["scaledContents"] = i18n("Scaled Contents");
+ m_propDesc["keepAspectRatio"] = i18n("Keep Aspect Ratio (short)", "Keep Ratio");
+
+ //hide classes that are replaced by db-aware versions
+ hideClass("KexiPictureLabel");
+ hideClass("KComboBox");
+
+ //used in labels, frames...
+ m_propDesc["frameColor"] = i18n("Frame Color");
+ m_propDesc["dropDownButtonVisible"] =
+ i18n("Drop-Down Button for Image Box Visible (a property name, keep the text narrow!)",
+ "Drop-Down\nButton Visible");
+
+ //for checkbox
+ m_propValDesc["TristateDefault"] = i18n("Tristate checkbox, default", "Default");
+ m_propValDesc["TristateOn"] = i18n("Tristate checkbox, yes", "Yes");
+ m_propValDesc["TristateOff"] = i18n("Tristate checkbox, no", "No");
+
+ //for combobox
+ m_propDesc["editable"] = i18n("Editable combobox", "Editable");
+}
+
+KexiDBFactory::~KexiDBFactory()
+{
+}
+
+QWidget*
+KexiDBFactory::createWidget(const QCString &c, QWidget *p, const char *n,
+ KFormDesigner::Container *container, int options)
+{
+ kexipluginsdbg << "KexiDBFactory::createWidget() " << this << endl;
+
+ QWidget *w=0;
+ QString text( container->form()->library()->textForWidgetName(n, c) );
+ const bool designMode = options & KFormDesigner::WidgetFactory::DesignViewMode;
+
+ if(c == "KexiDBSubForm")
+ w = new KexiDBSubForm(container->form(), p, n);
+ else if(c == "KexiDBLineEdit")
+ {
+ w = new KexiDBLineEdit(p, n);
+ if (designMode)
+ w->setCursor(QCursor(Qt::ArrowCursor));
+ }
+ else if(c == "KexiDBTextEdit")
+ {
+ w = new KexiDBTextEdit(p, n);
+ if (designMode)
+ w->setCursor(QCursor(Qt::ArrowCursor));
+ }
+ else if(c == "QFrame" || c == "KexiFrame")
+ {
+ w = new KexiFrame(p, n);
+ new KFormDesigner::Container(container, w, container);
+ }
+ else if(c == "KexiDBLabel")
+ w = new KexiDBLabel(text, p, n);
+#ifndef KEXI_NO_IMAGEBOX_WIDGET
+ else if(c == "KexiDBImageBox") {
+ w = new KexiDBImageBox(designMode, p, n);
+ connect(w, SIGNAL(idChanged(long)), this, SLOT(slotImageBoxIdChanged(long)));
+ }
+#endif
+#ifndef KEXI_NO_AUTOFIELD_WIDGET
+ else if(c == "KexiDBAutoField")
+ w = new KexiDBAutoField(p, n, designMode);
+#endif
+ else if(c == "KexiDBCheckBox")
+ w = new KexiDBCheckBox(text, p, n);
+ else if(c == "KexiDBComboBox")
+ w = new KexiDBComboBox(p, n, designMode);
+/* else if(c == "KexiDBTimeEdit")
+ w = new KexiDBTimeEdit(QTime::currentTime(), p, n);
+ else if(c == "KexiDBDateEdit")
+ w = new KexiDBDateEdit(QDate::currentDate(), p, n);
+ else if(c == "KexiDBDateTimeEdit")
+ w = new KexiDBDateTimeEdit(QDateTime::currentDateTime(), p, n);*/
+// else if(c == "KexiDBIntSpinBox")
+// w = new KexiDBIntSpinBox(p, n);
+// else if(c == "KexiDBDoubleSpinBox")
+// w = new KexiDBDoubleSpinBox(p, n);
+ else if(c == "KPushButton" || c == "KexiPushButton")
+ w = new KexiPushButton(text, p, n);
+
+ return w;
+}
+
+bool
+KexiDBFactory::createMenuActions(const QCString &classname, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *)
+{
+ if(classname == "QPushButton" || classname == "KPushButton" || classname == "KexiPushButton")
+ {
+/*! @todo also call createMenuActions() for inherited factory! */
+ m_assignAction->plug( menu );
+ return true;
+ }
+ else if(classname == "KexiDBImageBox")
+ {
+ KexiDBImageBox *imageBox = static_cast<KexiDBImageBox*>(w);
+ imageBox->contextMenu()->updateActionsAvailability();
+ KActionCollection *ac = imageBox->contextMenu()->actionCollection();
+ KPopupMenu *subMenu = new KPopupMenu();
+//! @todo make these actions undoable/redoable
+ menu->insertItem(i18n("&Image"), subMenu);
+ ac->action("insert")->plug(subMenu);
+ ac->action("file_save_as")->plug(subMenu);
+ subMenu->insertSeparator();
+ ac->action("edit_cut")->plug(subMenu);
+ ac->action("edit_copy")->plug(subMenu);
+ ac->action("edit_paste")->plug(subMenu);
+ ac->action("delete")->plug(subMenu);
+ if (ac->action("properties")) {
+ subMenu->insertSeparator();
+ ac->action("properties")->plug(subMenu);
+ }
+ }
+ return false;
+}
+
+void
+KexiDBFactory::createCustomActions(KActionCollection* col)
+{
+ //this will create shared instance action for design mode (special collection is provided)
+ m_assignAction = new KAction( i18n("&Assign Action..."), SmallIconSet("form_action"),
+ 0, 0, 0, col, "widget_assign_action");
+}
+
+bool
+KexiDBFactory::startEditing(const QCString &classname, QWidget *w, KFormDesigner::Container *container)
+{
+ m_container = container;
+ if(classname == "KexiDBLineEdit")
+ {
+//! @todo this code should not be copied here but
+//! just inherited StdWidgetFactory::clearWidgetContent() should be called
+ KLineEdit *lineedit = static_cast<KLineEdit*>(w);
+ createEditor(classname, lineedit->text(), lineedit, container,
+ lineedit->geometry(), lineedit->alignment(), true);
+ return true;
+ }
+ if(classname == "KexiDBTextEdit")
+ {
+//! @todo this code should not be copied here but
+//! just inherited StdWidgetFactory::clearWidgetContent() should be called
+ KTextEdit *textedit = static_cast<KTextEdit*>(w);
+ createEditor(classname, textedit->text(), textedit, container,
+ textedit->geometry(), textedit->alignment(), true, true);
+ //copy a few properties
+ KTextEdit *ed = dynamic_cast<KTextEdit *>( editor(w) );
+ ed->setWrapPolicy(textedit->wrapPolicy());
+ ed->setWordWrap(textedit->wordWrap());
+ ed->setTabStopWidth(textedit->tabStopWidth());
+ ed->setWrapColumnOrWidth(textedit->wrapColumnOrWidth());
+ ed->setLinkUnderline(textedit->linkUnderline());
+ ed->setTextFormat(textedit->textFormat());
+ ed->setHScrollBarMode(textedit->hScrollBarMode());
+ ed->setVScrollBarMode(textedit->vScrollBarMode());
+ return true;
+ }
+ else if ( classname == "KexiDBLabel" ) {
+ KexiDBLabel *label = static_cast<KexiDBLabel*>(w);
+ m_widget = w;
+ if(label->textFormat() == RichText)
+ {
+ QString text = label->text();
+ if ( editRichText( label, text ) )
+ {
+ changeProperty( "textFormat", "RichText", container->form() );
+ changeProperty( "text", text, container->form() );
+ }
+
+ if ( classname == "KexiDBLabel" )
+ w->resize(w->sizeHint());
+ }
+ else
+ {
+ createEditor(classname, label->text(), label, container,
+ label->geometry(), label->alignment(),
+ false, label->alignment() & Qt::WordBreak /*multiline*/);
+ }
+ return true;
+ }
+ else if (classname == "KexiDBSubForm") {
+ // open the form in design mode
+ KexiMainWindow *mainWin = KexiUtils::findParent<KexiMainWindow>(w, "KexiMainWindow");
+ KexiDBSubForm *subform = static_cast<KexiDBSubForm*>(w);
+ if(mainWin) {
+ bool openingCancelled;
+ mainWin->openObject("kexi/form", subform->formName(), Kexi::DesignViewMode,
+ openingCancelled);
+ }
+ return true;
+ }
+#if 0
+ else if( (classname == "KexiDBDateEdit") || (classname == "KexiDBDateTimeEdit") || (classname == "KexiDBTimeEdit")
+ /*|| (classname == "KexiDBIntSpinBox") || (classname == "KexiDBDoubleSpinBox")*/ ) {
+ disableFilter(w, container);
+ return true;
+ }
+#endif
+ else if(classname == "KexiDBAutoField") {
+ if(static_cast<KexiDBAutoField*>(w)->hasAutoCaption())
+ return false; // caption is auto, abort editing
+ QLabel *label = static_cast<KexiDBAutoField*>(w)->label();
+ createEditor(classname, label->text(), label, container, label->geometry(), label->alignment());
+ return true;
+ }
+ else if (classname == "KexiDBCheckBox") {
+ KexiDBCheckBox *cb = static_cast<KexiDBCheckBox*>(w);
+ QRect r( cb->geometry() );
+ r.setLeft( r.left() + 2 + cb->style().subRect( QStyle::SR_CheckBoxIndicator, cb ).width() );
+ createEditor(classname, cb->text(), cb, container, r, Qt::AlignAuto);
+ return true;
+ }
+ else if(classname == "KexiDBImageBox") {
+ KexiDBImageBox *image = static_cast<KexiDBImageBox*>(w);
+ image->insertFromFile();
+ return true;
+ }
+ return false;
+}
+
+bool
+KexiDBFactory::previewWidget(const QCString &, QWidget *, KFormDesigner::Container *)
+{
+ return false;
+}
+
+bool
+KexiDBFactory::clearWidgetContent(const QCString & /*classname*/, QWidget *w)
+{
+//! @todo this code should not be copied here but
+//! just inherited StdWidgetFactory::clearWidgetContent() should be called
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>(w);
+ if(iface)
+ iface->clear();
+ return true;
+}
+
+QValueList<QCString>
+KexiDBFactory::autoSaveProperties(const QCString & /*classname*/)
+{
+ QValueList<QCString> lst;
+// if(classname == "KexiDBSubForm")
+ //lst << "formName";
+// if(classname == "KexiDBLineEdit")
+// lst += "dataSource";
+// if(classname == "KexiDBAutoField")
+// lst << "labelCaption";
+ return lst;
+}
+
+bool
+KexiDBFactory::isPropertyVisibleInternal(const QCString& classname, QWidget *w,
+ const QCString& property, bool isTopLevel)
+{
+ //general
+ if (property=="dataSource" || property=="dataSourceMimeType") {
+ return false; //force
+ }
+
+ bool ok = true;
+
+ if(classname == "KexiPushButton") {
+ ok = property!="isDragEnabled"
+#ifdef KEXI_NO_UNFINISHED
+ && property!="onClickAction" /*! @todo reenable */
+ && property!="onClickActionOption" /*! @todo reenable */
+ && property!="iconSet" /*! @todo reenable */
+ && property!="stdItem" /*! @todo reenable stdItem */
+#endif
+ ;
+ }
+ else if(classname == "KexiDBLineEdit")
+ ok = property!="urlDropsEnabled"
+ && property!="vAlign"
+#ifdef KEXI_NO_UNFINISHED
+ && property!="inputMask"
+ && property!="maxLength" //!< we may want to integrate this with db schema
+#endif
+ ;
+ else if(classname == "KexiDBComboBox")
+ ok = property!="autoCaption"
+ && property!="labelPosition"
+ && property!="widgetType"
+ && property!="fieldTypeInternal"
+ && property!="fieldCaptionInternal"; //hide properties that come with KexiDBAutoField
+ else if(classname == "KexiDBTextEdit")
+ ok = property!="undoDepth"
+ && property!="undoRedoEnabled" //always true!
+ && property!="dragAutoScroll" //always true!
+ && property!="overwriteMode" //always false!
+ && property!="resizePolicy"
+ && property!="autoFormatting" //too complex
+#ifdef KEXI_NO_UNFINISHED
+ && property!="paper"
+#endif
+ ;
+ else if(classname == "KexiDBSubForm")
+ ok = property!="dragAutoScroll"
+ && property!="resizePolicy"
+ && property!="focusPolicy";
+ else if(classname == "KexiDBForm")
+ ok = property!="iconText"
+ && property!="geometry" /*nonsense for toplevel widget; for size, "size" property is used*/;
+ else if(classname == "KexiDBLabel")
+ ok = property!="focusPolicy";
+ else if(classname == "KexiDBAutoField") {
+ if (!isTopLevel && property=="caption")
+ return true; //force
+ if (property=="fieldTypeInternal" || property=="fieldCaptionInternal"
+//! @todo unhide in 2.0
+ || property=="widgetType")
+ return false;
+ ok = property!="text"; /* "text" is not needed as "caption" is used instead */
+ }
+ else if (classname == "KexiDBImageBox") {
+ ok = property!="font" && property!="wordbreak";
+ }
+ else if(classname == "KexiDBCheckBox") {
+ //hide text property if the widget is a child of an autofield beause there's already "caption" for this purpose
+ if (property=="text" && w && dynamic_cast<KFormDesigner::WidgetWithSubpropertiesInterface*>(w->parentWidget()))
+ return false;
+ ok = property!="autoRepeat";
+ }
+
+ return ok && WidgetFactory::isPropertyVisibleInternal(classname, w, property, isTopLevel);
+}
+
+bool
+KexiDBFactory::propertySetShouldBeReloadedAfterPropertyChange(const QCString& classname,
+ QWidget *w, const QCString& property)
+{
+ Q_UNUSED(classname);
+ Q_UNUSED(w);
+ if (property=="fieldTypeInternal" || property=="widgetType")
+ return true;
+ return false;
+}
+
+bool
+KexiDBFactory::changeText(const QString &text)
+{
+ KFormDesigner::Form *form = m_container ? m_container->form() : 0;
+ if (!form)
+ return false;
+ if (!form->selectedWidget())
+ return false;
+ QCString n( form->selectedWidget()->className() );
+// QWidget *w = WidgetFactory::widget();
+ if(n == "KexiDBAutoField") {
+ changeProperty("caption", text, form);
+ return true;
+ }
+ //! \todo check field's geometry
+ return false;
+}
+
+void
+KexiDBFactory::resizeEditor(QWidget *editor, QWidget *w, const QCString &classname)
+{
+ //QSize s = widget->size();
+ //QPoint p = widget->pos();
+
+ if(classname == "KexiDBAutoField")
+ editor->setGeometry( static_cast<KexiDBAutoField*>(w)->label()->geometry() );
+}
+
+void
+KexiDBFactory::slotImageBoxIdChanged(KexiBLOBBuffer::Id_t id)
+{
+//old KexiFormView *formView = KexiUtils::findParent<KexiFormView>((QWidget*)m_widget, "KexiFormView");
+
+ // (js) heh, porting to KFormDesigner::FormManager::self() singleton took me entire day of work...
+ KFormDesigner::Form *form = KFormDesigner::FormManager::self()->activeForm();
+ KexiFormView *formView = form ? KexiUtils::findParent<KexiFormView>((QWidget*)form->widget(), "KexiFormView") : 0;
+ if (formView) {
+ changeProperty("pixmapId", (uint)/*! @todo unsafe */id, form);
+//old formView->setUnsavedLocalBLOB(m_widget, id);
+ formView->setUnsavedLocalBLOB(form->selectedWidget(), id);
+ }
+}
+
+KFORMDESIGNER_WIDGET_FACTORY(KexiDBFactory, kexidbwidgets)
+
+#include "kexidbfactory.moc"
diff --git a/kexi/plugins/forms/kexidbfactory.h b/kexi/plugins/forms/kexidbfactory.h
new file mode 100644
index 00000000..6064a001
--- /dev/null
+++ b/kexi/plugins/forms/kexidbfactory.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ 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 KEXIDBFACTORY_H
+#define KEXIDBFACTORY_H
+
+#include <formeditor/widgetfactory.h>
+
+class KAction;
+
+namespace KFormDesigner {
+ class Form;
+ class FormManager;
+}
+
+//! Kexi Factory (DB widgets + subform)
+class KexiDBFactory : public KFormDesigner::WidgetFactory
+{
+ Q_OBJECT
+
+ public:
+ KexiDBFactory(QObject *parent, const char *name, const QStringList &args);
+ virtual ~KexiDBFactory();
+
+ virtual QWidget *createWidget(const QCString &classname, QWidget *parent, const char *name,
+ KFormDesigner::Container *container, int options = DefaultOptions );
+
+ virtual void createCustomActions(KActionCollection* col);
+ virtual bool createMenuActions(const QCString &classname, QWidget *w, QPopupMenu *menu,
+ KFormDesigner::Container *container);
+ virtual bool startEditing(const QCString &classname, QWidget *w, KFormDesigner::Container *container);
+ virtual bool previewWidget(const QCString &, QWidget *, KFormDesigner::Container *);
+ virtual bool clearWidgetContent(const QCString &classname, QWidget *w);
+
+ //virtual void saveSpecialProperty(const QString &classname, const QString &name, const QVariant &value, QWidget *w,
+ //QDomElement &parentNode, QDomDocument &parent) {}
+ //virtual void readSpecialProperty(const QCString &classname, QDomElement &node, QWidget *w, KFormDesigner::ObjectTreeItem *item) {}
+ virtual QValueList<QCString> autoSaveProperties(const QCString &classname);
+
+ protected slots:
+ void slotImageBoxIdChanged(long id); /*KexiBLOBBuffer::Id_t*/
+
+ protected:
+ virtual bool changeText(const QString &newText);
+ virtual void resizeEditor(QWidget *editor, QWidget *widget, const QCString &classname);
+
+ virtual bool isPropertyVisibleInternal(const QCString& classname, QWidget *w,
+ const QCString& property, bool isTopLevel);
+
+ //! Sometimes property sets should be reloaded when a given property value changed.
+ virtual bool propertySetShouldBeReloadedAfterPropertyChange(const QCString& classname, QWidget *w,
+ const QCString& property);
+
+ KAction* m_assignAction;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexidbtextwidgetinterface.cpp b/kexi/plugins/forms/kexidbtextwidgetinterface.cpp
new file mode 100644
index 00000000..47eabe9d
--- /dev/null
+++ b/kexi/plugins/forms/kexidbtextwidgetinterface.cpp
@@ -0,0 +1,71 @@
+/* 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 "kexidbtextwidgetinterface.h"
+#include "kexiformdataiteminterface.h"
+#include <kexidb/queryschema.h>
+#include <kexiutils/utils.h>
+#include <qframe.h>
+#include <qpainter.h>
+
+KexiDBTextWidgetInterface::KexiDBTextWidgetInterface()
+ : m_autonumberDisplayParameters(0)
+{
+}
+
+KexiDBTextWidgetInterface::~KexiDBTextWidgetInterface()
+{
+ delete m_autonumberDisplayParameters;
+}
+
+void KexiDBTextWidgetInterface::setColumnInfo(KexiDB::QueryColumnInfo* cinfo, QWidget *w)
+{
+ if (cinfo->field->isAutoIncrement()) {
+ if (!m_autonumberDisplayParameters)
+ m_autonumberDisplayParameters = new KexiDisplayUtils::DisplayParameters();
+ KexiDisplayUtils::initDisplayForAutonumberSign(*m_autonumberDisplayParameters, w);
+ }
+}
+
+void KexiDBTextWidgetInterface::paint( QFrame *w, QPainter* p, bool textIsEmpty, int alignment, bool hasFocus )
+{
+ KexiFormDataItemInterface *dataItemIface = dynamic_cast<KexiFormDataItemInterface*>(w);
+ KexiDB::QueryColumnInfo *columnInfo = dataItemIface ? dataItemIface->columnInfo() : 0;
+ if (columnInfo && columnInfo->field && dataItemIface->cursorAtNewRow() && textIsEmpty) {
+ const int margin = w->lineWidth() + w->midLineWidth();
+ if (columnInfo->field->isAutoIncrement() && m_autonumberDisplayParameters) {
+ if (w->hasFocus()) {
+ p->setPen(
+ KexiUtils::blendedColors(
+ m_autonumberDisplayParameters->textColor, w->palette().active().base(), 1, 3));
+ }
+ KexiDisplayUtils::paintAutonumberSign(*m_autonumberDisplayParameters, p,
+ 2 + margin + w->margin(), margin, w->width() - margin*2 -2-2,
+ w->height() - margin*2 -2, alignment, hasFocus);
+ }
+ }
+}
+
+void KexiDBTextWidgetInterface::event( QEvent * e, QWidget *w, bool textIsEmpty )
+{
+ if (e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut) {
+ if (m_autonumberDisplayParameters && textIsEmpty)
+ w->repaint();
+ }
+}
diff --git a/kexi/plugins/forms/kexidbtextwidgetinterface.h b/kexi/plugins/forms/kexidbtextwidgetinterface.h
new file mode 100644
index 00000000..ca10fc4e
--- /dev/null
+++ b/kexi/plugins/forms/kexidbtextwidgetinterface.h
@@ -0,0 +1,53 @@
+/* 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 KexiDBTextWidgetInterface_H
+#define KexiDBTextWidgetInterface_H
+
+#include <widget/utils/kexidisplayutils.h>
+
+namespace KexiDB {
+ class QueryColumnInfo;
+}
+class QFrame;
+
+//! @short An interface providing common text editor's functionality
+/*! Widgets (e.g. KexiDBLineEdit, KexiDBTextEdit) implementing KexiFormDataItemInterface
+ use this interface to customize painting and data handling. */
+class KEXIFORMUTILS_EXPORT KexiDBTextWidgetInterface
+{
+ public:
+ KexiDBTextWidgetInterface();
+ ~KexiDBTextWidgetInterface();
+
+ //! Called from KexiFormDataItemInterface::setColumnInfo(KexiDB::QueryColumnInfo* cinfo) implementation.
+ void setColumnInfo(KexiDB::QueryColumnInfo* cinfo, QWidget *w);
+
+ //! Called from paintEvent( QPaintEvent *pe ) method of the data aware widget.
+ void paint( QFrame *w, QPainter *p, bool textIsEmpty, int alignment, bool hasFocus );
+
+ //! Called from event( QEvent * e ) method of the data aware widget.
+ void event( QEvent * e, QWidget *w, bool textIsEmpty );
+
+ protected:
+ //! parameters for displaying autonumber sign
+ KexiDisplayUtils::DisplayParameters *m_autonumberDisplayParameters;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexiformdataiteminterface.cpp b/kexi/plugins/forms/kexiformdataiteminterface.cpp
new file mode 100644
index 00000000..c87a2dab
--- /dev/null
+++ b/kexi/plugins/forms/kexiformdataiteminterface.cpp
@@ -0,0 +1,68 @@
+/* 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 "kexiformdataiteminterface.h"
+#include "kexiformscrollview.h"
+#include <kexidb/queryschema.h>
+#include <kexiutils/utils.h>
+
+KexiFormDataItemInterface::KexiFormDataItemInterface()
+ : KexiDataItemInterface()
+ , m_columnInfo(0)
+ , m_displayParametersForEnteredValue(0)
+ , m_displayParametersForDefaultValue(0)
+ , m_displayDefaultValue(false)
+{
+}
+
+KexiFormDataItemInterface::~KexiFormDataItemInterface()
+{
+ delete m_displayParametersForEnteredValue;
+ delete m_displayParametersForDefaultValue;
+}
+
+void KexiFormDataItemInterface::undoChanges()
+{
+// m_disable_signalValueChanged = true;
+ setValueInternal(QString::null, false);
+// m_disable_signalValueChanged = false;
+}
+
+KexiDB::Field* KexiFormDataItemInterface::field() const
+{
+ return m_columnInfo ? m_columnInfo->field : 0;
+}
+
+void KexiFormDataItemInterface::setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue)
+{
+ m_displayDefaultValue = displayDefaultValue;
+ if (!m_displayParametersForDefaultValue) {
+ m_displayParametersForEnteredValue = new KexiDisplayUtils::DisplayParameters(widget);
+ m_displayParametersForDefaultValue = new KexiDisplayUtils::DisplayParameters();
+ KexiDisplayUtils::initDisplayForDefaultValue(*m_displayParametersForDefaultValue, widget);
+ }
+}
+
+void KexiFormDataItemInterface::cancelEditor()
+{
+ QWidget *parentWidget = dynamic_cast<QWidget*>(this)->parentWidget();
+ KexiFormScrollView* view = KexiUtils::findParent<KexiFormScrollView>(parentWidget, "KexiFormScrollView");
+ if (view)
+ view->cancelEditor();
+}
diff --git a/kexi/plugins/forms/kexiformdataiteminterface.h b/kexi/plugins/forms/kexiformdataiteminterface.h
new file mode 100644
index 00000000..99d20db4
--- /dev/null
+++ b/kexi/plugins/forms/kexiformdataiteminterface.h
@@ -0,0 +1,145 @@
+/* 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 KEXIFORMDATAITEMINTERFACE_H
+#define KEXIFORMDATAITEMINTERFACE_H
+
+#include <widget/utils/kexidisplayutils.h>
+#include <kexidataiteminterface.h>
+#include <qwidget.h>
+
+namespace KexiDB {
+ class Field;
+}
+
+//! An interface for declaring form widgets to be data-aware.
+class KEXIFORMUTILS_EXPORT KexiFormDataItemInterface : public KexiDataItemInterface
+{
+ public:
+ KexiFormDataItemInterface();
+ virtual ~KexiFormDataItemInterface();
+
+ //! \return the name of the data source for this widget.
+ //! Data source usually means here a table or query, a field name or an expression.
+ inline QString dataSource() const { return m_dataSource; }
+
+ //! Sets the name of the data source for this widget.
+ //! Data source usually means here a table or query or field name name.
+ inline void setDataSource(const QString &ds) { m_dataSource = ds; }
+
+ /*! \return the mime type of the data source for this widget.
+ Data source mime type means here types like "kexi/table" or "kexi/query"
+ in.the data source is set to object (as within form or subform) or is empty
+ if the data source is set to table field or query column. */
+ inline QCString dataSourceMimeType() const { return m_dataSourceMimeType; }
+
+ /*! Sets the mime type of the data source for this widget.
+ Data source usually means here a "kexi/table" or "kexi/query".
+ @see dataSourceMimeType() */
+ inline void setDataSourceMimeType(const QCString &ds) { m_dataSourceMimeType = ds; }
+
+ /*! If \a displayDefaultValue is true, the value set by KexiDataItemInterface::setValue()
+ is displayed in a special way. Used by KexiFormDataProvider::fillDataItems().
+ \a widget is equal to 'this'.
+ You can reimplement this in the widget. Always call the superclass' implementation.
+ setDisplayDefaultValue(.., false) is called in KexiFormScrollView::valueChanged()
+ as a response on data change performed by user. */
+ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue);
+
+ /*! \return true if default value is displayed for this item. */
+ virtual bool hasDisplayedDefaultValue() const { return m_displayDefaultValue; }
+
+ /*! Convenience function: casts this item to a QWidget.
+ Can return 0 if the item is not a QWidget-derived object. */
+ virtual QWidget* widget() { return dynamic_cast<QWidget*>(this); }
+
+ /*! Sets 'invalid' state, e.g. a text editor widget should display
+ text \a displayText and become read only to prevent entering data,
+ because updating at the database backend is not available.
+ \a displayText is usually set to something i18n'd like "#NAME?".
+ Note: that even widgets that usualy do not display texts (e.g. pixmaps)
+ should display \a displayText too.
+ */
+ virtual void setInvalidState( const QString& displayText ) = 0;
+
+ /*! Changes 'read only' flag, for this widget.
+ Typically this flag can be passed to a widget itself,
+ e.g. KLineEdit::setReadOnly(bool). */
+ virtual void setReadOnly( bool readOnly ) = 0;
+
+ //! \return database column information for this item
+ virtual KexiDB::Field* field() const;
+
+ //! \return database column information for this item
+ virtual KexiDB::QueryColumnInfo* columnInfo() const { return m_columnInfo; }
+
+ /*! Used internally to set database column information.
+ Reimplement if you need to do additional actions,
+ e.g. set data validator based on field type. Don't forget about
+ calling superclass implementation. */
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo) { m_columnInfo = cinfo; }
+
+ /*! Used internally to set visible database column information.
+ Reimplemented in KexiDBComboBox: except for combo box, this does nothing. */
+ virtual void setVisibleColumnInfo(KexiDB::QueryColumnInfo* cinfo) { Q_UNUSED(cinfo); }
+
+ /*! \return visible database column information for this item.
+ Except for combo box, this is exactly the same as columnInfo(). */
+ virtual KexiDB::QueryColumnInfo* visibleColumnInfo() const { return columnInfo(); }
+
+ /*! Does nothing, because within forms, widgets are always visible. */
+ virtual void hideWidget() { }
+
+ /*! Does nothing, because within forms, widgets are always visible. */
+ virtual void showWidget() { }
+
+ /*! Undoes changes made to this item - just resets the widget to original value.
+ Note: This is internal method called by KexiFormScrollView::cancelEditor().
+ To cancel editing of the widget's data from the widget's code,
+ use KexiFormDataItemInterface::cancelEditor().
+ Reimplemented in KexiDBComboBox to also revert the visible value (i.e. text) to the original state.
+ */
+ virtual void undoChanges();
+
+ /* Cancels editing of the widget's data. This method just looks for
+ the (grand)parent KexiFormScrollView object and calls
+ KexiFormScrollView::cancelEditor(). */
+ void cancelEditor();
+
+ /*! @internal
+ Called by top-level form on key press event.
+ Default implementation does nothing.
+ Implement this if you want to handle key presses from within the editor widget item.
+ \return true if \a ke should be accepted by the widget item.
+ This method is used e.g. in KexiDBImageBox for Key_Escape to if the popup is visible,
+ so the key press won't be consumed to perform "cancel editing". */
+ virtual bool keyPressed(QKeyEvent *ke) { Q_UNUSED(ke); return false; };
+
+ protected:
+ QString m_dataSource;
+ QCString m_dataSourceMimeType;
+ KexiDB::QueryColumnInfo* m_columnInfo;
+ KexiDisplayUtils::DisplayParameters *m_displayParametersForEnteredValue; //!< used in setDisplayDefaultValue()
+ KexiDisplayUtils::DisplayParameters *m_displayParametersForDefaultValue; //!< used in setDisplayDefaultValue()
+ bool m_displayDefaultValue : 1; //!< used by setDisplayDefaultValue()
+
+ friend class KexiDBAutoField;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexiformeventhandler.cpp b/kexi/plugins/forms/kexiformeventhandler.cpp
new file mode 100644
index 00000000..01bca201
--- /dev/null
+++ b/kexi/plugins/forms/kexiformeventhandler.cpp
@@ -0,0 +1,188 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-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 "kexiformeventhandler.h"
+
+#include <qwidget.h>
+#include <qobjectlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <tableview/kexitableitem.h>
+#include <tableview/kexitableviewdata.h>
+#include <kexidb/queryschema.h>
+#include <keximainwindow.h>
+#include <kexidialogbase.h>
+#include <kexipart.h>
+#include <kexipartinfo.h>
+#include <kexipartitem.h>
+
+KexiFormEventAction::ActionData::ActionData()
+{
+}
+
+bool KexiFormEventAction::ActionData::isEmpty() const
+{
+ return string.isEmpty();
+}
+
+KexiPart::Info* KexiFormEventAction::ActionData::decodeString(
+ QString& actionType, QString& actionArg, bool& ok) const
+{
+ const int idx = string.find(':');
+ ok = false;
+ if (idx==-1)
+ return 0;
+ const QString _actionType = string.left(idx);
+ const QString _actionArg = string.mid(idx+1);
+ if (_actionType.isEmpty() || _actionArg.isEmpty())
+ return 0;
+ KexiPart::Info *info = 0;
+ if (_actionType!="kaction" && _actionType!="currentForm") {
+ info = Kexi::partManager().infoForMimeType( QString("kexi/%1").arg(_actionType) );
+ if (!info)
+ return 0;
+ }
+ actionType = _actionType;
+ actionArg = _actionArg;
+ ok = true;
+ return info;
+}
+
+//-------------------------------------
+
+KexiFormEventAction::KexiFormEventAction(KexiMainWindow *mainWin, QObject* parent,
+ const QString& actionName, const QString& objectName, const QString& actionOption)
+ : KAction(parent), m_mainWin(mainWin), m_actionName(actionName), m_objectName(objectName)
+ , m_actionOption(actionOption)
+{
+}
+
+KexiFormEventAction::~KexiFormEventAction()
+{
+}
+
+void KexiFormEventAction::activate()
+{
+ KexiProject* project = m_mainWin->project();
+ if (!project)
+ return;
+ KexiPart::Part* part = Kexi::partManager().partForMimeType(
+ QString("kexi/%1").arg(m_actionName) );
+ if (!part)
+ return;
+ KexiPart::Item* item = project->item( part->info(), m_objectName );
+ if (!item)
+ return;
+ bool actionCancelled = false;
+ if (m_actionOption.isEmpty()) { // backward compatibility (good defaults)
+ if (part->info()->isExecuteSupported())
+ part->execute(item, parent());
+ else
+ m_mainWin->openObject(item, Kexi::DataViewMode, actionCancelled);
+ }
+ else {
+//! @todo react on failure...
+ if (m_actionOption == "open")
+ m_mainWin->openObject(item, Kexi::DataViewMode, actionCancelled);
+ else if (m_actionOption == "execute")
+ part->execute(item, parent());
+ else if (m_actionOption == "print") {
+ if (part->info()->isPrintingSupported())
+ m_mainWin->printItem(item);
+ }
+ else if (m_actionOption == "printPreview") {
+ if (part->info()->isPrintingSupported())
+ m_mainWin->printPreviewForItem(item);
+ }
+ else if (m_actionOption == "pageSetup") {
+ if (part->info()->isPrintingSupported())
+ m_mainWin->showPageSetupForItem(item);
+ }
+ else if (m_actionOption == "exportToCSV"
+ || m_actionOption == "copyToClipboardAsCSV")
+ {
+ if (part->info()->isDataExportSupported())
+ m_mainWin->executeCustomActionForObject(item, m_actionOption);
+ }
+ else if (m_actionOption == "new")
+ m_mainWin->newObject( part->info(), actionCancelled );
+ else if (m_actionOption == "design")
+ m_mainWin->openObject(item, Kexi::DesignViewMode, actionCancelled);
+ else if (m_actionOption == "editText")
+ m_mainWin->openObject(item, Kexi::TextViewMode, actionCancelled);
+ else if (m_actionOption == "close") {
+ tristate res = m_mainWin->closeObject(item);
+ if (~res)
+ actionCancelled = true;
+ }
+ }
+}
+
+//------------------------------------------
+
+KexiFormEventHandler::KexiFormEventHandler()
+ : m_mainWidget(0)
+{
+}
+
+KexiFormEventHandler::~KexiFormEventHandler()
+{
+}
+
+void KexiFormEventHandler::setMainWidgetForEventHandling(KexiMainWindow *mainWin, QWidget* mainWidget)
+{
+ m_mainWidget = mainWidget;
+ if (!m_mainWidget)
+ return;
+
+ //find widgets whose will work as data items
+//! @todo look for other widgets too
+ QObjectList *l = m_mainWidget->queryList( "KexiPushButton" );
+ QObjectListIt it( *l );
+ QObject *obj;
+ for ( ; (obj = it.current()) != 0; ++it ) {
+ bool ok;
+ KexiFormEventAction::ActionData data;
+ data.string = obj->property("onClickAction").toString();
+ data.option = obj->property("onClickActionOption").toString();
+ if (data.isEmpty())
+ continue;
+
+ QString actionType, actionArg;
+ KexiPart::Info* partInfo = data.decodeString(actionType, actionArg, ok);
+ if (!ok)
+ continue;
+ if (actionType=="kaction" || actionType=="currentForm") {
+ KAction *action = mainWin->actionCollection()->action( actionArg.latin1() );
+ if (!action)
+ continue;
+ QObject::disconnect( obj, SIGNAL(clicked()), action, SLOT(activate()) ); //safety
+ QObject::connect( obj, SIGNAL(clicked()), action, SLOT(activate()) );
+ }
+ else if (partInfo) { //'open or execute' action
+ KexiFormEventAction* action = new KexiFormEventAction(mainWin, obj, actionType, actionArg,
+ data.option);
+ QObject::disconnect( obj, SIGNAL(clicked()), action, SLOT(activate()) );
+ QObject::connect( obj, SIGNAL(clicked()), action, SLOT(activate()) );
+ }
+ }
+ delete l;
+}
diff --git a/kexi/plugins/forms/kexiformeventhandler.h b/kexi/plugins/forms/kexiformeventhandler.h
new file mode 100644
index 00000000..e92e9ff9
--- /dev/null
+++ b/kexi/plugins/forms/kexiformeventhandler.h
@@ -0,0 +1,101 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-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 KEXIFORMEVENTHANDLER_H
+#define KEXIFORMEVENTHANDLER_H
+
+#include <qwidget.h>
+#include <kaction.h>
+
+class KexiMainWindow;
+namespace KexiPart {
+ class Info;
+}
+
+//! The KexiFormEventHandler class handles events defined within Kexi Forms
+/*! For now only "onClickAction" property of Push Button widget is handled:
+ It's possible to connect this event to predefined global action.
+
+ Note: This interface will be extended in the future!
+
+ @see KexiFormPart::slotAssignAction()
+ */
+class KEXIFORMUTILS_EXPORT KexiFormEventHandler
+{
+ public:
+ KexiFormEventHandler();
+ virtual ~KexiFormEventHandler();
+
+ /*! Sets \a mainWidget to be a main widget for this handler.
+ Also find widgets having action assigned and connects them
+ to appropriate actions.
+ For now, all of them must be KexiPushButton).
+ \a mainWin is used to get action list. */
+ void setMainWidgetForEventHandling(KexiMainWindow *mainWin, QWidget* mainWidget);
+
+ protected:
+ QWidget *m_mainWidget;
+};
+
+//! @internal form-level action for handling "on click" actions
+class KEXIFORMUTILS_EXPORT KexiFormEventAction : public KAction
+{
+ public:
+ //! A structure used in currentActionName()
+ class KEXIFORMUTILS_EXPORT ActionData
+ {
+ public:
+ ActionData();
+
+ /*! Decodes action string into action type/action argument parts.
+ Action string has to be in a form of "actiontype:actionarg"
+ - Action type is passed to \a actionType on success. Action type can be "kaction"
+ or any of the part names (see KexiPart::Info::objectName()), e.g. "table", "query", etc.
+ - Action argument can be an action name in case of "kaction" type or object name
+ in case of action of type "table", "query", etc.
+ \a ok is set to true on success and to false on failure. On failure no other
+ values are passed.
+ \return part info if action type is "table", "query", etc., or 0 for "kaction" type. */
+ KexiPart::Info* decodeString(QString& actionType, QString& actionArg, bool& ok) const;
+
+ //! \return true if the action is empty
+ bool isEmpty() const;
+
+ QString string; //!< action string with prefix, like "kaction:edit_copy" or "table:<tableName>"
+
+ QString option; //!< option used when name is "table/query/etc.:\<objectName\>" is set;
+ //!< can be set to "open", "design", "editText", etc.
+ //!< @see ActionToExecuteListView::showActionsForMimeType()
+ };
+
+ KexiFormEventAction(KexiMainWindow *mainWin, QObject* parent, const QString& actionName,
+ const QString& objectName, const QString& actionOption);
+ virtual ~KexiFormEventAction();
+
+ public slots:
+ //! Activates the action. If the object supports executing (macro, script),
+ //! it is executed; otherwise (table, query, form,...) it is opened in its data view.
+ virtual void activate();
+
+ private:
+ KexiMainWindow *m_mainWin;
+ QString m_actionName, m_objectName, m_actionOption;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexiformhandler.desktop b/kexi/plugins/forms/kexiformhandler.desktop
new file mode 100644
index 00000000..3b476daa
--- /dev/null
+++ b/kexi/plugins/forms/kexiformhandler.desktop
@@ -0,0 +1,115 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Kexi/Handler
+
+GenericName=Forms
+GenericName[bg]=Формуляри
+GenericName[br]=Paperennoù-reol
+GenericName[ca]=Formularis
+GenericName[cs]=Formuláře
+GenericName[cy]=Ffurflenni
+GenericName[da]=Formularer
+GenericName[de]=Formulare
+GenericName[el]=Φόρμες
+GenericName[eo]=Formularoj
+GenericName[es]=Formularios
+GenericName[et]=Vormid
+GenericName[eu]=Formularioak
+GenericName[fa]=برگه‌ها
+GenericName[fi]=Lomakkeet
+GenericName[fr]=Formulaires
+GenericName[fy]=Formulieren
+GenericName[ga]=Foirmeacha
+GenericName[gl]=Formularios
+GenericName[he]=טפסים
+GenericName[hi]=फॉर्म्स
+GenericName[hr]=Obrasci
+GenericName[hu]=Űrlapok
+GenericName[is]=Form
+GenericName[it]=Moduli
+GenericName[ja]=フォーム
+GenericName[km]=សំណុំបែបបទ
+GenericName[lt]=Formos
+GenericName[lv]=Formas
+GenericName[ms]=Borang
+GenericName[nb]=Skjema
+GenericName[nds]=Kiekwarken
+GenericName[ne]=फारमहरू
+GenericName[nn]=Skjema
+GenericName[pl]=Formularze
+GenericName[pt]=Formulários
+GenericName[pt_BR]=Formulários
+GenericName[ru]=Формы
+GenericName[se]=Skovit
+GenericName[sk]=Formuláre
+GenericName[sl]=Obrazci
+GenericName[sr]=Форме
+GenericName[sr@Latn]=Forme
+GenericName[sv]=Formulär
+GenericName[ta]=படிவங்கள்
+GenericName[tr]=Formlar
+GenericName[uk]=Форми
+GenericName[uz]=Shakllar
+GenericName[uz@cyrillic]=Шакллар
+GenericName[zh_CN]=表单
+GenericName[zh_TW]=表單
+Name=Forms
+Name[bg]=Формуляри
+Name[br]=Paperennoù-reol
+Name[ca]=Formularis
+Name[cs]=Formuláře
+Name[cy]=Ffurflenni
+Name[da]=Formularer
+Name[de]=Formulare
+Name[el]=Φόρμες
+Name[eo]=Formularoj
+Name[es]=Formularios
+Name[et]=Vormid
+Name[eu]=Formularioak
+Name[fa]=برگه‌ها
+Name[fi]=Lomakkeet
+Name[fr]=Formulaires
+Name[fy]=Formulieren
+Name[ga]=Foirmeacha
+Name[gl]=Formularios
+Name[he]=טפסים
+Name[hi]=फ़ॉर्म
+Name[hr]=Obrasci
+Name[hu]=Űrlapok
+Name[is]=Form
+Name[it]=Moduli
+Name[ja]=フォーム
+Name[km]=សំណុំបែបបទ
+Name[lt]=Formos
+Name[lv]=Formas
+Name[ms]=Borang
+Name[nb]=Skjema
+Name[nds]=Kiekwarken
+Name[ne]=फारमहरू
+Name[nn]=Skjema
+Name[pl]=Formularze
+Name[pt]=Formulários
+Name[pt_BR]=Formulários
+Name[ru]=Формы
+Name[se]=Skovit
+Name[sk]=Formuláre
+Name[sl]=Obrazci
+Name[sr]=Форме
+Name[sr@Latn]=Forme
+Name[sv]=Formulär
+Name[ta]=Kவிதி
+Name[tg]=Шаклҳо
+Name[tr]=Formlar
+Name[uk]=Форми
+Name[uz]=Shakllar
+Name[uz@cyrillic]=Шакллар
+Name[zh_CN]=表单
+Name[zh_TW]=表單
+X-KDE-Library=kexihandler_form
+X-KDE-ParentApp=kexi
+X-Kexi-PartVersion=2
+X-Kexi-TypeName=form
+X-Kexi-TypeMime=kexi/form
+X-Kexi-ItemIcon=form
+X-Kexi-SupportsDataExport=false
+X-Kexi-SupportsPrinting=false
diff --git a/kexi/plugins/forms/kexiformmanager.cpp b/kexi/plugins/forms/kexiformmanager.cpp
new file mode 100644
index 00000000..6134cfc8
--- /dev/null
+++ b/kexi/plugins/forms/kexiformmanager.cpp
@@ -0,0 +1,235 @@
+/* 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 "kexiformmanager.h"
+#include "widgets/kexidbform.h"
+#include "widgets/kexidbautofield.h"
+#include "kexiformscrollview.h"
+#include "kexiformview.h"
+#include "kexidatasourcepage.h"
+
+#include <formeditor/formmanager.h>
+#include <formeditor/widgetpropertyset.h>
+#include <formeditor/form.h>
+#include <formeditor/widgetlibrary.h>
+#include <formeditor/commands.h>
+#include <formeditor/objecttree.h>
+
+#include <koproperty/set.h>
+#include <koproperty/property.h>
+#include <widget/kexicustompropertyfactory.h>
+
+KexiFormManager::KexiFormManager(KexiPart::Part *parent, const char* name)
+ : KFormDesigner::FormManager(parent,
+ KFormDesigner::FormManager::HideEventsInPopupMenu |
+ KFormDesigner::FormManager::SkipFileActions |
+ KFormDesigner::FormManager::HideSignalSlotConnections
+ , name)
+ , m_part(parent)
+{
+ m_emitSelectionSignalsUpdatesPropertySet = true;
+ KexiCustomPropertyFactory::init();
+}
+
+KexiFormManager::~KexiFormManager()
+{
+}
+
+KAction* KexiFormManager::action( const char* name )
+{
+ KActionCollection *col = m_part->actionCollectionForMode(Kexi::DesignViewMode);
+ if (!col)
+ return 0;
+ QCString n( translateName( name ).latin1() );
+ KAction *a = col->action(n);
+ if (a)
+ return a;
+ KexiDBForm *dbform;
+ if (!activeForm() || !activeForm()->designMode()
+ || !(dbform = dynamic_cast<KexiDBForm*>(activeForm()->formWidget())))
+ return 0;
+ KexiFormScrollView *scrollViewWidget = dynamic_cast<KexiFormScrollView*>(dbform->dataAwareObject());
+ if (!scrollViewWidget)
+ return 0;
+ KexiFormView* formViewWidget = dynamic_cast<KexiFormView*>(scrollViewWidget->parent());
+ if (!formViewWidget)
+ return 0;
+ return formViewWidget->parentDialog()->mainWin()->actionCollection()->action(n);
+}
+
+KexiFormView* KexiFormManager::activeFormViewWidget() const
+{
+ KexiDBForm *dbform;
+ if (!activeForm() || !activeForm()->designMode()
+ || !(dbform = dynamic_cast<KexiDBForm*>(activeForm()->formWidget())))
+ return 0;
+ KexiFormScrollView *scrollViewWidget = dynamic_cast<KexiFormScrollView*>(dbform->dataAwareObject());
+ if (!scrollViewWidget)
+ return 0;
+ return dynamic_cast<KexiFormView*>(scrollViewWidget->parent());
+}
+
+void KexiFormManager::enableAction( const char* name, bool enable )
+{
+ KexiFormView* formViewWidget = activeFormViewWidget();
+ if (!formViewWidget)
+ return;
+// if (QString(name)=="layout_menu")
+// kdDebug() << "!!!!!!!!!!! " << enable << endl;
+ formViewWidget->setAvailable(translateName( name ).latin1(), enable);
+}
+
+void KexiFormManager::setFormDataSource(const QCString& mime, const QCString& name)
+{
+ if (!activeForm())
+ return;
+ KexiDBForm* formWidget = dynamic_cast<KexiDBForm*>(activeForm()->widget());
+ if (!formWidget)
+ return;
+
+// setPropertyValueInDesignMode(formWidget, "dataSource", name);
+
+ QCString oldDataSourceMimeType( formWidget->dataSourceMimeType() );
+ QCString oldDataSource( formWidget->dataSource().latin1() );
+ if (mime!=oldDataSourceMimeType || name!=oldDataSource) {
+ QMap<QCString, QVariant> propValues;
+ propValues.insert("dataSource", name);
+ propValues.insert("dataSourceMimeType", mime);
+ KFormDesigner::CommandGroup *group
+ = new KFormDesigner::CommandGroup(i18n("Set Form's Data Source to \"%1\"").arg(name), propertySet());
+ propertySet()->createPropertyCommandsInDesignMode(formWidget, propValues, group, true /*addToActiveForm*/);
+ }
+
+/*
+ if (activeForm()->selectedWidget() == formWidget) {
+ //active form is selected: just use properties system
+ KFormDesigner::WidgetPropertySet *set = propertySet();
+ if (!set || !set->contains("dataSource"))
+ return;
+ (*set)["dataSource"].setValue(name);
+ if (set->contains("dataSourceMimeType"))
+ (*set)["dataSourceMimeType"].setValue(mime);
+ return;
+ }
+
+ //active form isn't selected: change it's data source and mime type by hand
+ QCString oldDataSourceMimeType( formWidget->dataSourceMimeType() );
+ QCString oldDataSource( formWidget->dataSource().latin1() );
+
+ if (mime!=oldDataSourceMimeType || name!=oldDataSource) {
+ formWidget->setDataSourceMimeType(mime);
+ formWidget->setDataSource(name);
+ emit dirty(activeForm(), true);
+
+ activeForm()->addCommand(
+ new KFormDesigner::PropertyCommand(propertySet(), QString(formWidget->name()),
+ oldDataSource, name, "dataSource"),
+ false );
+
+ // If the property is changed, we add it in ObjectTreeItem modifProp
+ KFormDesigner::ObjectTreeItem *fromTreeItem = activeForm()->objectTree()->lookup(formWidget->name());
+ fromTreeItem->addModifiedProperty("dataSourceMimeType", mime);
+ fromTreeItem->addModifiedProperty("dataSource", name);
+ }*/
+}
+
+void KexiFormManager::setDataSourceFieldOrExpression(const QString& string, const QString& caption,
+ KexiDB::Field::Type type)
+{
+ if (!activeForm())
+ return;
+// KexiFormDataItemInterface* dataWidget = dynamic_cast<KexiFormDataItemInterface*>(activeForm()->selectedWidget());
+// if (!dataWidget)
+// return;
+
+ KFormDesigner::WidgetPropertySet *set = propertySet();
+ if (!set || !set->contains("dataSource"))
+ return;
+
+ (*set)["dataSource"].setValue(string);
+
+ if (set->contains("autoCaption") && (*set)["autoCaption"].value().toBool()) {
+ if (set->contains("fieldCaptionInternal"))
+ (*set)["fieldCaptionInternal"].setValue(caption);
+ }
+ if (//type!=KexiDB::Field::InvalidType &&
+ set->contains("widgetType") && (*set)["widgetType"].value().toString()=="Auto")
+ {
+ if (set->contains("fieldTypeInternal"))
+ (*set)["fieldTypeInternal"].setValue(type);
+ }
+
+/* QString oldDataSource( dataWidget->dataSource() );
+ if (string!=oldDataSource) {
+ dataWidget->setDataSource(string);
+ emit dirty(activeForm(), true);
+
+ buffer
+ }*/
+}
+
+void KexiFormManager::insertAutoFields(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& fields)
+{
+ KexiFormView* formViewWidget = activeFormViewWidget();
+ if (!formViewWidget || !formViewWidget->form() || !formViewWidget->form()->activeContainer())
+ return;
+ formViewWidget->insertAutoFields(sourceMimeType, sourceName, fields,
+ formViewWidget->form()->activeContainer());
+}
+
+void KexiFormManager::slotHistoryCommandExecuted()
+{
+ const KFormDesigner::CommandGroup *group = dynamic_cast<const KFormDesigner::CommandGroup*>(sender());
+ if (group) {
+ if (group->commands().count()==2) {
+ KexiDBForm* formWidget = dynamic_cast<KexiDBForm*>(activeForm()->widget());
+ if (!formWidget)
+ return;
+ QPtrListIterator<KCommand> it(group->commands());
+ const KFormDesigner::PropertyCommand* pc1 = dynamic_cast<const KFormDesigner::PropertyCommand*>(it.current());
+ ++it;
+ const KFormDesigner::PropertyCommand* pc2 = dynamic_cast<const KFormDesigner::PropertyCommand*>(it.current());
+ if (pc1 && pc2 && pc1->property()=="dataSource" && pc2->property()=="dataSourceMimeType") {
+ const QMap<QCString, QVariant>::const_iterator it1( pc1->oldValues().constBegin() );
+ const QMap<QCString, QVariant>::const_iterator it2( pc2->oldValues().constBegin() );
+ if (it1.key()==formWidget->name() && it2.key()==formWidget->name())
+ static_cast<KexiFormPart*>(m_part)->dataSourcePage()->setDataSource(
+ formWidget->dataSourceMimeType(), formWidget->dataSource().latin1());
+ }
+ }
+ }
+}
+
+/*
+bool KexiFormManager::loadFormFromDomInternal(Form *form, QWidget *container, QDomDocument &inBuf)
+{
+ QMap<QCString,QString> customProperties;
+ FormIO::loadFormFromDom(myform, container, domDoc, &customProperties);
+}
+
+bool KexiFormManager::saveFormToStringInternal(Form *form, QString &dest, int indent)
+{
+ QMap<QCString,QString> customProperties;
+ return KFormDesigner::FormIO::saveFormToString(form, dest, indent, &customProperties);
+}
+
+*/
+
+#include "kexiformmanager.moc"
diff --git a/kexi/plugins/forms/kexiformmanager.h b/kexi/plugins/forms/kexiformmanager.h
new file mode 100644
index 00000000..1cc5f0c6
--- /dev/null
+++ b/kexi/plugins/forms/kexiformmanager.h
@@ -0,0 +1,87 @@
+/* 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 KEXIFORMMANAGER_H
+#define KEXIFORMMANAGER_H
+
+#include <formmanager.h>
+#include <kexipart.h>
+
+class KCommand;
+class KexiFormView;
+
+//! @internal
+//! Used to customize KFormDesigner::FormManager behaviour.
+class KEXIFORMUTILS_EXPORT KexiFormManager : public KFormDesigner::FormManager
+{
+ Q_OBJECT
+
+ public:
+ KexiFormManager(KexiPart::Part *parent, const char* name = 0);
+ virtual ~KexiFormManager();
+
+ virtual KAction* action( const char* name );
+ virtual void enableAction( const char* name, bool enable );
+
+ public slots:
+ //! Receives signal from KexiDataSourcePage about changed form's data source
+ void setFormDataSource(const QCString& mime, const QCString& name);
+
+ /*! Receives signal from KexiDataSourcePage about changed widget's data source.
+ This is because we couldn't pass objects like KexiDB::QueryColumnInfo.
+
+ Also sets following things in KexiDBAutoField:
+ - caption related to the data source
+ - data type related to the data source */
+ void setDataSourceFieldOrExpression(const QString& string, const QString& caption,
+ KexiDB::Field::Type type);
+
+ /*! Receives signal from KexiDataSourcePage and inserts autofields onto the current form. */
+ void insertAutoFields(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& fields);
+
+ protected slots:
+ void slotHistoryCommandExecuted();
+
+ protected:
+ inline QString translateName( const char* name ) const;
+
+ private:
+ //! Helper: return active form's view widget or 0 if there's no active form having such widget
+ KexiFormView* activeFormViewWidget() const;
+
+// virtual bool loadFormFromDomInternal(Form *form, QWidget *container, QDomDocument &inBuf);
+// virtual bool saveFormToStringInternal(Form *form, QString &dest, int indent = 0);
+
+ KexiPart::Part* m_part;
+};
+
+QString KexiFormManager::translateName( const char* name ) const
+{
+ QString n( name );
+ //translate to our name space:
+ if (n.startsWith("align_") || n.startsWith("adjust_") || n.startsWith("layout_")
+ || n=="format_raise" || n=="format_raise" || n=="taborder" | n=="break_layout")
+ {
+ n.prepend("formpart_");
+ }
+ return n;
+}
+
+#endif
diff --git a/kexi/plugins/forms/kexiformpart.cpp b/kexi/plugins/forms/kexiformpart.cpp
new file mode 100644
index 00000000..8693cb5b
--- /dev/null
+++ b/kexi/plugins/forms/kexiformpart.cpp
@@ -0,0 +1,550 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 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 <kdebug.h>
+#include <kgenericfactory.h>
+#include <kdialogbase.h>
+#include <klistview.h>
+#include <ktabwidget.h>
+#include <kiconloader.h>
+#include <kcombobox.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include <kexiviewbase.h>
+#include <keximainwindow.h>
+#include <kexiproject.h>
+#include <kexipartitem.h>
+#include <kexidialogbase.h>
+#include <kexidatasourcecombobox.h>
+#include <kexidb/connection.h>
+#include <kexidb/fieldlist.h>
+#include <kexidb/field.h>
+#include <kexiutils/utils.h>
+
+#include <form.h>
+#include <formIO.h>
+#include <widgetpropertyset.h>
+#include <widgetlibrary.h>
+#include <objecttreeview.h>
+#include <koproperty/property.h>
+
+#include "kexiformview.h"
+#include "widgets/kexidbform.h"
+#include "kexiformscrollview.h"
+#include "kexiactionselectiondialog.h"
+#include "kexiformmanager.h"
+#include "kexiformpart.h"
+#include "kexidatasourcepage.h"
+
+//! @todo #define KEXI_SHOW_SPLITTER_WIDGET
+
+KFormDesigner::WidgetLibrary* KexiFormPart::static_formsLibrary = 0L;
+
+//! @internal
+class KexiFormPart::Private
+{
+ public:
+ Private()
+ {
+ }
+ ~Private()
+ {
+ delete static_cast<KFormDesigner::ObjectTreeView*>(objectTreeView);
+ delete static_cast<KexiDataSourcePage*>(dataSourcePage);
+ }
+// QGuardedPtr<KFormDesigner::FormManager> manager;
+ QGuardedPtr<KFormDesigner::ObjectTreeView> objectTreeView;
+ QGuardedPtr<KexiDataSourcePage> dataSourcePage;
+ KexiDataSourceComboBox *dataSourceCombo;
+};
+
+KexiFormPart::KexiFormPart(QObject *parent, const char *name, const QStringList &l)
+ : KexiPart::Part(parent, name, l)
+ , d(new Private())
+{
+ // REGISTERED ID:
+ m_registeredPartID = (int)KexiPart::FormObjectType;
+
+ kexipluginsdbg << "KexiFormPart::KexiFormPart()" << endl;
+ m_names["instanceName"]
+ = i18n("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). "
+ "Use '_' character instead of spaces. First character should be a..z character. "
+ "If you cannot use latin characters in your language, use english word.",
+ "form");
+ m_names["instanceCaption"] = i18n("Form");
+ m_supportedViewModes = Kexi::DataViewMode | Kexi::DesignViewMode;
+ m_newObjectsAreDirty = true;
+
+ // Only create form manager if it's not yet created.
+ // KexiReportPart could have created it already.
+ KFormDesigner::FormManager *formManager = KFormDesigner::FormManager::self();
+ if (!formManager)
+ formManager = new KexiFormManager(this, "kexi_form_and_report_manager");
+
+ // Create and store a handle to forms' library. Reports will have their own library too.
+/* @todo add configuration for supported factory groups */
+ QStringList supportedFactoryGroups;
+ supportedFactoryGroups += "kexi";
+ static_formsLibrary = KFormDesigner::FormManager::createWidgetLibrary(
+ formManager, supportedFactoryGroups);
+ static_formsLibrary->setAdvancedPropertiesVisible(false);
+ connect(static_formsLibrary, SIGNAL(widgetCreated(QWidget*)),
+ this, SLOT(slotWidgetCreatedByFormsLibrary(QWidget*)));
+
+ connect(KFormDesigner::FormManager::self()->propertySet(), SIGNAL(widgetPropertyChanged(QWidget *, const QCString &, const QVariant&)),
+ this, SLOT(slotPropertyChanged(QWidget *, const QCString &, const QVariant&)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(autoTabStopsSet(KFormDesigner::Form*,bool)),
+ this, SLOT(slotAutoTabStopsSet(KFormDesigner::Form*,bool)));
+}
+
+KexiFormPart::~KexiFormPart()
+{
+ delete d;
+}
+
+KFormDesigner::WidgetLibrary* KexiFormPart::library()
+{
+ return static_formsLibrary;
+}
+
+#if 0
+void KexiFormPart::initPartActions(KActionCollection *collection)
+{
+//this is automatic? -no
+//create child guicilent: guiClient()->setXMLFile("kexidatatableui.rc");
+
+ kexipluginsdbg<<"FormPart INIT ACTIONS***********************************************************************"<<endl;
+ //TODO
+
+ //guiClient()->setXMLFile("kexiformui.rc");
+//js m_manager->createActions(collection, 0);
+}
+
+void KexiFormPart::initInstanceActions( int mode, KActionCollection *col )
+{
+ if (mode==Kexi::DesignViewMode) {
+ KFormDesigner::FormManager::self()->createActions(col, 0);
+ new KAction(i18n("Edit Tab Order..."), "tab_order", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(editTabOrder()), col, "taborder");
+ new KAction(i18n("Adjust Size"), "viewmagfit", KShortcut(0), KFormDesigner::FormManager::self(), SLOT(ajustWidgetSize()), col, "adjust");
+ }
+ //TODO
+}
+#endif
+
+void KexiFormPart::initPartActions()
+{
+// new KAction(i18n("Show Form UI Code"), "show_form_ui", CTRL+Key_U, m_manager, SLOT(showFormUICode()),
+// guiClient()->actionCollection(), "show_form_ui");
+}
+
+void KexiFormPart::initInstanceActions()
+{
+#ifdef KEXI_DEBUG_GUI
+ kapp->config()->setGroup("General");
+ if (kapp->config()->readBoolEntry("showInternalDebugger", false)) {
+ new KAction(i18n("Show Form UI Code"), "compfile",
+ CTRL+Key_U, KFormDesigner::FormManager::self(), SLOT(showFormUICode()),
+ actionCollectionForMode(Kexi::DesignViewMode), "show_form_ui");
+ }
+#endif
+
+ KActionCollection *col = actionCollectionForMode(Kexi::DesignViewMode);
+ KFormDesigner::FormManager::self()->createActions( library(), col, (KXMLGUIClient*)col->parentGUIClient() ); //guiClient() );
+
+ //connect actions provided by widget factories
+ connect( col->action("widget_assign_action"), SIGNAL(activated()), this, SLOT(slotAssignAction()));
+
+ createSharedAction(Kexi::DesignViewMode, i18n("Clear Widget Contents"), "editclear", 0, "formpart_clear_contents");
+ createSharedAction(Kexi::DesignViewMode, i18n("Edit Tab Order..."), "tab_order", 0, "formpart_taborder");
+//TODO createSharedAction(Kexi::DesignViewMode, i18n("Edit Pixmap Collection"), "icons", 0, "formpart_pixmap_collection");
+//TODO createSharedAction(Kexi::DesignViewMode, i18n("Edit Form Connections"), "connections", 0, "formpart_connections");
+
+// KFormDesigner::CreateLayoutCommand
+
+ KAction *action = createSharedAction(Kexi::DesignViewMode, i18n("Layout Widgets"), "", 0, "formpart_layout_menu", "KActionMenu");
+ KActionMenu *menu = static_cast<KActionMenu*>(action);
+
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("&Horizontally"),
+ QString::null, 0, "formpart_layout_hbox"));
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("&Vertically"),
+ QString::null, 0, "formpart_layout_vbox"));
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("In &Grid"),
+ QString::null, 0, "formpart_layout_grid"));
+#ifdef KEXI_SHOW_SPLITTER_WIDGET
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("Horizontally in &Splitter"),
+ QString::null, 0, "formpart_layout_hsplitter"));
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("Verti&cally in Splitter"),
+ QString::null, 0, "formpart_layout_vsplitter"));
+#endif
+
+ createSharedAction(Kexi::DesignViewMode, i18n("&Break Layout"), QString::null, 0, "formpart_break_layout");
+/*
+ createSharedAction(Kexi::DesignViewMode, i18n("Lay Out Widgets &Horizontally"), QString::null, 0, "formpart_layout_hbox");
+ createSharedAction(Kexi::DesignViewMode, i18n("Lay Out Widgets &Vertically"), QString::null, 0, "formpart_layout_vbox");
+ createSharedAction(Kexi::DesignViewMode, i18n("Lay Out Widgets in &Grid"), QString::null, 0, "formpart_layout_grid");
+*/
+ createSharedAction(Kexi::DesignViewMode, i18n("Bring Widget to Front"), "raise", 0, "formpart_format_raise");
+ createSharedAction(Kexi::DesignViewMode, i18n("Send Widget to Back"), "lower", 0, "formpart_format_lower");
+
+#ifndef KEXI_NO_UNFINISHED
+ action = createSharedAction(Kexi::DesignViewMode, i18n("Other Widgets"), "", 0, "other_widgets_menu", "KActionMenu");
+#endif
+
+ action = createSharedAction(Kexi::DesignViewMode, i18n("Align Widgets Position"), "aoleft", 0, "formpart_align_menu", "KActionMenu");
+ menu = static_cast<KActionMenu*>(action);
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Left"), "aoleft", 0, "formpart_align_to_left") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Right"), "aoright", 0, "formpart_align_to_right") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Top"), "aotop", 0, "formpart_align_to_top") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Bottom"), "aobottom", 0, "formpart_align_to_bottom") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Grid"), "aopos2grid", 0, "formpart_align_to_grid") );
+
+ action = createSharedAction(Kexi::DesignViewMode, i18n("Adjust Widgets Size"), "aogrid", 0, "formpart_adjust_size_menu", "KActionMenu");
+ menu = static_cast<KActionMenu*>(action);
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Fit"), "aofit", 0, "formpart_adjust_to_fit") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Grid"), "aogrid", 0, "formpart_adjust_size_grid") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Shortest"), "aoshortest", 0, "formpart_adjust_height_small") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Tallest"), "aotallest", 0, "formpart_adjust_height_big") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Narrowest"), "aonarrowest", 0, "formpart_adjust_width_small") );
+ menu->insert( createSharedAction(Kexi::DesignViewMode, i18n("To Widest"), "aowidest", 0, "formpart_adjust_width_big") );
+}
+
+KexiDialogTempData*
+KexiFormPart::createTempData(KexiDialogBase* dialog)
+{
+ return new KexiFormPart::TempData(dialog);
+}
+
+KexiViewBase* KexiFormPart::createView(QWidget *parent, KexiDialogBase* dialog,
+ KexiPart::Item &item, int viewMode, QMap<QString,QString>*)
+{
+ Q_UNUSED( viewMode );
+
+ kexipluginsdbg << "KexiFormPart::createView()" << endl;
+ KexiMainWindow *win = dialog->mainWin();
+ if (!win || !win->project() || !win->project()->dbConnection())
+ return 0;
+
+ KexiFormView *view = new KexiFormView(win, parent, item.name().latin1(),
+ win->project()->dbConnection() );
+
+ return view;
+}
+
+void
+KexiFormPart::generateForm(KexiDB::FieldList *list, QDomDocument &domDoc)
+{
+ //this form generates a .ui from FieldList list
+ //basically that is a Label and a LineEdit for each field
+ domDoc = QDomDocument("UI");
+ QDomElement uiElement = domDoc.createElement("UI");
+ domDoc.appendChild(uiElement);
+ uiElement.setAttribute("version", "3.1");
+ uiElement.setAttribute("stdsetdef", 1);
+
+ QDomElement baseClass = domDoc.createElement("class");
+ uiElement.appendChild(baseClass);
+ QDomText baseClassV = domDoc.createTextNode("QWidget");
+ baseClass.appendChild(baseClassV);
+ QDomElement baseWidget = domDoc.createElement("widget");
+ baseWidget.setAttribute("class", "QWidget");
+
+ int y=0;
+
+ for(unsigned int i=0; i < list->fieldCount(); i++)
+ {
+ QDomElement lclass = domDoc.createElement("widget");
+ baseWidget.appendChild(lclass);
+ lclass.setAttribute("class", "QLabel");
+ QDomElement lNameProperty = domDoc.createElement("property");
+ lNameProperty.setAttribute("name", "name");
+ QDomElement lType = domDoc.createElement("cstring");
+ QDomText lClassN = domDoc.createTextNode(QString("l%1").arg(list->field(i)->name()));
+ lType.appendChild(lClassN);
+ lNameProperty.appendChild(lType);
+ lclass.appendChild(lNameProperty);
+
+ QDomElement gNameProperty = domDoc.createElement("property");
+ gNameProperty.setAttribute("name", "geometry");
+ QDomElement lGType = domDoc.createElement("rect");
+
+ QDomElement lx = domDoc.createElement("x");
+ QDomText lxV = domDoc.createTextNode("10");
+ lx.appendChild(lxV);
+ QDomElement ly = domDoc.createElement("y");
+ QDomText lyV = domDoc.createTextNode(QString::number(y + 10));
+ ly.appendChild(lyV);
+ QDomElement lWidth = domDoc.createElement("width");
+ QDomText lWidthV = domDoc.createTextNode("100");
+ lWidth.appendChild(lWidthV);
+ QDomElement lHeight = domDoc.createElement("height");
+ QDomText lHeightV = domDoc.createTextNode("20");
+ lHeight.appendChild(lHeightV);
+
+ lGType.appendChild(lx);
+ lGType.appendChild(ly);
+ lGType.appendChild(lWidth);
+ lGType.appendChild(lHeight);
+
+ gNameProperty.appendChild(lGType);
+ lclass.appendChild(gNameProperty);
+
+ QDomElement tNameProperty = domDoc.createElement("property");
+ tNameProperty.setAttribute("name", "text");
+ QDomElement lTType = domDoc.createElement("string");
+ QDomText lTextV = domDoc.createTextNode(list->field(i)->name());
+ lTType.appendChild(lTextV);
+ tNameProperty.appendChild(lTType);
+ lclass.appendChild(tNameProperty);
+
+
+ ///line edit!
+
+
+ QDomElement vclass = domDoc.createElement("widget");
+ baseWidget.appendChild(vclass);
+ vclass.setAttribute("class", "KLineEdit");
+ QDomElement vNameProperty = domDoc.createElement("property");
+ vNameProperty.setAttribute("name", "name");
+ QDomElement vType = domDoc.createElement("cstring");
+ QDomText vClassN = domDoc.createTextNode(list->field(i)->name());
+ vType.appendChild(vClassN);
+ vNameProperty.appendChild(vType);
+ vclass.appendChild(vNameProperty);
+
+ QDomElement vgNameProperty = domDoc.createElement("property");
+ vgNameProperty.setAttribute("name", "geometry");
+ QDomElement vGType = domDoc.createElement("rect");
+
+ QDomElement vx = domDoc.createElement("x");
+ QDomText vxV = domDoc.createTextNode("110");
+ vx.appendChild(vxV);
+ QDomElement vy = domDoc.createElement("y");
+ QDomText vyV = domDoc.createTextNode(QString::number(y + 10));
+ vy.appendChild(vyV);
+ QDomElement vWidth = domDoc.createElement("width");
+ QDomText vWidthV = domDoc.createTextNode("200");
+ vWidth.appendChild(vWidthV);
+ QDomElement vHeight = domDoc.createElement("height");
+ QDomText vHeightV = domDoc.createTextNode("20");
+ vHeight.appendChild(vHeightV);
+
+ vGType.appendChild(vx);
+ vGType.appendChild(vy);
+ vGType.appendChild(vWidth);
+ vGType.appendChild(vHeight);
+
+ vgNameProperty.appendChild(vGType);
+ vclass.appendChild(vgNameProperty);
+
+ y += 20;
+ }
+
+ QDomElement lNameProperty = domDoc.createElement("property");
+ lNameProperty.setAttribute("name", "name");
+ QDomElement lType = domDoc.createElement("cstring");
+ QDomText lClassN = domDoc.createTextNode("DBForm");
+ lType.appendChild(lClassN);
+ lNameProperty.appendChild(lType);
+ baseWidget.appendChild(lNameProperty);
+
+ QDomElement wNameProperty = domDoc.createElement("property");
+ wNameProperty.setAttribute("name", "geometry");
+ QDomElement wGType = domDoc.createElement("rect");
+
+ QDomElement wx = domDoc.createElement("x");
+ QDomText wxV = domDoc.createTextNode("0");
+ wx.appendChild(wxV);
+ QDomElement wy = domDoc.createElement("y");
+ QDomText wyV = domDoc.createTextNode("0");
+ wy.appendChild(wyV);
+ QDomElement wWidth = domDoc.createElement("width");
+ QDomText wWidthV = domDoc.createTextNode("340");
+ wWidth.appendChild(wWidthV);
+ QDomElement wHeight = domDoc.createElement("height");
+ QDomText wHeightV = domDoc.createTextNode(QString::number(y + 30));
+ wHeight.appendChild(wHeightV);
+
+ wGType.appendChild(wx);
+ wGType.appendChild(wy);
+ wGType.appendChild(wWidth);
+ wGType.appendChild(wHeight);
+
+ wNameProperty.appendChild(wGType);
+ baseWidget.appendChild(wNameProperty);
+
+ uiElement.appendChild(baseWidget);
+}
+
+void KexiFormPart::slotAutoTabStopsSet(KFormDesigner::Form *form, bool set)
+{
+ Q_UNUSED( form );
+
+ KoProperty::Property &p = (*KFormDesigner::FormManager::self()->propertySet())["autoTabStops"];
+ if (!p.isNull())
+ p.setValue(QVariant(set, 4));
+}
+
+void KexiFormPart::slotAssignAction()
+{
+ KexiDBForm *dbform;
+ if (!KFormDesigner::FormManager::self()->activeForm() || !KFormDesigner::FormManager::self()->activeForm()->designMode()
+ || !(dbform = dynamic_cast<KexiDBForm*>(KFormDesigner::FormManager::self()->activeForm()->formWidget())))
+ return;
+
+ KFormDesigner::WidgetPropertySet * propSet = KFormDesigner::FormManager::self()->propertySet();
+
+ KoProperty::Property &onClickActionProp = propSet->property("onClickAction");
+ if (onClickActionProp.isNull())
+ return;
+ KoProperty::Property &onClickActionOptionProp = propSet->property("onClickActionOption");
+ KexiFormEventAction::ActionData data;
+ data.string = onClickActionProp.value().toString();
+ if (!onClickActionOptionProp.isNull())
+ data.option = onClickActionOptionProp.value().toString();
+
+ KexiFormScrollView *scrollViewWidget = dynamic_cast<KexiFormScrollView*>(dbform->dataAwareObject());
+ if (!scrollViewWidget)
+ return;
+ KexiFormView* formViewWidget = dynamic_cast<KexiFormView*>(scrollViewWidget->parent());
+ if (!formViewWidget)
+ return;
+
+ KexiMainWindow * mainWin = formViewWidget->parentDialog()->mainWin();
+ KexiActionSelectionDialog dlg(mainWin, dbform, data,
+ propSet->property("name").value().toCString());
+
+ if(dlg.exec() == QDialog::Accepted) {
+ data = dlg.currentAction();
+ //update property value
+ propSet->property("onClickAction").setValue(data.string);
+ propSet->property("onClickActionOption").setValue(data.option);
+ }
+}
+
+QString
+KexiFormPart::i18nMessage(const QCString& englishMessage, KexiDialogBase* dlg) const
+{
+ Q_UNUSED(dlg);
+ if (englishMessage=="Design of object \"%1\" has been modified.")
+ return i18n("Design of form \"%1\" has been modified.");
+ if (englishMessage=="Object \"%1\" already exists.")
+ return i18n("Form \"%1\" already exists.");
+
+ return englishMessage;
+}
+
+void
+KexiFormPart::slotPropertyChanged(QWidget *w, const QCString &name, const QVariant &value)
+{
+ Q_UNUSED( w );
+
+ if (!KFormDesigner::FormManager::self()->activeForm())
+ return;
+ if (name == "autoTabStops") {
+ //QWidget *w = KFormDesigner::FormManager::self()->activeForm()->selectedWidget();
+ //update autoTabStops setting at KFD::Form level
+ KFormDesigner::FormManager::self()->activeForm()->setAutoTabStops( value.toBool() );
+ }
+ if (KFormDesigner::FormManager::self()->activeForm()->widget() && name == "geometry") {
+ //fall back to sizeInternal property....
+ if (KFormDesigner::FormManager::self()->propertySet()->contains("sizeInternal"))
+ KFormDesigner::FormManager::self()->propertySet()->property("sizeInternal").setValue(value.toRect().size());
+ }
+}
+
+/*KFormDesigner::FormManager*
+KexiFormPart::manager() const
+{
+ return d->manager;
+}*/
+
+KexiDataSourcePage* KexiFormPart::dataSourcePage() const
+{
+ return d->dataSourcePage;
+}
+
+void KexiFormPart::setupCustomPropertyPanelTabs(KTabWidget *tab, KexiMainWindow* mainWin)
+{
+ if (!d->objectTreeView) {
+ d->objectTreeView = new KFormDesigner::ObjectTreeView(0, "KexiFormPart:ObjectTreeView");
+ KFormDesigner::FormManager::self()->setObjectTreeView(d->objectTreeView); //important: assign to manager
+ d->dataSourcePage = new KexiDataSourcePage(0, "dataSourcePage");
+ connect(d->dataSourcePage, SIGNAL(jumpToObjectRequested(const QCString&, const QCString&)),
+ mainWin, SLOT(highlightObject(const QCString&, const QCString&)));
+ connect(d->dataSourcePage, SIGNAL(formDataSourceChanged(const QCString&, const QCString&)),
+ KFormDesigner::FormManager::self(), SLOT(setFormDataSource(const QCString&, const QCString&)));
+ connect(d->dataSourcePage, SIGNAL(dataSourceFieldOrExpressionChanged(const QString&, const QString&, KexiDB::Field::Type)),
+ KFormDesigner::FormManager::self(), SLOT(setDataSourceFieldOrExpression(const QString&, const QString&, KexiDB::Field::Type)));
+ connect(d->dataSourcePage, SIGNAL(insertAutoFields(const QString&, const QString&, const QStringList&)),
+ KFormDesigner::FormManager::self(), SLOT(insertAutoFields(const QString&, const QString&, const QStringList&)));
+ }
+
+ KexiProject *prj = mainWin->project();
+ d->dataSourcePage->setProject(prj);
+
+ tab->addTab( d->dataSourcePage, SmallIconSet("database"), "");
+ tab->setTabToolTip( d->dataSourcePage, i18n("Data Source"));
+
+ tab->addTab( d->objectTreeView, SmallIconSet("widgets"), "");
+ tab->setTabToolTip( d->objectTreeView, i18n("Widgets"));
+}
+
+void KexiFormPart::slotWidgetCreatedByFormsLibrary(QWidget* widget)
+{
+ QStrList signalNames(widget->metaObject()->signalNames());
+ if (!signalNames.isEmpty()) {
+ const char *handleDragMoveEventSignal = "handleDragMoveEvent(QDragMoveEvent*)";
+ const char *handleDropEventSignal = "handleDropEvent(QDropEvent*)";
+
+ for (QStrListIterator it(signalNames); it.current(); ++it) {
+ if (0==qstrcmp(it.current(), handleDragMoveEventSignal)) {
+ kdDebug() << it.current() << endl;
+ KexiFormView *formView = KexiUtils::findParent<KexiFormView>(widget, "KexiFormView");
+ if (formView) {
+ connect(widget, SIGNAL(handleDragMoveEvent(QDragMoveEvent*)),
+ formView, SLOT(slotHandleDragMoveEvent(QDragMoveEvent*)));
+ }
+ }
+ else if (0==qstrcmp(it.current(), handleDropEventSignal)) {
+ kdDebug() << it.current() << endl;
+ KexiFormView *formView = KexiUtils::findParent<KexiFormView>(widget, "KexiFormView");
+ if (formView) {
+ connect(widget, SIGNAL(handleDropEvent(QDropEvent*)),
+ formView, SLOT(slotHandleDropEvent(QDropEvent*)));
+ }
+ }
+ }
+ }
+}
+
+//----------------
+
+KexiFormPart::TempData::TempData(QObject* parent)
+ : KexiDialogTempData(parent)
+{
+}
+
+KexiFormPart::TempData::~TempData()
+{
+}
+
+#include "kexiformpart.moc"
diff --git a/kexi/plugins/forms/kexiformpart.h b/kexi/plugins/forms/kexiformpart.h
new file mode 100644
index 00000000..1ddbab53
--- /dev/null
+++ b/kexi/plugins/forms/kexiformpart.h
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 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 KEXIFORMPART_H
+#define KEXIFORMPART_H
+
+#include <qdom.h>
+#include <qcstring.h>
+
+#include <kexi.h>
+#include <kexipart.h>
+#include <kexidialogbase.h>
+#include <kexiblobbuffer.h>
+
+namespace KFormDesigner
+{
+ class WidgetLibrary;
+ class FormManager;
+ class Form;
+}
+
+namespace KexiDB
+{
+ class FieldList;
+}
+
+class KexiDataSourcePage;
+
+//! Kexi Form Plugin
+/*! It just creates a \ref KexiFormView. See there for most of code. */
+class KEXIFORMUTILS_EXPORT KexiFormPart : public KexiPart::Part
+{
+ Q_OBJECT
+
+ public:
+ KexiFormPart(QObject *parent, const char *name, const QStringList &);
+ virtual ~KexiFormPart();
+
+ //! \return a pointer to Forms Widget Library.
+ static KFormDesigner::WidgetLibrary* library();
+
+ KexiDataSourcePage* dataSourcePage() const;
+
+ void generateForm(KexiDB::FieldList *list, QDomDocument &domDoc);
+
+ class TempData : public KexiDialogTempData
+ {
+ public:
+ TempData(QObject* parent);
+ ~TempData();
+ QGuardedPtr<KFormDesigner::Form> form;
+ QGuardedPtr<KFormDesigner::Form> previewForm;
+ QString tempForm;
+ QPoint scrollViewContentsPos; //!< to preserve contents pos after switching to other view
+ int resizeMode; //!< form's window's resize mode -one of KexiFormView::ResizeMode items
+ //! Used in KexiFormView::setUnsavedLocalBLOBs()
+ QMap<QWidget*, KexiBLOBBuffer::Id_t> unsavedLocalBLOBs;
+ //! Used when loading a form from (temporary) XML in Data View
+ //! to get unsaved blobs collected at design mode.
+ QMap<QCString, KexiBLOBBuffer::Id_t> unsavedLocalBLOBsByName;
+ };
+
+ virtual QString i18nMessage(const QCString& englishMessage,
+ KexiDialogBase* dlg) const;
+
+ protected:
+ virtual KexiDialogTempData* createTempData(KexiDialogBase* dialog);
+
+ virtual KexiViewBase* createView(QWidget *parent, KexiDialogBase* dialog,
+ KexiPart::Item &item, int viewMode = Kexi::DataViewMode, QMap<QString,QString>* staticObjectArgs = 0);
+
+ virtual void initPartActions();
+ virtual void initInstanceActions();
+ virtual void setupCustomPropertyPanelTabs(KTabWidget *tab, KexiMainWindow* mainWin);
+
+ static KFormDesigner::WidgetLibrary* static_formsLibrary;
+
+ protected slots:
+ void slotAutoTabStopsSet(KFormDesigner::Form *form, bool set);
+ void slotAssignAction();
+ void slotPropertyChanged(QWidget *widget, const QCString &name, const QVariant &value);
+ void slotWidgetCreatedByFormsLibrary(QWidget* widget);
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif
+
diff --git a/kexi/plugins/forms/kexiformpartinstui.rc b/kexi/plugins/forms/kexiformpartinstui.rc
new file mode 100644
index 00000000..75f233f2
--- /dev/null
+++ b/kexi/plugins/forms/kexiformpartinstui.rc
@@ -0,0 +1,77 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kexiformpartinst" version="13">
+
+<MenuBar>
+ <Menu name="edit">
+ <Action name="fompart_clear_contents"/>
+ <Separator />
+ <Action name="formpart_taborder"/>
+ <Action name="formpart_adjust_size"/>
+ <Action name="formpart_pixmap_collection"/>
+ <Action name="formpart_connections"/>
+ <!-- Action name="change_style"/ -->
+ </Menu>
+ <Menu name="format" noMerge="0">
+ <text>&amp;Format</text>
+ <Action name="snap_to_grid"/>
+ <Separator/>
+ <Action name="formpart_layout_menu"/>
+ <Action name="formpart_break_layout"/>
+ <Separator/>
+ <Action name="formpart_align_menu"/>
+ <Action name="formpart_adjust_size_menu"/>
+ <Separator/>
+ <Action name="formpart_format_raise"/>
+ <Action name="formpart_format_lower"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="widgets" fullWidth="false">
+ <text>Widgets</text>
+ <Action name="pointer"/>
+ <!-- Action name="drag_connection"/ -->
+ <Separator/>
+ <Action name="library_widget_KexiDBAutoField"/>
+ <Action name="library_widget_KexiDBLabel"/>
+ <Action name="library_widget_KexiPictureLabel"/>
+ <Action name="library_widget_KexiDBImageBox"/>
+ <Action name="library_widget_KexiDBLineEdit"/>
+ <Action name="library_widget_KexiDBTextEdit"/>
+ <Action name="library_widget_KPushButton"/>
+ <Action name="library_widget_KexiDBComboBox"/>
+ <!-- Action name="library_widget_QRadioButton"/ -->
+ <Action name="library_widget_KexiDBCheckBox"/>
+ <Action name="library_widget_Spacer"/>
+ <Action name="library_widget_Line"/>
+ <Separator/>
+ <Action name="library_widget_KexiFrame"/>
+ <Action name="library_widget_QGroupBox"/>
+ <Action name="library_widget_KFDTabWidget"/>
+ <!-- TODO Action name="library_widget_KexiDBSubForm"/ -->
+ <Separator/>
+ <Action name="library_widget_Spring"/>
+ <Separator/>
+ <Action name="other_widgets_menu"/>
+ <ActionList name="library_widgets" />
+ <Merge/>
+</ToolBar>
+<ToolBar name="format" fullWidth="false" noMerge="1">
+<text>Format</text>
+ <!-- Action name="formpart_layout_menu"/ -->
+ <Action name="formpart_align_menu"/>
+ <Action name="formpart_adjust_size_menu"/>
+ <Action name="show_form_ui" />
+</ToolBar>
+<!-- ToolBar name="tools" fullWidth="false">
+ <Action name="change_style"/>
+</ToolBar -->
+
+<Menu name="other_widgets_menu">
+ <Action name="library_widget_KexiDBIntSpinBox"/>
+ <Action name="library_widget_KexiDBDoubleSpinBox"/>
+ <Action name="library_widget_KexiDBDateEdit"/>
+ <Action name="library_widget_KexiDBTimeEdit"/>
+ <Action name="library_widget_KexiDBDateTimeEdit"/>
+</Menu>
+
+</kpartgui>
diff --git a/kexi/plugins/forms/kexiformpartui.rc b/kexi/plugins/forms/kexiformpartui.rc
new file mode 100644
index 00000000..20fd49d8
--- /dev/null
+++ b/kexi/plugins/forms/kexiformpartui.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kexiformpart" version="6">
+
+<!-- ToolBar name="design" fullWidth="false" noMerge="0">
+ <text>Design</text>
+ <Action name="show_form_ui"/>
+</ToolBar -->
+
+</kpartgui>
+
diff --git a/kexi/plugins/forms/kexiforms.cpp b/kexi/plugins/forms/kexiforms.cpp
new file mode 100644
index 00000000..07c4726f
--- /dev/null
+++ b/kexi/plugins/forms/kexiforms.cpp
@@ -0,0 +1,25 @@
+/* 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 <kgenericfactory.h>
+
+#include "kexiformpart.h"
+
+K_EXPORT_COMPONENT_FACTORY( kexihandler_form, KGenericFactory<KexiFormPart>("kexihandler_form") )
+
diff --git a/kexi/plugins/forms/kexiformscrollview.cpp b/kexi/plugins/forms/kexiformscrollview.cpp
new file mode 100644
index 00000000..351a1e3e
--- /dev/null
+++ b/kexi/plugins/forms/kexiformscrollview.cpp
@@ -0,0 +1,587 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ 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 "kexiformscrollview.h"
+//#include "kexiformview.h"
+
+#include <formeditor/form.h>
+#include <formeditor/formmanager.h>
+#include <formeditor/objecttree.h>
+#include <formeditor/commands.h>
+#include <widget/utils/kexirecordmarker.h>
+
+#include <kpopupmenu.h>
+#include <kdebug.h>
+
+KexiFormScrollView::KexiFormScrollView(QWidget *parent, bool preview)
+ : KexiScrollView(parent, preview)
+ , KexiRecordNavigatorHandler()
+ , KexiSharedActionClient()
+ , KexiDataAwareObjectInterface()
+ , KexiFormDataProvider()
+ , KexiFormEventHandler()
+{
+ m_currentLocalSortColumn = -1; /* no column */
+ m_localSortingOrder = -1; /* no sorting */
+ m_previousItem = 0;
+ m_navPanel = m_scrollViewNavPanel; //copy this pointer from KexiScrollView
+ if (preview) {
+ setRecordNavigatorVisible(true);
+//tmp
+// recordNavigator()->setEditingIndicatorEnabled(true);
+// recordNavigator()->showEditingIndicator(true);
+ }
+
+ connect(this, SIGNAL(resizingStarted()), this, SLOT(slotResizingStarted()));
+
+ m_popupMenu = new KPopupMenu(this, "contextMenu");
+
+// setFocusPolicy(NoFocus);
+}
+
+KexiFormScrollView::~KexiFormScrollView()
+{
+ if (m_owner)
+ delete m_data;
+ m_data = 0;
+}
+
+void
+KexiFormScrollView::show()
+{
+ KexiScrollView::show();
+
+#if 0 //moved to KexiFormView, OK?
+ //now get resize mode settings for entire form
+ if (m_preview) {
+ KexiFormView* fv = dynamic_cast<KexiFormView*>(parent());
+ int resizeMode = fv ? fv->resizeMode() : KexiFormView::ResizeAuto;
+ if (resizeMode == KexiFormView::ResizeAuto)
+ setResizePolicy(AutoOneFit);
+ }
+#endif
+}
+
+void
+KexiFormScrollView::slotResizingStarted()
+{
+ if(m_form && KFormDesigner::FormManager::self())
+ setSnapToGrid(KFormDesigner::FormManager::self()->snapWidgetsToGrid(), m_form->gridSize());
+ else
+ setSnapToGrid(false);
+}
+
+int KexiFormScrollView::rowsPerPage() const
+{
+ //! @todo
+ return 10;
+}
+
+void KexiFormScrollView::selectCellInternal()
+{
+ //m_currentItem is already set by KexiDataAwareObjectInterface::setCursorPosition()
+ if (m_currentItem) {
+ if (m_currentItem!=m_previousItem) {
+ fillDataItems(*m_currentItem, cursorAtNewRow());
+ m_previousItem = m_currentItem;
+ }
+ }
+ else {
+ m_previousItem = 0;
+ }
+}
+
+void KexiFormScrollView::ensureCellVisible(int row, int col/*=-1*/)
+{
+ Q_UNUSED( row );
+ Q_UNUSED( col );
+ //! @todo
+// if (m_currentItem)
+ //fillDataItems(*m_currentItem);
+
+// if (m_form->tabStops()->first() && m_form->tabStops()->first()->widget())
+// m_form->tabStops()->first()->widget()->setFocus();
+}
+
+void KexiFormScrollView::moveToRecordRequested(uint r)
+{
+ //! @todo
+ selectRow(r);
+}
+
+void KexiFormScrollView::moveToLastRecordRequested()
+{
+ //! @todo
+ selectLastRow();
+}
+
+void KexiFormScrollView::moveToPreviousRecordRequested()
+{
+ //! @todo
+ selectPrevRow();
+}
+
+void KexiFormScrollView::moveToNextRecordRequested()
+{
+ //! @todo
+ selectNextRow();
+}
+
+void KexiFormScrollView::moveToFirstRecordRequested()
+{
+ //! @todo
+ selectFirstRow();
+}
+
+void KexiFormScrollView::clearColumnsInternal(bool repaint)
+{
+ Q_UNUSED( repaint );
+ //! @todo
+}
+
+void KexiFormScrollView::addHeaderColumn(const QString& caption, const QString& description,
+ const QIconSet& icon, int width)
+{
+ Q_UNUSED( caption );
+ Q_UNUSED( description );
+ Q_UNUSED( icon );
+ Q_UNUSED( width );
+
+ //! @todo
+}
+
+int KexiFormScrollView::currentLocalSortingOrder() const
+{
+ //! @todo
+ return m_localSortingOrder;
+}
+
+int KexiFormScrollView::currentLocalSortColumn() const
+{
+ return m_currentLocalSortColumn;
+}
+
+void KexiFormScrollView::setLocalSortingOrder(int col, int order)
+{
+ //! @todo
+ m_currentLocalSortColumn = col;
+ m_localSortingOrder = order;
+}
+
+void KexiFormScrollView::sortColumnInternal(int col, int order)
+{
+ Q_UNUSED( col );
+ Q_UNUSED( order );
+ //! @todo
+}
+
+void KexiFormScrollView::updateGUIAfterSorting()
+{
+ //! @todo
+}
+
+void KexiFormScrollView::createEditor(int row, int col, const QString& addText,
+ bool removeOld)
+{
+ Q_UNUSED( row );
+ Q_UNUSED( addText );
+ Q_UNUSED( removeOld );
+
+ if (isReadOnly()) {
+ kexipluginsdbg << "KexiFormScrollView::createEditor(): DATA IS READ ONLY!"<<endl;
+ return;
+ }
+ if (column( col )->isReadOnly()) {
+ kexipluginsdbg << "KexiFormScrollView::createEditor(): COL IS READ ONLY!"<<endl;
+ return;
+ }
+
+ //! @todo
+ const bool startRowEdit = !m_rowEditing; //remember if we're starting row edit
+
+ if (!m_rowEditing) {
+ //we're starting row editing session
+ m_data->clearRowEditBuffer();
+
+ m_rowEditing = true;
+ //indicate on the vheader that we are editing:
+ if (m_verticalHeader)
+ m_verticalHeader->setEditRow(m_curRow);
+ if (isInsertingEnabled() && m_currentItem==m_insertItem) {
+ //we should know that we are in state "new row editing"
+ m_newRowEditing = true;
+ //'insert' row editing: show another row after that:
+ m_data->append( m_insertItem );
+ //new empty insert item
+ m_insertItem = m_data->createItem(); //new KexiTableItem(dataColumns());
+// updateContents();
+ if (m_verticalHeader)
+ m_verticalHeader->addLabel();
+// m_verticalHeaderAlreadyAdded = true;
+ updateWidgetContentsSize();
+ //refr. current and next row
+// updateContents(columnPos(0), rowPos(row), viewport()->width(), d->rowHeight*2);
+//js: warning this breaks behaviour (cursor is skipping, etc.): qApp->processEvents(500);
+// ensureVisible(columnPos(m_curCol), rowPos(row+1)+d->rowHeight-1, columnWidth(m_curCol), d->rowHeight);
+
+// m_verticalHeader->setOffset(contentsY());
+ }
+ }
+
+ m_editor = editor(col); //m_dataItems.at(col);
+ if (!m_editor)
+ return;
+
+ if (startRowEdit) {
+ recordNavigator()->showEditingIndicator(true);
+// recordNavigator()->updateButtons(); //refresh 'next btn'
+
+ emit rowEditStarted(m_curRow);
+ }
+}
+
+KexiDataItemInterface *KexiFormScrollView::editor( int col, bool ignoreMissingEditor )
+{
+ Q_UNUSED( ignoreMissingEditor );
+
+ if (!m_data || col<0 || col>=columns())
+ return 0;
+
+ return dynamic_cast<KexiFormDataItemInterface*>(dbFormWidget()->orderedDataAwareWidgets()->at( col ));
+// KexiFormDataItemInterface *item = m_dataItems.at(col);
+ //return item;
+
+/*
+ KexiTableViewColumn *tvcol = m_data->column(col);
+// int t = tvcol->field->type();
+
+ //find the editor for this column
+ KexiDataItemInterface *editor = d->editors[ tvcol ];
+ if (editor)
+ return editor;
+
+ //not found: create
+// editor = KexiCellEditorFactory::createEditor(*m_data->column(col)->field, this);
+ editor = KexiCellEditorFactory::createEditor(*m_data->column(col), this);
+ if (!editor) {//create error!
+ if (!ignoreMissingEditor) {
+ //js TODO: show error???
+ cancelRowEdit();
+ }
+ return 0;
+ }
+ editor->hide();
+ connect(editor,SIGNAL(editRequested()),this,SLOT(slotEditRequested()));
+ connect(editor,SIGNAL(cancelRequested()),this,SLOT(cancelEditor()));
+ connect(editor,SIGNAL(acceptRequested()),this,SLOT(acceptEditor()));
+
+ editor->resize(columnWidth(col)-1, rowHeight()-1);
+ editor->installEventFilter(this);
+ if (editor->widget())
+ editor->widget()->installEventFilter(this);
+ //store
+ d->editors.insert( tvcol, editor );
+ return editor;*/
+}
+
+void KexiFormScrollView::editorShowFocus( int row, int col )
+{
+ Q_UNUSED( row );
+ Q_UNUSED( col );
+ //! @todo
+// if (m_currentItem)
+// m_provider->fillDataItems(*m_currentItem);
+}
+
+void KexiFormScrollView::updateCell(int row, int col)
+{
+ Q_UNUSED( row );
+ Q_UNUSED( col );
+ //! @todo
+}
+
+void KexiFormScrollView::updateCurrentCell()
+{
+}
+
+void KexiFormScrollView::updateRow(int row)
+{
+ Q_UNUSED(row)
+ //! @todo
+}
+
+void KexiFormScrollView::updateWidgetContents()
+{
+ //! @todo
+}
+
+void KexiFormScrollView::updateWidgetContentsSize()
+{
+ //! @todo
+}
+
+void KexiFormScrollView::updateWidgetScrollBars()
+{
+ //! @todo
+}
+
+void KexiFormScrollView::slotRowRepaintRequested(KexiTableItem& item)
+{
+ Q_UNUSED( item );
+ //! @todo
+}
+
+/*void KexiFormScrollView::slotAboutToDeleteRow(KexiTableItem& item,
+ KexiDB::ResultInfo* result, bool repaint)
+{
+ //! @todo
+}*/
+
+/*void KexiFormScrollView::slotRowDeleted()
+{
+ //! @todo
+}*/
+
+void KexiFormScrollView::slotRowInserted(KexiTableItem *item, bool repaint)
+{
+ Q_UNUSED( item );
+ Q_UNUSED( repaint );
+ //! @todo
+}
+
+void KexiFormScrollView::slotRowInserted(KexiTableItem *item, uint row, bool repaint)
+{
+ Q_UNUSED( item );
+ Q_UNUSED( row );
+ Q_UNUSED( repaint );
+ //! @todo
+}
+
+void KexiFormScrollView::slotRowsDeleted( const QValueList<int> & )
+{
+ //! @todo
+}
+
+KexiDBForm* KexiFormScrollView::dbFormWidget() const
+{
+ return dynamic_cast<KexiDBForm*>(m_widget);
+}
+
+int KexiFormScrollView::columns() const
+{
+ return dbFormWidget()->orderedDataAwareWidgets()->count(); //m_dataItems.count();
+}
+
+/*uint KexiFormScrollView::fieldNumberForColumn(int col)
+{
+ KexiFormDataItemInterface *item = dynamic_cast<KexiFormDataItemInterface*>(dbFormWidget()->orderedDataAwareWidgets()->at( col ));
+ if (!item)
+ return -1;
+ KexiFormDataItemInterfaceToIntMap::ConstIterator it(m_fieldNumbersForDataItems.find( item ));
+ return it!=m_fieldNumbersForDataItems.constEnd() ? it.data() : -1;
+}*/
+
+bool KexiFormScrollView::columnEditable(int col)
+{
+ kexipluginsdbg << "KexiFormScrollView::columnEditable(" << col << ")" << endl;
+ foreach_list (QPtrListIterator<KexiFormDataItemInterface>, it, m_dataItems) {
+ kexipluginsdbg << (dynamic_cast<QWidget*>(it.current()) ? dynamic_cast<QWidget*>(it.current())->name() : "" )
+ << " " << it.current()->dataSource() << endl;
+ }
+ kexipluginsdbg << "-- focus widgets --" << endl;
+ foreach_list (QPtrListIterator<QWidget>, it, *dbFormWidget()->orderedFocusWidgets()) {
+ kexipluginsdbg << it.current()->name() << endl;
+ }
+ kexipluginsdbg << "-- data-aware widgets --" << endl;
+ foreach_list (QPtrListIterator<QWidget>, it, *dbFormWidget()->orderedDataAwareWidgets()) {
+ kexipluginsdbg << it.current()->name() << endl;
+ }
+
+ //int index = dbFormWidget()->indexForDataItem( item );
+// KexiFormDataItemInterface *item1 = dynamic_cast<KexiFormDataItemInterface*>(dbFormWidget()->orderedFocusWidgets()->at( col ));
+ KexiFormDataItemInterface *item = dynamic_cast<KexiFormDataItemInterface*>(dbFormWidget()->orderedDataAwareWidgets()->at( col ));
+
+ if (!item || item->isReadOnly())
+ return false;
+
+// KexiFormDataItemInterfaceToIntMap::ConstIterator it(m_fieldNumbersForDataItems.find( item ));
+// return KexiDataAwareObjectInterface::columnEditable( it!=m_fieldNumbersForDataItems.constEnd() ? it.data() : -1 );
+ return KexiDataAwareObjectInterface::columnEditable( col );
+}
+
+void KexiFormScrollView::valueChanged(KexiDataItemInterface* item)
+{
+ if (!item)
+ return;
+ //only signal start editing when no row editing was started already
+ kexipluginsdbg << "** KexiFormScrollView::valueChanged(): editedItem="
+ << (dbFormWidget()->editedItem ? dbFormWidget()->editedItem->value().toString() : QString::null)
+ << ", "
+ << (item ? item->value().toString() : QString::null)
+ << endl;
+ if (dbFormWidget()->editedItem!=item) {
+ kexipluginsdbg << "**>>> dbFormWidget()->editedItem = dynamic_cast<KexiFormDataItemInterface*>(item)" << endl;
+ dbFormWidget()->editedItem = dynamic_cast<KexiFormDataItemInterface*>(item);
+ startEditCurrentCell();
+ }
+ fillDuplicatedDataItems(dynamic_cast<KexiFormDataItemInterface*>(item), item->value());
+
+ //value changed: clear 'default value' mode (e.g. a blue italic text)
+ dynamic_cast<KexiFormDataItemInterface*>(item)->setDisplayDefaultValue(dynamic_cast<QWidget*>(item), false);
+}
+
+bool KexiFormScrollView::cursorAtNewRow() const
+{
+ return isInsertingEnabled() && ( m_currentItem==m_insertItem || m_newRowEditing );
+}
+
+void KexiFormScrollView::initDataContents()
+{
+ KexiDataAwareObjectInterface::initDataContents();
+
+ if (m_preview) {
+//! @todo here we can react if user wanted to show the navigator
+ setRecordNavigatorVisible(m_data);
+ recordNavigator()->setEnabled(m_data);
+ if (m_data) {
+ recordNavigator()->setEditingIndicatorEnabled( !isReadOnly() );
+ recordNavigator()->showEditingIndicator(false);
+ }
+
+ dbFormWidget()->updateReadOnlyFlags();
+ }
+}
+
+KexiTableViewColumn* KexiFormScrollView::column(int col)
+{
+ const int id = fieldNumberForColumn(col);
+ return (id >= 0) ? m_data->column( id ) : 0;
+}
+
+bool KexiFormScrollView::shouldDisplayDefaultValueForItem(KexiFormDataItemInterface* itemIface) const
+{
+ return cursorAtNewRow()
+ && !itemIface->columnInfo()->field->defaultValue().isNull()
+//?? && (m_editor ? m_editor->value()==itemIface->columnInfo()->field->defaultValue() : true)
+ && !itemIface->columnInfo()->field->isAutoIncrement(); // default value defined
+}
+
+bool KexiFormScrollView::cancelEditor()
+{
+ if (!dynamic_cast<KexiFormDataItemInterface*>(m_editor))
+ return false;
+
+ if (m_errorMessagePopup)
+ m_errorMessagePopup->close();
+
+ KexiFormDataItemInterface *itemIface = dynamic_cast<KexiFormDataItemInterface*>(m_editor);
+ itemIface->undoChanges();
+
+ const bool displayDefaultValue = shouldDisplayDefaultValueForItem(itemIface);
+ // now disable/enable "display default value" if needed (do it after setValue(), before setValue() turns it off)
+ if (itemIface->hasDisplayedDefaultValue() != displayDefaultValue)
+ itemIface->setDisplayDefaultValue( dynamic_cast<QWidget*>(itemIface), displayDefaultValue );
+
+ fillDuplicatedDataItems(itemIface, m_editor->value());
+
+ // this will clear editor pointer and close message popup (if present)
+ return KexiDataAwareObjectInterface::cancelEditor();
+}
+
+void KexiFormScrollView::updateAfterCancelRowEdit()
+{
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ if (dynamic_cast<QWidget*>(it.current())) {
+ kexipluginsdbg << "KexiFormScrollView::updateAfterCancelRowEdit(): "
+ << dynamic_cast<QWidget*>(it.current())->className() << " "
+ << dynamic_cast<QWidget*>(it.current())->name() << endl;
+ }
+ KexiFormDataItemInterface *itemIface = it.current();
+ const bool displayDefaultValue = shouldDisplayDefaultValueForItem(itemIface);
+ itemIface->undoChanges();
+ if (itemIface->hasDisplayedDefaultValue() != displayDefaultValue)
+ itemIface->setDisplayDefaultValue( dynamic_cast<QWidget*>(itemIface), displayDefaultValue );
+ }
+ recordNavigator()->showEditingIndicator(false);
+ dbFormWidget()->editedItem = 0;
+}
+
+void KexiFormScrollView::updateAfterAcceptRowEdit()
+{
+ if (!m_currentItem)
+ return;
+ recordNavigator()->showEditingIndicator(false);
+ dbFormWidget()->editedItem = 0;
+ //update visible data because there could be auto-filled (eg. autonumber) fields
+ fillDataItems(*m_currentItem, cursorAtNewRow());
+ m_previousItem = m_currentItem;
+}
+
+void KexiFormScrollView::beforeSwitchView()
+{
+ m_editor = 0;
+}
+
+void KexiFormScrollView::refreshContentsSize()
+{
+ KexiScrollView::refreshContentsSize();
+ //only clear cmd history when KexiScrollView::refreshContentsSizeLater() has been called
+ if (!m_preview && sender()==&m_delayedResize) {
+ if (m_form)
+ m_form->clearCommandHistory();
+ }
+}
+
+void KexiFormScrollView::handleDataWidgetAction(const QString& actionName)
+{
+ QWidget *w = focusWidget();
+ KexiFormDataItemInterface *item = 0;
+ while (w) {
+ item = dynamic_cast<KexiFormDataItemInterface*>(w);
+ if (item)
+ break;
+ w = w->parentWidget();
+ }
+ if (item)
+ item->handleAction(actionName);
+}
+
+void KexiFormScrollView::copySelection()
+{
+ handleDataWidgetAction("edit_copy");
+}
+
+void KexiFormScrollView::cutSelection()
+{
+ handleDataWidgetAction("edit_cut");
+}
+
+void KexiFormScrollView::paste()
+{
+ handleDataWidgetAction("edit_paste");
+}
+
+int KexiFormScrollView::lastVisibleRow() const
+{
+//! @todo unimplemented for now, this will be used for continuous forms
+ return -1;
+}
+
+#include "kexiformscrollview.moc"
diff --git a/kexi/plugins/forms/kexiformscrollview.h b/kexi/plugins/forms/kexiformscrollview.h
new file mode 100644
index 00000000..12315761
--- /dev/null
+++ b/kexi/plugins/forms/kexiformscrollview.h
@@ -0,0 +1,297 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ 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 KEXIFORMSCROLLVIEW_H
+#define KEXIFORMSCROLLVIEW_H
+
+#include "kexidataprovider.h"
+#include "kexiformeventhandler.h"
+#include "widgets/kexidbform.h"
+#include <widget/kexiscrollview.h>
+#include <widget/utils/kexirecordnavigator.h>
+#include <widget/utils/kexisharedactionclient.h>
+#include <widget/tableview/kexidataawareobjectiface.h>
+
+//! @short KexiFormScrollView class provides a widget for displaying data in a form view
+/*! This class also implements:
+ - record navigation handling (KexiRecordNavigatorHandler)
+ - shared actions handling (KexiSharedActionClient)
+ - data-aware behaviour (KexiDataAwareObjectInterface)
+ - data provider bound to data-aware widgets (KexiFormDataProvider)
+
+ @see KexiTableView
+*/
+class KEXIFORMUTILS_EXPORT KexiFormScrollView :
+ public KexiScrollView,
+ public KexiRecordNavigatorHandler,
+ public KexiSharedActionClient,
+ public KexiDataAwareObjectInterface,
+ public KexiFormDataProvider,
+ public KexiFormEventHandler
+{
+ Q_OBJECT
+ KEXI_DATAAWAREOBJECTINTERFACE
+
+ public:
+ KexiFormScrollView(QWidget *parent, bool preview);
+ virtual ~KexiFormScrollView();
+
+ void setForm(KFormDesigner::Form *form) { m_form = form; }
+
+ /*! Reimplemented from KexiDataAwareObjectInterface
+ for checking 'readOnly' flag from a widget
+ ('readOnly' flag from data member is still checked though). */
+ virtual bool columnEditable(int col);
+
+ /*! \return number of visible columns in this view.
+ There can be a number of duplicated columns defined,
+ so columns() can return greater or smaller number than dataColumns(). */
+ virtual int columns() const;
+
+ /*! \return column information for column number \a col.
+ Reimplemented for KexiDataAwareObjectInterface:
+ column data corresponding to widget number is used here
+ (see fieldNumberForColumn()). */
+ virtual KexiTableViewColumn* column(int col);
+
+ /*! \return field number within data model connected to a data-aware
+ widget at column \a col. */
+ virtual int fieldNumberForColumn(int col) {
+ KexiFormDataItemInterface *item = dynamic_cast<KexiFormDataItemInterface*>(
+ dbFormWidget()->orderedDataAwareWidgets()->at( col ));
+ if (!item)
+ return -1;
+ KexiFormDataItemInterfaceToIntMap::ConstIterator it(m_fieldNumbersForDataItems.find( item ));
+ return it!=m_fieldNumbersForDataItems.constEnd() ? (int)it.data() : -1;
+ }
+
+ /*! @internal Used by KexiFormView in view switching. */
+ void beforeSwitchView();
+
+ /*! \return last row visible on the screen (counting from 0).
+ The returned value is guaranteed to be smaller or equal to currentRow() or -1
+ if there are no rows.
+ Implemented for KexiDataAwareObjectInterface. */
+//! @todo unimplemented for now, this will be used for continuous forms
+ virtual int lastVisibleRow() const;
+
+ /*! \return vertical scrollbar. Implemented for KexiDataAwareObjectInterface. */
+ virtual QScrollBar* verticalScrollBar() const { return KexiScrollView::verticalScrollBar(); }
+
+ public slots:
+ /*! Reimplemented to update resize policy. */
+ virtual void show();
+
+ //virtual void setFocus();
+
+ //! Implementation for KexiDataAwareObjectInterface
+ //! \return arbitraty value of 10.
+ virtual int rowsPerPage() const;
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void ensureCellVisible(int row, int col/*=-1*/);
+
+ virtual void moveToRecordRequested(uint r);
+ virtual void moveToLastRecordRequested();
+ virtual void moveToPreviousRecordRequested();
+ virtual void moveToNextRecordRequested();
+ virtual void moveToFirstRecordRequested();
+ virtual void addNewRecordRequested() { KexiDataAwareObjectInterface::addNewRecordRequested(); }
+
+ /*! Cancels changes made to the currently active editor.
+ Reverts the editor's value to old one.
+ \return true on success or false on failure (e.g. when editor does not exist) */
+ virtual bool cancelEditor();
+
+ public slots:
+ /*! Reimplemented to also clear command history right after final resize. */
+ virtual void refreshContentsSize();
+
+ /*! Handles verticalScrollBar()'s valueChanged(int) signal.
+ Called when vscrollbar's value has been changed. */
+//! @todo unused for now, will be used for continuous forms
+ virtual void vScrollBarValueChanged(int v) { KexiDataAwareObjectInterface::vScrollBarValueChanged(v); }
+
+ /*! Handles sliderReleased() signal of the verticalScrollBar(). Used to hide the "row number" tooltip. */
+//! @todo unused for now, will be used for continuous forms
+ virtual void vScrollBarSliderReleased() { KexiDataAwareObjectInterface::vScrollBarSliderReleased(); }
+
+ /*! Handles timeout() signal of the m_scrollBarTipTimer. If the tooltip is visible,
+ m_scrollBarTipTimerCnt is set to 0 and m_scrollBarTipTimerCnt is restarted;
+ else the m_scrollBarTipTimerCnt is just set to 0.*/
+//! @todo unused for now, will be used for continuous forms
+ virtual void scrollBarTipTimeout() { KexiDataAwareObjectInterface::scrollBarTipTimeout(); }
+
+ signals:
+ virtual void itemChanged(KexiTableItem *, int row, int col);
+ virtual void itemChanged(KexiTableItem *, int row, int col, QVariant oldValue);
+ virtual void itemDeleteRequest(KexiTableItem *, int row, int col);
+ virtual void currentItemDeleteRequest();
+ virtual void newItemAppendedForAfterDeletingInSpreadSheetMode(); //!< does nothing
+ virtual void dataRefreshed();
+ virtual void dataSet( KexiTableViewData *data );
+ virtual void itemSelected(KexiTableItem *);
+ virtual void cellSelected(int col, int row);
+ virtual void sortedColumnChanged(int col);
+ virtual void rowEditStarted(int row);
+ virtual void rowEditTerminated(int row);
+ virtual void reloadActions();
+
+ protected slots:
+ void slotResizingStarted();
+
+ //! Handles KexiTableViewData::rowRepaintRequested() signal
+ virtual void slotRowRepaintRequested(KexiTableItem& item);
+
+ //! Handles KexiTableViewData::aboutToDeleteRow() signal. Prepares info for slotRowDeleted().
+ virtual void slotAboutToDeleteRow(KexiTableItem& item, KexiDB::ResultInfo* result, bool repaint)
+ { KexiDataAwareObjectInterface::slotAboutToDeleteRow(item, result, repaint); }
+
+ //! Handles KexiTableViewData::rowDeleted() signal to repaint when needed.
+ virtual void slotRowDeleted() { KexiDataAwareObjectInterface::slotRowDeleted(); }
+
+ //! Handles KexiTableViewData::rowInserted() signal to repaint when needed.
+ virtual void slotRowInserted(KexiTableItem *item, bool repaint);
+
+ //! Like above, not db-aware version
+ virtual void slotRowInserted(KexiTableItem *item, uint row, bool repaint);
+
+ virtual void slotRowsDeleted( const QValueList<int> & );
+
+ virtual void slotDataDestroying() { KexiDataAwareObjectInterface::slotDataDestroying(); }
+
+ /*! Reloads data for this widget.
+ Handles KexiTableViewData::reloadRequested() signal. */
+ virtual void reloadData() { KexiDataAwareObjectInterface::reloadData(); }
+
+ //! Copy current selection to a clipboard (e.g. cell)
+ virtual void copySelection();
+
+ //! Cut current selection to a clipboard (e.g. cell)
+ virtual void cutSelection();
+
+ //! Paste current clipboard contents (e.g. to a cell)
+ virtual void paste();
+
+ protected:
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void clearColumnsInternal(bool repaint);
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void addHeaderColumn(const QString& caption, const QString& description,
+ const QIconSet& icon, int width);
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual int currentLocalSortingOrder() const;
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual int currentLocalSortColumn() const;
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void setLocalSortingOrder(int col, int order);
+
+ //! Implementation for KexiDataAwareObjectInterface
+ void sortColumnInternal(int col, int order = 0);
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void updateGUIAfterSorting();
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void createEditor(int row, int col, const QString& addText = QString::null,
+ bool removeOld = false);
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual KexiDataItemInterface *editor( int col, bool ignoreMissingEditor = false );
+
+ //! Implementation for KexiDataAwareObjectInterface
+ virtual void editorShowFocus( int row, int col );
+
+ /*! Implementation for KexiDataAwareObjectInterface
+ Redraws specified cell. */
+ virtual void updateCell(int row, int col);
+
+ /*! Redraws the current cell. Implemented after KexiDataAwareObjectInterface. */
+ virtual void updateCurrentCell();
+
+ /*! Implementation for KexiDataAwareObjectInterface
+ Redraws all cells of specified row. */
+ virtual void updateRow(int row);
+
+ /*! Implementation for KexiDataAwareObjectInterface
+ Updates contents of the widget. Just call update() here on your widget. */
+ virtual void updateWidgetContents();
+
+ /*! Implementation for KexiDataAwareObjectInterface
+ Implementation for KexiDataAwareObjectInterface
+ Updates widget's contents size e.g. using QScrollView::resizeContents(). */
+ virtual void updateWidgetContentsSize();
+
+ /*! Implementation for KexiDataAwareObjectInterface
+ Updates scrollbars of the widget.
+ QScrollView::updateScrollbars() will be usually called here. */
+ virtual void updateWidgetScrollBars();
+
+ KexiDBForm* dbFormWidget() const;
+
+ //! Reimplemented from KexiFormDataProvider. Reaction for change of \a item.
+ virtual void valueChanged(KexiDataItemInterface* item);
+
+ /*! Reimplemented from KexiFormDataProvider.
+ \return information whether we're currently at new row or now.
+ This can be used e.g. by data-aware widgets to determine if "(autonumber)"
+ label should be displayed. */
+ virtual bool cursorAtNewRow() const;
+
+ //! Implementation for KexiDataAwareObjectInterface
+ //! Called by KexiDataAwareObjectInterface::setCursorPosition()
+ //! if cursor's position is really changed.
+ inline virtual void selectCellInternal();
+
+ /*! Reimplementation: used to refresh "editing indicator" visibility. */
+ virtual void initDataContents();
+
+ /*! @internal
+ Updates row appearance after canceling row edit.
+ Reimplemented from KexiDataAwareObjectInterface: just undoes changes for every data item.
+ Used by cancelRowEdit(). */
+ virtual void updateAfterCancelRowEdit();
+
+ /*! @internal
+ Updates row appearance after accepting row edit.
+ Reimplemented from KexiDataAwareObjectInterface: just clears 'edit' indicator.
+ Used by cancelRowEdit(). */
+ virtual void updateAfterAcceptRowEdit();
+
+ /*! @internal
+ Used to invoke copy/paste/cut etc. actions at the focused widget's level. */
+ void handleDataWidgetAction(const QString& actionName);
+
+ /*! @internal */
+ bool shouldDisplayDefaultValueForItem(KexiFormDataItemInterface* itemIface) const;
+
+ //virtual bool focusNextPrevChild( bool next );
+
+ KFormDesigner::Form *m_form;
+ int m_currentLocalSortColumn, m_localSortingOrder;
+ //! Used in selectCellInternal() to avoid fetching the same record twice
+ KexiTableItem *m_previousItem;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kexiformview.cpp b/kexi/plugins/forms/kexiformview.cpp
new file mode 100644
index 00000000..7e52e5b6
--- /dev/null
+++ b/kexi/plugins/forms/kexiformview.cpp
@@ -0,0 +1,1278 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ 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 "kexiformview.h"
+
+#include <qobjectlist.h>
+#include <qfileinfo.h>
+
+#include <formeditor/form.h>
+#include <formeditor/formIO.h>
+#include <formeditor/formmanager.h>
+#include <formeditor/objecttree.h>
+#include <formeditor/container.h>
+#include <formeditor/widgetpropertyset.h>
+#include <formeditor/commands.h>
+#include <formeditor/widgetwithsubpropertiesinterface.h>
+#include <formeditor/objecttree.h>
+
+#include <kexi.h>
+#include <kexidialogbase.h>
+#include <kexidragobjects.h>
+#include <kexidb/field.h>
+#include <kexidb/fieldlist.h>
+#include <kexidb/connection.h>
+#include <kexidb/cursor.h>
+#include <kexidb/utils.h>
+#include <kexidb/preparedstatement.h>
+#include <tableview/kexitableitem.h>
+#include <tableview/kexitableviewdata.h>
+#include <widget/kexipropertyeditorview.h>
+#include <widget/kexiqueryparameters.h>
+#include <kexiutils/utils.h>
+
+#include <koproperty/set.h>
+#include <koproperty/property.h>
+
+#include "widgets/kexidbform.h"
+#include "kexiformscrollview.h"
+#include "kexidatasourcepage.h"
+#include "widgets/kexidbautofield.h"
+
+#define NO_DSWIZARD
+
+//! @todo #define KEXI_SHOW_SPLITTER_WIDGET
+
+KexiFormView::KexiFormView(KexiMainWindow *mainWin, QWidget *parent,
+ const char *name, bool /*dbAware*/)
+ : KexiDataAwareView( mainWin, parent, name )
+ , m_propertySet(0)
+ , m_resizeMode(KexiFormView::ResizeDefault)
+ , m_query(0)
+ , m_queryIsOwned(false)
+ , m_cursor(0)
+// , m_firstFocusWidget(0)
+{
+ m_delayedFormContentsResizeOnShow = 0;
+
+ QHBoxLayout *l = new QHBoxLayout(this);
+ l->setAutoAdd(true);
+
+ m_scrollView = new KexiFormScrollView(this, viewMode()==Kexi::DataViewMode);
+
+//moved setViewWidget(m_scrollView);
+// m_scrollView->show();
+
+ m_dbform = new KexiDBForm(m_scrollView->viewport(), m_scrollView, name/*, conn*/);
+// m_dbform->resize( m_scrollView->viewport()->size() - QSize(20, 20) );
+// m_dbform->resize(QSize(400, 300));
+ m_scrollView->setWidget(m_dbform);
+ m_scrollView->setResizingEnabled(viewMode()!=Kexi::DataViewMode);
+
+// initForm();
+
+ if (viewMode()==Kexi::DataViewMode) {
+ m_scrollView->recordNavigator()->setRecordHandler( m_scrollView );
+ m_scrollView->viewport()->setPaletteBackgroundColor(m_dbform->palette().active().background());
+//moved to formmanager connect(formPart()->manager(), SIGNAL(noFormSelected()), SLOT(slotNoFormSelected()));
+ }
+ else
+ {
+ connect(KFormDesigner::FormManager::self(), SIGNAL(propertySetSwitched(KoProperty::Set*, bool, const QCString&)),
+ this, SLOT(slotPropertySetSwitched(KoProperty::Set*, bool, const QCString&)));
+ connect(KFormDesigner::FormManager::self(), SIGNAL(dirty(KFormDesigner::Form *, bool)),
+ this, SLOT(slotDirty(KFormDesigner::Form *, bool)));
+
+ connect(m_dbform, SIGNAL(handleDragMoveEvent(QDragMoveEvent*)),
+ this, SLOT(slotHandleDragMoveEvent(QDragMoveEvent*)));
+ connect(m_dbform, SIGNAL(handleDropEvent(QDropEvent*)),
+ this, SLOT(slotHandleDropEvent(QDropEvent*)));
+
+ // action stuff
+ plugSharedAction("formpart_taborder", KFormDesigner::FormManager::self(), SLOT(editTabOrder()));
+ plugSharedAction("formpart_adjust_size", KFormDesigner::FormManager::self(), SLOT(adjustWidgetSize()));
+//TODO plugSharedAction("formpart_pixmap_collection", formPart()->manager(), SLOT(editFormPixmapCollection()));
+//TODO plugSharedAction("formpart_connections", formPart()->manager(), SLOT(editConnections()));
+
+ plugSharedAction("edit_copy", KFormDesigner::FormManager::self(), SLOT(copyWidget()));
+ plugSharedAction("edit_cut", KFormDesigner::FormManager::self(), SLOT(cutWidget()));
+ plugSharedAction("edit_paste", KFormDesigner::FormManager::self(), SLOT(pasteWidget()));
+ plugSharedAction("edit_delete", KFormDesigner::FormManager::self(), SLOT(deleteWidget()));
+ plugSharedAction("edit_select_all", KFormDesigner::FormManager::self(), SLOT(selectAll()));
+ plugSharedAction("formpart_clear_contents", KFormDesigner::FormManager::self(), SLOT(clearWidgetContent()));
+ plugSharedAction("edit_undo", KFormDesigner::FormManager::self(), SLOT(undo()));
+ plugSharedAction("edit_redo", KFormDesigner::FormManager::self(), SLOT(redo()));
+
+ plugSharedAction("formpart_layout_menu", KFormDesigner::FormManager::self(), 0 );
+ plugSharedAction("formpart_layout_hbox", KFormDesigner::FormManager::self(), SLOT(layoutHBox()) );
+ plugSharedAction("formpart_layout_vbox", KFormDesigner::FormManager::self(), SLOT(layoutVBox()) );
+ plugSharedAction("formpart_layout_grid", KFormDesigner::FormManager::self(), SLOT(layoutGrid()) );
+#ifdef KEXI_SHOW_SPLITTER_WIDGET
+ plugSharedAction("formpart_layout_hsplitter", KFormDesigner::FormManager::self(), SLOT(layoutHSplitter()) );
+ plugSharedAction("formpart_layout_vsplitter", KFormDesigner::FormManager::self(), SLOT(layoutVSplitter()) );
+#endif
+ plugSharedAction("formpart_break_layout", KFormDesigner::FormManager::self(), SLOT(breakLayout()) );
+
+ plugSharedAction("formpart_format_raise", KFormDesigner::FormManager::self(), SLOT(bringWidgetToFront()) );
+ plugSharedAction("formpart_format_lower", KFormDesigner::FormManager::self(), SLOT(sendWidgetToBack()) );
+
+ plugSharedAction("other_widgets_menu", KFormDesigner::FormManager::self(), 0 );
+ setAvailable("other_widgets_menu", true);
+
+ plugSharedAction("formpart_align_menu", KFormDesigner::FormManager::self(), 0 );
+ plugSharedAction("formpart_align_to_left", KFormDesigner::FormManager::self(),SLOT(alignWidgetsToLeft()) );
+ plugSharedAction("formpart_align_to_right", KFormDesigner::FormManager::self(), SLOT(alignWidgetsToRight()) );
+ plugSharedAction("formpart_align_to_top", KFormDesigner::FormManager::self(), SLOT(alignWidgetsToTop()) );
+ plugSharedAction("formpart_align_to_bottom", KFormDesigner::FormManager::self(), SLOT(alignWidgetsToBottom()) );
+ plugSharedAction("formpart_align_to_grid", KFormDesigner::FormManager::self(), SLOT(alignWidgetsToGrid()) );
+
+ plugSharedAction("formpart_adjust_size_menu", KFormDesigner::FormManager::self(), 0 );
+ plugSharedAction("formpart_adjust_to_fit", KFormDesigner::FormManager::self(), SLOT(adjustWidgetSize()) );
+ plugSharedAction("formpart_adjust_size_grid", KFormDesigner::FormManager::self(), SLOT(adjustSizeToGrid()) );
+ plugSharedAction("formpart_adjust_height_small", KFormDesigner::FormManager::self(), SLOT(adjustHeightToSmall()) );
+ plugSharedAction("formpart_adjust_height_big", KFormDesigner::FormManager::self(), SLOT(adjustHeightToBig()) );
+ plugSharedAction("formpart_adjust_width_small", KFormDesigner::FormManager::self(), SLOT(adjustWidthToSmall()) );
+ plugSharedAction("formpart_adjust_width_big", KFormDesigner::FormManager::self(), SLOT(adjustWidthToBig()) );
+
+ plugSharedAction("format_font", KFormDesigner::FormManager::self(), SLOT(changeFont()) );
+ }
+
+ initForm();
+
+ KexiDataAwareView::init( m_scrollView, m_scrollView, m_scrollView,
+ /* skip data-awarness if design mode */ viewMode()==Kexi::DesignViewMode );
+
+ connect(this, SIGNAL(focus(bool)), this, SLOT(slotFocus(bool)));
+ /// @todo skip this if ther're no borders
+// m_dbform->resize( m_dbform->size()+QSize(m_scrollView->verticalScrollBar()->width(), m_scrollView->horizontalScrollBar()->height()) );
+}
+
+KexiFormView::~KexiFormView()
+{
+ if (m_cursor) {
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ conn->deleteCursor(m_cursor);
+ m_cursor = 0;
+ }
+ deleteQuery();
+
+ // Important: form window is closed.
+ // Set property set to 0 because there is *only one* instance of a property set class
+ // in Kexi, so the main window wouldn't know the set in fact has been changed.
+ m_propertySet = 0;
+ propertySetSwitched();
+}
+
+void
+KexiFormView::deleteQuery()
+{
+ if (m_cursor) {
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ conn->deleteCursor(m_cursor);
+ m_cursor = 0;
+ }
+
+ if (m_queryIsOwned) {
+ delete m_query;
+ } else {
+//! @todo remove this shared query from listened queries list
+ }
+ m_query = 0;
+}
+
+KFormDesigner::Form*
+KexiFormView::form() const
+{
+ if(viewMode()==Kexi::DataViewMode)
+ return tempData()->previewForm;
+ else
+ return tempData()->form;
+}
+
+void
+KexiFormView::setForm(KFormDesigner::Form *f)
+{
+ if(viewMode()==Kexi::DataViewMode)
+ tempData()->previewForm = f;
+ else
+ tempData()->form = f;
+}
+
+void
+KexiFormView::initForm()
+{
+ setForm( new KFormDesigner::Form(KexiFormPart::library(), 0, viewMode()==Kexi::DesignViewMode) );
+// if (viewMode()==Kexi::DataViewMode)
+ //form()->setDesignMode(false);
+ form()->createToplevel(m_dbform, m_dbform);
+
+ if (viewMode()==Kexi::DesignViewMode) {
+ //we want to be informed about executed commands
+ connect(form()->commandHistory(), SIGNAL(commandExecuted()),
+ KFormDesigner::FormManager::self(), SLOT(slotHistoryCommandExecuted()));
+ }
+
+ const bool newForm = parentDialog()->id() < 0;
+
+ KexiDB::FieldList *fields = 0;
+ if (newForm) {
+ // Show the form wizard if this is a new Form
+#ifndef NO_DSWIZARD
+ KexiDataSourceWizard *w = new KexiDataSourceWizard(mainWin(), (QWidget*)mainWin(), "datasource_wizard");
+ if(!w->exec())
+ fields = 0;
+ else
+ fields = w->fields();
+ delete w;
+#endif
+ }
+
+ if(fields)
+ {
+ QDomDocument dom;
+ formPart()->generateForm(fields, dom);
+ KFormDesigner::FormIO::loadFormFromDom(form(), m_dbform, dom);
+ //! @todo handle errors
+ }
+ else
+ loadForm();
+
+ if(form()->autoTabStops())
+ form()->autoAssignTabStops();
+
+ //collect tab order information
+ m_dbform->updateTabStopsOrder(form());
+
+// if (m_dbform->orderedFocusWidgets()->first())
+ // m_scrollView->setFocusProxy( m_dbform->orderedFocusWidgets()->first() );
+
+ KFormDesigner::FormManager::self()->importForm(form(), viewMode()==Kexi::DataViewMode);
+ m_scrollView->setForm(form());
+
+// m_dbform->updateTabStopsOrder(form());
+// QSize s = m_dbform->size();
+// QApplication::sendPostedEvents();
+// m_scrollView->resize( s );
+// m_dbform->resize(s);
+ m_scrollView->refreshContentsSize();
+// m_scrollView->refreshContentsSizeLater(true,true);
+
+ if (newForm && !fields) {
+ /* Our form's area will be resized more than once.
+ Let's resize form widget itself later. */
+ m_delayedFormContentsResizeOnShow = 3;
+ }
+
+ updateDataSourcePage();
+
+ if (!newForm && viewMode()==Kexi::DesignViewMode) {
+ form()->clearCommandHistory();
+ }
+}
+
+void KexiFormView::updateAutoFieldsDataSource()
+{
+//! @todo call this when form's data source is changed
+ //update autofields:
+ //-inherit captions
+ //-inherit data types
+ //(this data has not been stored in the form)
+ QString dataSourceString( m_dbform->dataSource() );
+ QCString dataSourceMimeTypeString( m_dbform->dataSourceMimeType() );
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ KexiDB::TableOrQuerySchema tableOrQuery(
+ conn, dataSourceString.latin1(), dataSourceMimeTypeString=="kexi/table");
+ if (!tableOrQuery.table() && !tableOrQuery.query())
+ return;
+ for (KFormDesigner::ObjectTreeDictIterator it(*form()->objectTree()->dict());
+ it.current(); ++it)
+ {
+ KexiDBAutoField *afWidget = dynamic_cast<KexiDBAutoField*>( it.current()->widget() );
+ if (afWidget) {
+ KexiDB::QueryColumnInfo *colInfo = tableOrQuery.columnInfo( afWidget->dataSource() );
+ if (colInfo) {
+ afWidget->setColumnInfo(colInfo);
+ //setFieldTypeInternal((int)colInfo->field->type());
+ //afWidget->setFieldCaptionInternal(colInfo->captionOrAliasOrName());
+ }
+ }
+ }
+}
+
+void KexiFormView::updateValuesForSubproperties()
+{
+//! @todo call this when form's data source is changed
+ //update autofields:
+ //-inherit captions
+ //-inherit data types
+ //(this data has not been stored in the form)
+ QString dataSourceString( m_dbform->dataSource() );
+ QCString dataSourceMimeTypeString( m_dbform->dataSourceMimeType() );
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ KexiDB::TableOrQuerySchema tableOrQuery(
+ conn, dataSourceString.latin1(), dataSourceMimeTypeString=="kexi/table");
+ if (!tableOrQuery.table() && !tableOrQuery.query())
+ return;
+
+ for (KFormDesigner::ObjectTreeDictIterator it(*form()->objectTree()->dict());
+ it.current(); ++it)
+ {
+ // (delayed) set values for subproperties
+//! @todo this could be at the KFD level, but KFD is going to be merged anyway with kexiforms, right?
+ KFormDesigner::WidgetWithSubpropertiesInterface* subpropIface
+ = dynamic_cast<KFormDesigner::WidgetWithSubpropertiesInterface*>( it.current()->widget() );
+ if (subpropIface && subpropIface->subwidget() && it.current()->subproperties() ) {
+ QWidget *subwidget = subpropIface->subwidget();
+ QMap<QString, QVariant>* subprops = it.current()->subproperties();
+ for (QMapConstIterator<QString, QVariant> subpropIt = subprops->constBegin(); subpropIt!=subprops->constEnd(); ++subpropIt) {
+ kexipluginsdbg << "KexiFormView::loadForm(): delayed setting of the subproperty: widget="
+ << it.current()->widget()->name() << " prop=" << subpropIt.key() << " val=" << subpropIt.data() << endl;
+
+ const int count = subwidget->metaObject()->findProperty(subpropIt.key().latin1(), true);
+ const QMetaProperty *meta = count!=-1 ? subwidget->metaObject()->property(count, true) : 0;
+ if (meta) {
+ // Special case: the property value of type enum (set) but is saved as a string list,
+ // not as int, so we need to translate it to int. It's been created as such
+ // by FormIO::readPropertyValue(). Example: "alignment" property.
+ if (meta->isSetType() && subpropIt.data().type()==QVariant::StringList) {
+ QStrList keys;
+ const QStringList list( subpropIt.data().toStringList() );
+ for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
+ keys.append((*it).latin1());
+ subwidget->setProperty( subpropIt.key().latin1(), meta->keysToValue(keys) );
+ }
+ else {
+ subwidget->setProperty( subpropIt.key().latin1(), subpropIt.data() );
+ }
+ }
+ }//for
+ }
+ }
+}
+
+//! Used in KexiFormView::loadForm()
+static void setUnsavedBLOBIdsForDataViewMode(
+ QWidget* widget, const QMap<QCString, KexiBLOBBuffer::Id_t>& unsavedLocalBLOBsByName)
+{
+ if (-1 != widget->metaObject()->findProperty("pixmapId")) {
+ const KexiBLOBBuffer::Id_t blobID = unsavedLocalBLOBsByName[ widget->name() ];
+ if (blobID > 0)
+ widget->setProperty("pixmapId", (uint /* KexiBLOBBuffer::Id_t is unsafe and unsupported by QVariant - will be fixed in Qt4*/)blobID);
+ }
+ const QObjectList *list = widget->children();
+ if (!list)
+ return;
+ for (QObjectListIterator it(*list); it.current(); ++it) {
+ if (dynamic_cast<QWidget*>(it.current()))
+ setUnsavedBLOBIdsForDataViewMode(dynamic_cast<QWidget*>(it.current()), unsavedLocalBLOBsByName);
+ }
+}
+
+void
+KexiFormView::loadForm()
+{
+//@todo also load m_resizeMode !
+
+ kexipluginsdbg << "KexiFormView::loadForm() Loading the form with id : " << parentDialog()->id() << endl;
+ // If we are previewing the Form, use the tempData instead of the form stored in the db
+ if(viewMode()==Kexi::DataViewMode && !tempData()->tempForm.isNull() )
+ {
+ KFormDesigner::FormIO::loadFormFromString(form(), m_dbform, tempData()->tempForm);
+ setUnsavedBLOBIdsForDataViewMode( m_dbform, tempData()->unsavedLocalBLOBsByName );
+ updateAutoFieldsDataSource();
+ updateValuesForSubproperties();
+ return;
+ }
+
+ // normal load
+ QString data;
+ loadDataBlock(data);
+ KFormDesigner::FormIO::loadFormFromString(form(), m_dbform, data);
+
+ //"autoTabStops" property is loaded -set it within the form tree as well
+ form()->setAutoTabStops( m_dbform->autoTabStops() );
+
+ updateAutoFieldsDataSource();
+ updateValuesForSubproperties();
+}
+
+void
+KexiFormView::slotPropertySetSwitched(KoProperty::Set *set, bool forceReload, const QCString& propertyToSelect)
+{
+// if (set && parentDialog()!=parentDialog()->mainWin()->currentDialog())
+ if (form() != KFormDesigner::FormManager::self()->activeForm())
+ return; //this is not the current form view
+ m_propertySet = set;
+ if (forceReload)
+ propertySetReloaded(true/*preservePrevSelection*/, propertyToSelect);
+ else
+ propertySetSwitched();
+
+ formPart()->dataSourcePage()->assignPropertySet(m_propertySet);
+}
+
+tristate
+KexiFormView::beforeSwitchTo(int mode, bool &dontStore)
+{
+ if (mode!=viewMode()) {
+ if (viewMode()==Kexi::DataViewMode) {
+ if (!m_scrollView->acceptRowEdit())
+ return cancelled;
+
+ m_scrollView->beforeSwitchView();
+ }
+ else {
+ //remember our pos
+ tempData()->scrollViewContentsPos
+ = QPoint(m_scrollView->contentsX(), m_scrollView->contentsY());
+ }
+ }
+
+ // we don't store on db, but in our TempData
+ dontStore = true;
+ if(dirty() && (mode == Kexi::DataViewMode) && form()->objectTree()) {
+ KexiFormPart::TempData* temp = tempData();
+ if (!KFormDesigner::FormIO::saveFormToString(form(), temp->tempForm))
+ return false;
+
+ //collect blobs from design mode by name for use in data view mode
+ temp->unsavedLocalBLOBsByName.clear();
+ for (QMapConstIterator<QWidget*, KexiBLOBBuffer::Id_t> it = temp->unsavedLocalBLOBs.constBegin();
+ it!=temp->unsavedLocalBLOBs.constEnd(); ++it)
+ {
+ if (!it.key())
+ continue;
+ temp->unsavedLocalBLOBsByName.insert( it.key()->name(), it.data() );
+ }
+ }
+
+ return true;
+}
+
+tristate
+KexiFormView::afterSwitchFrom(int mode)
+{
+ if (mode == 0 || mode == Kexi::DesignViewMode) {
+ if (parentDialog()->neverSaved()) {
+ m_dbform->resize(QSize(400, 300));
+ m_scrollView->refreshContentsSizeLater(true,true);
+ //m_delayedFormContentsResizeOnShow = false;
+ }
+ }
+
+ if (mode != 0 && mode != Kexi::DesignViewMode) {
+ //preserve contents pos after switching to other view
+ m_scrollView->setContentsPos(tempData()->scrollViewContentsPos.x(),
+ tempData()->scrollViewContentsPos.y());
+ }
+// if (mode == Kexi::DesignViewMode) {
+ //m_scrollView->move(0,0);
+ //m_scrollView->setContentsPos(0,0);
+ //m_scrollView->moveChild(m_dbform, 0, 0);
+// }
+
+ if((mode == Kexi::DesignViewMode) && viewMode()==Kexi::DataViewMode) {
+ // The form may have been modified, so we must recreate the preview
+ delete m_dbform; // also deletes form()
+ m_dbform = new KexiDBForm(m_scrollView->viewport(), m_scrollView, "KexiDBForm");
+ m_scrollView->setWidget(m_dbform);
+
+ initForm();
+//moved to formmanager slotNoFormSelected();
+
+ //reset position
+ m_scrollView->setContentsPos(0,0);
+ m_dbform->move(0,0);
+
+ }
+
+ //update tab stops if needed
+ if (viewMode()==Kexi::DataViewMode) {
+// //propagate current "autoTabStops" property value to the form tree
+// form()->setAutoTabStops( m_dbform->autoTabStops() );
+
+// if(form()->autoTabStops())
+// form()->autoAssignTabStops();
+ }
+ else {
+ //set "autoTabStops" property
+ m_dbform->setAutoTabStops( form()->autoTabStops() );
+ }
+
+ if (viewMode() == Kexi::DataViewMode) {
+//TMP!!
+ initDataSource();
+
+ //handle events for this form
+ m_scrollView->setMainWidgetForEventHandling(parentDialog()->mainWin(), m_dbform);
+
+ //set focus on 1st focusable widget which has valid dataSource property set
+ if (!m_dbform->orderedFocusWidgets()->isEmpty()) {
+// QWidget *www = focusWidget();
+ //if (Kexi::hasParent(this, qApp->focusWidget())) {
+ KexiUtils::unsetFocusWithReason(qApp->focusWidget(), QFocusEvent::Tab);
+ //}
+
+ QPtrListIterator<QWidget> it(*m_dbform->orderedFocusWidgets());
+ for (;it.current(); ++it) {
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>(it.current());
+ if (iface)
+ kexipluginsdbg << iface->dataSource() << endl;
+ if (iface && iface->columnInfo() && !iface->isReadOnly()
+/*! @todo add option for skipping autoincremented fields */
+ /* also skip autoincremented fields:*/
+ && !iface->columnInfo()->field->isAutoIncrement()) //!iface->dataSource().isEmpty()
+ break;
+ }
+ if (!it.current()) //eventually, focus first available widget if nothing other is available
+ it.toFirst();
+
+ it.current()->setFocus();
+ KexiUtils::setFocusWithReason(it.current(), QFocusEvent::Tab);
+ m_setFocusInternalOnce = it.current();
+ }
+
+ if (m_query)
+ m_scrollView->selectFirstRow();
+ }
+
+ //dirty only if it's a new object
+ if (mode == 0)
+ setDirty( parentDialog()->partItem()->neverSaved() );
+
+ if (mode==Kexi::DataViewMode && viewMode()==Kexi::DesignViewMode) {
+// slotPropertySetSwitched
+// emit KFormDesigner::FormManager::self()->propertySetSwitched( KFormDesigner::FormManager::self()->propertySet()->set(), true );
+ }
+
+ return true;
+}
+
+void KexiFormView::initDataSource()
+{
+ deleteQuery();
+ QString dataSourceString( m_dbform->dataSource() );
+ QCString dataSourceMimeTypeString( m_dbform->dataSourceMimeType() );
+//! @todo also handle anonymous (not stored) queries provided as statements here
+ bool ok = !dataSourceString.isEmpty();
+
+/* if (m_previousDataSourceString.lower()==dataSourceString.lower() && !m_cursor) {
+ //data source changed: delete previous cursor
+ m_conn->deleteCursor(m_cursor);
+ m_cursor = 0;
+ }*/
+
+ KexiDB::TableSchema *tableSchema = 0;
+ KexiDB::Connection *conn = 0;
+ QStringList sources;
+ bool forceReadOnlyDataSource = false;
+
+ if (ok) {
+// m_previousDataSourceString = dataSourceString;
+
+ //collect all data-aware widgets and create query schema
+ m_scrollView->setMainDataSourceWidget(m_dbform);
+ sources = m_scrollView->usedDataSources();
+ conn = parentDialog()->mainWin()->project()->dbConnection();
+ if (dataSourceMimeTypeString.isEmpty() /*table type is the default*/
+ || dataSourceMimeTypeString=="kexi/table")
+ {
+ tableSchema = conn->tableSchema( dataSourceString );
+ if (tableSchema) {
+ /* We will build a _minimum_ query schema from selected table fields. */
+ m_query = new KexiDB::QuerySchema();
+ m_queryIsOwned = true;
+
+ if (dataSourceMimeTypeString.isEmpty())
+ m_dbform->setDataSourceMimeType("kexi/table"); //update for compatibility
+ }
+ }
+
+ if (!tableSchema) {
+ if (dataSourceMimeTypeString.isEmpty() /*also try to find a query (for compatibility with Kexi<=0.9)*/
+ || dataSourceMimeTypeString=="kexi/query")
+ {
+ //try to find predefined query schema.
+ //Note: In general, we could not skip unused fields within this query because
+ // it can have GROUP BY clause.
+ //! @todo check if the query could have skipped unused fields (no GROUP BY, no joins, etc.)
+ m_query = conn->querySchema( dataSourceString );
+ m_queryIsOwned = false;
+ ok = m_query != 0;
+ if (ok && dataSourceMimeTypeString.isEmpty())
+ m_dbform->setDataSourceMimeType("kexi/query"); //update for compatibility
+ // query results are read-only
+//! @todo There can be read-write queries, e.g. simple "SELECT * FROM...". Add a checking function to KexiDB.
+ forceReadOnlyDataSource = true;
+ }
+ else //no other mime types supported
+ ok = false;
+ }
+ }
+
+ QDict<char> invalidSources(997);
+ if (ok) {
+ KexiDB::IndexSchema *pkey = tableSchema ? tableSchema->primaryKey() : 0;
+ if (pkey) {
+ //always add all fields from table's primary key
+ // (don't worry about duplicates, unique list will be computed later)
+ sources += pkey->names();
+ kexipluginsdbg << "KexiFormView::initDataSource(): pkey added to data sources: " << pkey->names() << endl;
+ }
+ kexipluginsdbg << "KexiFormView::initDataSource(): sources=" << sources << endl;
+
+ uint index = 0;
+ for (QStringList::ConstIterator it = sources.constBegin();
+ it!=sources.constEnd(); ++it, index++) {
+/*! @todo add expression support */
+ QString fieldName( (*it).lower() );
+ //remove "tablename." if it was prepended
+ if (tableSchema && fieldName.startsWith( tableSchema->name().lower()+"." ))
+ fieldName = fieldName.mid(tableSchema->name().length()+1);
+ //remove "queryname." if it was prepended
+ if (!tableSchema && fieldName.startsWith( m_query->name().lower()+"." ))
+ fieldName = fieldName.mid(m_query->name().length()+1);
+ KexiDB::Field *f = tableSchema ? tableSchema->field(fieldName) : m_query->field(fieldName);
+ if (!f) {
+/*! @todo show error */
+ //remove this widget from the set of data widgets in the provider
+/*! @todo fieldName is ok, but what about expressions? */
+ invalidSources.insert( fieldName, (const char*)1 ); // += index;
+ kexipluginsdbg << "KexiFormView::initDataSource(): invalidSources+=" << index << " ("
+ << (*it) << ")" << endl;
+ continue;
+ }
+ if (tableSchema) {
+ if (!m_query->hasField( f )) {
+ //we're building a new query: add this field
+ m_query->addField( f );
+ }
+ }
+ }
+ if (invalidSources.count()==sources.count()) {
+ //all data sources are invalid! don't execute the query
+ deleteQuery();
+ }
+ else {
+ KexiDB::debug( m_query->parameters() );
+ // like in KexiQueryView::executeQuery()
+ QValueList<QVariant> params;
+ {
+ KexiUtils::WaitCursorRemover remover;
+ params = KexiQueryParameters::getParameters(this, *conn->driver(), *m_query, ok);
+ }
+ if (ok) //input cancelled
+ m_cursor = conn->executeQuery( *m_query, params );
+ }
+ m_scrollView->invalidateDataSources( invalidSources, m_query );
+ ok = m_cursor!=0;
+ }
+
+ if (!invalidSources.isEmpty())
+ m_dbform->updateTabStopsOrder();
+
+ if (ok) {
+//! @todo PRIMITIVE!! data setting:
+//! @todo KexiTableViewData is not great name for data class here... rename/move?
+ KexiTableViewData* data = new KexiTableViewData(m_cursor);
+ if (forceReadOnlyDataSource)
+ data->setReadOnly(true);
+ data->preloadAllRows();
+
+///*! @todo few backends return result count for free! - no need to reopen() */
+// int resultCount = -1;
+// if (ok) {
+// resultCount = m_conn->resultCount(m_conn->selectStatement(*m_query));
+// ok = m_cursor->reopen();
+// }
+// if (ok)
+// ok = ! (!m_cursor->moveFirst() && m_cursor->error());
+
+ m_scrollView->setData( data, true /*owner*/ );
+ }
+ else
+ m_scrollView->setData( 0, false );
+}
+
+void
+KexiFormView::slotDirty(KFormDesigner::Form *dirtyForm, bool isDirty)
+{
+ if(dirtyForm == form())
+ KexiViewBase::setDirty(isDirty);
+}
+
+KexiDB::SchemaData*
+KexiFormView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
+{
+ KexiDB::SchemaData *s = KexiViewBase::storeNewData(sdata, cancel);
+ kexipluginsdbg << "KexiDBForm::storeNewData(): new id:" << s->id() << endl;
+
+ if (!s || cancel) {
+ delete s;
+ return 0;
+ }
+ if (!storeData()) {
+ //failure: remove object's schema data to avoid garbage
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ conn->removeObject( s->id() );
+ delete s;
+ return 0;
+ }
+ return s;
+}
+
+tristate
+KexiFormView::storeData(bool dontAsk)
+{
+ Q_UNUSED(dontAsk);
+ kexipluginsdbg << "KexiDBForm::storeData(): " << parentDialog()->partItem()->name()
+ << " [" << parentDialog()->id() << "]" << endl;
+
+ //-- first, store local BLOBs, so identifiers can be updated
+//! @todo remove unused data stored previously
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ KexiDB::TableSchema *blobsTable = conn->tableSchema("kexi__blobs");
+ if (!blobsTable) { //compatibility check for older Kexi project versions
+//! @todo show message about missing kexi__blobs?
+ return false;
+ }
+ // Not all engines accept passing NULL to PKEY o_id, so we're omitting it.
+ QStringList blobsFieldNamesWithoutID(blobsTable->names());
+ blobsFieldNamesWithoutID.pop_front();
+ KexiDB::FieldList *blobsFieldsWithoutID = blobsTable->subList(blobsFieldNamesWithoutID);
+
+ KexiDB::PreparedStatement::Ptr st = conn->prepareStatement(
+ KexiDB::PreparedStatement::InsertStatement, *blobsFieldsWithoutID);
+ if (!st) {
+ delete blobsFieldsWithoutID;
+ //! @todo show message
+ return false;
+ }
+ KexiBLOBBuffer *blobBuf = KexiBLOBBuffer::self();
+ KexiFormView *designFormView
+ = dynamic_cast<KexiFormView*>( parentDialog()->viewForMode(Kexi::DesignViewMode) );
+ if (designFormView) {
+ for (QMapConstIterator<QWidget*, KexiBLOBBuffer::Id_t> it = tempData()->unsavedLocalBLOBs.constBegin();
+ it!=tempData()->unsavedLocalBLOBs.constEnd(); ++it)
+ {
+ if (!it.key()) {
+ kexipluginswarn << "KexiFormView::storeData(): it.key()==0 !" << endl;
+ continue;
+ }
+ kexipluginsdbg << "name=" << it.key()->name() << " dataID=" << it.data() << endl;
+ KexiBLOBBuffer::Handle h( blobBuf->objectForId(it.data(), /*!stored*/false) );
+ if (!h)
+ continue; //no BLOB assigned
+
+ QString originalFileName(h.originalFileName());
+ QFileInfo fi(originalFileName);
+ QString caption(fi.baseName().replace('_', " ").simplifyWhiteSpace());
+
+ if (st) {
+ *st /* << NO, (pgsql doesn't support this):QVariant()*/ /*id*/
+ << h.data() << originalFileName << caption
+ << h.mimeType() << (uint)/*! @todo unsafe */h.folderId();
+ if (!st->execute()) {
+ delete blobsFieldsWithoutID;
+ kexipluginsdbg << " execute error" << endl;
+ return false;
+ }
+ }
+ delete blobsFieldsWithoutID;
+ blobsFieldsWithoutID=0;
+ const Q_ULLONG storedBLOBID = conn->lastInsertedAutoIncValue("o_id", "kexi__blobs");
+ if ((Q_ULLONG)-1 == storedBLOBID) {
+ //! @todo show message?
+ return false;
+ }
+ kexipluginsdbg << " storedDataID=" << storedBLOBID << endl;
+ h.setStoredWidthID((KexiBLOBBuffer::Id_t /*unsafe - will be fixed in Qt4*/)storedBLOBID);
+ //set widget's internal property so it can be saved...
+ const QVariant oldStoredPixmapId( it.key()->property("storedPixmapId") );
+ it.key()->setProperty("storedPixmapId",
+ QVariant((uint /* KexiBLOBBuffer::Id_t is unsafe and unsupported by QVariant - will be fixed in Qt4*/)storedBLOBID));
+ KFormDesigner::ObjectTreeItem *widgetItem = designFormView->form()->objectTree()->lookup(it.key()->name()); //form()->objectTree()->lookup(it.key()->name());
+ if (widgetItem)
+ widgetItem->addModifiedProperty( "storedPixmapId", oldStoredPixmapId );
+ else
+ kexipluginswarn << "KexiFormView::storeData(): no '" << widgetItem->name() << "' widget found within a form" << endl;
+ }
+ }
+
+ //-- now, save form's XML
+ QString data;
+ if (!KFormDesigner::FormIO::saveFormToString(tempData()->form, data))
+ return false;
+ if (!storeDataBlock(data))
+ return false;
+
+ //all blobs are now saved
+ tempData()->unsavedLocalBLOBs.clear();
+
+ tempData()->tempForm = QString::null;
+ return true;
+}
+
+#if 0
+/// Action stuff /////////////////
+void
+KexiFormView::slotWidgetSelected(KFormDesigner::Form *f, bool multiple)
+{
+ if(f != form())
+ return;
+
+ enableFormActions();
+ // Enable edit actions
+ setAvailable("edit_copy", true);
+ setAvailable("edit_cut", true);
+ setAvailable("edit_clear", true);
+
+ // 'Align Widgets' menu
+ setAvailable("formpart_align_menu", multiple);
+ setAvailable("formpart_align_to_left", multiple);
+ setAvailable("formpart_align_to_right", multiple);
+ setAvailable("formpart_align_to_top", multiple);
+ setAvailable("formpart_align_to_bottom", multiple);
+
+ setAvailable("formpart_adjust_size_menu", true);
+ setAvailable("formpart_adjust_width_small", multiple);
+ setAvailable("formpart_adjust_width_big", multiple);
+ setAvailable("formpart_adjust_height_small", multiple);
+ setAvailable("formpart_adjust_height_big", multiple);
+
+ setAvailable("formpart_format_raise", true);
+ setAvailable("formpart_format_lower", true);
+
+ // If the widgets selected is a container, we enable layout actions
+ if(!multiple)
+ {
+ KFormDesigner::ObjectTreeItem *item = f->objectTree()->lookup( f->selectedWidgets()->first()->name() );
+ if(item && item->container())
+ multiple = true;
+ }
+ // Layout actions
+ setAvailable("formpart_layout_hbox", multiple);
+ setAvailable("formpart_layout_vbox", multiple);
+ setAvailable("formpart_layout_grid", multiple);
+
+ KFormDesigner::Container *container = f->activeContainer();
+ setAvailable("formpart_break_layout", container ?
+ (container->layoutType() != KFormDesigner::Container::NoLayout) : false );
+}
+
+void
+KexiFormView::slotFormWidgetSelected(KFormDesigner::Form *f)
+{
+ if(f != form())
+ return;
+
+ disableWidgetActions();
+ enableFormActions();
+
+ // Layout actions
+ setAvailable("formpart_layout_hbox", true);
+ setAvailable("formpart_layout_vbox", true);
+ setAvailable("formpart_layout_grid", true);
+ setAvailable("formpart_break_layout", (f->toplevelContainer()->layoutType() != KFormDesigner::Container::NoLayout));
+}
+
+void
+KexiFormView::slotNoFormSelected() // == form in preview mode
+{
+ disableWidgetActions();
+
+ // Disable paste action
+ setAvailable("edit_paste", false);
+ setAvailable("edit_undo", false);
+ setAvailable("edit_redo", false);
+
+ // Disable 'Tools' actions
+ setAvailable("formpart_pixmap_collection", false);
+ setAvailable("formpart_connections", false);
+ setAvailable("formpart_taborder", false);
+ setAvailable("formpart_change_style", false);
+}
+
+void
+KexiFormView::enableFormActions()
+{
+ // Enable 'Tools' actions
+ setAvailable("formpart_pixmap_collection", true);
+ setAvailable("formpart_connections", true);
+ setAvailable("formpart_taborder", true);
+
+ setAvailable("edit_paste", KFormDesigner::FormManager::self()->isPasteEnabled());
+}
+
+void
+KexiFormView::disableWidgetActions()
+{
+ // Disable edit actions
+ setAvailable("edit_copy", false);
+ setAvailable("edit_cut", false);
+ setAvailable("edit_clear", false);
+
+ // Disable format functions
+ setAvailable("formpart_align_menu", false);
+ setAvailable("formpart_align_to_left", false);
+ setAvailable("formpart_align_to_right", false);
+ setAvailable("formpart_align_to_top", false);
+ setAvailable("formpart_align_to_bottom", false);
+
+ setAvailable("formpart_adjust_size_menu", false);
+ setAvailable("formpart_adjust_width_small", false);
+ setAvailable("formpart_adjust_width_big", false);
+ setAvailable("formpart_adjust_height_small", false);
+ setAvailable("formpart_adjust_height_big", false);
+
+ setAvailable("formpart_format_raise", false);
+ setAvailable("formpart_format_lower", false);
+
+ setAvailable("formpart_layout_hbox", false);
+ setAvailable("formpart_layout_vbox", false);
+ setAvailable("formpart_layout_grid", false);
+ setAvailable("formpart_break_layout", false);
+}
+
+void
+KexiFormView::setUndoEnabled(bool enabled)
+{
+ setAvailable("edit_undo", enabled);
+}
+
+void
+KexiFormView::setRedoEnabled(bool enabled)
+{
+ setAvailable("edit_redo", enabled);
+}
+#endif //0
+
+QSize
+KexiFormView::preferredSizeHint(const QSize& otherSize)
+{
+ if (parentDialog()->neverSaved()) {
+ //ignore otherSize if possible
+// return KexiViewBase::preferredSizeHint( (parentDialog() && parentDialog()->mdiParent()) ? QSize(10000,10000) : otherSize);
+ }
+
+ return (m_dbform->size()
+ +QSize(m_scrollView->verticalScrollBar()->isVisible() ? m_scrollView->verticalScrollBar()->width()*3/2 : 10,
+ m_scrollView->horizontalScrollBar()->isVisible() ? m_scrollView->horizontalScrollBar()->height()*3/2 : 10))
+ .expandedTo( KexiViewBase::preferredSizeHint(otherSize) );
+}
+
+void
+KexiFormView::resizeEvent( QResizeEvent *e )
+{
+ if (viewMode()==Kexi::DataViewMode) {
+ m_scrollView->refreshContentsSizeLater(
+ e->size().width()!=e->oldSize().width(),
+ e->size().height()!=e->oldSize().height()
+ );
+ }
+ KexiViewBase::resizeEvent(e);
+ m_scrollView->updateNavPanelGeometry();
+ if (m_delayedFormContentsResizeOnShow>0) { // && isVisible()) {
+ m_delayedFormContentsResizeOnShow--;
+ m_dbform->resize( e->size() - QSize(30, 30) );
+ }
+}
+
+void
+KexiFormView::setFocusInternal()
+{
+ if (viewMode() == Kexi::DataViewMode) {
+ if (m_dbform->focusWidget()) {
+ //better-looking focus
+ if (m_setFocusInternalOnce) {
+ KexiUtils::setFocusWithReason(m_setFocusInternalOnce, QFocusEvent::Other);//Tab);
+ m_setFocusInternalOnce = 0;
+ }
+ else {
+ //ok? SET_FOCUS_USING_REASON(m_dbform->focusWidget(), QFocusEvent::Other);//Tab);
+ }
+ return;
+ }
+ }
+ QWidget::setFocus();
+}
+
+void
+KexiFormView::show()
+{
+ KexiDataAwareView::show();
+
+//moved from KexiFormScrollView::show():
+
+ //now get resize mode settings for entire form
+ // if (resizeMode() == KexiFormView::ResizeAuto)
+ if (viewMode()==Kexi::DataViewMode) {
+ if (resizeMode() == KexiFormView::ResizeAuto)
+ m_scrollView->setResizePolicy(QScrollView::AutoOneFit);
+ }
+}
+
+void
+KexiFormView::slotFocus(bool in)
+{
+ if(in && form() && KFormDesigner::FormManager::self() && KFormDesigner::FormManager::self()->activeForm() != form()) {
+ KFormDesigner::FormManager::self()->windowChanged(m_dbform);
+ updateDataSourcePage();
+ }
+}
+
+void
+KexiFormView::updateDataSourcePage()
+{
+ if (viewMode()==Kexi::DesignViewMode) {
+ QCString dataSourceMimeType, dataSource;
+ KFormDesigner::WidgetPropertySet *set = KFormDesigner::FormManager::self()->propertySet();
+ if (set->contains("dataSourceMimeType"))
+ dataSourceMimeType = (*set)["dataSourceMimeType"].value().toCString();
+ if (set->contains("dataSource"))
+ dataSource = (*set)["dataSource"].value().toCString();
+
+ formPart()->dataSourcePage()->setDataSource(dataSourceMimeType, dataSource);
+ }
+}
+
+void
+KexiFormView::slotHandleDragMoveEvent(QDragMoveEvent* e)
+{
+ if (KexiFieldDrag::canDecodeMultiple( e )) {
+ e->accept(true);
+ //dirty: drawRect(QRect( e->pos(), QSize(50, 20)), 2);
+ }
+}
+
+void
+KexiFormView::slotHandleDropEvent(QDropEvent* e)
+{
+ const QWidget *targetContainerWidget = dynamic_cast<const QWidget*>(sender());
+ KFormDesigner::ObjectTreeItem *targetContainerWidgetItem = targetContainerWidget
+ ? form()->objectTree()->lookup( targetContainerWidget->name() ) : 0;
+ if (targetContainerWidgetItem && targetContainerWidgetItem->container()
+ && KexiFieldDrag::canDecodeMultiple( e ))
+ {
+ QString sourceMimeType, sourceName;
+ QStringList fields;
+ if (!KexiFieldDrag::decodeMultiple( e, sourceMimeType, sourceName, fields ))
+ return;
+ insertAutoFields(sourceMimeType, sourceName, fields,
+ targetContainerWidgetItem->container(), e->pos());
+ }
+}
+
+void
+KexiFormView::insertAutoFields(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& fields, KFormDesigner::Container* targetContainer, const QPoint& _pos)
+{
+ if (fields.isEmpty())
+ return;
+
+ KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
+ KexiDB::TableOrQuerySchema tableOrQuery(conn, sourceName.latin1(), sourceMimeType=="kexi/table");
+ if (!tableOrQuery.table() && !tableOrQuery.query()) {
+ kexipluginswarn << "KexiFormView::insertAutoFields(): no such table/query \""
+ << sourceName << "\"" << endl;
+ return;
+ }
+
+ QPoint pos(_pos);
+ //if pos is not specified, compute a new position:
+ if (pos==QPoint(-1,-1)) {
+ if (m_widgetGeometryForRecentInsertAutoFields.isValid()) {
+ pos = m_widgetGeometryForRecentInsertAutoFields.bottomLeft()
+ + QPoint(0,form()->gridSize());
+ }
+ else {
+ pos = QPoint(40, 40); //start here
+ }
+ }
+
+ // there will be many actions performed, do not update property pane until all that's finished
+ KFormDesigner::FormManager::self()->blockPropertyEditorUpdating(this);
+
+//! todo unnamed query colums are not supported
+
+// KFormDesigner::WidgetList* prevSelection = form()->selectedWidgets();
+ KFormDesigner::WidgetList widgetsToSelect;
+ KFormDesigner::CommandGroup *group = new KFormDesigner::CommandGroup(
+ fields.count()==1 ? i18n("Insert AutoField widget") : i18n("Insert %1 AutoField widgets").arg(fields.count()),
+ KFormDesigner::FormManager::self()->propertySet()
+ );
+
+ foreach( QStringList::ConstIterator, it, fields ) {
+ KexiDB::QueryColumnInfo* column = tableOrQuery.columnInfo(*it);
+ if (!column) {
+ kexipluginswarn << "KexiFormView::insertAutoFields(): no such field \""
+ << *it << "\" in table/query \"" << sourceName << "\"" << endl;
+ continue;
+ }
+//! todo add autolabel using field's caption or name
+ //KFormDesigner::Container *targetContainer;
+/* QWidget* targetContainerWidget = QApplication::widgetAt(pos, true);
+ while (targetContainerWidget
+ && !dynamic_cast<KFormDesigner::Container*>(targetContainerWidget))
+ {
+ targetContainerWidget = targetContainerWidget->parentWidget();
+ }
+ if (dynamic_cast<KFormDesigner::Container*>(targetContainerWidget))
+ targetContainer = dynamic_cast<KFormDesigner::Container*>(targetContainerWidget);
+ else
+ targetContainer = form()->toplevelContainer();*/
+ KFormDesigner::InsertWidgetCommand *insertCmd
+ = new KFormDesigner::InsertWidgetCommand(targetContainer,
+ //! todo this is hardcoded!
+ "KexiDBAutoField",
+ //! todo this name can be invalid for expressions: if so, fall back to a default class' prefix!
+ pos, column->aliasOrName()
+ );
+ insertCmd->execute();
+ group->addCommand(insertCmd, false/*don't exec twice*/);
+
+ KFormDesigner::ObjectTreeItem *newWidgetItem
+ = form()->objectTree()->dict()->find(insertCmd->widgetName());
+ KexiDBAutoField* newWidget
+ = newWidgetItem ? dynamic_cast<KexiDBAutoField*>(newWidgetItem->widget()) : 0;
+ widgetsToSelect.append(newWidget);
+//#if 0
+ KFormDesigner::CommandGroup *subGroup
+ = new KFormDesigner::CommandGroup("", KFormDesigner::FormManager::self()->propertySet());
+ QMap<QCString, QVariant> propValues;
+ propValues.insert("dataSource", column->aliasOrName());
+ propValues.insert("fieldTypeInternal", (int)column->field->type());
+ propValues.insert("fieldCaptionInternal", column->captionOrAliasOrName());
+ KFormDesigner::FormManager::self()->propertySet()->createPropertyCommandsInDesignMode(
+ newWidget, propValues, subGroup, false/*!addToActiveForm*/,
+ true /*!execFlagForSubCommands*/);
+ subGroup->execute();
+ group->addCommand( subGroup, false/*will not be executed on CommandGroup::execute()*/ );
+
+//#endif
+ //set data source and caption
+ //-we don't need to use PropertyCommand here beacause we don't need UNDO
+ // for these single commands
+// newWidget->setDataSource(column->aliasOrName());
+// newWidget->setFieldTypeInternal((int)column->field->type());
+// newWidget->setFieldCaptionInternal(column->captionOrAliasOrName());
+ //resize again because autofield's type changed what can lead to changed sizeHint()
+// newWidget->resize(newWidget->sizeHint());
+ KFormDesigner::WidgetList list;
+ list.append(newWidget);
+ KFormDesigner::AdjustSizeCommand *adjustCommand
+ = new KFormDesigner::AdjustSizeCommand(KFormDesigner::AdjustSizeCommand::SizeToFit,
+ list, form());
+ adjustCommand->execute();
+ group->addCommand( adjustCommand,
+ false/*will not be executed on CommandGroup::execute()*/
+ );
+
+ if (newWidget) {//move position down for next widget
+ pos.setY( pos.y() + newWidget->height() + form()->gridSize());
+ }
+ }
+ if (widgetsToSelect.last()) {
+ //resize form if needed
+ QRect oldFormRect( m_dbform->geometry() );
+ QRect newFormRect( oldFormRect );
+ newFormRect.setWidth(QMAX(m_dbform->width(), widgetsToSelect.last()->geometry().right()+1));
+ newFormRect.setHeight(QMAX(m_dbform->height(), widgetsToSelect.last()->geometry().bottom()+1));
+ if (newFormRect != oldFormRect) {
+ //1. resize by hand
+ m_dbform->setGeometry( newFormRect );
+ //2. store information about resize
+ KFormDesigner::PropertyCommand *resizeFormCommand = new KFormDesigner::PropertyCommand(
+ KFormDesigner::FormManager::self()->propertySet(), m_dbform->name(),
+ oldFormRect, newFormRect, "geometry");
+ group->addCommand(resizeFormCommand, true/*will be executed on CommandGroup::execute()*/);
+ }
+
+ //remember geometry of the last inserted widget
+ m_widgetGeometryForRecentInsertAutoFields = widgetsToSelect.last()->geometry();
+ }
+
+ //eventually, add entire command group to active form
+ form()->addCommand( group, true/*exec*/ );
+
+// group->debug();
+
+ //enable proper REDO usage
+ group->resetAllowExecuteFlags();
+
+ m_scrollView->repaint();
+ m_scrollView->viewport()->repaint();
+ m_scrollView->repaintContents();
+ m_scrollView->updateContents();
+ m_scrollView->clipper()->repaint();
+ m_scrollView->refreshContentsSize();
+
+ //select all inserted widgets, if multiple
+ if (widgetsToSelect.count()>1) {
+ form()->setSelectedWidget(0);
+ foreach_list (KFormDesigner::WidgetListIterator, it, widgetsToSelect)
+ form()->setSelectedWidget(it.current(), true/*add*/, true/*dontRaise*/);
+ }
+
+ // eventually, update property pane
+ KFormDesigner::FormManager::self()->unblockPropertyEditorUpdating(this, KFormDesigner::FormManager::self()->propertySet());
+}
+
+void
+KexiFormView::setUnsavedLocalBLOB(QWidget *widget, KexiBLOBBuffer::Id_t id)
+{
+//! @todo if there already was data assigned, remember it should be dereferenced
+ if (id==0)
+ tempData()->unsavedLocalBLOBs.remove(widget);
+ else
+ tempData()->unsavedLocalBLOBs.insert(widget, id);
+}
+
+/*
+todo
+void KexiFormView::updateActions(bool activated)
+{
+ if (viewMode()==Kexi::DesignViewMode) {
+ if (form()->selectedWidget()) {
+ if (form()->widget() == form()->selectedWidget())
+ KFormDesigner::FormManager::self()->emitFormWidgetSelected( form() );
+ else
+ KFormDesigner::FormManager::self()->emitWidgetSelected( form(), false );
+ }
+ else if (form()->selectedWidgets()) {
+ KFormDesigner::FormManager::self()->emitWidgetSelected( form(), true );
+ }
+ }
+ KexiDataAwareView::updateActions(activated);
+}*/
+
+/*
+void KexiFormView::parentDialogDetached()
+{
+ m_dbform->updateTabStopsOrder(form());
+}
+
+void KexiFormView::parentDialogAttached(KMdiChildFrm *)
+{
+ m_dbform->updateTabStopsOrder(form());
+}*/
+
+#include "kexiformview.moc"
+
diff --git a/kexi/plugins/forms/kexiformview.h b/kexi/plugins/forms/kexiformview.h
new file mode 100644
index 00000000..0a774556
--- /dev/null
+++ b/kexi/plugins/forms/kexiformview.h
@@ -0,0 +1,231 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ 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 KEXIFORMVIEW_H
+#define KEXIFORMVIEW_H
+
+#include <qtimer.h>
+
+#include <kexiviewbase.h>
+#include <widget/kexidataawareview.h>
+
+#include "kexiformpart.h"
+#include <core/kexiblobbuffer.h>
+
+class KexiFormPart;
+class KexiMainWindow;
+class KexiDBForm;
+class KexiTableItem;
+class KexiTableViewData;
+class KexiFormScrollView;
+namespace KexiDB { class Cursor; }
+namespace KFormDesigner
+{
+ class Container;
+}
+
+//! The KexiFormView lass provides a data-driven (record-based) form view .
+/*! The KexiFormView can display data provided "by hand"
+ or from KexiDB-compatible database source.
+
+ This class provides a single view used inside KexiDialogBase.
+ It takes care of saving/loading form, of enabling actions when needed.
+ One KexiFormView object is instantiated for data view mode
+ and a second KexiFormView object is instantiated for design view mode.
+
+ @see KexiDataTable
+*/
+class KEXIFORMUTILS_EXPORT KexiFormView : public KexiDataAwareView
+{
+ Q_OBJECT
+
+ public:
+ enum ResizeMode {
+ ResizeAuto = 0,
+ ResizeDefault = ResizeAuto,
+ ResizeFixed = 1,
+ NoResize = 2 /*! @todo */
+ };
+
+// KexiFormView(KexiMainWindow *win, QWidget *parent, const char *name, KexiDB::Connection *conn);
+ KexiFormView(KexiMainWindow *mainWin, QWidget *parent, const char *name = 0,
+ bool dbAware = true);
+ virtual ~KexiFormView();
+
+// KexiDB::Connection* connection() { return m_conn; }
+
+ virtual QSize preferredSizeHint(const QSize& otherSize);
+
+ int resizeMode() const { return m_resizeMode; }
+
+ KFormDesigner::Form* form() const;
+
+ /*! Assigns \a id local (static) BLOB's identifier for \a widget widget.
+ Previously assigned BLOB will be usassigned.
+ If \a id is 0, BLOB is unassigned and no new is assigned.
+
+ This method is called when a widget supporting BLOB data
+ (currently, images from KexiDBImageBox, within KexiDBFactory) has BLOB assigned by identifier \a id.
+ BLOB identifiers are defined by KexiBLOBBuffer (KexiBLOBBuffer::self() instance).
+
+ The data collected by this method is used on form's design saving (in design mode).
+ Local BLOBs are retrieved KexiBLOBBuffer::self() and stored in "kexi__blobs" 'system' table.
+ Note that db-aware BLOBs (non local) are not handled this way.
+ */
+ void setUnsavedLocalBLOB(QWidget *widget, KexiBLOBBuffer::Id_t id);
+
+ public slots:
+ /*! Reimplemented to update resize policy. */
+ virtual void show();
+
+ /*! Inserts autofields onto the form at \a pos position.
+ \a sourceMimeType can be "kexi/table" or "kexi/query",
+ \a sourceName is a name of a table or query, \a fields is a list of fields to insert (one or more)
+ Fields are inserted using standard KFormDesigner::InsertWidgetCommand framework,
+ so undo/redo is available for this operation.
+
+ If multiple fields are provided, they will be aligned vertically.
+ If \a pos is QPoint(-1,-1) (the default), position is computed automatically
+ based on a position last inserted field using this method.
+ If this method has not been called yet, position of QPoint(40, 40) will be set.
+
+ Called by:
+ - slotHandleDropEvent() when field(s) are dropped from the data source pane onto the form
+ - KexiFormManager is a used clicked "Insert fields" button on the data source pane. */
+ void insertAutoFields(const QString& sourceMimeType, const QString& sourceName,
+ const QStringList& fields, KFormDesigner::Container* targetContainerWidget,
+ const QPoint& pos = QPoint(-1,-1));
+
+ protected slots:
+ void slotPropertySetSwitched(KoProperty::Set *b, bool forceReload = false,
+ const QCString& propertyToSelect = QCString());
+ void slotDirty(KFormDesigner::Form *f, bool isDirty);
+ void slotFocus(bool in);
+ void slotHandleDragMoveEvent(QDragMoveEvent* e);
+
+ //! Handles field(s) dropping from the data source pane onto the form
+ //! @see insertAutoFields()
+ void slotHandleDropEvent(QDropEvent* e);
+
+//moved to formmanager void slotWidgetSelected(KFormDesigner::Form *form, bool multiple);
+//moved to formmanager void slotFormWidgetSelected(KFormDesigner::Form *form);
+//moved to formmanager void slotNoFormSelected();
+
+//moved to formmanager void setUndoEnabled(bool enabled);
+//moved to formmanager void setRedoEnabled(bool enabled);
+
+ protected:
+ virtual tristate beforeSwitchTo(int mode, bool &dontStore);
+ virtual tristate afterSwitchFrom(int mode);
+ virtual KoProperty::Set* propertySet() { return m_propertySet; }
+
+ virtual KexiDB::SchemaData* storeNewData(const KexiDB::SchemaData& sdata, bool &cancel);
+ virtual tristate storeData(bool dontAsk = false);
+
+ KexiFormPart::TempData* tempData() const {
+ return dynamic_cast<KexiFormPart::TempData*>(parentDialog()->tempData()); }
+ KexiFormPart* formPart() const { return dynamic_cast<KexiFormPart*>(part()); }
+
+//moved to formmanager void disableWidgetActions();
+//moved to formmanager void enableFormActions();
+
+ void setForm(KFormDesigner::Form *f);
+
+ void initForm();
+
+ void loadForm();
+
+ //! Used in loadForm()
+ void updateAutoFieldsDataSource();
+
+ //! Used in loadForm()
+ void updateValuesForSubproperties();
+
+ virtual void resizeEvent ( QResizeEvent * );
+
+ void initDataSource();
+
+ virtual void setFocusInternal();
+
+/* // for navigator
+ virtual void moveToRecordRequested(uint r);
+ virtual void moveToLastRecordRequested();
+ virtual void moveToPreviousRecordRequested();
+ virtual void moveToNextRecordRequested();
+ virtual void moveToFirstRecordRequested();
+ virtual void addNewRecordRequested();*/
+
+ /*! Called after loading the form contents (before showing it).
+ Also called when the form window (KexiDialogBase) is detached
+ (in KMDI's Child Frame mode), because otherwise tabstop ordering can get broken. */
+ void updateTabStopsOrder();
+
+ /*! @internal */
+ void deleteQuery();
+
+ /*! @internal */
+ void updateDataSourcePage();
+
+ /*! Reimplemented after KexiViewBase.
+ Updates actions (e.g. availability). */
+// todo virtual void updateActions(bool activated);
+
+ KexiDBForm *m_dbform;
+ KexiFormScrollView *m_scrollView;
+ KoProperty::Set *m_propertySet;
+
+ /*! Database cursor used for data retrieving.
+ It is shared between subsequent Data view sessions (just reopened on switch),
+ but deleted and recreated from scratch when form's "dataSource" property changed
+ since last form viewing (m_previousDataSourceString is used for that). */
+ QString m_previousDataSourceString;
+
+ int m_resizeMode;
+
+ KexiDB::QuerySchema* m_query;
+
+ /*! True, if m_query is created as temporary object within this form.
+ If user selected an existing, predefined (stored) query, m_queryIsOwned will be false,
+ so the query object will not be destroyed. */
+ bool m_queryIsOwned;
+
+ KexiDB::Cursor *m_cursor;
+
+ /*! For new (empty) forms only:
+ Our form's area will be resized more than once.
+ We will resize form widget itself later (in resizeEvent()). */
+ int m_delayedFormContentsResizeOnShow;
+
+ //! Used in setFocusInternal()
+ QGuardedPtr<QWidget> m_setFocusInternalOnce;
+
+
+ /*! Stores geometry of widget recently inserted using insertAutoFields() method.
+ having this information, we'r eable to compute position for a newly
+ inserted widget in insertAutoFields() is such position has not been specified.
+ (the position is specified when a widget is inserted with mouse drag & dropping
+ but not with clicking of 'Insert fields' button from Data Source pane) */
+ QRect m_widgetGeometryForRecentInsertAutoFields;
+
+ //! Used in setUnsavedLocalBLOBs()
+// QMap<QWidget*, KexiBLOBBuffer::Id_t> m_unsavedLocalBLOBs;
+};
+
+#endif
diff --git a/kexi/plugins/forms/kformdesigner_kexidbfactory.desktop b/kexi/plugins/forms/kformdesigner_kexidbfactory.desktop
new file mode 100644
index 00000000..4e5bb719
--- /dev/null
+++ b/kexi/plugins/forms/kformdesigner_kexidbfactory.desktop
@@ -0,0 +1,55 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KFormDesigner/WidgetFactory
+
+Name=Kexi DB Widgets
+Name[bg]=Графични обекти на Kexi за бази данни
+Name[ca]=Estris DB de Kexi
+Name[cy]=Celfigion Cronfa Ddata Kexi
+Name[da]=Kexi DB-kontroller
+Name[de]=Kexi Datenbank-Elemente
+Name[el]=Γραφικά συστατικά Kexi DB
+Name[eo]=Kexi DB-fenestraĵo
+Name[es]=Wigdet de BD de Kexi
+Name[et]=Kexi andmebaasividinad
+Name[eu]=Kexi-ren datu-baseko trepetak
+Name[fa]=عناصر Kexi DB
+Name[fi]=Kexi tietokantaelementit
+Name[fr]=Éléments graphiques de base de données Kexi
+Name[fy]=Kexi DB-widgets
+Name[gl]=Elementos de Base de Datos Kexi
+Name[he]=פריטי מסד נתונים של Kexi
+Name[hr]=Kexi DB widgeti
+Name[hu]=Kexi adatbázis-kezelési grafikus elemek
+Name[is]=Kexi gagnagrunns hlutir
+Name[it]=Oggetti per banche dati per Kexi
+Name[ja]=Kexi DB ウィジェット
+Name[km]=ធាតុ​ក្រាហ្វិក DB សម្រាប់ Kexi
+Name[lv]=Kexi DB logdaļas
+Name[ms]=Widget DB Kexi
+Name[nb]=DB-element for Kexi
+Name[nds]=Datenbank-Stüerelementen för Kexi
+Name[ne]=केक्सी DB विजेटहरू
+Name[nl]=Kexi DB-widgets
+Name[nn]=DB-element for Kexi
+Name[pl]=Kontrolki baz danych dla Kexi
+Name[pt]=Elementos de Base de Dados Kexi
+Name[pt_BR]=Widgets de BD do Kexi
+Name[ru]=Элементы управления для работы с базами данных Kexi
+Name[se]=Kexi-DV-áđat
+Name[sk]=Komponenty Kexi DB
+Name[sl]=Gradniki za zbirko podatkov za Kexi
+Name[sr]=Kexi-јеве DB контроле
+Name[sr@Latn]=Kexi-jeve DB kontrole
+Name[sv]=Kexi-databaskomponenter
+Name[ta]=கெக்சி டிபி சாளர உருக்கள்
+Name[tr]=Kexi DB Parçacıkları
+Name[uk]=Віджети Kexi DB
+Name[uz]=Kexi maʼlumot baza vidjetlari
+Name[uz@cyrillic]=Kexi маълумот база виджетлари
+Name[zh_CN]=Kexi 数据库部件
+Name[zh_TW]=Kexi DB 視窗元件
+
+X-KDE-Library=kformdesigner_kexidbwidgets
+X-KFormDesigner-FactoryGroup=kexi
+X-KFormDesigner-WidgetFactoryVersion=2
diff --git a/kexi/plugins/forms/widgets/Makefile.am b/kexi/plugins/forms/widgets/Makefile.am
new file mode 100644
index 00000000..5ca5cbd8
--- /dev/null
+++ b/kexi/plugins/forms/widgets/Makefile.am
@@ -0,0 +1,28 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+noinst_LTLIBRARIES = libkexiformutilswidgets.la
+
+libkexiformutilswidgets_la_SOURCES = \
+ kexidbutils.cpp \
+ kexidbautofield.cpp \
+ kexidbform.cpp \
+ kexidbsubform.cpp \
+ kexidblabel.cpp \
+ kexidbimagebox.cpp \
+ kexipushbutton.cpp \
+ kexiframe.cpp \
+ kexidblineedit.cpp \
+ kexidbcheckbox.cpp \
+ kexidbtextedit.cpp \
+ kexidbcombobox.cpp
+
+libkexiformutilswidgets_la_LDFLAGS = $(all_libraries) -Wnounresolved
+libkexiformutilswidgets_la_LIBADD =
+
+libkexiformutilswidgets_la_METASOURCES = AUTO
+
+SUBDIRS = .
+
+# set the include path for X, qt and KDE
+INCLUDES= -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/plugins/forms -I$(top_srcdir)/kexi/core $(all_includes)
+
diff --git a/kexi/plugins/forms/widgets/kexidbautofield.cpp b/kexi/plugins/forms/widgets/kexidbautofield.cpp
new file mode 100644
index 00000000..36fbdb1a
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbautofield.cpp
@@ -0,0 +1,846 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Christian Nitschkowski <segfault_ii@web.de>
+ Copyright (C) 2005-2007 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 "kexidbautofield.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qmetaobject.h>
+#include <qapplication.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kexidbcheckbox.h"
+#include "kexidbimagebox.h"
+#include "kexidblabel.h"
+#include "kexidblineedit.h"
+#include "kexidbtextedit.h"
+#include "kexidbcombobox.h"
+#include "kexipushbutton.h"
+#include "kexidbform.h"
+
+#include <kexidb/queryschema.h>
+#include <formeditor/utils.h>
+#include <kexiutils/utils.h>
+
+#define KexiDBAutoField_SPACING 10 //10 pixel for spacing between a label and an editor widget
+
+//! @internal
+class KexiDBAutoField::Private
+{
+ public:
+ Private()
+ {
+ }
+
+ WidgetType widgetType; //!< internal: equal to m_widgetType_property or equal to result
+ //!< of widgetTypeForFieldType() if widgetTypeForFieldType is Auto
+ WidgetType widgetType_property; //!< provides widget type or Auto
+ LabelPosition lblPosition;
+ QBoxLayout *layout;
+ QLabel *label;
+ QString caption;
+ KexiDB::Field::Type fieldTypeInternal;
+ QString fieldCaptionInternal;
+ QColor baseColor; //!< needed because for unbound mode editor==0
+ QColor textColor; //!< needed because for unbound mode editor==0
+ bool autoCaption : 1;
+ bool focusPolicyChanged : 1;
+ bool designMode : 1;
+};
+
+//-------------------------------------
+
+KexiDBAutoField::KexiDBAutoField(const QString &text, WidgetType type, LabelPosition pos,
+ QWidget *parent, const char *name, bool designMode)
+ : QWidget(parent, name)
+ , KexiFormDataItemInterface()
+ , KFormDesigner::DesignTimeDynamicChildWidgetHandler()
+ , d( new Private() )
+{
+ d->designMode = designMode;
+ init(text, type, pos);
+}
+
+KexiDBAutoField::KexiDBAutoField(QWidget *parent, const char *name, bool designMode, LabelPosition pos)
+ : QWidget(parent, name)
+ , KexiFormDataItemInterface()
+ , KFormDesigner::DesignTimeDynamicChildWidgetHandler()
+ , d( new Private() )
+{
+ d->designMode = designMode;
+ init(QString::null/*i18n("Auto Field")*/, Auto, pos);
+}
+
+KexiDBAutoField::~KexiDBAutoField()
+{
+ setUpdatesEnabled(false);
+ if (m_subwidget)
+ m_subwidget->setUpdatesEnabled(false);
+ delete d;
+}
+
+void
+KexiDBAutoField::init(const QString &text, WidgetType type, LabelPosition pos)
+{
+ d->fieldTypeInternal = KexiDB::Field::InvalidType;
+ d->layout = 0;
+ m_subwidget = 0;
+ d->label = new QLabel(text, this);
+ d->label->installEventFilter( this );
+ //QFontMetrics fm( font() );
+ //d->label->setFixedWidth( fm.width("This is a test string length") );
+ d->autoCaption = true;
+ d->focusPolicyChanged = false;
+ d->widgetType = Auto;
+ d->widgetType_property = (type==Auto ? Text : type); //to force "differ" to be true in setWidgetType()
+ setLabelPosition(pos);
+ setWidgetType(type);
+ d->baseColor = palette().active().base();
+ d->textColor = palette().active().text();
+}
+
+void
+KexiDBAutoField::setWidgetType(WidgetType type)
+{
+ const bool differ = (type != d->widgetType_property);
+ d->widgetType_property = type;
+ if(differ) {
+ if(type == Auto) {// try to guess type from data source type
+ if (visibleColumnInfo())
+ d->widgetType = KexiDBAutoField::widgetTypeForFieldType(visibleColumnInfo()->field->type());
+ else
+ d->widgetType = Auto;
+ }
+ else
+ d->widgetType = d->widgetType_property;
+ createEditor();
+ }
+}
+
+void
+KexiDBAutoField::createEditor()
+{
+ if(m_subwidget) {
+ delete (QWidget *)m_subwidget;
+ }
+
+ QWidget *newSubwidget;
+ switch( d->widgetType ) {
+ case Text:
+ case Double: //! @todo setup validator
+ case Integer: //! @todo setup validator
+ case Date:
+ case Time:
+ case DateTime:
+ newSubwidget = new KexiDBLineEdit( this, QCString("KexiDBAutoField_KexiDBLineEdit:")+name() );
+ break;
+ case MultiLineText:
+ newSubwidget = new KexiDBTextEdit( this, QCString("KexiDBAutoField_KexiDBTextEdit:")+name() );
+ break;
+ case Boolean:
+ newSubwidget = new KexiDBCheckBox(dataSource(), this, QCString("KexiDBAutoField_KexiDBCheckBox:")+name());
+ break;
+ case Image:
+ newSubwidget = new KexiDBImageBox(d->designMode, this, QCString("KexiDBAutoField_KexiDBImageBox:")+name());
+ break;
+ case ComboBox:
+ newSubwidget = new KexiDBComboBox(this, QCString("KexiDBAutoField_KexiDBComboBox:")+name(), d->designMode);
+ break;
+ default:
+ newSubwidget = 0;
+ changeText(d->caption);
+ //d->label->setText( d->dataSource.isEmpty() ? "<datasource>" : d->dataSource );
+ break;
+ }
+
+ setSubwidget( newSubwidget ); //this will also allow to declare subproperties, see KFormDesigner::WidgetWithSubpropertiesInterface
+ if(newSubwidget) {
+ newSubwidget->setName( QCString("KexiDBAutoField_") + newSubwidget->className() );
+ dynamic_cast<KexiDataItemInterface*>(newSubwidget)->setParentDataItemInterface(this);
+ dynamic_cast<KexiFormDataItemInterface*>(newSubwidget)
+ ->setColumnInfo(columnInfo()); //needed at least by KexiDBImageBox
+ dynamic_cast<KexiFormDataItemInterface*>(newSubwidget)
+ ->setVisibleColumnInfo(visibleColumnInfo()); //needed at least by KexiDBComboBox
+ newSubwidget->setProperty("dataSource", dataSource()); //needed at least by KexiDBImageBox
+ KFormDesigner::DesignTimeDynamicChildWidgetHandler::childWidgetAdded(this);
+ newSubwidget->show();
+ d->label->setBuddy(newSubwidget);
+ if (d->focusPolicyChanged) {//if focusPolicy is changed at top level, editor inherits it
+ newSubwidget->setFocusPolicy(focusPolicy());
+ }
+ else {//if focusPolicy is not changed at top level, inherit it from editor
+ QWidget::setFocusPolicy(newSubwidget->focusPolicy());
+ }
+ setFocusProxy(newSubwidget); //ok?
+ if (parentWidget())
+ newSubwidget->setPalette( qApp->palette() );
+ copyPropertiesToEditor();
+// KFormDesigner::installRecursiveEventFilter(newSubwidget, this);
+ }
+
+ setLabelPosition(labelPosition());
+}
+
+void KexiDBAutoField::copyPropertiesToEditor()
+{
+ if (m_subwidget) {
+// kdDebug() << "KexiDBAutoField::copyPropertiesToEditor(): base col: " << d->baseColor.name() <<
+// "; text col: " << d->textColor.name() << endl;
+ QPalette p( m_subwidget->palette() );
+ p.setColor( QPalette::Active, QColorGroup::Base, d->baseColor );
+ if(d->widgetType == Boolean)
+ p.setColor( QPalette::Active, QColorGroup::Foreground, d->textColor );
+ else
+ p.setColor( QPalette::Active, QColorGroup::Text, d->textColor );
+ m_subwidget->setPalette(p);
+ //m_subwidget->setPaletteBackgroundColor( d->baseColor );
+ }
+}
+
+void
+KexiDBAutoField::setLabelPosition(LabelPosition position)
+{
+ d->lblPosition = position;
+ if(d->layout) {
+ QBoxLayout *lyr = d->layout;
+ d->layout = 0;
+ delete lyr;
+ }
+
+ if(m_subwidget)
+ m_subwidget->show();
+ //! \todo support right-to-left layout where positions are inverted
+ if (position==Top || position==Left) {
+ int align = d->label->alignment();
+ if(position == Top) {
+ d->layout = (QBoxLayout*) new QVBoxLayout(this);
+ align |= AlignVertical_Mask;
+ align ^= AlignVertical_Mask;
+ align |= AlignTop;
+ }
+ else {
+ d->layout = (QBoxLayout*) new QHBoxLayout(this);
+ align |= AlignVertical_Mask;
+ align ^= AlignVertical_Mask;
+ align |= AlignVCenter;
+ }
+ d->label->setAlignment(align);
+ if(d->widgetType == Boolean
+ || (d->widgetType == Auto && fieldTypeInternal() == KexiDB::Field::InvalidType && !d->designMode))
+ {
+ d->label->hide();
+ }
+ else {
+ d->label->show();
+ }
+ d->layout->addWidget(d->label, 0, position == Top ? int(Qt::AlignLeft) : 0);
+ if(position == Left && d->widgetType != Boolean)
+ d->layout->addSpacing(KexiDBAutoField_SPACING);
+ d->layout->addWidget(m_subwidget, 1);
+ KexiSubwidgetInterface *subwidgetInterface = dynamic_cast<KexiSubwidgetInterface*>((QWidget*)m_subwidget);
+ if (subwidgetInterface) {
+ if (subwidgetInterface->appendStretchRequired(this))
+ d->layout->addStretch(0);
+ if (subwidgetInterface->subwidgetStretchRequired(this)) {
+ QSizePolicy sizePolicy( m_subwidget->sizePolicy() );
+ if(position == Left) {
+ sizePolicy.setHorData( QSizePolicy::Minimum );
+ d->label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ }
+ else {
+ sizePolicy.setVerData( QSizePolicy::Minimum );
+ d->label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ }
+ m_subwidget->setSizePolicy(sizePolicy);
+ }
+ }
+// if(m_subwidget)
+ // m_subwidget->setSizePolicy(...);
+ }
+ else {
+ d->layout = (QBoxLayout*) new QHBoxLayout(this);
+ d->label->hide();
+ d->layout->addWidget(m_subwidget);
+ }
+ //a hack to force layout to be refreshed (any better idea for this?)
+ resize(size()+QSize(1,0));
+ resize(size()-QSize(1,0));
+ if (dynamic_cast<KexiDBAutoField*>((QWidget*)m_subwidget)) {
+ //needed for KexiDBComboBox
+ dynamic_cast<KexiDBAutoField*>((QWidget*)m_subwidget)->setLabelPosition(position);
+ }
+}
+
+void
+KexiDBAutoField::setInvalidState( const QString &text )
+{
+ // Widget with an invalid dataSource is just a QLabel
+ if (d->designMode)
+ return;
+ d->widgetType = Auto;
+ createEditor();
+ setFocusPolicy(QWidget::NoFocus);
+ if (m_subwidget)
+ m_subwidget->setFocusPolicy(QWidget::NoFocus);
+//! @todo or set this to editor's text?
+ d->label->setText( text );
+}
+
+bool
+KexiDBAutoField::isReadOnly() const
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->isReadOnly();
+ else
+ return false;
+}
+
+void
+KexiDBAutoField::setReadOnly( bool readOnly )
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->setReadOnly(readOnly);
+}
+
+void
+KexiDBAutoField::setValueInternal(const QVariant& add, bool removeOld)
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->setValue(m_origValue, add, removeOld);
+// iface->setValueInternal(add, removeOld);
+}
+
+QVariant
+KexiDBAutoField::value()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->value();
+ return QVariant();
+}
+
+bool
+KexiDBAutoField::valueIsNull()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->valueIsNull();
+ return true;
+}
+
+bool
+KexiDBAutoField::valueIsEmpty()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->valueIsEmpty();
+ return true;
+}
+
+bool
+KexiDBAutoField::valueIsValid()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->valueIsValid();
+ return true;
+}
+
+bool
+KexiDBAutoField::valueChanged()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ kexipluginsdbg << m_origValue << endl;
+ if(iface)
+ return iface->valueChanged();
+ return false;
+}
+
+void
+KexiDBAutoField::installListener(KexiDataItemChangesListener* listener)
+{
+ KexiFormDataItemInterface::installListener(listener);
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->installListener(listener);
+}
+
+KexiDBAutoField::WidgetType KexiDBAutoField::widgetType() const
+{
+ return d->widgetType_property;
+}
+
+KexiDBAutoField::LabelPosition KexiDBAutoField::labelPosition() const
+{
+ return d->lblPosition;
+}
+
+QString KexiDBAutoField::caption() const
+{
+ return d->caption;
+}
+
+bool KexiDBAutoField::hasAutoCaption() const
+{
+ return d->autoCaption;
+}
+
+QWidget* KexiDBAutoField::editor() const
+{
+ return m_subwidget;
+}
+
+QLabel* KexiDBAutoField::label() const
+{
+ return d->label;
+}
+
+int KexiDBAutoField::fieldTypeInternal() const
+{
+ return d->fieldTypeInternal;
+}
+
+QString KexiDBAutoField::fieldCaptionInternal() const
+{
+ return d->fieldCaptionInternal;
+}
+
+bool
+KexiDBAutoField::cursorAtStart()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->cursorAtStart();
+ return false;
+}
+
+bool
+KexiDBAutoField::cursorAtEnd()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ return iface->cursorAtEnd();
+ return false;
+}
+
+void
+KexiDBAutoField::clear()
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->clear();
+}
+
+void
+KexiDBAutoField::setFieldTypeInternal(int kexiDBFieldType)
+{
+ d->fieldTypeInternal = (KexiDB::Field::Type)kexiDBFieldType;
+ KexiDB::Field::Type fieldType;
+ //find real fied type to use
+ if (d->fieldTypeInternal==KexiDB::Field::InvalidType) {
+ if (visibleColumnInfo())
+ fieldType = KexiDB::Field::Text;
+ else
+ fieldType = KexiDB::Field::InvalidType;
+ }
+ else
+ fieldType = d->fieldTypeInternal;
+
+ const WidgetType newWidgetType = KexiDBAutoField::widgetTypeForFieldType( fieldType );
+
+ if(d->widgetType != newWidgetType) {
+ d->widgetType = newWidgetType;
+ createEditor();
+ }
+ setFieldCaptionInternal(d->fieldCaptionInternal);
+}
+
+void
+KexiDBAutoField::setFieldCaptionInternal(const QString& text)
+{
+ d->fieldCaptionInternal = text;
+ //change text only if autocaption is set and no columnInfo is available
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if((!iface || !iface->columnInfo()) && d->autoCaption) {
+ changeText(d->fieldCaptionInternal);
+ }
+}
+
+void
+KexiDBAutoField::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ KexiFormDataItemInterface::setColumnInfo(cinfo);
+ setColumnInfoInternal(cinfo, cinfo);
+}
+
+void
+KexiDBAutoField::setColumnInfoInternal(KexiDB::QueryColumnInfo* cinfo, KexiDB::QueryColumnInfo* visibleColumnInfo)
+{
+ // change widget type depending on field type
+ if(d->widgetType_property == Auto) {
+ WidgetType newWidgetType = Auto;
+ KexiDB::Field::Type fieldType;
+ if (cinfo)
+ fieldType = visibleColumnInfo->field->type();
+ else if (dataSource().isEmpty())
+ fieldType = KexiDB::Field::InvalidType;
+ else
+ fieldType = KexiDB::Field::Text;
+
+ if (fieldType != KexiDB::Field::InvalidType) {
+ newWidgetType = KexiDBAutoField::widgetTypeForFieldType( fieldType );
+ }
+ if(d->widgetType != newWidgetType || newWidgetType==Auto) {
+ d->widgetType = newWidgetType;
+ createEditor();
+ }
+ }
+ // update label's text
+ changeText((cinfo && d->autoCaption) ? cinfo->captionOrAliasOrName() : d->caption);
+
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->setColumnInfo(visibleColumnInfo);
+}
+
+//static
+KexiDBAutoField::WidgetType
+KexiDBAutoField::widgetTypeForFieldType(KexiDB::Field::Type type)
+{
+ switch(type) {
+ case KexiDB::Field::Integer:
+ case KexiDB::Field::ShortInteger:
+ case KexiDB::Field::BigInteger:
+ return Integer;
+ case KexiDB::Field::Boolean:
+ return Boolean;
+ case KexiDB::Field::Float:
+ case KexiDB::Field::Double:
+ return Double;
+ case KexiDB::Field::Date:
+ return Date;
+ case KexiDB::Field::DateTime:
+ return DateTime;
+ case KexiDB::Field::Time:
+ return Time;
+ case KexiDB::Field::Text:
+ return Text;
+ case KexiDB::Field::LongText:
+ return MultiLineText;
+ case KexiDB::Field::Enum:
+ return ComboBox;
+ case KexiDB::Field::InvalidType:
+ return Auto;
+ case KexiDB::Field::BLOB:
+ return Image;
+ default:
+ break;
+ }
+ return Text;
+}
+
+void
+KexiDBAutoField::changeText(const QString &text, bool beautify)
+{
+ QString realText;
+ bool unbound = false;
+ if (d->autoCaption && (d->widgetType==Auto || dataSource().isEmpty())) {
+ if (d->designMode)
+ realText = QString::fromLatin1(name())+" "+i18n("Unbound Auto Field", "(unbound)");
+ else
+ realText = QString::null;
+ unbound = true;
+ }
+ else {
+ if (beautify) {
+ /*! @todo look at appendColonToAutoLabels setting [bool]
+ @todo look at makeFirstCharacterUpperCaseInCaptions setting [bool]
+ (see doc/dev/settings.txt) */
+ if (!text.isEmpty()) {
+ realText = text[0].upper() + text.mid(1);
+ if (d->widgetType!=Boolean) {
+//! @todo ":" suffix looks weird for checkbox; remove this condition when [x] is displayed _after_ label
+//! @todo support right-to-left layout where position of ":" is inverted
+ realText += ": ";
+ }
+ }
+ }
+ else
+ realText = text;
+ }
+
+ if (unbound)
+ d->label->setAlignment( Qt::AlignCenter | Qt::WordBreak );
+ else
+ d->label->setAlignment( Qt::AlignCenter );
+// QWidget* widgetToAlterForegroundColor;
+ if(d->widgetType == Boolean) {
+ static_cast<QCheckBox*>((QWidget*)m_subwidget)->setText(realText);
+// widgetToAlterForegroundColor = m_subwidget;
+ }
+ else {
+ d->label->setText(realText);
+// widgetToAlterForegroundColor = d->label;
+ }
+/*
+ if (unbound)
+ widgetToAlterForegroundColor->setPaletteForegroundColor(
+ KexiUtils::blendedColors(
+ widgetToAlterForegroundColor->paletteForegroundColor(),
+ widgetToAlterForegroundColor->paletteBackgroundColor(), 2, 1));
+ else
+ widgetToAlterForegroundColor->setPaletteForegroundColor( paletteForegroundColor() );*/
+}
+
+void
+KexiDBAutoField::setCaption(const QString &caption)
+{
+ d->caption = caption;
+ if(!d->autoCaption && !caption.isEmpty())
+ changeText(d->caption);
+}
+
+void
+KexiDBAutoField::setAutoCaption(bool autoCaption)
+{
+ d->autoCaption = autoCaption;
+ if(d->autoCaption) {
+ //d->caption = QString::null;
+ if(columnInfo()) {
+ changeText(columnInfo()->captionOrAliasOrName());
+ }
+ else {
+ changeText(d->fieldCaptionInternal);
+ }
+ }
+ else
+ changeText(d->caption);
+}
+
+void
+KexiDBAutoField::setDataSource( const QString &ds ) {
+ KexiFormDataItemInterface::setDataSource(ds);
+ if (ds.isEmpty()) {
+ setColumnInfo(0);
+ }
+}
+
+QSize
+KexiDBAutoField::sizeHint() const
+{
+ if (d->lblPosition == NoLabel)
+ return m_subwidget ? m_subwidget->sizeHint() : QWidget::sizeHint();
+
+ QSize s1(0,0);
+ if (m_subwidget)
+ s1 = m_subwidget->sizeHint();
+ QSize s2(d->label->sizeHint());
+ if (d->lblPosition == Top)
+ return QSize(QMAX(s1.width(), s2.width()), s1.height()+KexiDBAutoField_SPACING+s2.height());
+
+ //left
+ return QSize(s1.width()+KexiDBAutoField_SPACING+s2.width(), QMAX(s1.height(), s2.height()));
+}
+
+void
+KexiDBAutoField::setFocusPolicy( FocusPolicy policy )
+{
+ d->focusPolicyChanged = true;
+ QWidget::setFocusPolicy(policy);
+ d->label->setFocusPolicy(policy);
+ if (m_subwidget)
+ m_subwidget->setFocusPolicy(policy);
+}
+
+void
+KexiDBAutoField::updateInformationAboutUnboundField()
+{
+ if ( (d->autoCaption && (dataSource().isEmpty() || dataSourceMimeType().isEmpty()))
+ || (!d->autoCaption && d->caption.isEmpty()) )
+ {
+ d->label->setText( QString::fromLatin1(name())+" "+i18n("Unbound Auto Field", " (unbound)") );
+ }
+// else
+// d->label->setText( QString::fromLatin1(name())+" "+i18n(" (unbound)") );
+}
+
+/*void
+KexiDBAutoField::paintEvent( QPaintEvent* pe )
+{
+ QWidget::paintEvent( pe );
+
+ if ( (d->autoCaption && (dataSource().isEmpty() || dataSourceMimeType().isEmpty()))
+ || (!d->autoCaption && d->caption.isEmpty()) )
+ {
+ QPainter p(this);
+ p.setPen( d->label->paletteForegroundColor() );
+ p.setClipRect(pe->rect());
+ p.setFont(d->label->font());
+ p.drawText(rect(), Qt::AlignLeft | Qt::WordBreak,
+ QString::fromLatin1(name())+" "+i18n(" (unbound)"));
+ }
+}*/
+
+void
+KexiDBAutoField::paletteChange( const QPalette& oldPal )
+{
+ Q_UNUSED(oldPal);
+ d->label->setPalette( palette() );
+}
+
+void KexiDBAutoField::unsetPalette()
+{
+ QWidget::unsetPalette();
+
+}
+
+// ===== methods below are just proxies for the internal editor or label =====
+
+const QColor & KexiDBAutoField::paletteForegroundColor() const
+{
+ return d->textColor;
+}
+
+void KexiDBAutoField::setPaletteForegroundColor( const QColor & color )
+{
+ d->textColor = color;
+ copyPropertiesToEditor();
+}
+
+const QColor & KexiDBAutoField::paletteBackgroundColor() const
+{
+ return d->baseColor;
+}
+
+void KexiDBAutoField::setPaletteBackgroundColor( const QColor & color )
+{
+ d->baseColor = color;
+ copyPropertiesToEditor();
+}
+
+const QColor & KexiDBAutoField::foregroundLabelColor() const
+{
+ if(d->widgetType == Boolean)
+ return paletteForegroundColor();
+
+ return d->label->paletteForegroundColor();
+}
+
+void KexiDBAutoField::setForegroundLabelColor( const QColor & color )
+{
+ if(d->widgetType == Boolean)
+ setPaletteForegroundColor(color);
+ else {
+ d->label->setPaletteForegroundColor(color);
+ QWidget::setPaletteForegroundColor(color);
+ }
+}
+
+const QColor & KexiDBAutoField::backgroundLabelColor() const
+{
+ if(d->widgetType == Boolean)
+ return paletteBackgroundColor();
+
+ return d->label->paletteBackgroundColor();
+}
+
+void KexiDBAutoField::setBackgroundLabelColor( const QColor & color )
+{
+ if(d->widgetType == Boolean)
+ setPaletteBackgroundColor(color);
+ else {
+ d->label->setPaletteBackgroundColor(color);
+ QWidget::setPaletteBackgroundColor(color);
+ }
+
+// if (m_subwidget)
+// m_subwidget->setPalette( qApp->palette() );
+}
+
+QVariant KexiDBAutoField::property( const char * name ) const
+{
+ bool ok;
+ QVariant val = KFormDesigner::WidgetWithSubpropertiesInterface::subproperty(name, ok);
+ if (ok)
+ return val;
+ return QWidget::property(name);
+}
+
+bool KexiDBAutoField::setProperty( const char * name, const QVariant & value )
+{
+ bool ok = KFormDesigner::WidgetWithSubpropertiesInterface::setSubproperty(name, value);
+ if (ok)
+ return true;
+ return QWidget::setProperty(name, value);
+}
+
+bool KexiDBAutoField::eventFilter( QObject *o, QEvent *e )
+{
+ if (o==d->label && d->label->buddy() && e->type()==QEvent::MouseButtonRelease) {
+ //focus label's buddy when user clicked the label
+ d->label->buddy()->setFocus();
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+void KexiDBAutoField::setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue)
+{
+ KexiFormDataItemInterface::setDisplayDefaultValue(widget, displayDefaultValue);
+ if (dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget))
+ dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget)->setDisplayDefaultValue(m_subwidget, displayDefaultValue);
+}
+
+void KexiDBAutoField::moveCursorToEnd()
+{
+ KexiDataItemInterface *iface = dynamic_cast<KexiDataItemInterface*>((QWidget*)m_subwidget);
+ if (iface)
+ iface->moveCursorToEnd();
+}
+
+void KexiDBAutoField::moveCursorToStart()
+{
+ KexiDataItemInterface *iface = dynamic_cast<KexiDataItemInterface*>((QWidget*)m_subwidget);
+ if (iface)
+ iface->moveCursorToStart();
+}
+
+void KexiDBAutoField::selectAll()
+{
+ KexiDataItemInterface *iface = dynamic_cast<KexiDataItemInterface*>((QWidget*)m_subwidget);
+ if (iface)
+ iface->selectAll();
+}
+
+bool KexiDBAutoField::keyPressed(QKeyEvent *ke)
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if (iface && iface->keyPressed(ke))
+ return true;
+ return false;
+}
+
+#include "kexidbautofield.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbautofield.h b/kexi/plugins/forms/widgets/kexidbautofield.h
new file mode 100644
index 00000000..981a0519
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbautofield.h
@@ -0,0 +1,210 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005 Christian Nitschkowski <segfault_ii@web.de>
+ 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 KEXIDBAUTOFIELD_H
+#define KEXIDBAUTOFIELD_H
+
+#include <qwidget.h>
+#include <kexidb/field.h>
+#include <formeditor/container.h>
+#include <formeditor/widgetwithsubpropertiesinterface.h>
+#include "kexiformdataiteminterface.h"
+
+class QBoxLayout;
+class QLabel;
+
+//! Universal "Auto Field" widget for Kexi forms
+/*! It acts as a container for most data-aware widgets. */
+class KEXIFORMUTILS_EXPORT KexiDBAutoField :
+ public QWidget,
+ public KexiFormDataItemInterface,
+ public KFormDesigner::DesignTimeDynamicChildWidgetHandler,
+ public KFormDesigner::WidgetWithSubpropertiesInterface
+{
+ Q_OBJECT
+//'caption' is uncovered now Q_PROPERTY(QString labelCaption READ caption WRITE setCaption DESIGNABLE true)
+ Q_OVERRIDE(QString caption READ caption WRITE setCaption DESIGNABLE true)
+ Q_OVERRIDE(QColor paletteForegroundColor READ paletteForegroundColor WRITE setPaletteForegroundColor DESIGNABLE true RESET unsetPalette)
+ Q_OVERRIDE(QColor paletteBackgroundColor READ paletteBackgroundColor WRITE setPaletteBackgroundColor DESIGNABLE true RESET unsetPalette)
+ Q_PROPERTY(QColor foregroundLabelColor READ foregroundLabelColor WRITE setForegroundLabelColor DESIGNABLE true RESET unsetPalette)
+ Q_PROPERTY(QColor backgroundLabelColor READ backgroundLabelColor WRITE setBackgroundLabelColor DESIGNABLE true RESET unsetPalette)
+ Q_PROPERTY(bool autoCaption READ hasAutoCaption WRITE setAutoCaption DESIGNABLE true)
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
+ Q_PROPERTY(LabelPosition labelPosition READ labelPosition WRITE setLabelPosition DESIGNABLE true)
+ Q_PROPERTY(WidgetType widgetType READ widgetType WRITE setWidgetType DESIGNABLE true)
+ /*internal, for design time only*/
+ Q_PROPERTY(int fieldTypeInternal READ fieldTypeInternal WRITE setFieldTypeInternal DESIGNABLE true STORED false)
+ Q_PROPERTY(QString fieldCaptionInternal READ fieldCaptionInternal WRITE setFieldCaptionInternal DESIGNABLE true STORED false)
+ Q_ENUMS( WidgetType LabelPosition )
+
+ public:
+ enum WidgetType { Auto = 100, Text, Integer, Double, Boolean, Date, Time, DateTime,
+ MultiLineText, ComboBox, Image };
+ enum LabelPosition { Left = 300, Top, NoLabel };
+
+ KexiDBAutoField(const QString &text, WidgetType type, LabelPosition pos,
+ QWidget *parent = 0, const char *name = 0, bool designMode = true);
+ KexiDBAutoField(QWidget *parent = 0, const char *name = 0, bool designMode = true,
+ LabelPosition pos = Left);
+
+ virtual ~KexiDBAutoField();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual void setDataSource( const QString &ds );
+ virtual void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+
+ virtual void setInvalidState(const QString& text);
+ virtual bool isReadOnly() const;
+ virtual void setReadOnly( bool readOnly );
+
+ virtual QVariant value();
+ virtual bool valueIsNull();
+ virtual bool valueIsEmpty();
+ virtual bool valueIsValid();
+ virtual bool valueChanged();
+ virtual void clear();
+
+ //! Reimpelmented to also install \a listenter for internal editor
+ virtual void installListener(KexiDataItemChangesListener* listener);
+
+ WidgetType widgetType() const;
+ void setWidgetType(WidgetType type);
+
+ LabelPosition labelPosition() const;
+ virtual void setLabelPosition(LabelPosition position);
+
+ QString caption() const;
+ void setCaption(const QString &caption);
+
+ bool hasAutoCaption() const;
+ void setAutoCaption(bool autoCaption);
+
+ /*! If \a displayDefaultValue is true, the value set by KexiDataItemInterface::setValue()
+ is displayed in a special way. Used by KexiFormDataProvider::fillDataItems().
+ \a widget is equal to 'this'.
+ Reimplemented after KexiFormDataItemInterface. */
+ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue);
+
+ QWidget* editor() const;
+ QLabel* label() const;
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+
+ static WidgetType widgetTypeForFieldType(KexiDB::Field::Type type);
+
+ /*! On design time it is not possible to pass a reference to KexiDB::Field object
+ so we're just providing field type. Only used when widget type is Auto.
+ @internal */
+ void setFieldTypeInternal(int kexiDBFieldType);
+
+ /*! On design time it is not possible to pass a reference to KexiDB::Field object
+ so we're just providing field caption. Only used when widget type is Auto.
+ @internal */
+ void setFieldCaptionInternal(const QString& text);
+
+ /*! @internal */
+ int fieldTypeInternal() const;
+
+ /*! @internal */
+ QString fieldCaptionInternal() const;
+
+ virtual QSize sizeHint() const;
+ virtual void setFocusPolicy ( FocusPolicy policy );
+
+ //! Reimplemented to return internal editor's color.
+ const QColor & paletteForegroundColor() const;
+
+ //! Reimplemented to set internal editor's color.
+ void setPaletteForegroundColor( const QColor & color );
+
+ //! Reimplemented to return internal editor's color.
+ const QColor & paletteBackgroundColor() const;
+
+ //! Reimplemented to set internal editor's color.
+ virtual void setPaletteBackgroundColor( const QColor & color );
+
+ //! \return label's foreground color
+ const QColor & foregroundLabelColor() const;
+
+ //! Sets label's foreground color
+ virtual void setForegroundLabelColor( const QColor & color );
+
+ //! \return label's background color
+ const QColor & backgroundLabelColor() const;
+
+ //! Sets label's background color
+ virtual void setBackgroundLabelColor( const QColor & color );
+
+ //! Reimplemented to accept subproperties. @see KFormDesigner::WidgetWithSubpropertiesInterface
+ virtual QVariant property( const char * name ) const;
+
+ //! Reimplemented to accept subproperties. @see KFormDesigner::WidgetWithSubpropertiesInterface
+ virtual bool setProperty( const char * name, const QVariant & value );
+
+ /*! Called by the top-level form on key press event to consume widget-specific shortcuts. */
+ virtual bool keyPressed(QKeyEvent *ke);
+
+ public slots:
+ virtual void unsetPalette();
+
+ protected slots:
+// void slotValueChanged();
+ virtual void paletteChange( const QPalette& oldPal );
+
+ //! Implemented for KexiDataItemInterface
+ virtual void moveCursorToEnd();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void moveCursorToStart();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void selectAll();
+
+ protected:
+ virtual void setValueInternal(const QVariant&add, bool removeOld);
+ void init(const QString &text, WidgetType type, LabelPosition pos);
+ virtual void createEditor();
+ void changeText(const QString &text, bool beautify = true);
+// virtual void paintEvent( QPaintEvent* pe );
+ void updateInformationAboutUnboundField();
+
+ //! internal editor can be created too late, so certain properties should be copied
+ void copyPropertiesToEditor();
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+ //! Used by @ref setLabelPositionInternal(LabelPosition)
+ void setLabelPositionInternal(LabelPosition position, bool noLabel);
+
+ //! Used by KexiDBAutoField::setColumnInfo() and KexiDBComboBox::setColumnInfo()
+ void setColumnInfoInternal(KexiDB::QueryColumnInfo* cinfo, KexiDB::QueryColumnInfo* visibleColumnInfo);
+
+ private:
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbcheckbox.cpp b/kexi/plugins/forms/widgets/kexidbcheckbox.cpp
new file mode 100644
index 00000000..6b63851a
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbcheckbox.cpp
@@ -0,0 +1,175 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbcheckbox.h"
+
+#include <kexiutils/utils.h>
+#include <kexidb/queryschema.h>
+
+KexiDBCheckBox::KexiDBCheckBox(const QString &text, QWidget *parent, const char *name)
+ : QCheckBox(text, parent, name), KexiFormDataItemInterface()
+ , m_invalidState(false)
+ , m_tristateChanged(false)
+ , m_tristate(TristateDefault)
+{
+ setFocusPolicy(QWidget::StrongFocus);
+ updateTristate();
+ connect(this, SIGNAL(stateChanged(int)), this, SLOT(slotStateChanged(int)));
+}
+
+KexiDBCheckBox::~KexiDBCheckBox()
+{
+}
+
+void KexiDBCheckBox::setInvalidState( const QString& displayText )
+{
+ setEnabled(false);
+ setState(NoChange);
+ m_invalidState = true;
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+ setText(displayText);
+}
+
+void
+KexiDBCheckBox::setEnabled(bool enabled)
+{
+ if(enabled && m_invalidState)
+ return;
+ QCheckBox::setEnabled(enabled);
+}
+
+void
+KexiDBCheckBox::setReadOnly(bool readOnly)
+{
+ setEnabled(!readOnly);
+}
+
+void KexiDBCheckBox::setValueInternal(const QVariant &add, bool removeOld)
+{
+ Q_UNUSED(add);
+ Q_UNUSED(removeOld);
+ if (isTristateInternal())
+ setState( m_origValue.isNull() ? NoChange : (m_origValue.toBool() ? On : Off) );
+ else
+ setState( m_origValue.toBool() ? On : Off );
+}
+
+QVariant
+KexiDBCheckBox::value()
+{
+ if (state()==NoChange)
+ return QVariant();
+ return QVariant(state()==On, 1);
+}
+
+void KexiDBCheckBox::slotStateChanged(int )
+{
+ signalValueChanged();
+}
+
+bool KexiDBCheckBox::valueIsNull()
+{
+ return state() == NoChange;
+}
+
+bool KexiDBCheckBox::valueIsEmpty()
+{
+ return false;
+}
+
+bool KexiDBCheckBox::isReadOnly() const
+{
+ return !isEnabled();
+}
+
+QWidget*
+KexiDBCheckBox::widget()
+{
+ return this;
+}
+
+bool KexiDBCheckBox::cursorAtStart()
+{
+ return false; //! \todo ?
+}
+
+bool KexiDBCheckBox::cursorAtEnd()
+{
+ return false; //! \todo ?
+}
+
+void KexiDBCheckBox::clear()
+{
+ setState(NoChange);
+}
+
+void KexiDBCheckBox::setTristate(KexiDBCheckBox::Tristate tristate)
+{
+ m_tristateChanged = true;
+ m_tristate = tristate;
+ updateTristate();
+}
+
+KexiDBCheckBox::Tristate KexiDBCheckBox::isTristate() const
+{
+ return m_tristate;
+}
+
+bool KexiDBCheckBox::isTristateInternal() const
+{
+ if (m_tristate == TristateDefault)
+ return !dataSource().isEmpty();
+
+ return m_tristate == TristateOn;
+}
+
+void KexiDBCheckBox::updateTristate()
+{
+ if (m_tristate == TristateDefault) {
+//! @todo the data source may be defined as NOT NULL... thus disallowing NULL state
+ QCheckBox::setTristate( !dataSource().isEmpty() );
+ }
+ else {
+ QCheckBox::setTristate( m_tristate == TristateOn );
+ }
+}
+
+void KexiDBCheckBox::setDataSource(const QString &ds)
+{
+ KexiFormDataItemInterface::setDataSource(ds);
+ updateTristate();
+}
+
+void KexiDBCheckBox::setDisplayDefaultValue(QWidget *widget, bool displayDefaultValue)
+{
+ KexiFormDataItemInterface::setDisplayDefaultValue(widget, displayDefaultValue);
+ // initialize display parameters for default / entered value
+ KexiDisplayUtils::DisplayParameters * const params
+ = displayDefaultValue ? m_displayParametersForDefaultValue : m_displayParametersForEnteredValue;
+// setFont(params->font);
+ QPalette pal(palette());
+// pal.setColor(QPalette::Active, QColorGroup::Text, params->textColor);
+ pal.setColor(QPalette::Active, QColorGroup::Foreground, params->textColor);
+ setPalette(pal);
+}
+
+#include "kexidbcheckbox.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbcheckbox.h b/kexi/plugins/forms/widgets/kexidbcheckbox.h
new file mode 100644
index 00000000..d4a68bf3
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbcheckbox.h
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBCheckBox_H
+#define KexiDBCheckBox_H
+
+#include "kexiformdataiteminterface.h"
+#include <qcheckbox.h>
+
+//! @short A db-aware check box
+class KEXIFORMUTILS_EXPORT KexiDBCheckBox : public QCheckBox, public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_OVERRIDE( Tristate tristate READ isTristate WRITE setTristate )
+ Q_ENUMS( Tristate )
+
+ public:
+ KexiDBCheckBox(const QString &text, QWidget *parent, const char *name=0);
+ virtual ~KexiDBCheckBox();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setEnabled(bool enabled);
+
+ enum Tristate { TristateDefault, TristateOn, TristateOff };
+
+ void setTristate(Tristate tristate);
+ Tristate isTristate() const;
+
+ /*! Reimplemented after KexiFormDataItemInterface. */
+ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue);
+
+ public slots:
+ void setDataSource(const QString &ds);
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ void slotStateChanged(int state);
+
+ //! This implementation just disables read only widget
+ virtual void setReadOnly( bool readOnly );
+
+ protected:
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+
+ //! \return true in isTristate() == TristateDefault and the widget has bound data source
+ //! or if isTristate() == TristateOn, else false is returned.
+ bool isTristateInternal() const;
+
+ //! Updates tristate in QCheckBox itself according to m_tristate.
+ void updateTristate();
+
+ private:
+ bool m_invalidState : 1;
+ bool m_tristateChanged : 1; //!< used in setTristate()
+ Tristate m_tristate; //!< used in isTristate() and setTristate()
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbcombobox.cpp b/kexi/plugins/forms/widgets/kexidbcombobox.cpp
new file mode 100644
index 00000000..19366a15
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbcombobox.cpp
@@ -0,0 +1,550 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 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 "kexidbcombobox.h"
+#include "kexidblineedit.h"
+#include "../kexiformscrollview.h"
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#include <qmetaobject.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qdrawutil.h>
+#include <qptrdict.h>
+#include <qcursor.h>
+
+#include <kexidb/queryschema.h>
+#include <widget/tableview/kexicomboboxpopup.h>
+#include <widget/tableview/kexicelleditorfactory.h>
+#include <kexiutils/utils.h>
+
+//! @internal
+class KexiDBComboBox::Private
+{
+ public:
+ Private()
+ : popup(0)
+ , visibleColumnInfo(0)
+ , subWidgetsWithDisabledEvents(0)
+ , isEditable(false)
+ , buttonPressed(false)
+ , mouseOver(false)
+ , dataEnteredByHand(true)
+ {
+ }
+ ~Private()
+ {
+ delete subWidgetsWithDisabledEvents;
+ subWidgetsWithDisabledEvents = 0;
+ }
+
+ KexiComboBoxPopup *popup;
+ KComboBox *paintedCombo; //!< fake combo used only to pass it as 'this' for QStyle (because styles use <static_cast>)
+ QSize sizeHint; //!< A cache for KexiDBComboBox::sizeHint(),
+ //!< rebuilt by KexiDBComboBox::fontChange() and KexiDBComboBox::styleChange()
+ KexiDB::QueryColumnInfo* visibleColumnInfo;
+ QPtrDict<char> *subWidgetsWithDisabledEvents; //! used to collect subwidget and its children (if isEditable is false)
+ bool isEditable : 1; //!< true is the combo box is editable
+ bool buttonPressed : 1;
+ bool mouseOver : 1;
+ bool dataEnteredByHand : 1;
+ bool designMode : 1;
+};
+
+//-------------------------------------
+
+KexiDBComboBox::KexiDBComboBox(QWidget *parent, const char *name, bool designMode)
+ : KexiDBAutoField(parent, name, designMode, NoLabel)
+ , KexiComboBoxBase()
+ , d(new Private())
+{
+ setMouseTracking(true);
+ setFocusPolicy(WheelFocus);
+ installEventFilter(this);
+ d->designMode = designMode;
+ d->paintedCombo = new KComboBox(this);
+ d->paintedCombo->hide();
+ d->paintedCombo->move(0,0);
+}
+
+KexiDBComboBox::~KexiDBComboBox()
+{
+ delete d;
+}
+
+KexiComboBoxPopup *KexiDBComboBox::popup() const
+{
+ return d->popup;
+}
+
+void KexiDBComboBox::setPopup(KexiComboBoxPopup *popup)
+{
+ d->popup = popup;
+}
+
+void KexiDBComboBox::setEditable(bool set)
+{
+ if (d->isEditable == set)
+ return;
+ d->isEditable = set;
+ d->paintedCombo->setEditable(set);
+ if (set)
+ createEditor();
+ else {
+ delete m_subwidget;
+ m_subwidget = 0;
+ }
+ update();
+}
+
+bool KexiDBComboBox::isEditable() const
+{
+ return d->isEditable;
+}
+
+void KexiDBComboBox::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ QColorGroup cg( palette().active() );
+// if ( hasFocus() )
+// cg.setColor(QColorGroup::Base, cg.highlight());
+// else
+ cg.setColor(QColorGroup::Base, paletteBackgroundColor()); //update base color using (reimplemented) bg color
+ p.setPen(cg.text());
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (d->mouseOver)
+ flags |= QStyle::Style_MouseOver;
+
+ if ( width() < 5 || height() < 5 ) {
+ qDrawShadePanel( &p, rect(), cg, FALSE, 2, &cg.brush( QColorGroup::Button ) );
+ return;
+ }
+
+//! @todo support reverse layout
+//bool reverse = QApplication::reverseLayout();
+ style().drawComplexControl( QStyle::CC_ComboBox, &p, d->paintedCombo /*this*/, rect(), cg,
+ flags, (uint)QStyle::SC_All,
+ (d->buttonPressed ? QStyle::SC_ComboBoxArrow : QStyle::SC_None )
+ );
+
+ if (d->isEditable) {
+ //if editable, editor paints itself, nothing to do
+ }
+ else { //not editable: we need to paint the current item
+ QRect editorGeometry( this->editorGeometry() );
+ if ( hasFocus() ) {
+ if (0==qstrcmp(style().name(), "windows")) //a hack
+ p.fillRect( editorGeometry, cg.brush( QColorGroup::Highlight ) );
+ QRect r( QStyle::visualRect( style().subRect( QStyle::SR_ComboBoxFocusRect, d->paintedCombo ), this ) );
+ r = QRect(r.left()-1, r.top()-1, r.width()+2, r.height()+2); //enlare by 1 pixel each side to avoid covering by the subwidget
+ style().drawPrimitive( QStyle::PE_FocusRect, &p,
+ r, cg, flags | QStyle::Style_FocusAtBorder, QStyleOption(cg.highlight()));
+ }
+ //todo
+ }
+}
+
+QRect KexiDBComboBox::editorGeometry() const
+{
+ QRect r( QStyle::visualRect(
+ style().querySubControlMetrics(QStyle::CC_ComboBox, d->paintedCombo,
+ QStyle::SC_ComboBoxEditField), d->paintedCombo ) );
+
+ //if ((height()-r.bottom())<6)
+ // r.setBottom(height()-6);
+ return r;
+}
+
+void KexiDBComboBox::createEditor()
+{
+ KexiDBAutoField::createEditor();
+ if (m_subwidget) {
+ m_subwidget->setGeometry( editorGeometry() );
+ if (!d->isEditable) {
+ m_subwidget->setCursor(QCursor(Qt::ArrowCursor)); // widgets like listedit have IbeamCursor, we don't want that
+//! @todo Qt4: set transparent background, for now we're setting button color
+ QPalette subwidgetPalette( m_subwidget->palette() );
+ subwidgetPalette.setColor(QPalette::Active, QColorGroup::Base,
+ subwidgetPalette.color(QPalette::Active, QColorGroup::Button));
+ m_subwidget->setPalette( subwidgetPalette );
+ if (d->subWidgetsWithDisabledEvents)
+ d->subWidgetsWithDisabledEvents->clear();
+ else
+ d->subWidgetsWithDisabledEvents = new QPtrDict<char>();
+ d->subWidgetsWithDisabledEvents->insert(m_subwidget, (char*)1);
+ m_subwidget->installEventFilter(this);
+ QObjectList *l = m_subwidget->queryList( "QWidget" );
+ for ( QObjectListIt it( *l ); it.current(); ++it ) {
+ d->subWidgetsWithDisabledEvents->insert(it.current(), (char*)1);
+ it.current()->installEventFilter(this);
+ }
+ delete l;
+ }
+ }
+ updateGeometry();
+}
+
+void KexiDBComboBox::setLabelPosition(LabelPosition position)
+{
+ if(m_subwidget) {
+ if (-1 != m_subwidget->metaObject()->findProperty("frameShape", true))
+ m_subwidget->setProperty("frameShape", QVariant((int)QFrame::NoFrame));
+ m_subwidget->setGeometry( editorGeometry() );
+ }
+// KexiSubwidgetInterface *subwidgetInterface = dynamic_cast<KexiSubwidgetInterface*>((QWidget*)m_subwidget);
+ // update size policy
+// if (subwidgetInterface && subwidgetInterface->subwidgetStretchRequired(this)) {
+ QSizePolicy sizePolicy( this->sizePolicy() );
+ if(position == Left)
+ sizePolicy.setHorData( QSizePolicy::Minimum );
+ else
+ sizePolicy.setVerData( QSizePolicy::Minimum );
+ //m_subwidget->setSizePolicy(sizePolicy);
+ setSizePolicy(sizePolicy);
+ //}
+// }
+}
+
+QRect KexiDBComboBox::buttonGeometry() const
+{
+ QRect arrowRect(
+ style().querySubControlMetrics( QStyle::CC_ComboBox, d->paintedCombo, QStyle::SC_ComboBoxArrow) );
+ arrowRect = QStyle::visualRect(arrowRect, d->paintedCombo);
+ arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) ); // a fix for Motif style
+ return arrowRect;
+}
+
+bool KexiDBComboBox::handleMousePressEvent(QMouseEvent *e)
+{
+ if ( e->button() != Qt::LeftButton || d->designMode )
+ return true;
+/*todo if ( m_discardNextMousePress ) {
+ d->discardNextMousePress = FALSE;
+ return;
+ }*/
+
+ if ( /*count() &&*/ ( !isEditable() || buttonGeometry().contains( e->pos() ) ) ) {
+ d->buttonPressed = false;
+
+/* if ( d->usingListBox() ) {
+ listBox()->blockSignals( TRUE );
+ qApp->sendEvent( listBox(), e ); // trigger the listbox's autoscroll
+ listBox()->setCurrentItem(d->current);
+ listBox()->blockSignals( FALSE );
+ popup();
+ if ( arrowRect.contains( e->pos() ) ) {
+ d->arrowPressed = TRUE;
+ d->arrowDown = TRUE;
+ repaint( FALSE );
+ }
+ } else {*/
+ showPopup();
+ return true;
+ }
+ return false;
+}
+
+bool KexiDBComboBox::handleKeyPressEvent(QKeyEvent *ke)
+{
+ const int k = ke->key();
+ const bool dropDown = (ke->state() == Qt::NoButton && ((k==Qt::Key_F2 && !d->isEditable) || k==Qt::Key_F4))
+ || (ke->state() == Qt::AltButton && k==Qt::Key_Down);
+ const bool escPressed = ke->state() == Qt::NoButton && k==Qt::Key_Escape;
+ const bool popupVisible = popup() && popup()->isVisible();
+ if ((dropDown || escPressed) && popupVisible) {
+ popup()->hide();
+ return true;
+ }
+ else if (dropDown && !popupVisible) {
+ d->buttonPressed = false;
+ showPopup();
+ return true;
+ }
+ else if (popupVisible) {
+ const bool enterPressed = k==Qt::Key_Enter || k==Qt::Key_Return;
+ if (enterPressed/* && m_internalEditorValueChanged*/) {
+ acceptPopupSelection();
+ return true;
+ }
+ return handleKeyPressForPopup( ke );
+ }
+
+ return false;
+}
+
+bool KexiDBComboBox::keyPressed(QKeyEvent *ke)
+{
+ if (KexiDBAutoField::keyPressed(ke))
+ return true;
+
+ const int k = ke->key();
+ const bool popupVisible = popup() && popup()->isVisible();
+ const bool escPressed = ke->state() == Qt::NoButton && k==Qt::Key_Escape;
+ if (escPressed && popupVisible) {
+ popup()->hide();
+ return true;
+ }
+ if (ke->state() == Qt::NoButton && (k==Qt::Key_PageDown || k==Qt::Key_PageUp) && popupVisible)
+ return true;
+ return false;
+}
+
+void KexiDBComboBox::mousePressEvent( QMouseEvent *e )
+{
+ if (handleMousePressEvent(e))
+ return;
+
+// QTimer::singleShot( 200, this, SLOT(internalClickTimeout()));
+// d->shortClick = TRUE;
+// }
+ KexiDBAutoField::mousePressEvent( e );
+}
+
+void KexiDBComboBox::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ mousePressEvent( e );
+}
+
+bool KexiDBComboBox::eventFilter( QObject *o, QEvent *e )
+{
+ if (o==this) {
+ if (e->type()==QEvent::Resize) {
+ d->paintedCombo->resize(size());
+ if (m_subwidget)
+ m_subwidget->setGeometry( editorGeometry() );
+ }
+ else if (e->type()==QEvent::Enter) {
+ if (!d->isEditable
+ || /*over button if editable combo*/buttonGeometry().contains( static_cast<QMouseEvent*>(e)->pos() ))
+ {
+ d->mouseOver = true;
+ update();
+ }
+ }
+ else if (e->type()==QEvent::MouseMove) {
+ if (d->isEditable) {
+ const bool overButton = buttonGeometry().contains( static_cast<QMouseEvent*>(e)->pos() );
+ if (overButton != d->mouseOver) {
+ d->mouseOver = overButton;
+ update();
+ }
+ }
+ }
+ else if (e->type()==QEvent::Leave) {
+ d->mouseOver = false;
+ update();
+ }
+ else if (e->type()==QEvent::KeyPress) {
+ // handle F2/F4
+ if (handleKeyPressEvent(static_cast<QKeyEvent*>(e)))
+ return true;
+ }
+ else if (e->type()==QEvent::FocusOut) {
+ if (popup() && popup()->isVisible()) {
+ popup()->hide();
+ undoChanges();
+ }
+ }
+ }
+ else if (!d->isEditable && d->subWidgetsWithDisabledEvents && d->subWidgetsWithDisabledEvents->find(o)) {
+ if (e->type()==QEvent::MouseButtonPress) {
+ // clicking the subwidget should mean the same as clicking the combo box (i.e. show the popup)
+ if (handleMousePressEvent(static_cast<QMouseEvent*>(e)))
+ return true;
+ }
+ else if (e->type()==QEvent::KeyPress) {
+ if (handleKeyPressEvent(static_cast<QKeyEvent*>(e)))
+ return true;
+ }
+ return e->type()!=QEvent::Paint;
+ }
+ return KexiDBAutoField::eventFilter( o, e );
+}
+
+bool KexiDBComboBox::subwidgetStretchRequired(KexiDBAutoField* autoField) const
+{
+ Q_UNUSED(autoField);
+ return true;
+}
+
+void KexiDBComboBox::setPaletteBackgroundColor( const QColor & color )
+{
+ KexiDBAutoField::setPaletteBackgroundColor(color);
+ QPalette pal(palette());
+ QColorGroup cg(pal.active());
+ pal.setColor(QColorGroup::Base, red);
+ pal.setColor(QColorGroup::Background, red);
+ pal.setActive(cg);
+ QWidget::setPalette(pal);
+ update();
+}
+
+bool KexiDBComboBox::valueChanged()
+{
+ kdDebug() << "KexiDataItemInterface::valueChanged(): " << m_origValue.toString() << " ? " << value().toString() << endl;
+ return m_origValue != value();
+}
+
+void
+KexiDBComboBox::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ KexiFormDataItemInterface::setColumnInfo(cinfo);
+}
+
+void KexiDBComboBox::setVisibleColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ d->visibleColumnInfo = cinfo;
+ // we're assuming we already have columnInfo()
+ setColumnInfoInternal(columnInfo(), d->visibleColumnInfo);
+}
+
+KexiDB::QueryColumnInfo* KexiDBComboBox::visibleColumnInfo() const
+{
+ return d->visibleColumnInfo;
+}
+
+void KexiDBComboBox::moveCursorToEndInInternalEditor()
+{
+ if (d->isEditable && m_moveCursorToEndInInternalEditor_enabled)
+ moveCursorToEnd();
+}
+
+void KexiDBComboBox::selectAllInInternalEditor()
+{
+ if (d->isEditable && m_selectAllInInternalEditor_enabled)
+ selectAll();
+}
+
+void KexiDBComboBox::setValueInternal(const QVariant& add, bool removeOld)
+{
+ //// use KexiDBAutoField instead of KexiComboBoxBase::setValueInternal
+ //// expects existing popup(), but we want to have delayed creation
+ if (popup())
+ popup()->hide();
+ KexiComboBoxBase::setValueInternal(add, removeOld);
+}
+
+void KexiDBComboBox::setVisibleValueInternal(const QVariant& value)
+{
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->setValue(value, QVariant(), false /*!removeOld*/);
+}
+
+QVariant KexiDBComboBox::visibleValue()
+{
+ return KexiComboBoxBase::visibleValue();
+}
+
+void KexiDBComboBox::setValueInInternalEditor(const QVariant& value)
+{
+ if (!m_setValueInInternalEditor_enabled)
+ return;
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if(iface)
+ iface->setValue(value, QVariant(), false/*!removeOld*/);
+}
+
+QVariant KexiDBComboBox::valueFromInternalEditor()
+{
+ return KexiDBAutoField::value();
+}
+
+QPoint KexiDBComboBox::mapFromParentToGlobal(const QPoint& pos) const
+{
+// const KexiFormScrollView* view = KexiUtils::findParentConst<const KexiFormScrollView>(this, "KexiFormScrollView");
+ if (!parentWidget())
+ return QPoint(-1,-1);
+ return parentWidget()->mapToGlobal(pos);
+// return view->viewport()->mapToGlobal(pos);
+}
+
+int KexiDBComboBox::popupWidthHint() const
+{
+ return width(); //popup() ? popup()->width() : 0;
+}
+
+void KexiDBComboBox::fontChange( const QFont & oldFont )
+{
+ d->sizeHint = QSize(); //force rebuild the cache
+ KexiDBAutoField::fontChange(oldFont);
+}
+
+void KexiDBComboBox::styleChange( QStyle& oldStyle )
+{
+ KexiDBAutoField::styleChange( oldStyle );
+ d->sizeHint = QSize(); //force rebuild the cache
+ if (m_subwidget)
+ m_subwidget->setGeometry( editorGeometry() );
+}
+
+QSize KexiDBComboBox::sizeHint() const
+{
+ if ( isVisible() && d->sizeHint.isValid() )
+ return d->sizeHint;
+
+ const int maxWidth = 7 * fontMetrics().width(QChar('x')) + 18;
+ const int maxHeight = QMAX( fontMetrics().lineSpacing(), 14 ) + 2;
+ d->sizeHint = (style().sizeFromContents(QStyle::CT_ComboBox, d->paintedCombo,
+ QSize(maxWidth, maxHeight)).expandedTo(QApplication::globalStrut()));
+
+ return d->sizeHint;
+}
+
+void KexiDBComboBox::editRequested()
+{
+}
+
+void KexiDBComboBox::acceptRequested()
+{
+ signalValueChanged();
+}
+
+void KexiDBComboBox::slotRowAccepted(KexiTableItem *item, int row)
+{
+ d->dataEnteredByHand = false;
+ KexiComboBoxBase::slotRowAccepted(item, row);
+ d->dataEnteredByHand = true;
+}
+
+void KexiDBComboBox::beforeSignalValueChanged()
+{
+ if (d->dataEnteredByHand) {
+ KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
+ if (iface) {
+ slotInternalEditorValueChanged( iface->value() );
+ }
+ }
+}
+
+void KexiDBComboBox::undoChanges()
+{
+ KexiDBAutoField::undoChanges();
+ KexiComboBoxBase::undoChanges();
+}
+
+#include "kexidbcombobox.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbcombobox.h b/kexi/plugins/forms/widgets/kexidbcombobox.h
new file mode 100644
index 00000000..5208d37d
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbcombobox.h
@@ -0,0 +1,181 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 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 KexiDBComboBox_H
+#define KexiDBComboBox_H
+
+#include "kexidbutils.h"
+#include "kexidbautofield.h"
+#include <widget/tableview/kexicomboboxbase.h>
+
+//! @short Combo box widget for Kexi forms
+/*! This widget is implemented on top of KexiDBAutoField,
+ so as it uses KexiDBAutoField's ability of embedding subwidgets,
+ it can display not only a line edit but also text edit or image box
+ (more can be added in the future).
+ A drop-down button is added to mimic native combo box widget's functionality.
+*/
+class KEXIFORMUTILS_EXPORT KexiDBComboBox :
+ public KexiDBAutoField, public KexiComboBoxBase
+{
+ Q_OBJECT
+ Q_PROPERTY( bool editable READ isEditable WRITE setEditable )
+ //properties from KexiDBAutoField that should not be visible:
+ Q_OVERRIDE(QColor paletteBackgroundColor READ paletteBackgroundColor WRITE setPaletteBackgroundColor DESIGNABLE true RESET unsetPalette)
+ Q_OVERRIDE(QColor foregroundLabelColor DESIGNABLE false)
+ Q_OVERRIDE(QColor backgroundLabelColor DESIGNABLE false)
+ Q_OVERRIDE(bool autoCaption DESIGNABLE false)
+
+ public:
+ KexiDBComboBox(QWidget *parent, const char *name=0, bool designMode = true);
+ virtual ~KexiDBComboBox();
+
+ //! Implemented for KexiComboBoxBase: form has no 'related data' model (only the full database model)
+ virtual KexiTableViewColumn *column() const { return 0; }
+
+ //! Implemented for KexiComboBoxBase
+ virtual KexiDB::Field *field() const { return KexiDBAutoField::field(); }
+
+ //! Implemented for KexiComboBoxBase
+ virtual QVariant origValue() const { return m_origValue; }
+
+ void setEditable(bool set);
+ bool isEditable() const;
+
+ virtual void setLabelPosition(LabelPosition position);
+
+ virtual QVariant value() { return KexiComboBoxBase::value(); }
+
+ virtual QVariant visibleValue();
+
+ //! Reimpemented because to avoid taking value from the internal editor (index is taken from the popup instead)
+ virtual bool valueChanged();
+
+ virtual QSize sizeHint() const;
+
+ //! Reimplemented after KexiDBAutoField: jsut sets \a cinfo without initializing a subwidget.
+ //! Initialization is performed by \ref setVisibleColumnInfo().
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+
+ /*! Used internally to set visible database column information.
+ Reimplemented: performs initialization of the subwidget. */
+ virtual void setVisibleColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+
+ /*! \return visible database column information for this item.
+ Reimplemented. */
+ virtual KexiDB::QueryColumnInfo* visibleColumnInfo() const;
+
+ const QColor & paletteBackgroundColor() const { return KexiDBAutoField::paletteBackgroundColor(); }
+
+ //! Reimplemented to also set 'this' widget's background color, not only subwidget's.
+ virtual void setPaletteBackgroundColor( const QColor & color );
+
+ /*! Undoes changes made to this item - just resets the widget to original value.
+ Reimplemented after KexiFormDataItemInterface to also revert the visible value
+ (i.e. text) to the original state. */
+ virtual void undoChanges();
+
+ public slots:
+ void slotRowAccepted(KexiTableItem *item, int row);
+ void slotItemSelected(KexiTableItem* item) { KexiComboBoxBase::slotItemSelected(item); }
+
+ protected slots:
+ void slotInternalEditorValueChanged(const QVariant& v)
+ { KexiComboBoxBase::slotInternalEditorValueChanged(v); }
+
+ protected:
+ QRect buttonGeometry() const;
+
+ virtual void paintEvent( QPaintEvent * );
+
+ virtual void mousePressEvent( QMouseEvent *e );
+
+ void mouseDoubleClickEvent( QMouseEvent *e );
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+ //! \return internal editor's geometry
+ QRect editorGeometry() const;
+
+ //! Creates editor. Reimplemented, because if the combo box is not editable,
+ //! editor should not be created.
+ virtual void createEditor();
+
+ /*! Reimplemented */
+ virtual void styleChange( QStyle& oldStyle );
+
+ /*! Reimplemented */
+ virtual void fontChange( const QFont & oldFont );
+
+ virtual bool subwidgetStretchRequired(KexiDBAutoField* autoField) const;
+
+ //! Implemented for KexiComboBoxBase
+ virtual QWidget *internalEditor() const { return /*WidgetWithSubpropertiesInterface*/m_subwidget; }
+
+ //! Implemented for KexiComboBoxBase. Does nothing if the widget is not editable.
+ virtual void moveCursorToEndInInternalEditor();
+
+ //! Implemented for KexiComboBoxBase. Does nothing if the widget is not editable.
+ virtual void selectAllInInternalEditor();
+
+ //! Implemented for KexiComboBoxBase
+ virtual void setValueInInternalEditor(const QVariant& value);
+
+ //! Implemented for KexiComboBoxBase
+ virtual QVariant valueFromInternalEditor();
+
+ //! Implemented for KexiComboBoxBase
+ virtual void editRequested();
+
+ //! Implemented for KexiComboBoxBase
+ virtual void acceptRequested();
+
+ //! Implement this to return a position \a pos mapped from parent (e.g. viewport)
+ //! to global coordinates. QPoint(-1, -1) should be returned if this cannot be computed.
+ virtual QPoint mapFromParentToGlobal(const QPoint& pos) const;
+
+ //! Implement this to return a hint for popup width.
+ virtual int popupWidthHint() const;
+
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+
+ //! Implemented to handle visible value instead of index
+ virtual void setVisibleValueInternal(const QVariant& value);
+
+ bool handleMousePressEvent(QMouseEvent *e);
+
+ bool handleKeyPressEvent(QKeyEvent *ke);
+
+ //! Implemented for KexiDataItemInterface
+ virtual void beforeSignalValueChanged();
+
+ virtual KexiComboBoxPopup *popup() const;
+ virtual void setPopup(KexiComboBoxPopup *popup);
+
+ /*! Called by top-level form on key press event.
+ Used for Key_Escape to if the popup is visible,
+ so the key press won't be consumed to perform "cancel editing".
+ Also used for grabbing page down/up keys. */
+ virtual bool keyPressed(QKeyEvent *ke);
+
+ class Private;
+ Private * const d;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbdateedit.cpp b/kexi/plugins/forms/widgets/kexidbdateedit.cpp
new file mode 100644
index 00000000..32584fce
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbdateedit.cpp
@@ -0,0 +1,230 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbdateedit.h"
+#include <qlayout.h>
+#include <qtoolbutton.h>
+#include <kpopupmenu.h>
+#include <kdatepicker.h>
+#include <kdatetbl.h>
+
+#include <kexiutils/utils.h>
+#include <kexidb/queryschema.h>
+
+KexiDBDateEdit::KexiDBDateEdit(const QDate &date, QWidget *parent, const char *name)
+ : QWidget(parent, name), KexiFormDataItemInterface()
+{
+ m_invalidState = false;
+ m_cleared = false;
+ m_readOnly = false;
+
+ m_edit = new QDateEdit(date, this);
+ m_edit->setAutoAdvance(true);
+ m_edit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
+ connect( m_edit, SIGNAL(valueChanged(const QDate&)), this, SLOT(slotValueChanged(const QDate&)) );
+ connect( m_edit, SIGNAL(valueChanged(const QDate&)), this, SIGNAL(dateChanged(const QDate&)) );
+
+ QToolButton* btn = new QToolButton(this);
+ btn->setText("...");
+ btn->setFixedWidth( QFontMetrics(btn->font()).width(" ... ") );
+ btn->setPopupDelay(1); //1 ms
+
+#ifdef QDateTimeEditor_HACK
+ m_dte_date = KexiUtils::findFirstChild<QDateTimeEditor>(m_edit, "QDateTimeEditor");
+#else
+ m_dte_date = 0;
+#endif
+
+ m_datePickerPopupMenu = new KPopupMenu(0, "date_popup");
+ connect(m_datePickerPopupMenu, SIGNAL(aboutToShow()), this, SLOT(slotShowDatePicker()));
+ m_datePicker = new KDatePicker(m_datePickerPopupMenu, QDate::currentDate(), 0);
+
+ KDateTable *dt = KexiUtils::findFirstChild<KDateTable>(m_datePicker, "KDateTable");
+ if (dt)
+ connect(dt, SIGNAL(tableClicked()), this, SLOT(acceptDate()));
+ m_datePicker->setCloseButton(true);
+ m_datePicker->installEventFilter(this);
+ m_datePickerPopupMenu->insertItem(m_datePicker);
+ btn->setPopup(m_datePickerPopupMenu);
+
+ QHBoxLayout* layout = new QHBoxLayout(this);
+ layout->addWidget(m_edit, 1);
+ layout->addWidget(btn, 0);
+
+ setFocusProxy(m_edit);
+}
+
+KexiDBDateEdit::~KexiDBDateEdit()
+{
+}
+
+void KexiDBDateEdit::setInvalidState( const QString& )
+{
+ setEnabled(false);
+ setReadOnly(true);
+ m_invalidState = true;
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+}
+
+void
+KexiDBDateEdit::setEnabled(bool enabled)
+{
+ // prevent the user from reenabling the widget when it is in invalid state
+ if(enabled && m_invalidState)
+ return;
+ QWidget::setEnabled(enabled);
+}
+
+void KexiDBDateEdit::setValueInternal(const QVariant &add, bool removeOld)
+{
+ int setNumberOnFocus = -1;
+ QDate d;
+ QString addString(add.toString());
+ if (removeOld) {
+ if (!addString.isEmpty() && addString[0].latin1()>='0' && addString[0].latin1() <='9') {
+ setNumberOnFocus = addString[0].latin1()-'0';
+ d = QDate(setNumberOnFocus*1000, 1, 1);
+ }
+ }
+ else
+ d = m_origValue.toDate();
+
+ m_edit->setDate(d);
+}
+
+QVariant
+KexiDBDateEdit::value()
+{
+ return QVariant(m_edit->date());
+}
+
+bool KexiDBDateEdit::valueIsNull()
+{
+ return !m_edit->date().isValid() || m_edit->date().isNull();
+}
+
+bool KexiDBDateEdit::valueIsEmpty()
+{
+ return m_cleared;
+}
+
+bool KexiDBDateEdit::isReadOnly() const
+{
+ //! @todo: data/time edit API has no readonly flag,
+ //! so use event filter to avoid changes made by keyboard or mouse when m_readOnly==true
+ return m_readOnly; //!isEnabled();
+}
+
+void KexiDBDateEdit::setReadOnly(bool set)
+{
+ m_readOnly = set;
+}
+
+QWidget*
+KexiDBDateEdit::widget()
+{
+ return this;
+}
+
+bool KexiDBDateEdit::cursorAtStart()
+{
+#ifdef QDateTimeEditor_HACK
+ return m_dte_date && m_edit->hasFocus() && m_dte_date->focusSection()==0;
+#else
+ return false;
+#endif
+}
+
+bool KexiDBDateEdit::cursorAtEnd()
+{
+#ifdef QDateTimeEditor_HACK
+ return m_dte_date && m_edit->hasFocus()
+ && m_dte_date->focusSection()==int(m_dte_date->sectionCount()-1);
+#else
+ return false;
+#endif
+}
+
+void KexiDBDateEdit::clear()
+{
+ m_edit->setDate(QDate());
+ m_cleared = true;
+}
+
+void
+KexiDBDateEdit::slotValueChanged(const QDate&)
+{
+ m_cleared = false;
+}
+
+void
+KexiDBDateEdit::slotShowDatePicker()
+{
+ QDate date = m_edit->date();
+
+ m_datePicker->setDate(date);
+ m_datePicker->setFocus();
+ m_datePicker->show();
+ m_datePicker->setFocus();
+}
+
+void
+KexiDBDateEdit::acceptDate()
+{
+ m_edit->setDate(m_datePicker->date());
+ m_datePickerPopupMenu->hide();
+}
+
+bool
+KexiDBDateEdit::eventFilter(QObject *o, QEvent *e)
+{
+ if (o != m_datePicker)
+ return false;
+
+ switch (e->type()) {
+ case QEvent::Hide:
+ m_datePickerPopupMenu->hide();
+ break;
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ QKeyEvent *ke = (QKeyEvent *)e;
+ if (ke->key()==Qt::Key_Enter || ke->key()==Qt::Key_Return) {
+ //accepting picker
+ acceptDate();
+ return true;
+ }
+ else if (ke->key()==Qt::Key_Escape) {
+ //canceling picker
+ m_datePickerPopupMenu->hide();
+ return true;
+ }
+ else
+ m_datePickerPopupMenu->setFocus();
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+#include "kexidbdateedit.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbdateedit.h b/kexi/plugins/forms/widgets/kexidbdateedit.h
new file mode 100644
index 00000000..2ad693a8
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbdateedit.h
@@ -0,0 +1,118 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBDateEdit_H
+#define KexiDBDateEdit_H
+
+#include "kexiformdataiteminterface.h"
+#include <qdatetimeedit.h>
+
+class KPopupMenu;
+class KDatePicker;
+class QDateTimeEditor;
+
+//! @short A db-aware date editor
+class KEXIFORMUTILS_EXPORT KexiDBDateEdit : public QWidget, public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ // properties copied from QDateEdit
+ Q_ENUMS( Order )
+ Q_PROPERTY( Order order READ order WRITE setOrder DESIGNABLE true)
+ Q_PROPERTY( QDate date READ date WRITE setDate DESIGNABLE true)
+ Q_PROPERTY( bool autoAdvance READ autoAdvance WRITE setAutoAdvance DESIGNABLE true)
+ Q_PROPERTY( QDate maxValue READ maxValue WRITE setMaxValue DESIGNABLE true)
+ Q_PROPERTY( QDate minValue READ minValue WRITE setMinValue DESIGNABLE true)
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true )
+
+ public:
+ enum Order { DMY = QDateEdit::DMY, MDY = QDateEdit::MDY, YMD = QDateEdit::YMD, YDM = QDateEdit::YDM };
+
+ KexiDBDateEdit(const QDate &date, QWidget *parent, const char *name=0);
+ virtual ~KexiDBDateEdit();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setEnabled(bool enabled);
+
+ // property functions
+ inline QDate date() const { return m_edit->date(); }
+ inline void setOrder(Order order) { m_edit->setOrder( (QDateEdit::Order) order); }
+ inline Order order() const { return (Order)m_edit->order(); }
+ inline void setAutoAdvance( bool advance ) { m_edit->setAutoAdvance(advance); }
+ inline bool autoAdvance() const { return m_edit->autoAdvance(); }
+ inline void setMinValue(const QDate& d) { m_edit->setMinValue(d); }
+ inline QDate minValue() const { return m_edit->minValue(); }
+ inline void setMaxValue(const QDate& d) { m_edit->setMaxValue(d); }
+ inline QDate maxValue() const { return m_edit->maxValue(); }
+
+ signals:
+ void dateChanged(const QDate &date);
+
+ public slots:
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ inline void setDate(const QDate& date) { m_edit->setDate(date); }
+ virtual void setReadOnly(bool set);
+
+ protected slots:
+ void slotValueChanged(const QDate&);
+ void slotShowDatePicker();
+ void acceptDate();
+
+ protected:
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+ private:
+ KDatePicker *m_datePicker;
+ QDateEdit *m_edit;
+ KPopupMenu *m_datePickerPopupMenu;
+ QDateTimeEditor *m_dte_date;
+ bool m_invalidState : 1;
+ bool m_cleared : 1;
+ bool m_readOnly : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbdatetimeedit.cpp b/kexi/plugins/forms/widgets/kexidbdatetimeedit.cpp
new file mode 100644
index 00000000..faaeca66
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbdatetimeedit.cpp
@@ -0,0 +1,243 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbdatetimeedit.h"
+
+#include <qtoolbutton.h>
+#include <qlayout.h>
+#include <kpopupmenu.h>
+#include <kdatepicker.h>
+#include <kdatetbl.h>
+#include <kexiutils/utils.h>
+
+KexiDBDateTimeEdit::KexiDBDateTimeEdit(const QDateTime &datetime, QWidget *parent, const char *name)
+ : QWidget(parent, name), KexiFormDataItemInterface()
+{
+ m_invalidState = false;
+ m_cleared = false;
+ m_readOnly = false;
+
+ m_dateEdit = new QDateEdit(datetime.date(), this);
+ m_dateEdit->setAutoAdvance(true);
+ m_dateEdit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
+// m_dateEdit->setFixedWidth( QFontMetrics(m_dateEdit->font()).width("8888-88-88___") );
+ connect(m_dateEdit, SIGNAL(valueChanged(const QDate&)), this, SLOT(slotValueChanged()));
+ connect(m_dateEdit, SIGNAL(valueChanged(const QDate&)), this, SIGNAL(dateTimeChanged()));
+
+ QToolButton* btn = new QToolButton(this);
+ btn->setText("...");
+ btn->setFixedWidth( QFontMetrics(btn->font()).width(" ... ") );
+ btn->setPopupDelay(1); //1 ms
+
+ m_timeEdit = new QTimeEdit(datetime.time(), this);;
+ m_timeEdit->setAutoAdvance(true);
+ m_timeEdit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
+ connect(m_timeEdit, SIGNAL(valueChanged(const QTime&)), this, SLOT(slotValueChanged()));
+ connect(m_timeEdit, SIGNAL(valueChanged(const QTime&)), this, SIGNAL(dateTimeChanged()));
+
+#ifdef QDateTimeEditor_HACK
+ m_dte_date = KexiUtils::findFirstChild<QDateTimeEditor>(m_dateEdit, "QDateTimeEditor");
+ m_dte_time = KexiUtils::findFirstChild<QDateTimeEditor>(m_timeEdit, "QDateTimeEditor");
+#else
+ m_dte_date = 0;
+#endif
+
+ m_datePickerPopupMenu = new KPopupMenu(0, "date_popup");
+ connect(m_datePickerPopupMenu, SIGNAL(aboutToShow()), this, SLOT(slotShowDatePicker()));
+ m_datePicker = new KDatePicker(m_datePickerPopupMenu, QDate::currentDate(), 0);
+
+ KDateTable *dt = KexiUtils::findFirstChild<KDateTable>(m_datePicker, "KDateTable");
+ if (dt)
+ connect(dt, SIGNAL(tableClicked()), this, SLOT(acceptDate()));
+ m_datePicker->setCloseButton(true);
+ m_datePicker->installEventFilter(this);
+ m_datePickerPopupMenu->insertItem(m_datePicker);
+ btn->setPopup(m_datePickerPopupMenu);
+
+ QHBoxLayout* layout = new QHBoxLayout(this);
+ layout->addWidget(m_dateEdit, 0);
+ layout->addWidget(btn, 0);
+ layout->addWidget(m_timeEdit, 0);
+ //layout->addStretch(1);
+
+ setFocusProxy(m_dateEdit);
+}
+
+KexiDBDateTimeEdit::~KexiDBDateTimeEdit()
+{
+}
+
+void KexiDBDateTimeEdit::setInvalidState(const QString & /*! @todo paint this text: text*/)
+{
+ setEnabled(false);
+ setReadOnly(true);
+ m_invalidState = true;
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+}
+
+void
+KexiDBDateTimeEdit::setEnabled(bool enabled)
+{
+ // prevent the user from reenabling the widget when it is in invalid state
+ if(enabled && m_invalidState)
+ return;
+ QWidget::setEnabled(enabled);
+}
+
+void KexiDBDateTimeEdit::setValueInternal(const QVariant &, bool )
+{
+ m_dateEdit->setDate(m_origValue.toDate());
+ m_timeEdit->setTime(m_origValue.toTime());
+}
+
+QVariant
+KexiDBDateTimeEdit::value()
+{
+ return QDateTime(m_dateEdit->date(), m_timeEdit->time());
+}
+
+bool KexiDBDateTimeEdit::valueIsNull()
+{
+ return !m_dateEdit->date().isValid() || m_dateEdit->date().isNull()
+ || !m_timeEdit->time().isValid() || m_timeEdit->time().isNull();
+}
+
+bool KexiDBDateTimeEdit::valueIsEmpty()
+{
+ return m_cleared;
+}
+
+bool KexiDBDateTimeEdit::isReadOnly() const
+{
+ //! @todo: data/time edit API has no readonly flag,
+ //! so use event filter to avoid changes made by keyboard or mouse when m_readOnly==true
+ return m_readOnly; //!isEnabled();
+}
+
+void KexiDBDateTimeEdit::setReadOnly(bool set)
+{
+ m_readOnly = set;
+}
+
+QWidget*
+KexiDBDateTimeEdit::widget()
+{
+ return m_dateEdit;
+}
+
+bool KexiDBDateTimeEdit::cursorAtStart()
+{
+#ifdef QDateTimeEditor_HACK
+ return m_dte_date && m_dateEdit->hasFocus() && m_dte_date->focusSection()==0;
+#else
+ return false;
+#endif
+}
+
+bool KexiDBDateTimeEdit::cursorAtEnd()
+{
+#ifdef QDateTimeEditor_HACK
+ return m_dte_time && m_timeEdit->hasFocus()
+ && m_dte_time->focusSection()==int(m_dte_time->sectionCount()-1);
+#else
+ return false;
+#endif
+}
+
+void KexiDBDateTimeEdit::clear()
+{
+ m_dateEdit->setDate(QDate());
+ m_timeEdit->setTime(QTime());
+ m_cleared = true;
+}
+
+void
+KexiDBDateTimeEdit::slotValueChanged()
+{
+ m_cleared = false;
+}
+
+void
+KexiDBDateTimeEdit::slotShowDatePicker()
+{
+ QDate date = m_dateEdit->date();
+
+ m_datePicker->setDate(date);
+ m_datePicker->setFocus();
+ m_datePicker->show();
+ m_datePicker->setFocus();
+}
+
+void
+KexiDBDateTimeEdit::acceptDate()
+{
+ m_dateEdit->setDate(m_datePicker->date());
+ m_datePickerPopupMenu->hide();
+}
+
+bool
+KexiDBDateTimeEdit::eventFilter(QObject *o, QEvent *e)
+{
+ if (o != m_datePicker)
+ return false;
+
+ switch (e->type()) {
+ case QEvent::Hide:
+ m_datePickerPopupMenu->hide();
+ break;
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ QKeyEvent *ke = (QKeyEvent *)e;
+ if (ke->key()==Qt::Key_Enter || ke->key()==Qt::Key_Return) {
+ //accepting picker
+ acceptDate();
+ return true;
+ }
+ else if (ke->key()==Qt::Key_Escape) {
+ //canceling picker
+ m_datePickerPopupMenu->hide();
+ return true;
+ }
+ else
+ m_datePickerPopupMenu->setFocus();
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+QDateTime
+KexiDBDateTimeEdit::dateTime() const
+{
+ return QDateTime(m_dateEdit->date(), m_timeEdit->time());
+}
+
+void
+KexiDBDateTimeEdit::setDateTime(const QDateTime &dt)
+{
+ m_dateEdit->setDate(dt.date());
+ m_timeEdit->setTime(dt.time());
+}
+
+#include "kexidbdatetimeedit.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbdatetimeedit.h b/kexi/plugins/forms/widgets/kexidbdatetimeedit.h
new file mode 100644
index 00000000..1f185b16
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbdatetimeedit.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBDateTimeEdit_H
+#define KexiDBDateTimeEdit_H
+
+#include "kexiformdataiteminterface.h"
+#include <qdatetimeedit.h>
+
+class KDatePicker;
+class QDateTimeEditor;
+class KPopupMenu;
+
+//! @short A db-aware datetime editor
+class KEXIFORMUTILS_EXPORT KexiDBDateTimeEdit : public QWidget, public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ // properties copied from QDateTimeEdit
+ Q_PROPERTY( QDateTime dateTime READ dateTime WRITE setDateTime )
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true )
+
+ public:
+ enum Order { DMY, MDY, YMD, YDM };
+
+ KexiDBDateTimeEdit(const QDateTime &datetime, QWidget *parent, const char *name=0);
+ virtual ~KexiDBDateTimeEdit();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setEnabled(bool enabled);
+
+ // property functions
+ QDateTime dateTime() const;
+
+ signals:
+ void dateTimeChanged();
+
+ public slots:
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ void setDateTime(const QDateTime &dt);
+ virtual void setReadOnly(bool set);
+
+ protected:
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+ protected slots:
+ void slotValueChanged();
+ void slotShowDatePicker();
+ void acceptDate();
+
+ private:
+ KDatePicker *m_datePicker;
+ QDateEdit* m_dateEdit;
+ QTimeEdit* m_timeEdit;
+ QDateTimeEditor *m_dte_date, *m_dte_time;
+ KPopupMenu *m_datePickerPopupMenu;
+ bool m_invalidState : 1;
+ bool m_cleared : 1;
+ bool m_readOnly : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbdoublespinbox.cpp b/kexi/plugins/forms/widgets/kexidbdoublespinbox.cpp
new file mode 100644
index 00000000..67a2c1a6
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbdoublespinbox.cpp
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbdoublespinbox.h"
+
+#include <qlineedit.h>
+
+KexiDBDoubleSpinBox::KexiDBDoubleSpinBox(QWidget *parent, const char *name)
+ : KDoubleSpinBox(parent, name) , KexiFormDataItemInterface()
+{
+ connect(this, SIGNAL(valueChanged(double)), this, SLOT(slotValueChanged()));
+}
+
+KexiDBDoubleSpinBox::~KexiDBDoubleSpinBox()
+{
+}
+
+void KexiDBDoubleSpinBox::setInvalidState( const QString& displayText )
+{
+ m_invalidState = true;
+ setEnabled(false);
+ setReadOnly(true);
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+ setSpecialValueText(displayText);
+ KDoubleSpinBox::setValue(minValue());
+}
+
+void
+KexiDBDoubleSpinBox::setEnabled(bool enabled)
+{
+ // prevent the user from reenabling the widget when it is in invalid state
+ if(enabled && m_invalidState)
+ return;
+ KDoubleSpinBox::setEnabled(enabled);
+}
+
+void KexiDBDoubleSpinBox::setValueInternal(const QVariant&, bool )
+{
+ KDoubleSpinBox::setValue(m_origValue.toDouble());
+}
+
+QVariant
+KexiDBDoubleSpinBox::value()
+{
+ return KDoubleSpinBox::value();
+}
+
+void KexiDBDoubleSpinBox::slotValueChanged()
+{
+ signalValueChanged();
+}
+
+bool KexiDBDoubleSpinBox::valueIsNull()
+{
+ return cleanText().isEmpty();
+}
+
+bool KexiDBDoubleSpinBox::valueIsEmpty()
+{
+ return false;
+}
+
+bool KexiDBDoubleSpinBox::isReadOnly() const
+{
+ return editor()->isReadOnly();
+}
+
+void KexiDBDoubleSpinBox::setReadOnly(bool set)
+{
+ editor()->setReadOnly(set);
+}
+
+QWidget*
+KexiDBDoubleSpinBox::widget()
+{
+ return this;
+}
+
+bool KexiDBDoubleSpinBox::cursorAtStart()
+{
+ return false; //! \todo ?
+}
+
+bool KexiDBDoubleSpinBox::cursorAtEnd()
+{
+ return false; //! \todo ?
+}
+
+void KexiDBDoubleSpinBox::clear()
+{
+ KDoubleSpinBox::setValue(minValue());
+}
+
+#include "kexidbdoublespinbox.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbdoublespinbox.h b/kexi/plugins/forms/widgets/kexidbdoublespinbox.h
new file mode 100644
index 00000000..c6bc627d
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbdoublespinbox.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBDoubleSpinBox_H
+#define KexiDBDoubleSpinBox_H
+
+#include "kexiformdataiteminterface.h"
+#include <qwidget.h>
+#include <knuminput.h>
+
+//! @short A db-aware int spin box
+class KEXIFORMUTILS_EXPORT KexiDBDoubleSpinBox : public KDoubleSpinBox, public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true )
+
+ public:
+ KexiDBDoubleSpinBox(QWidget *parent, const char *name=0);
+ virtual ~KexiDBDoubleSpinBox();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ public slots:
+ virtual void setEnabled(bool enabled);
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ void slotValueChanged();
+ virtual void setReadOnly(bool set);
+
+ protected:
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+
+ private:
+ bool m_invalidState : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbform.cpp b/kexi/plugins/forms/widgets/kexidbform.cpp
new file mode 100644
index 00000000..cff12c7c
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbform.cpp
@@ -0,0 +1,714 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005-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 <qobjectlist.h>
+#include <qpainter.h>
+#include <qcursor.h>
+#include <qapplication.h>
+#include <qfocusdata.h>
+
+#include <kdebug.h>
+
+#include "kexidbform.h"
+#include "kexiformpart.h"
+#include "kexiformscrollview.h"
+
+#include <formeditor/objecttree.h>
+#include <formeditor/formmanager.h>
+#include <formeditor/widgetlibrary.h>
+#include <widget/tableview/kexidataawareobjectiface.h>
+#include <widget/kexiscrollview.h>
+#include <kexiutils/utils.h>
+
+//! @internal
+class KexiDBForm::Private
+{
+ public:
+ Private()
+ : dataAwareObject(0)
+ , orderedFocusWidgetsIterator(orderedFocusWidgets)
+ , autoTabStops(false)
+ , popupFocused(false)
+ {
+ }
+
+ ~Private()
+ {
+ }
+
+ //! \return index of data-aware widget \a widget
+ int indexOfDataAwareWidget(QWidget *widget) const
+ {
+ if (!dynamic_cast<KexiDataItemInterface*>(widget))
+ return -1;
+ return indexOfDataItem( dynamic_cast<KexiDataItemInterface*>(widget) );
+ }
+
+ //! \return index of data item \a item, or -1 if not found
+ int indexOfDataItem( KexiDataItemInterface* item ) const
+ {
+ QMapConstIterator<KexiDataItemInterface*, uint> indicesForDataAwareWidgetsIt(
+ indicesForDataAwareWidgets.find(item));
+ if (indicesForDataAwareWidgetsIt == indicesForDataAwareWidgets.constEnd())
+ return -1;
+ kexipluginsdbg << "KexiDBForm: column # for item: "
+ << indicesForDataAwareWidgetsIt.data() << endl;
+ return indicesForDataAwareWidgetsIt.data();
+ }
+
+ //! Sets orderedFocusWidgetsIterator member to a position pointing to \a widget
+ void setOrderedFocusWidgetsIteratorTo( QWidget *widget )
+ {
+ if (orderedFocusWidgetsIterator.current() == widget)
+ return;
+ orderedFocusWidgetsIterator.toFirst();
+ while (orderedFocusWidgetsIterator.current() && orderedFocusWidgetsIterator.current()!=widget)
+ ++orderedFocusWidgetsIterator;
+ }
+
+ KexiDataAwareObjectInterface* dataAwareObject;
+ //! ordered list of focusable widgets (can be both data-widgets or buttons, etc.)
+ QPtrList<QWidget> orderedFocusWidgets;
+ //! ordered list of data-aware widgets
+ QPtrList<QWidget> orderedDataAwareWidgets;
+ QMap<KexiDataItemInterface*, uint> indicesForDataAwareWidgets; //!< a subset of orderedFocusWidgets mapped to indices
+ QPtrListIterator<QWidget> orderedFocusWidgetsIterator;
+ QPixmap buffer; //!< stores grabbed entire form's area for redraw
+ QRect prev_rect; //!< previously selected rectangle
+// QGuardedPtr<QWidget> widgetFocusedBeforePopup;
+ bool autoTabStops : 1;
+ bool popupFocused : 1; //!< used in KexiDBForm::eventFilter()
+};
+
+//========================
+
+KexiDBForm::KexiDBForm(QWidget *parent, KexiDataAwareObjectInterface* dataAwareObject,
+ const char *name/*, KexiDB::Connection *conn*/)
+ : KexiDBFormBase(parent, name)
+ , KexiFormDataItemInterface()
+ , d(new Private())
+{
+ installEventFilter(this);
+//test setDisplayMode( KexiGradientWidget::SimpleGradient );
+ editedItem = 0;
+ d->dataAwareObject = dataAwareObject;
+ m_hasFocusableWidget = false;
+
+ kexipluginsdbg << "KexiDBForm::KexiDBForm(): " << endl;
+ setCursor(QCursor(Qt::ArrowCursor)); //to avoid keeping Size cursor when moving from form's boundaries
+ setAcceptDrops( true );
+}
+
+KexiDBForm::~KexiDBForm()
+{
+ kexipluginsdbg << "KexiDBForm::~KexiDBForm(): close" << endl;
+ delete d;
+}
+
+KexiDataAwareObjectInterface* KexiDBForm::dataAwareObject() const { return d->dataAwareObject; }
+
+//repaint all children widgets
+static void repaintAll(QWidget *w)
+{
+ QObjectList *list = w->queryList("QWidget");
+ QObjectListIt it(*list);
+ for (QObject *obj; (obj=it.current()); ++it ) {
+ static_cast<QWidget*>(obj)->repaint();
+ }
+ delete list;
+}
+
+void
+KexiDBForm::drawRect(const QRect& r, int type)
+{
+ QValueList<QRect> l;
+ l.append(r);
+ drawRects(l, type);
+}
+
+void
+KexiDBForm::drawRects(const QValueList<QRect> &list, int type)
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ if (d->prev_rect.isValid()) {
+ //redraw prev. selection's rectangle
+ p.drawPixmap( QPoint(d->prev_rect.x()-2, d->prev_rect.y()-2), d->buffer,
+ QRect(d->prev_rect.x()-2, d->prev_rect.y()-2, d->prev_rect.width()+4, d->prev_rect.height()+4));
+ }
+ p.setBrush(QBrush::NoBrush);
+ if(type == 1) // selection rect
+ p.setPen(QPen(white, 1, Qt::DotLine));
+ else if(type == 2) // insert rect
+ p.setPen(QPen(white, 2));
+ p.setRasterOp(XorROP);
+
+ d->prev_rect = QRect();
+ QValueList<QRect>::ConstIterator endIt = list.constEnd();
+ for(QValueList<QRect>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
+ p.drawRect(*it);
+ if (d->prev_rect.isValid())
+ d->prev_rect = d->prev_rect.unite(*it);
+ else
+ d->prev_rect = *it;
+ }
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+}
+
+void
+KexiDBForm::initBuffer()
+{
+ repaintAll(this);
+ d->buffer.resize( width(), height() );
+ d->buffer = QPixmap::grabWindow( winId() );
+ d->prev_rect = QRect();
+}
+
+void
+KexiDBForm::clearForm()
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ //redraw entire form surface
+ p.drawPixmap( QPoint(0,0), d->buffer, QRect(0,0,d->buffer.width(), d->buffer.height()) );
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+
+ repaintAll(this);
+}
+
+void
+KexiDBForm::highlightWidgets(QWidget *from, QWidget *to)//, const QPoint &point)
+{
+ QPoint fromPoint, toPoint;
+ if(from && from->parentWidget() && (from != this))
+ fromPoint = from->parentWidget()->mapTo(this, from->pos());
+ if(to && to->parentWidget() && (to != this))
+ toPoint = to->parentWidget()->mapTo(this, to->pos());
+
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ if (d->prev_rect.isValid()) {
+ //redraw prev. selection's rectangle
+ p.drawPixmap( QPoint(d->prev_rect.x(), d->prev_rect.y()), d->buffer,
+ QRect(d->prev_rect.x(), d->prev_rect.y(), d->prev_rect.width(), d->prev_rect.height()));
+ }
+
+ p.setPen( QPen(Qt::red, 2) );
+
+ if(to)
+ {
+ QPixmap pix1 = QPixmap::grabWidget(from);
+ QPixmap pix2 = QPixmap::grabWidget(to);
+
+ if((from != this) && (to != this))
+ p.drawLine( from->parentWidget()->mapTo(this, from->geometry().center()), to->parentWidget()->mapTo(this, to->geometry().center()) );
+
+ p.drawPixmap(fromPoint.x(), fromPoint.y(), pix1);
+ p.drawPixmap(toPoint.x(), toPoint.y(), pix2);
+
+ if(to == this)
+ p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
+ else
+ p.drawRoundRect(toPoint.x(), toPoint.y(), to->width(), to->height(), 5, 5);
+ }
+
+ if(from == this)
+ p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
+ else
+ p.drawRoundRect(fromPoint.x(), fromPoint.y(), from->width(), from->height(), 5, 5);
+
+ if((to == this) || (from == this))
+ d->prev_rect = QRect(0, 0, d->buffer.width(), d->buffer.height());
+ else if(to)
+ {
+ d->prev_rect.setX( (fromPoint.x() < toPoint.x()) ? (fromPoint.x() - 5) : (toPoint.x() - 5) );
+ d->prev_rect.setY( (fromPoint.y() < toPoint.y()) ? (fromPoint.y() - 5) : (toPoint.y() - 5) );
+ d->prev_rect.setRight( (fromPoint.x() < toPoint.x()) ? (toPoint.x() + to->width() + 10) : (fromPoint.x() + from->width() + 10) );
+ d->prev_rect.setBottom( (fromPoint.y() < toPoint.y()) ? (toPoint.y() + to->height() + 10) : (fromPoint.y() + from->height() + 10) ) ;
+ }
+ else
+ d->prev_rect = QRect(fromPoint.x()- 5, fromPoint.y() -5, from->width() + 10, from->height() + 10);
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+}
+
+QSize
+KexiDBForm::sizeHint() const
+{
+ //todo: find better size (user configured?)
+ return QSize(400,300);
+}
+
+void KexiDBForm::setInvalidState( const QString& displayText )
+{
+ Q_UNUSED( displayText );
+
+ //! @todo draw "invalid data source" text on the surface?
+}
+
+bool KexiDBForm::autoTabStops() const
+{
+ return d->autoTabStops;
+}
+
+void KexiDBForm::setAutoTabStops(bool set)
+{
+ d->autoTabStops = set;
+}
+
+QPtrList<QWidget>* KexiDBForm::orderedFocusWidgets() const
+{
+ return &d->orderedFocusWidgets;
+}
+
+QPtrList<QWidget>* KexiDBForm::orderedDataAwareWidgets() const
+{
+ return &d->orderedDataAwareWidgets;
+}
+
+void KexiDBForm::updateTabStopsOrder(KFormDesigner::Form* form)
+{
+ QWidget *fromWidget = 0;
+ //QWidget *topLevelWidget = form->widget()->topLevelWidget();
+//js form->updateTabStopsOrder(); //certain widgets can have now updated focusPolicy properties, fix this
+ uint numberOfDataAwareWidgets = 0;
+// if (d->orderedFocusWidgets.isEmpty()) {
+ //generate a new list
+ for (KFormDesigner::ObjectTreeListIterator it(form->tabStopsIterator()); it.current(); ++it) {
+ if (it.current()->widget()->focusPolicy() & QWidget::TabFocus) {
+ //this widget has tab focus:
+ it.current()->widget()->installEventFilter(this);
+ //also filter events for data-aware children of this widget (i.e. KexiDBAutoField's editors)
+ QObjectList *children = it.current()->widget()->queryList("QWidget");
+ for (QObjectListIt childrenIt(*children); childrenIt.current(); ++childrenIt) {
+ // if (dynamic_cast<KexiFormDataItemInterface*>(childrenIt.current())) {
+ kexipluginsdbg << "KexiDBForm::updateTabStopsOrder(): also adding '"
+ << childrenIt.current()->className() << " " << childrenIt.current()->name()
+ << "' child to filtered widgets" << endl;
+ //it.current()->widget()->installEventFilter(static_cast<QWidget*>(childrenIt.current()));
+ childrenIt.current()->installEventFilter(this);
+ // }
+ }
+ delete children;
+ if (fromWidget) {
+ kexipluginsdbg << "KexiDBForm::updateTabStopsOrder() tab order: " << fromWidget->name()
+ << " -> " << it.current()->widget()->name() << endl;
+ // setTabOrder( fromWidget, it.current()->widget() );
+ }
+ fromWidget = it.current()->widget();
+ d->orderedFocusWidgets.append( it.current()->widget() );
+ }
+
+ KexiFormDataItemInterface* dataItem = dynamic_cast<KexiFormDataItemInterface*>( it.current()->widget() );
+ if (dataItem && !dataItem->dataSource().isEmpty()) {
+ kexipluginsdbg << "#" << numberOfDataAwareWidgets << ": "
+ << dataItem->dataSource() << " (" << it.current()->widget()->name() << ")" << endl;
+
+// /*! @todo d->indicesForDataAwareWidgets SHOULDNT BE UPDATED HERE BECAUSE
+// THERE CAN BE ALSO NON-TABSTOP DATA WIDGETS!
+// */
+ d->indicesForDataAwareWidgets.replace(
+ dataItem,
+ numberOfDataAwareWidgets );
+ numberOfDataAwareWidgets++;
+
+ d->orderedDataAwareWidgets.append( it.current()->widget() );
+ }
+ }//for
+// }
+/* else {
+ //restore ordering
+ for (QPtrListIterator<QWidget> it(d->orderedFocusWidgets); it.current(); ++it) {
+ if (fromWidget) {
+ kdDebug() << "KexiDBForm::updateTabStopsOrder() tab order: " << fromWidget->name()
+ << " -> " << it.current()->name() << endl;
+ setTabOrder( fromWidget, it.current() );
+ }
+ fromWidget = it.current();
+ }
+// SET_FOCUS_USING_REASON(focusWidget(), QFocusEvent::Tab);
+ }*/
+}
+
+void KexiDBForm::updateTabStopsOrder()
+{
+ for (QPtrListIterator<QWidget> it( d->orderedFocusWidgets ); it.current();) {
+ if (! (it.current()->focusPolicy() & QWidget::TabFocus))
+ d->orderedFocusWidgets.remove( it.current() );
+ else
+ ++it;
+ }
+}
+
+void KexiDBForm::updateReadOnlyFlags()
+{
+ for (QPtrListIterator<QWidget> it(d->orderedDataAwareWidgets); it.current(); ++it) {
+ KexiFormDataItemInterface* dataItem = dynamic_cast<KexiFormDataItemInterface*>( it.current() );
+ if (dataItem && !dataItem->dataSource().isEmpty()) {
+ if (dataAwareObject()->isReadOnly()) {
+ dataItem->setReadOnly( true );
+ }
+ }
+ }
+}
+
+bool KexiDBForm::eventFilter( QObject * watched, QEvent * e )
+{
+ //kexipluginsdbg << e->type() << endl;
+ if (e->type()==QEvent::Resize && watched == this)
+ kexipluginsdbg << "RESIZE" << endl;
+ if (e->type()==QEvent::KeyPress) {
+ if (preview()) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ const int key = ke->key();
+ bool tab = ke->state() == Qt::NoButton && key == Qt::Key_Tab;
+ bool backtab = ((ke->state() == Qt::NoButton || ke->state() == Qt::ShiftButton) && key == Qt::Key_Backtab)
+ || (ke->state() == Qt::ShiftButton && key == Qt::Key_Tab);
+ QObject *o = watched; //focusWidget();
+ QWidget* realWidget = dynamic_cast<QWidget*>(o); //will beused below (for tab/backtab handling)
+
+ if (!tab && !backtab) {
+ //for buttons, left/up and right/down keys act like tab/backtab (see qbutton.cpp)
+ if (realWidget->inherits("QButton")) {
+ if (ke->state() == Qt::NoButton && (key == Qt::Key_Right || key == Qt::Key_Down))
+ tab = true;
+ else if (ke->state() == Qt::NoButton && (key == Qt::Key_Left || key == Qt::Key_Up))
+ backtab = true;
+ }
+ }
+
+ if (!tab && !backtab) {
+ // allow the editor widget to grab the key press event
+ while (true) {
+ if (!o || o == dynamic_cast<QObject*>(d->dataAwareObject))
+ break;
+ if (dynamic_cast<KexiFormDataItemInterface*>(o)) {
+ realWidget = dynamic_cast<QWidget*>(o); //will be used below
+ if (realWidget == this) //we have encountered 'this' form surface, give up
+ return false;
+ KexiFormDataItemInterface* dataItemIface = dynamic_cast<KexiFormDataItemInterface*>(o);
+ while (dataItemIface) {
+ if (dataItemIface->keyPressed(ke))
+ return false;
+ dataItemIface = dynamic_cast<KexiFormDataItemInterface*>(dataItemIface->parentInterface()); //try in parent, e.g. in combobox
+ }
+ break;
+ }
+ o = o->parent();
+ }
+ // try to handle global shortcuts at the KexiDataAwareObjectInterface
+ // level (e.g. for "next record" action)
+ int curRow = d->dataAwareObject->currentRow();
+ int curCol = d->dataAwareObject->currentColumn();
+ bool moveToFirstField; //if true, we'll move focus to the first field (in tab order)
+ bool moveToLastField; //if true, we'll move focus to the first field (in tab order)
+ if (! (ke->state() == Qt::NoButton && (key == Qt::Key_Home
+ || key == Qt::Key_End || key == Qt::Key_Down || key == Qt::Key_Up))
+ /* ^^ home/end/down/up are already handled by widgets */
+ && d->dataAwareObject->handleKeyPress(
+ ke, curRow, curCol, false/*!fullRowSelection*/, &moveToFirstField, &moveToLastField))
+ {
+ if (ke->isAccepted())
+ return true;
+ QWidget* widgetToFocus;
+ if (moveToFirstField) {
+ widgetToFocus = d->orderedFocusWidgets.first(); //?
+ curCol = d->indexOfDataAwareWidget( widgetToFocus );
+ }
+ else if (moveToLastField) {
+ widgetToFocus = d->orderedFocusWidgets.last(); //?
+ curCol = d->indexOfDataAwareWidget( widgetToFocus );
+ }
+ else
+ widgetToFocus = d->orderedDataAwareWidgets.at( curCol ); //?
+
+ d->dataAwareObject->setCursorPosition( curRow, curCol );
+
+ if (widgetToFocus)
+ widgetToFocus->setFocus();
+ else
+ kexipluginswarn << "KexiDBForm::eventFilter(): widgetToFocus not found!" << endl;
+
+ ke->accept();
+ return true;
+ }
+ if (key == Qt::Key_Delete && ke->state()==Qt::ControlButton) {
+//! @todo remove hardcoded shortcuts: can be reconfigured...
+ d->dataAwareObject->deleteCurrentRow();
+ return true;
+ }
+ }
+ // handle Esc key
+ if (ke->state() == Qt::NoButton && key == Qt::Key_Escape) {
+ //cancel field editing/row editing if possible
+ if (d->dataAwareObject->cancelEditor())
+ return true;
+ else if (d->dataAwareObject->cancelRowEdit())
+ return true;
+ return false; // canceling not needed - pass the event to the active widget
+ }
+ // jstaniek: Fix for Qt bug (handling e.g. Alt+2, Ctrl+2 keys on every platform)
+ // It's important because we're using alt+2 short cut by default
+ // Damn! I've reported this to Trolltech in November 2004 - still not fixed.
+ if (ke->isAccepted() && (ke->state() & Qt::AltButton) && ke->text()>="0" && ke->text()<="9")
+ return true;
+
+ if (tab || backtab) {
+ //the watched widget can be a subwidget of a real widget, e.g. a drop down button of image box: find it
+ while (!KexiFormPart::library()->widgetInfoForClassName(realWidget->className()))
+ realWidget = realWidget->parentWidget();
+ if (!realWidget)
+ return true; //ignore
+ //the watched widget can be a subwidget of a real widget, e.g. autofield: find it
+ //QWidget* realWidget = static_cast<QWidget*>(watched);
+ while (dynamic_cast<KexiDataItemInterface*>(realWidget) && dynamic_cast<KexiDataItemInterface*>(realWidget)->parentInterface())
+ realWidget = dynamic_cast<QWidget*>( dynamic_cast<KexiDataItemInterface*>(realWidget)->parentInterface() );
+
+ d->setOrderedFocusWidgetsIteratorTo( realWidget );
+ kexipluginsdbg << realWidget->name() << endl;
+
+ // find next/prev widget to focus
+ QWidget *widgetToUnfocus = realWidget;
+ QWidget *widgetToFocus = 0;
+ bool wasAtFirstWidget = false; //used to protect against infinite loop
+ while (true) {
+ if (tab) {
+ if (d->orderedFocusWidgets.first() && realWidget == d->orderedFocusWidgets.last()) {
+ if (wasAtFirstWidget)
+ break;
+ d->orderedFocusWidgetsIterator.toFirst();
+ wasAtFirstWidget = true;
+ }
+ else if (realWidget == d->orderedFocusWidgetsIterator.current()) {
+ ++d->orderedFocusWidgetsIterator; //next
+ }
+ else
+ return true; //ignore
+ }
+ else {//backtab
+ if (d->orderedFocusWidgets.last() && realWidget == d->orderedFocusWidgets.first()) {
+ d->orderedFocusWidgetsIterator.toLast();
+ }
+ else if (realWidget == d->orderedFocusWidgetsIterator.current()) {
+ --d->orderedFocusWidgetsIterator; //prev
+ }
+ else
+ return true; //ignore
+ }
+
+ widgetToFocus = d->orderedFocusWidgetsIterator.current();
+
+ QObject *pageFor_widgetToFocus = 0;
+ KFormDesigner::TabWidget *tabWidgetFor_widgetToFocus
+ = KFormDesigner::findParent<KFormDesigner::TabWidget>(
+ widgetToFocus, "KFormDesigner::TabWidget", pageFor_widgetToFocus);
+ if (tabWidgetFor_widgetToFocus && tabWidgetFor_widgetToFocus->currentPage()!=pageFor_widgetToFocus) {
+ realWidget = widgetToFocus;
+ continue; //the new widget to focus is placed on invisible tab page: move to next widget
+ }
+ break;
+ }//while
+
+ //set focus, but don't use just setFocus() because certain widgets
+ //behaves differently (e.g. QLineEdit calls selectAll()) when
+ //focus event's reason is QFocusEvent::Tab
+ if (widgetToFocus->focusProxy())
+ widgetToFocus = widgetToFocus->focusProxy();
+ if (widgetToFocus && d->dataAwareObject->acceptEditor()) {
+ if (tab) {
+ //try to accept this will validate the current input (if any)
+ KexiUtils::unsetFocusWithReason(widgetToUnfocus, QFocusEvent::Tab);
+ KexiUtils::setFocusWithReason(widgetToFocus, QFocusEvent::Tab);
+ kexipluginsdbg << "focusing " << widgetToFocus->name() << endl;
+ }
+ else {//backtab
+ KexiUtils::unsetFocusWithReason(widgetToUnfocus, QFocusEvent::Backtab);
+ //set focus, see above note
+ KexiUtils::setFocusWithReason(d->orderedFocusWidgetsIterator.current(), QFocusEvent::Backtab);
+ kexipluginsdbg << "focusing " << d->orderedFocusWidgetsIterator.current()->name() << endl;
+ }
+ }
+ return true;
+ }
+ }
+ }
+ else if (e->type()==QEvent::FocusIn) {
+ bool focusDataWidget = preview();
+ if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Popup) {
+ kdDebug() << "->>> focus IN, popup" <<endl;
+ focusDataWidget = !d->popupFocused;
+ d->popupFocused = false;
+// if (d->widgetFocusedBeforePopup) {
+// watched = d->widgetFocusedBeforePopup;
+// d->widgetFocusedBeforePopup = 0;
+// }
+ }
+
+ if (focusDataWidget) {
+ kexipluginsdbg << "KexiDBForm: FocusIn: " << watched->className() << " " << watched->name() << endl;
+ if (d->dataAwareObject) {
+ QWidget *dataItem = dynamic_cast<QWidget*>(watched);
+ while (dataItem) {
+ while (dataItem && !dynamic_cast<KexiDataItemInterface*>(dataItem))
+ dataItem = dataItem->parentWidget();
+ if (!dataItem)
+ break;
+ kexipluginsdbg << "KexiDBForm: FocusIn: FOUND " << dataItem->className() << " " << dataItem->name() << endl;
+
+ const int index = d->indexOfDataAwareWidget(dataItem);
+ if (index>=0) {
+ kexipluginsdbg << "KexiDBForm: moving cursor to column #" << index << endl;
+ editedItem = 0;
+ if ((int)index!=d->dataAwareObject->currentColumn()) {
+ d->dataAwareObject->setCursorPosition( d->dataAwareObject->currentRow(), index /*column*/ );
+ }
+ break;
+ }
+ else
+ dataItem = dataItem->parentWidget();
+
+ dataItem->update();
+ }
+ }
+ }
+ }
+ else if (e->type()==QEvent::FocusOut) {
+ if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Popup) {
+ //d->widgetFocusedBeforePopup = (QWidget*)watched;
+ d->popupFocused = true;
+ }
+ else
+ d->popupFocused = false;
+// d->widgetFocusedBeforePopup = 0;
+// kdDebug() << "e->type()==QEvent::FocusOut " << watched->className() << " " <<watched->name() << endl;
+// UNSET_FOCUS_USING_REASON(watched, static_cast<QFocusEvent*>(e)->reason());
+ }
+ return KexiDBFormBase::eventFilter(watched, e);
+}
+
+bool KexiDBForm::valueIsNull()
+{
+ return true;
+}
+
+bool KexiDBForm::valueIsEmpty()
+{
+ return true;
+}
+
+bool KexiDBForm::isReadOnly() const
+{
+ if (d->dataAwareObject)
+ return d->dataAwareObject->isReadOnly();
+//! @todo ?
+ return false;
+}
+
+void KexiDBForm::setReadOnly( bool readOnly )
+{
+ if (d->dataAwareObject)
+ d->dataAwareObject->setReadOnly( readOnly ); //???
+}
+
+QWidget* KexiDBForm::widget()
+{
+ return this;
+}
+
+bool KexiDBForm::cursorAtStart()
+{
+ return false;
+}
+
+bool KexiDBForm::cursorAtEnd()
+{
+ return false;
+}
+
+void KexiDBForm::clear()
+{
+ //! @todo clear all fields?
+}
+
+bool KexiDBForm::preview() const {
+ return dynamic_cast<KexiScrollView*>(d->dataAwareObject)
+ ? dynamic_cast<KexiScrollView*>(d->dataAwareObject)->preview() : false;
+}
+
+void KexiDBForm::dragMoveEvent( QDragMoveEvent *e )
+{
+ KexiDBFormBase::dragMoveEvent( e );
+ emit handleDragMoveEvent(e);
+}
+
+void KexiDBForm::dropEvent( QDropEvent *e )
+{
+ KexiDBFormBase::dropEvent( e );
+ emit handleDropEvent(e);
+}
+
+void KexiDBForm::setCursor( const QCursor & cursor )
+{
+ //js: empty, to avoid fscking problems with random cursors!
+ //! @todo?
+
+ if (KFormDesigner::FormManager::self()->isInserting()) //exception
+ KexiDBFormBase::setCursor(cursor);
+}
+
+//! @todo: Qt4? XORed resize rectangles instead of black widgets
+/*
+void KexiDBForm::paintEvent( QPaintEvent *e )
+{
+ QPainter p;
+ p.begin(this, true);
+ bool unclipped = testWFlags( WPaintUnclipped );
+ setWFlags( WPaintUnclipped );
+
+ p.setPen(white);
+ p.setRasterOp(XorROP);
+ p.drawLine(e->rect().topLeft(), e->rect().bottomRight());
+
+ if (!unclipped)
+ clearWFlags( WPaintUnclipped );
+ p.end();
+ KexiDBFormBase::paintEvent(e);
+}
+*/
+
+#include "kexidbform.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbform.h b/kexi/plugins/forms/widgets/kexidbform.h
new file mode 100644
index 00000000..81a71bba
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbform.h
@@ -0,0 +1,139 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2005-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 KEXIDBFORM_H
+#define KEXIDBFORM_H
+
+#include <qpixmap.h>
+
+#include <formeditor/form.h>
+#include "../kexiformdataiteminterface.h"
+
+#ifdef KEXI_USE_GRADIENT_WIDGET
+#include <kexigradientwidget.h>
+# define KexiDBFormBase KexiGradientWidget
+#else
+# define KexiDBFormBase QWidget
+#endif
+
+class KexiDataAwareObjectInterface;
+class KexiFormScrollView;
+
+//! @short A DB-aware form widget, acting as form's toplevel widget
+class KEXIFORMUTILS_EXPORT KexiDBForm :
+ public KexiDBFormBase,
+ public KFormDesigner::FormWidget,
+ public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_PROPERTY(bool autoTabStops READ autoTabStops WRITE setAutoTabStops DESIGNABLE true)
+ //original "size" property is not designable, so here's a custom (not storable) replacement
+ Q_PROPERTY( QSize sizeInternal READ sizeInternal WRITE resizeInternal DESIGNABLE true STORED false )
+ public:
+ KexiDBForm(QWidget *parent, KexiDataAwareObjectInterface* dataAwareObject, const char *name="kexi_dbform");
+ virtual ~KexiDBForm();
+
+ KexiDataAwareObjectInterface* dataAwareObject() const;
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+
+ //! no effect
+ QVariant value() { return QVariant(); }
+
+ virtual void setInvalidState( const QString& displayText );
+
+ virtual void drawRect(const QRect& r, int type);
+ virtual void drawRects(const QValueList<QRect> &list, int type);
+ virtual void initBuffer();
+ virtual void clearForm();
+ virtual void highlightWidgets(QWidget *from, QWidget *to/*, const QPoint &p*/);
+
+ virtual QSize sizeHint() const;
+
+ bool autoTabStops() const;
+
+ QPtrList<QWidget>* orderedFocusWidgets() const;
+
+ QPtrList<QWidget>* orderedDataAwareWidgets() const;
+
+ void updateTabStopsOrder(KFormDesigner::Form* form);
+
+ void updateTabStopsOrder();
+
+ virtual bool eventFilter ( QObject * watched, QEvent * e );
+
+ virtual bool valueIsNull();
+ virtual bool valueIsEmpty();
+ virtual bool isReadOnly() const;
+ virtual QWidget* widget();
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ bool preview() const;
+
+ virtual void setCursor( const QCursor & cursor );
+
+ public slots:
+ void setAutoTabStops(bool set);
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+
+ //! This implementation just disables read only widget
+ virtual void setReadOnly( bool readOnly );
+
+ //! @internal for sizeInternal property
+ QSize sizeInternal() const { return KexiDBFormBase::size(); }
+
+ //! @internal for sizeInternal property
+ void resizeInternal(const QSize& s) { KexiDBFormBase::resize(s); }
+
+ signals:
+ void handleDragMoveEvent(QDragMoveEvent *e);
+ void handleDropEvent(QDropEvent *e);
+
+ protected:
+ //! no effect
+ virtual void setValueInternal(const QVariant&, bool) {}
+
+ //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface
+ virtual void dragMoveEvent( QDragMoveEvent *e );
+
+ //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface
+ virtual void dropEvent( QDropEvent *e );
+
+ //! called from KexiFormScrollView::initDataContents()
+ void updateReadOnlyFlags();
+// virtual void paintEvent( QPaintEvent * );
+
+ //! Points to a currently edited data item.
+ //! It is cleared when the focus is moved to other
+ KexiFormDataItemInterface *editedItem;
+
+ class Private;
+ Private *d;
+
+ friend class KexiFormScrollView;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbimagebox.cpp b/kexi/plugins/forms/widgets/kexidbimagebox.cpp
new file mode 100644
index 00000000..82e70086
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbimagebox.cpp
@@ -0,0 +1,870 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 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 "kexidbimagebox.h"
+
+#include <qapplication.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qclipboard.h>
+#include <qtooltip.h>
+#include <qimage.h>
+#include <qbuffer.h>
+#include <qfiledialog.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kimageio.h>
+#include <kstandarddirs.h>
+#include <kstaticdeleter.h>
+#include <kimageeffect.h>
+#include <kstdaccel.h>
+#include <kmessagebox.h>
+#include <kguiitem.h>
+
+#include <widget/utils/kexidropdownbutton.h>
+#include <widget/utils/kexicontextmenuutils.h>
+#include <kexiutils/utils.h>
+#include <kexidb/field.h>
+#include <kexidb/utils.h>
+#include <kexidb/queryschema.h>
+#include <formeditor/widgetlibrary.h>
+
+#ifdef Q_WS_WIN
+#include <win32_utils.h>
+#include <krecentdirs.h>
+#endif
+
+#include "kexidbutils.h"
+#include "../kexiformpart.h"
+
+static KStaticDeleter<QPixmap> KexiDBImageBox_pmDeleter;
+static QPixmap* KexiDBImageBox_pm = 0;
+static KStaticDeleter<QPixmap> KexiDBImageBox_pmSmallDeleter;
+static QPixmap* KexiDBImageBox_pmSmall = 0;
+
+KexiDBImageBox::KexiDBImageBox( bool designMode, QWidget *parent, const char *name )
+ : KexiFrame( parent, name, Qt::WNoAutoErase )
+ , KexiFormDataItemInterface()
+ , m_alignment(Qt::AlignAuto|Qt::AlignTop)
+ , m_designMode(designMode)
+ , m_readOnly(false)
+ , m_scaledContents(false)
+ , m_keepAspectRatio(true)
+ , m_insideSetData(false)
+ , m_setFocusOnButtonAfterClosingPopup(false)
+ , m_lineWidthChanged(false)
+ , m_paintEventEnabled(true)
+ , m_dropDownButtonVisible(true)
+ , m_insideSetPalette(false)
+{
+ installEventFilter(this);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ //setup popup menu
+ m_popupMenu = new KexiImageContextMenu(this);
+ m_popupMenu->installEventFilter(this);
+
+ if (m_designMode) {
+ m_chooser = 0;
+ }
+ else {
+ m_chooser = new KexiDropDownButton(this);
+ m_chooser->setFocusPolicy(StrongFocus);
+ m_chooser->setPopup(m_popupMenu);
+ setFocusProxy(m_chooser);
+ m_chooser->installEventFilter(this);
+// m_chooser->setPalette(qApp->palette());
+// hlyr->addWidget(m_chooser);
+ }
+
+ setBackgroundMode(Qt::NoBackground);
+ setFrameShape(QFrame::Box);
+ setFrameShadow(QFrame::Plain);
+ setFrameColor(Qt::black);
+
+ m_paletteBackgroundColorChanged = false; //set this here, not before
+
+ connect(m_popupMenu, SIGNAL(updateActionsAvailabilityRequested(bool&, bool&)),
+ this, SLOT(slotUpdateActionsAvailabilityRequested(bool&, bool&)));
+ connect(m_popupMenu, SIGNAL(insertFromFileRequested(const KURL&)),
+ this, SLOT(handleInsertFromFileAction(const KURL&)));
+ connect(m_popupMenu, SIGNAL(saveAsRequested(const QString&)),
+ this, SLOT(handleSaveAsAction(const QString&)));
+ connect(m_popupMenu, SIGNAL(cutRequested()),
+ this, SLOT(handleCutAction()));
+ connect(m_popupMenu, SIGNAL(copyRequested()),
+ this, SLOT(handleCopyAction()));
+ connect(m_popupMenu, SIGNAL(pasteRequested()),
+ this, SLOT(handlePasteAction()));
+ connect(m_popupMenu, SIGNAL(clearRequested()),
+ this, SLOT(clear()));
+ connect(m_popupMenu, SIGNAL(showPropertiesRequested()),
+ this, SLOT(handleShowPropertiesAction()));
+
+// connect(m_popupMenu, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHidePopupMenu()));
+// if (m_chooser) {
+ //we couldn't use m_chooser->setPopup() because of drawing problems
+// connect(m_chooser, SIGNAL(pressed()), this, SLOT(slotChooserPressed()));
+// connect(m_chooser, SIGNAL(released()), this, SLOT(slotChooserReleased()));
+// connect(m_chooser, SIGNAL(toggled(bool)), this, SLOT(slotToggled(bool)));
+// }
+
+ setDataSource( QString::null ); //to initialize popup menu and actions availability
+}
+
+KexiDBImageBox::~KexiDBImageBox()
+{
+}
+
+KexiImageContextMenu* KexiDBImageBox::contextMenu() const
+{
+ return m_popupMenu;
+}
+
+QVariant KexiDBImageBox::value()
+{
+ if (dataSource().isEmpty()) {
+ //not db-aware
+ return QVariant();
+ }
+ //db-aware mode
+ return m_value; //todo
+ //return QVariant(); //todo
+}
+
+void KexiDBImageBox::setValueInternal( const QVariant& add, bool removeOld, bool loadPixmap )
+{
+ if (isReadOnly())
+ return;
+ m_popupMenu->hide();
+ if (removeOld)
+ m_value = add.toByteArray();
+ else //do not add "m_origValue" to "add" as this is QByteArray
+ m_value = m_origValue.toByteArray();
+ bool ok = !m_value.isEmpty();
+ if (ok) {
+ ///unused (m_valueMimeType is not available unless the px is inserted) QString type( KImageIO::typeForMime(m_valueMimeType) );
+ ///ok = KImageIO::canRead( type );
+ ok = loadPixmap ? m_pixmap.loadFromData(m_value) : true; //, type.latin1());
+ if (!ok) {
+ //! @todo inform about error?
+ }
+ }
+ if (!ok) {
+ m_valueMimeType = QString::null;
+ m_pixmap = QPixmap();
+ }
+ repaint();
+}
+
+void KexiDBImageBox::setInvalidState( const QString& displayText )
+{
+ Q_UNUSED( displayText );
+
+// m_pixmapLabel->setPixmap(QPixmap());
+ if (!dataSource().isEmpty()) {
+ m_value = QByteArray();
+ }
+// m_pixmap = QPixmap();
+// m_originalFileName = QString::null;
+
+//! @todo m_pixmapLabel->setText( displayText );
+
+ if (m_chooser)
+ m_chooser->hide();
+ setReadOnly(true);
+}
+
+bool KexiDBImageBox::valueIsNull()
+{
+ return m_value.isEmpty();
+// return !m_pixmapLabel->pixmap() || m_pixmapLabel->pixmap()->isNull();
+}
+
+bool KexiDBImageBox::valueIsEmpty()
+{
+ return false;
+}
+
+bool KexiDBImageBox::isReadOnly() const
+{
+ return m_readOnly;
+}
+
+void KexiDBImageBox::setReadOnly(bool set)
+{
+ m_readOnly = set;
+}
+
+QPixmap KexiDBImageBox::pixmap() const
+{
+ if (dataSource().isEmpty()) {
+ //not db-aware
+ return m_data.pixmap();
+ }
+ //db-aware mode
+ return m_pixmap;
+}
+
+uint KexiDBImageBox::pixmapId() const
+{
+ if (dataSource().isEmpty()) {// && !m_data.stored()) {
+ //not db-aware
+ return m_data.id();
+ }
+ return 0;
+}
+
+void KexiDBImageBox::setPixmapId(uint id)
+{
+ if (m_insideSetData) //avoid recursion
+ return;
+ setData(KexiBLOBBuffer::self()->objectForId( id, /*unstored*/false ));
+ repaint();
+}
+
+uint KexiDBImageBox::storedPixmapId() const
+{
+ if (dataSource().isEmpty() && m_data.stored()) {
+ //not db-aware
+ return m_data.id();
+ }
+ return 0;
+}
+
+void KexiDBImageBox::setStoredPixmapId(uint id)
+{
+ setData(KexiBLOBBuffer::self()->objectForId( id, /*stored*/true ));
+ repaint();
+}
+
+bool KexiDBImageBox::hasScaledContents() const
+{
+ return m_scaledContents;
+// return m_pixmapLabel->hasScaledContents();
+}
+
+/*void KexiDBImageBox::setPixmap(const QByteArray& pixmap)
+{
+ setValueInternal(pixmap, true);
+// setBackgroundMode(pixmap.isNull() ? Qt::NoBackground : Qt::PaletteBackground);
+}*/
+
+void KexiDBImageBox::setScaledContents(bool set)
+{
+//todo m_pixmapLabel->setScaledContents(set);
+ m_scaledContents = set;
+ repaint();
+}
+
+void KexiDBImageBox::setKeepAspectRatio(bool set)
+{
+ m_keepAspectRatio = set;
+ if (m_scaledContents)
+ repaint();
+}
+
+QWidget* KexiDBImageBox::widget()
+{
+ //! @todo
+// return m_pixmapLabel;
+ return this;
+}
+
+bool KexiDBImageBox::cursorAtStart()
+{
+ return true;
+}
+
+bool KexiDBImageBox::cursorAtEnd()
+{
+ return true;
+}
+
+QByteArray KexiDBImageBox::data() const
+{
+ if (dataSource().isEmpty()) {
+ //static mode
+ return m_data.data();
+ }
+ else {
+ //db-aware mode
+ return m_value;
+ }
+}
+
+void KexiDBImageBox::insertFromFile()
+{
+ m_popupMenu->insertFromFile();
+}
+
+void KexiDBImageBox::handleInsertFromFileAction(const KURL& url)
+{
+ if (!dataSource().isEmpty() && isReadOnly())
+ return;
+
+ if (dataSource().isEmpty()) {
+ //static mode
+ KexiBLOBBuffer::Handle h = KexiBLOBBuffer::self()->insertPixmap( url );
+ if (!h)
+ return;
+ setData(h);
+ repaint();
+ }
+ else {
+ //db-aware
+ 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;
+ }
+ QByteArray ba = f.readAll();
+ if (f.status()!=IO_Ok) {
+ //! @todo err msg
+ f.close();
+ return;
+ }
+ m_valueMimeType = KImageIO::mimeType( fileName );
+ setValueInternal( ba, true );
+ }
+
+//! @todo emit signal for setting "dirty" flag within the design
+ if (!dataSource().isEmpty()) {
+ signalValueChanged();
+ }
+}
+
+void KexiDBImageBox::handleAboutToSaveAsAction(QString& origFilename, QString& fileExtension, bool& dataIsEmpty)
+{
+ if (data().isEmpty()) {
+ kdWarning() << "KexiDBImageBox::handleAboutToSaveAs(): no pixmap!" << endl;
+ dataIsEmpty = false;
+ return;
+ }
+ if (dataSource().isEmpty()) { //for static images filename and mimetype can be available
+ origFilename = m_data.originalFileName();
+ if (!origFilename.isEmpty())
+ origFilename = QString("/") + origFilename;
+ if (!m_data.mimeType().isEmpty())
+ fileExtension = KImageIO::typeForMime(m_data.mimeType()).lower();
+ }
+}
+
+void KexiDBImageBox::handleSaveAsAction(const QString& fileName)
+{
+ QFile f(fileName);
+ if (!f.open(IO_WriteOnly)) {
+ //! @todo err msg
+ return;
+ }
+ f.writeBlock( data() );
+ if (f.status()!=IO_Ok) {
+ //! @todo err msg
+ f.close();
+ return;
+ }
+ f.close();
+}
+
+void KexiDBImageBox::handleCutAction()
+{
+ if (!dataSource().isEmpty() && isReadOnly())
+ return;
+ handleCopyAction();
+ clear();
+}
+
+void KexiDBImageBox::handleCopyAction()
+{
+ qApp->clipboard()->setPixmap(pixmap(), QClipboard::Clipboard);
+}
+
+void KexiDBImageBox::handlePasteAction()
+{
+ if (isReadOnly() || (!m_designMode && !hasFocus()))
+ return;
+ QPixmap pm( qApp->clipboard()->pixmap(QClipboard::Clipboard) );
+// if (!pm.isNull())
+// setValueInternal(pm, true);
+ if (dataSource().isEmpty()) {
+ //static mode
+ setData(KexiBLOBBuffer::self()->insertPixmap( pm ));
+ }
+ else {
+ //db-aware mode
+ m_pixmap = pm;
+ QByteArray ba;
+ QBuffer buffer( ba );
+ buffer.open( IO_WriteOnly );
+ if (m_pixmap.save( &buffer, "PNG" )) {// write pixmap into ba in PNG format
+ setValueInternal( ba, true, false/* !loadPixmap */ );
+ }
+ else {
+ setValueInternal( QByteArray(), true );
+ }
+ }
+
+ repaint();
+ if (!dataSource().isEmpty()) {
+// emit pixmapChanged();
+ signalValueChanged();
+ }
+}
+
+void KexiDBImageBox::clear()
+{
+ if (dataSource().isEmpty()) {
+ //static mode
+ setData(KexiBLOBBuffer::Handle());
+ }
+ else {
+ if (isReadOnly())
+ return;
+ //db-aware mode
+ setValueInternal(QByteArray(), true);
+ //m_pixmap = QPixmap();
+ }
+
+// m_originalFileName = QString::null;
+
+ //! @todo emit signal for setting "dirty" flag within the design
+
+// m_pixmap = QPixmap(); //will be loaded on demand
+ repaint();
+ if (!dataSource().isEmpty()) {
+// emit pixmapChanged();//valueChanged(data());
+ signalValueChanged();
+ }
+}
+
+void KexiDBImageBox::handleShowPropertiesAction()
+{
+ //! @todo
+}
+
+void KexiDBImageBox::slotUpdateActionsAvailabilityRequested(bool& valueIsNull, bool& valueIsReadOnly)
+{
+ valueIsNull = !(
+ (dataSource().isEmpty() && !pixmap().isNull()) /*static pixmap available*/
+ || (!dataSource().isEmpty() && !this->valueIsNull()) /*db-aware pixmap available*/
+ );
+ // read-only if static pixmap or db-aware pixmap for read-only widget:
+ valueIsReadOnly = !m_designMode && dataSource().isEmpty() || !dataSource().isEmpty() && isReadOnly()
+ || m_designMode && !dataSource().isEmpty();
+}
+
+/*
+void KexiDBImageBox::slotAboutToHidePopupMenu()
+{
+// kexipluginsdbg << "##### slotAboutToHidePopupMenu() " << endl;
+ m_clickTimer.start(50, true);
+ if (m_chooser && m_chooser->isOn()) {
+ m_chooser->toggle();
+ if (m_setFocusOnButtonAfterClosingPopup) {
+ m_setFocusOnButtonAfterClosingPopup = false;
+ m_chooser->setFocus();
+ }
+ }
+}*/
+
+void KexiDBImageBox::contextMenuEvent( QContextMenuEvent * e )
+{
+ if (popupMenuAvailable())
+ m_popupMenu->exec( e->globalPos(), -1 );
+}
+
+/*void KexiDBImageBox::slotChooserPressed()
+{
+// if (!m_clickTimer.isActive())
+// return;
+// m_chooser->setDown( false );
+}
+
+void KexiDBImageBox::slotChooserReleased()
+{
+}
+
+void KexiDBImageBox::slotToggled(bool on)
+{
+ return;
+
+// kexipluginsdbg << "##### slotToggled() " << on << endl;
+ if (m_clickTimer.isActive() || !on) {
+ m_chooser->disableMousePress = true;
+ return;
+ }
+ m_chooser->disableMousePress = false;
+ QRect screen = qApp->desktop()->availableGeometry( m_chooser );
+ QPoint p;
+ if ( QApplication::reverseLayout() ) {
+ if ( (mapToGlobal( m_chooser->rect().bottomLeft() ).y() + m_popupMenu->sizeHint().height()) <= screen.height() )
+ p = m_chooser->mapToGlobal( m_chooser->rect().bottomRight() );
+ else
+ p = m_chooser->mapToGlobal( m_chooser->rect().topRight() - QPoint( 0, m_popupMenu->sizeHint().height() ) );
+ p.rx() -= m_popupMenu->sizeHint().width();
+ }
+ else {
+ if ( (m_chooser->mapToGlobal( m_chooser->rect().bottomLeft() ).y() + m_popupMenu->sizeHint().height()) <= screen.height() )
+ p = m_chooser->mapToGlobal( m_chooser->rect().bottomLeft() );
+ else
+ p = m_chooser->mapToGlobal( m_chooser->rect().topLeft() - QPoint( 0, m_popupMenu->sizeHint().height() ) );
+ }
+ if (!m_popupMenu->isVisible() && on) {
+ m_popupMenu->exec( p, -1 );
+ m_popupMenu->setFocus();
+ }
+ //m_chooser->setDown( false );
+}*/
+
+void KexiDBImageBox::updateActionStrings()
+{
+ if (!m_popupMenu)
+ return;
+ if (m_designMode) {
+/* QString titleString( i18n("Image Box") );
+ if (!dataSource().isEmpty())
+ titleString.prepend(dataSource() + " : ");
+ m_popupMenu->changeTitle(m_popupMenu->idAt(0), m_popupMenu->titlePixmap(m_popupMenu->idAt(0)), titleString);*/
+ }
+ else {
+ //update title in data view mode, based on the data source
+ if (columnInfo()) {
+ KexiImageContextMenu::updateTitle( m_popupMenu, columnInfo()->captionOrAliasOrName(),
+ KexiFormPart::library()->iconName(className()) );
+ }
+ }
+
+ if (m_chooser) {
+ if (popupMenuAvailable() && dataSource().isEmpty()) { //this may work in the future (see @todo below)
+ QToolTip::add(m_chooser, i18n("Click to show actions for this image box"));
+ } else {
+ QString beautifiedImageBoxName;
+ if (m_designMode) {
+ beautifiedImageBoxName = dataSource();
+ }
+ else {
+ beautifiedImageBoxName = columnInfo() ? columnInfo()->captionOrAliasOrName() : QString::null;
+ /*! @todo look at makeFirstCharacterUpperCaseInCaptions setting [bool]
+ (see doc/dev/settings.txt) */
+ beautifiedImageBoxName = beautifiedImageBoxName[0].upper() + beautifiedImageBoxName.mid(1);
+ }
+ QToolTip::add(m_chooser, i18n("Click to show actions for \"%1\" image box").arg(beautifiedImageBoxName));
+ }
+ }
+}
+
+bool KexiDBImageBox::popupMenuAvailable()
+{
+/*! @todo add kexi-global setting which anyway, allows to show this button
+ (read-only actions like copy/save as/print can be available) */
+ //chooser button can be only visible when data source is specified
+ return !dataSource().isEmpty();
+}
+
+void KexiDBImageBox::setDataSource( const QString &ds )
+{
+ KexiFormDataItemInterface::setDataSource( ds );
+ setData(KexiBLOBBuffer::Handle());
+ updateActionStrings();
+ KexiFrame::setFocusPolicy( focusPolicy() ); //set modified policy
+
+ if (m_chooser) {
+ m_chooser->setEnabled(popupMenuAvailable());
+ if (m_dropDownButtonVisible && popupMenuAvailable()) {
+ m_chooser->show();
+ }
+ else {
+ m_chooser->hide();
+ }
+ }
+
+ // update some properties s not changed by user
+//! @todo get default line width from global style settings
+ if (!m_lineWidthChanged) {
+ KexiFrame::setLineWidth( ds.isEmpty() ? 0 : 1 );
+ }
+ if (!m_paletteBackgroundColorChanged && parentWidget()) {
+ KexiFrame::setPaletteBackgroundColor(
+ dataSource().isEmpty() ? parentWidget()->paletteBackgroundColor() : palette().active().base() );
+ }
+}
+
+QSize KexiDBImageBox::sizeHint() const
+{
+ if (pixmap().isNull())
+ return QSize(80, 80);
+ return pixmap().size();
+}
+
+int KexiDBImageBox::realLineWidth() const
+{
+ if (frameShape()==QFrame::Box && (frameShadow()==QFrame::Sunken || frameShadow()==QFrame::Raised))
+ return 2 * lineWidth();
+ else
+ return lineWidth();
+}
+
+void KexiDBImageBox::paintEvent( QPaintEvent *pe )
+{
+ if (!m_paintEventEnabled)
+ return;
+ QPainter p(this);
+ p.setClipRect(pe->rect());
+ const int m = realLineWidth() + margin();
+ QColor bg(eraseColor());
+ if (m_designMode && pixmap().isNull()) {
+ QPixmap pm(size()-QSize(m, m));
+ QPainter p2;
+ p2.begin(&pm, this);
+ p2.fillRect(0,0,width(),height(), bg);
+
+ updatePixmap();
+ QPixmap *imagBoxPm;
+ const bool tooLarge = (height()-m-m) <= KexiDBImageBox_pm->height();
+ if (tooLarge || (width()-m-m) <= KexiDBImageBox_pm->width())
+ imagBoxPm = KexiDBImageBox_pmSmall;
+ else
+ imagBoxPm = KexiDBImageBox_pm;
+ QImage img(imagBoxPm->convertToImage());
+ img = KImageEffect::flatten(img, bg.dark(150),
+ qGray( bg.rgb() ) <= 20 ? QColor(Qt::gray).dark(150) : bg.light(105));
+
+ QPixmap converted;
+ converted.convertFromImage(img);
+// if (tooLarge)
+// p2.drawPixmap(2, 2, converted);
+// else
+ p2.drawPixmap(2, height()-m-m-imagBoxPm->height()-2, converted);
+ QFont f(qApp->font());
+ p2.setFont(f);
+ p2.setPen( KexiUtils::contrastColor( bg ) );
+ p2.drawText(pm.rect(), Qt::AlignCenter,
+ dataSource().isEmpty()
+ ? QString::fromLatin1(name())+"\n"+i18n("Unbound Image Box", "(unbound)") //i18n("No Image")
+ : dataSource());
+ p2.end();
+ bitBlt(this, m, m, &pm);
+ }
+ else {
+ QSize internalSize(size());
+ if (m_chooser && m_dropDownButtonVisible && !dataSource().isEmpty())
+ internalSize.setWidth( internalSize.width() - m_chooser->width() );
+
+ //clearing needed here because we may need to draw a pixmap with transparency
+ p.fillRect(0,0,width(),height(), bg);
+
+ KexiUtils::drawPixmap( p, m, QRect(QPoint(0,0), internalSize), pixmap(), m_alignment,
+ m_scaledContents, m_keepAspectRatio );
+ }
+ KexiFrame::drawFrame( &p );
+
+ // if the widget is focused, draw focus indicator rect _if_ there is no chooser button
+ if (!m_designMode && !dataSource().isEmpty() && hasFocus() && (!m_chooser || !m_chooser->isVisible())) {
+ style().drawPrimitive(
+ QStyle::PE_FocusRect, &p, style().subRect(QStyle::SR_PushButtonContents, this),
+ palette().active() );
+ }
+}
+
+/* virtual void KexiDBImageBox::paletteChange ( const QPalette & oldPalette )
+{
+ QFrame::paletteChange(oldPalette);
+ if (oldPalette.active().background()!=palette().active().background()) {
+ delete KexiDBImageBox_pm;
+ KexiDBImageBox_pm = 0;
+ repaint();
+ }
+}*/
+
+void KexiDBImageBox::updatePixmap()
+{
+ if (! (m_designMode && pixmap().isNull()) )
+ return;
+
+ if (!KexiDBImageBox_pm) {
+ QString fname( locate("data", QString("kexi/pics/imagebox.png")) );
+ KexiDBImageBox_pmDeleter.setObject( KexiDBImageBox_pm, new QPixmap(fname, "PNG") );
+ QImage img(KexiDBImageBox_pm->convertToImage());
+ KexiDBImageBox_pmSmallDeleter.setObject( KexiDBImageBox_pmSmall,
+ new QPixmap( img.smoothScale(img.width()/2, img.height()/2, QImage::ScaleMin) ) );
+ }
+}
+
+void KexiDBImageBox::setAlignment(int alignment)
+{
+ m_alignment = alignment;
+ if (!m_scaledContents || m_keepAspectRatio)
+ repaint();
+}
+
+void KexiDBImageBox::setData(const KexiBLOBBuffer::Handle& handle)
+{
+ if (m_insideSetData) //avoid recursion
+ return;
+ m_insideSetData = true;
+ m_data = handle;
+ emit idChanged(handle.id());
+ m_insideSetData = false;
+ update();
+}
+
+void KexiDBImageBox::resizeEvent( QResizeEvent * e )
+{
+ KexiFrame::resizeEvent(e);
+ if (m_chooser) {
+ QSize s( m_chooser->sizeHint() );
+ QSize margin( realLineWidth(), realLineWidth() );
+ s.setHeight( height() - 2*margin.height() );
+ s = s.boundedTo( size()-2*margin );
+ m_chooser->resize( s );
+ m_chooser->move( QRect(QPoint(0,0), e->size() - m_chooser->size() - margin + QSize(1,1)).bottomRight() );
+ }
+}
+
+/*
+bool KexiDBImageBox::setProperty( const char * name, const QVariant & value )
+{
+ const bool ret = QLabel::setProperty(name, value);
+ if (p_shadowEnabled) {
+ if (0==qstrcmp("indent", name) || 0==qstrcmp("font", name) || 0==qstrcmp("margin", name)
+ || 0==qstrcmp("frameShadow", name) || 0==qstrcmp("frameShape", name)
+ || 0==qstrcmp("frameStyle", name) || 0==qstrcmp("midLineWidth", name)
+ || 0==qstrcmp("lineWidth", name)) {
+ p_privateLabel->setProperty(name, value);
+ updatePixmap();
+ }
+ }
+ return ret;
+}
+*/
+
+void KexiDBImageBox::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ KexiFormDataItemInterface::setColumnInfo(cinfo);
+ //updating strings and title is needed
+ updateActionStrings();
+}
+
+bool KexiDBImageBox::keyPressed(QKeyEvent *ke)
+{
+ // Esc key should close the popup
+ if (ke->state() == Qt::NoButton && ke->key() == Qt::Key_Escape) {
+ if (m_popupMenu->isVisible()) {
+ m_setFocusOnButtonAfterClosingPopup = true;
+ return true;
+ }
+ }
+// else if (ke->state() == Qt::ControlButton && KStdAccel::shortcut(KStdAccel::Copy).keyCodeQt() == (ke->key()|Qt::CTRL)) {
+// }
+ return false;
+}
+
+void KexiDBImageBox::setLineWidth( int width )
+{
+ m_lineWidthChanged = true;
+ KexiFrame::setLineWidth(width);
+}
+
+void KexiDBImageBox::setPalette( const QPalette &pal )
+{
+ KexiFrame::setPalette(pal);
+ if (m_insideSetPalette)
+ return;
+ m_insideSetPalette = true;
+ setPaletteBackgroundColor(pal.active().base());
+ setPaletteForegroundColor(pal.active().foreground());
+ m_insideSetPalette = false;
+}
+
+void KexiDBImageBox::setPaletteBackgroundColor( const QColor & color )
+{
+ kexipluginsdbg << "KexiDBImageBox::setPaletteBackgroundColor(): " << color.name() << endl;
+ m_paletteBackgroundColorChanged = true;
+ KexiFrame::setPaletteBackgroundColor(color);
+ if (m_chooser)
+ m_chooser->setPalette( qApp->palette() );
+}
+
+bool KexiDBImageBox::dropDownButtonVisible() const
+{
+ return m_dropDownButtonVisible;
+}
+
+void KexiDBImageBox::setDropDownButtonVisible( bool set )
+{
+//! @todo use global default setting for this property
+ if (m_dropDownButtonVisible == set)
+ return;
+ m_dropDownButtonVisible = set;
+ if (m_chooser) {
+ if (m_dropDownButtonVisible)
+ m_chooser->show();
+ else
+ m_chooser->hide();
+ }
+}
+
+bool KexiDBImageBox::subwidgetStretchRequired(KexiDBAutoField* autoField) const
+{
+ Q_UNUSED(autoField);
+ return true;
+}
+
+bool KexiDBImageBox::eventFilter( QObject * watched, QEvent * e )
+{
+ if (watched==this || watched==m_chooser) { //we're watching chooser as well because it's a focus proxy even if invisible
+ if (e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut || e->type()==QEvent::MouseButtonPress) {
+ update(); //to repaint focus rect
+ }
+ }
+ // hide popup menu as soon as it loses focus
+ if (watched==m_popupMenu && e->type()==QEvent::FocusOut) {
+ m_popupMenu->hide();
+ }
+ return KexiFrame::eventFilter(watched, e);
+}
+
+QWidget::FocusPolicy KexiDBImageBox::focusPolicy() const
+{
+ if (dataSource().isEmpty())
+ return NoFocus;
+ return m_focusPolicyInternal;
+}
+
+QWidget::FocusPolicy KexiDBImageBox::focusPolicyInternal() const
+{
+ return m_focusPolicyInternal;
+}
+
+void KexiDBImageBox::setFocusPolicy( FocusPolicy policy )
+{
+ m_focusPolicyInternal = policy;
+ KexiFrame::setFocusPolicy( focusPolicy() ); //set modified policy
+}
+
+#include "kexidbimagebox.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbimagebox.h b/kexi/plugins/forms/widgets/kexidbimagebox.h
new file mode 100644
index 00000000..3ad2f710
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbimagebox.h
@@ -0,0 +1,275 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 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 KexiDBImageBox_H
+#define KexiDBImageBox_H
+
+#include "kexiformdataiteminterface.h"
+#include "kexiframe.h"
+#include "kexidbutils.h"
+#include <kexiblobbuffer.h>
+
+class KexiDropDownButton;
+class KexiImageContextMenu;
+
+//! @short A data-aware, editable image box.
+/*! Can also act as a normal static image box.
+*/
+class KEXIFORMUTILS_EXPORT KexiDBImageBox :
+ public KexiFrame,
+ public KexiFormDataItemInterface,
+ public KexiSubwidgetInterface
+{
+ Q_OBJECT
+ Q_PROPERTY( QString dataSource READ dataSource WRITE setDataSource )
+ Q_PROPERTY( QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType )
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
+// Q_PROPERTY( QPixmap pixmap READ pixmap WRITE setPixmap )
+// Q_PROPERTY( QByteArray pixmapData READ pixmapData WRITE setPixmapData )
+ Q_PROPERTY( uint pixmapId READ pixmapId WRITE setPixmapId DESIGNABLE true STORED false )
+ Q_PROPERTY( uint storedPixmapId READ storedPixmapId WRITE setStoredPixmapId DESIGNABLE false STORED true )
+ Q_PROPERTY( bool scaledContents READ hasScaledContents WRITE setScaledContents )
+ Q_PROPERTY( bool keepAspectRatio READ keepAspectRatio WRITE setKeepAspectRatio )
+ Q_PROPERTY( Alignment alignment READ alignment WRITE setAlignment )
+// Q_PROPERTY( QString originalFileName READ originalFileName WRITE setOriginalFileName DESIGNABLE false )
+// Q_OVERRIDE( FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy )
+ Q_PROPERTY( bool dropDownButtonVisible READ dropDownButtonVisible WRITE setDropDownButtonVisible )
+ Q_OVERRIDE( int lineWidth READ lineWidth WRITE setLineWidth )
+ Q_OVERRIDE( FocusPolicy focusPolicy READ focusPolicyInternal WRITE setFocusPolicy )
+
+ public:
+ KexiDBImageBox( bool designMode, QWidget *parent, const char *name = 0 );
+ virtual ~KexiDBImageBox();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+
+ virtual QVariant value(); // { return m_value.data(); }
+
+// QByteArray pixmapData() const { return m_value.data(); }
+
+ QPixmap pixmap() const;
+
+ uint pixmapId() const;
+
+ uint storedPixmapId() const;
+//
+ virtual void setInvalidState( const QString& displayText );
+
+ virtual bool valueIsNull();
+
+ virtual bool valueIsEmpty();
+
+ virtual QWidget* widget();
+
+ //! always true
+ virtual bool cursorAtStart();
+
+ //! always true
+ virtual bool cursorAtEnd();
+
+// //! used to catch setIndent(), etc.
+// virtual bool setProperty ( const char * name, const QVariant & value );
+
+ virtual bool isReadOnly() const;
+
+ bool hasScaledContents() const;
+
+// bool designMode() const { return m_designMode; }
+
+ int alignment() const { return m_alignment; }
+
+ bool keepAspectRatio() const { return m_keepAspectRatio; }
+
+ virtual QSize sizeHint() const;
+
+ KexiImageContextMenu *contextMenu() const;
+
+ /*! \return original file name of image loaded from a file.
+ This can be later reused for displaying the image within a collection (to be implemented)
+ or on saving the image data back to file. */
+//todo QString originalFileName() const { return m_value.originalFileName(); }
+
+ //! Reimplemented to override behaviour of "lineWidth" property.
+ virtual void setLineWidth( int width );
+
+ //! Reimplemented to override behaviour of "paletteBackgroundColor"
+ //! and "paletteForegroundColor" properties.
+ virtual void setPalette( const QPalette &pal );
+
+ //! Reimplemented to override behaviour of "paletteBackgroundColor" property.
+ virtual void setPaletteBackgroundColor( const QColor & color );
+
+ //! \return true id drop down button should be visible (the default).
+ bool dropDownButtonVisible() const;
+
+ //! For overridden property
+ int lineWidth() const { return KexiFrame::lineWidth(); }
+
+ /*! Overriden to change the policy behaviour a bit:
+ NoFocus is returned regardless the real focus flag
+ if the data source is empty (see dataSource()). */
+ FocusPolicy focusPolicy() const;
+
+ //! \return the internal focus policy value, i.e. the one unrelated to data source presence.
+ FocusPolicy focusPolicyInternal() const;
+
+ /*! Sets the internal focus policy value.
+ "Internal" means that if there is no data source set, real policy becomes NoFocus. */
+ virtual void setFocusPolicy( FocusPolicy policy );
+
+ public slots:
+ void setPixmapId(uint id);
+
+ void setStoredPixmapId(uint id);
+
+ //! Sets the datasource to \a ds
+ virtual void setDataSource( const QString &ds );
+
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+
+ virtual void setReadOnly(bool set);
+
+ //! Sets \a pixmapData data for this widget. If the widget has data source set,
+ //! the pixmap will be also placed inside of the buffer and saved later.
+//todo void setPixmapData(const QByteArray& pixmapData) { m_value.setData(pixmapData); }
+
+ /*! Sets original file name of image loaded from a file.
+ @see originalFileName() */
+//todo void setOriginalFileName(const QString& name) { m_value.setOriginalFileName(name); }
+
+ void setScaledContents(bool set);
+
+ void setAlignment(int alignment);
+
+ void setKeepAspectRatio(bool set);
+
+// void updateActionsAvailability();
+
+ //! @internal
+// void slotToggled( bool on );
+
+ //! \return sets dropDownButtonVisible property. @see dropDownButtonVisible()
+ void setDropDownButtonVisible( bool set );
+
+ //! Forces execution of "insert from file" action
+ void insertFromFile();
+
+ signals:
+ //! Used for db-aware mode. Emitted when value has been changed.
+ //! Actual value can be obtained using value().
+// virtual void pixmapChanged();
+// virtual void valueChanged(const QByteArray& data);
+
+ void idChanged(long id);
+
+ protected slots:
+ void slotUpdateActionsAvailabilityRequested(bool& valueIsNull, bool& valueIsReadOnly);
+
+ void handleInsertFromFileAction(const KURL& url);
+ void handleAboutToSaveAsAction(QString& origFilename, QString& fileExtension, bool& dataIsEmpty);
+ void handleSaveAsAction(const QString& fileName);
+ void handleCutAction();
+ void handleCopyAction();
+ void handlePasteAction();
+ virtual void clear();
+ void handleShowPropertiesAction();
+
+ protected:
+ //! \return data depending on the current mode (db-aware or static)
+ QByteArray data() const;
+
+ virtual void contextMenuEvent ( QContextMenuEvent * e );
+// virtual void mousePressEvent( QMouseEvent *e );
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+ virtual void paintEvent( QPaintEvent* );
+ virtual void resizeEvent( QResizeEvent* e );
+ virtual bool eventFilter( QObject * watched, QEvent * e );
+
+ //! Sets value \a value for a widget.
+ virtual void setValueInternal( const QVariant& add, bool removeOld ) {
+ setValueInternal( add, removeOld, true /*loadPixmap*/ );
+ }
+
+ //! @internal, added \a loadPixmap option used by paste().
+ void setValueInternal( const QVariant& add, bool removeOld, bool loadPixmap );
+
+ //! Updates i18n'd action strings after datasource change
+ void updateActionStrings();
+ void updatePixmap();
+
+ //! @internal
+ void setData(const KexiBLOBBuffer::Handle& handle);
+
+ bool popupMenuAvailable();
+
+ /*! Called by top-level form on key press event.
+ Used for Key_Escape to if the popup is visible,
+ so the key press won't be consumed to perform "cancel editing". */
+ virtual bool keyPressed(QKeyEvent *ke);
+
+ //! \return real line width, i.e. for Boxed sunken or Boxed raised
+ //! frames returns doubled width value.
+ int realLineWidth() const;
+
+ //! Implemented for KexiSubwidgetInterface
+ virtual bool subwidgetStretchRequired(KexiDBAutoField* autoField) const;
+
+// virtual void drawContents ( QPainter *p );
+
+// virtual void fontChange( const QFont& font );
+// virtual void styleChange( QStyle& style );
+// virtual void enabledChange( bool enabled );
+
+// virtual void paletteChange( const QPalette& pal );
+// virtual void frameChanged();
+// virtual void showEvent( QShowEvent* e );
+
+// void updatePixmapLater();
+// class ImageLabel;
+// ImageLabel *m_pixmapLabel;
+ QPixmap m_pixmap;
+ QByteArray m_value; //!< for db-aware mode
+ QString m_valueMimeType; //!< for db-aware mode
+// PixmapData m_value;
+ KexiBLOBBuffer::Handle m_data;
+// QString m_originalFileName;
+ KexiDropDownButton *m_chooser;
+ KexiImageContextMenu *m_popupMenu;
+//moved KActionCollection m_actionCollection;
+//moved KAction *m_insertFromFileAction, *m_saveAsAction, *m_cutAction, *m_copyAction, *m_pasteAction,
+// *m_deleteAction, *m_propertiesAction;
+// QTimer m_clickTimer;
+ int m_alignment;
+ FocusPolicy m_focusPolicyInternal; //!< Used for focusPolicyInternal()
+ bool m_designMode : 1;
+ bool m_readOnly : 1;
+ bool m_scaledContents : 1;
+ bool m_keepAspectRatio : 1;
+ bool m_insideSetData : 1;
+ bool m_setFocusOnButtonAfterClosingPopup : 1;
+ bool m_lineWidthChanged : 1;
+ bool m_paletteBackgroundColorChanged : 1;
+ bool m_paintEventEnabled : 1; //!< used to disable paintEvent()
+ bool m_dropDownButtonVisible : 1;
+ bool m_insideSetPalette : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbintspinbox.cpp b/kexi/plugins/forms/widgets/kexidbintspinbox.cpp
new file mode 100644
index 00000000..ac923347
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbintspinbox.cpp
@@ -0,0 +1,114 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbintspinbox.h"
+
+#include <qlineedit.h>
+#include <knumvalidator.h>
+
+KexiDBIntSpinBox::KexiDBIntSpinBox(QWidget *parent, const char *name)
+ : KIntSpinBox(parent, name) , KexiFormDataItemInterface()
+{
+ connect(this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged()));
+}
+
+KexiDBIntSpinBox::~KexiDBIntSpinBox()
+{
+}
+
+void KexiDBIntSpinBox::setInvalidState( const QString& displayText )
+{
+ m_invalidState = true;
+ setEnabled(false);
+ setReadOnly(true);
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+ setSpecialValueText(displayText);
+ KIntSpinBox::setValue(minValue());
+}
+
+void
+KexiDBIntSpinBox::setEnabled(bool enabled)
+{
+ // prevent the user from reenabling the widget when it is in invalid state
+ if(enabled && m_invalidState)
+ return;
+ KIntSpinBox::setEnabled(enabled);
+}
+
+void KexiDBIntSpinBox::setValueInternal(const QVariant&, bool)
+{
+ KIntSpinBox::setValue(m_origValue.toInt());
+}
+
+QVariant
+KexiDBIntSpinBox::value()
+{
+ return KIntSpinBox::value();
+}
+
+void KexiDBIntSpinBox::slotValueChanged()
+{
+ signalValueChanged();
+}
+
+bool KexiDBIntSpinBox::valueIsNull()
+{
+ return cleanText().isEmpty();
+}
+
+bool KexiDBIntSpinBox::valueIsEmpty()
+{
+ return false;
+}
+
+bool KexiDBIntSpinBox::isReadOnly() const
+{
+ return editor()->isReadOnly();
+}
+
+void KexiDBIntSpinBox::setReadOnly(bool set)
+{
+ editor()->setReadOnly(set);
+}
+
+QWidget*
+KexiDBIntSpinBox::widget()
+{
+ return this;
+}
+
+bool KexiDBIntSpinBox::cursorAtStart()
+{
+ return false; //! \todo ?
+}
+
+bool KexiDBIntSpinBox::cursorAtEnd()
+{
+ return false; //! \todo ?
+}
+
+void KexiDBIntSpinBox::clear()
+{
+ KIntSpinBox::setValue(minValue()); //! \todo ?
+}
+
+#include "kexidbintspinbox.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbintspinbox.h b/kexi/plugins/forms/widgets/kexidbintspinbox.h
new file mode 100644
index 00000000..cddc614e
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbintspinbox.h
@@ -0,0 +1,80 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBIntSpinBox_H
+#define KexiDBIntSpinBox_H
+
+#include "kexiformdataiteminterface.h"
+#include <qwidget.h>
+#include <knuminput.h>
+
+//! @short A db-aware int spin box
+class KEXIFORMUTILS_EXPORT KexiDBIntSpinBox : public KIntSpinBox, public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true )
+
+ public:
+ KexiDBIntSpinBox(QWidget *parent, const char *name=0);
+ virtual ~KexiDBIntSpinBox();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setEnabled(bool enabled);
+
+ public slots:
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ void slotValueChanged();
+ virtual void setReadOnly(bool set);
+
+ protected:
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+
+ private:
+ bool m_invalidState : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidblabel.cpp b/kexi/plugins/forms/widgets/kexidblabel.cpp
new file mode 100644
index 00000000..e30cc19e
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidblabel.cpp
@@ -0,0 +1,650 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Christian Nitschkowski <segfault_ii@web.de>
+ Copyright (C) 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 "kexidblabel.h"
+
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qdrawutil.h>
+#include <qapplication.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kimageeffect.h>
+
+#include <kexidb/field.h>
+#include <kexiutils/utils.h>
+
+#define SHADOW_OFFSET_X 3
+#define SHADOW_OFFSET_Y 3
+#define SHADOW_FACTOR 16.0
+#define SHADOW_OPACITY 50.0
+#define SHADOW_AXIS_FACTOR 2.0
+#define SHADOW_DIAGONAL_FACTOR 1.0
+#define SHADOW_THICKNESS 1
+
+//! @internal
+class KexiDBInternalLabel : public QLabel {
+ friend class KexiDBLabel;
+ public:
+ KexiDBInternalLabel( KexiDBLabel* );
+ virtual ~KexiDBInternalLabel();
+
+ protected:
+ void updateFrame();
+
+ QImage makeShadow( const QImage& textImage, const QColor &bgColor, const QRect& boundingRect );
+ QRect getBounding( const QImage &image, const QRect& startRect );
+// double defaultDecay( QImage& source, int i, int j );
+ KPixmap getShadowPixmap();
+
+ QRect m_shadowRect;
+ KexiDBLabel *m_parentLabel;
+};
+
+KexiDBInternalLabel::KexiDBInternalLabel( KexiDBLabel* parent )
+ : QLabel( parent )
+ , m_parentLabel(parent)
+{
+ int a = alignment() | Qt::WordBreak;
+ a &= (0xffffff ^ Qt::AlignVertical_Mask);
+ a |= Qt::AlignTop;
+ setAlignment( a );
+ updateFrame();
+}
+
+void KexiDBInternalLabel::updateFrame()
+{
+ setIndent(m_parentLabel->indent());
+ setMargin(m_parentLabel->margin());
+ setFont(m_parentLabel->font());
+
+ setFrameShadow(m_parentLabel->frameShadow());
+ setFrameShape(m_parentLabel->frameShape());
+ setFrameStyle(m_parentLabel->frameStyle());
+ setMidLineWidth(m_parentLabel->midLineWidth());
+ setLineWidth(m_parentLabel->lineWidth());
+}
+
+KexiDBInternalLabel::~KexiDBInternalLabel()
+{
+}
+
+/*!
+* This method is copied from kdebase/kdesktop/kshadowengine.cpp
+* Some modifactions were made.
+* --
+* Christian Nitschkowski
+*/
+QImage KexiDBInternalLabel::makeShadow( const QImage& textImage,
+ const QColor &bgColor, const QRect& boundingRect )
+{
+ QImage result;
+ QString origText( text() );
+
+ // create a new image for for the shaddow
+ const int w = textImage.width();
+ const int h = textImage.height();
+
+ // avoid calling these methods for every pixel
+ const int bgRed = bgColor.red();
+ const int bgGreen = bgColor.green();
+ const int bgBlue = bgColor.blue();
+
+ const int startX = boundingRect.x() + SHADOW_THICKNESS;
+ const int startY = boundingRect.y() + SHADOW_THICKNESS;
+ const int effectWidth = boundingRect.bottomRight().x() - SHADOW_THICKNESS;
+ const int effectHeight = boundingRect.bottomRight().y() - SHADOW_THICKNESS;
+// const int period = (effectWidth - startX) / 10;
+
+ double alphaShadow;
+
+ /*
+ * This is the source pixmap
+ */
+ QImage img = textImage.convertDepth( 32 );
+
+ /*
+ * Resize the image if necessary
+ */
+ if ( ( result.width() != w ) || ( result.height() != h ) ) {
+ result.create( w, h, 32 );
+ }
+
+// result.fill( 0 ); // all black
+ double realOpacity = SHADOW_OPACITY + QMIN(50.0/double(256.0-qGray(bgColor.rgb())), 50.0);
+ //int _h, _s, _v;
+ //.getHsv( &_h, &_s, &_v );
+ if (colorGroup().background()==Qt::red)//_s>=250 && _v>=250) //for colors like cyan or red, make the result more white
+ realOpacity += 50.0;
+ result.fill( (int)realOpacity );
+ result.setAlphaBuffer( true );
+
+ for ( int i = startX; i < effectWidth; i++ ) {
+ for ( int j = startY; j < effectHeight; j++ ) {
+ /*!
+ * This method is copied from kdebase/kdesktop/kshadowengine.cpp
+ * Some modifactions were made.
+ * --
+ * Christian Nitschkowski
+ */
+ if ( ( i < 1 ) || ( j < 1 ) || ( i > img.width() - 2 ) || ( j > img.height() - 2 ) )
+ continue;
+ else
+ alphaShadow = ( qGray( img.pixel( i - 1, j - 1 ) ) * SHADOW_DIAGONAL_FACTOR +
+ qGray( img.pixel( i - 1, j ) ) * SHADOW_AXIS_FACTOR +
+ qGray( img.pixel( i - 1, j + 1 ) ) * SHADOW_DIAGONAL_FACTOR +
+ qGray( img.pixel( i , j - 1 ) ) * SHADOW_AXIS_FACTOR +
+ 0 +
+ qGray( img.pixel( i , j + 1 ) ) * SHADOW_AXIS_FACTOR +
+ qGray( img.pixel( i + 1, j - 1 ) ) * SHADOW_DIAGONAL_FACTOR +
+ qGray( img.pixel( i + 1, j ) ) * SHADOW_AXIS_FACTOR +
+ qGray( img.pixel( i + 1, j + 1 ) ) * SHADOW_DIAGONAL_FACTOR ) / SHADOW_FACTOR;
+
+ // update the shadow's i,j pixel.
+ if (alphaShadow > 0)
+ result.setPixel( i, j, qRgba( bgRed, bgGreen , bgBlue,
+ ( int ) (( alphaShadow > realOpacity ) ? realOpacity : alphaShadow)
+ ) );
+ }
+/*caused too much redraw problems if (period && i % period) {
+ qApp->processEvents();
+ if (text() != origText) //text has been changed in the meantime: abort
+ return QImage();
+ }*/
+ }
+ return result;
+}
+
+KPixmap KexiDBInternalLabel::getShadowPixmap() {
+ /*!
+ * Backup the default color used to draw text.
+ */
+ const QColor textColor = colorGroup().foreground();
+
+ /*!
+ * Temporary storage for the generated shadow
+ */
+ KPixmap finalPixmap, tempPixmap;
+ QImage shadowImage, tempImage;
+ QPainter painter;
+
+ m_shadowRect = QRect();
+
+ tempPixmap.resize( size() );
+ tempPixmap.fill( Qt::black );
+ tempPixmap.setMask( tempPixmap.createHeuristicMask( true ) );
+
+ /*!
+ * The textcolor has to be white for creating shadows!
+ */
+ setPaletteForegroundColor( Qt::white );
+
+ /*!
+ Draw the label "as usual" in a pixmap
+ */
+ painter.begin( &tempPixmap );
+ painter.setFont( font() );
+ drawContents( &painter );
+ painter.end();
+ setPaletteForegroundColor( textColor );
+
+ /*!
+ * Calculate the first bounding rect.
+ * This will fit around the unmodified text.
+ */
+ shadowImage = tempPixmap;
+ tempPixmap.setMask( QBitmap() );
+
+ /*!
+ Get the first bounding rect.
+ This may speed up makeShadow later.
+ */
+ m_shadowRect = getBounding( shadowImage, m_shadowRect );
+
+ /*!
+ * Enlarge the bounding rect to make sure the shadow
+ * will fit in.
+ * The new rect has to fit in the pixmap.
+ * I have to admit this isn't really nice code...
+ */
+ m_shadowRect.setX( QMAX( m_shadowRect.x() - ( m_shadowRect.width() / 4 ), 0 ) );
+ m_shadowRect.setY( QMAX( m_shadowRect.y() - ( m_shadowRect.height() / 4 ), 0 ) );
+ m_shadowRect.setBottomRight( QPoint(
+ QMIN( m_shadowRect.x() + ( m_shadowRect.width() * 3 / 2 ), shadowImage.width() ),
+ QMIN( m_shadowRect.y() + ( m_shadowRect.height() * 3 / 2 ), shadowImage.height() ) ) );
+
+ shadowImage = makeShadow( shadowImage,
+ qGray( colorGroup().background().rgb() ) < 127 ? Qt::white : Qt::black,
+ m_shadowRect );
+ if (shadowImage.isNull())
+ return KPixmap();
+
+ /*!
+ Now get the final bounding rect.
+ */
+ m_shadowRect = getBounding( shadowImage, m_shadowRect );
+
+ /*!
+ Paint the labels background in a new pixmap.
+ */
+ finalPixmap.resize( size() );
+ painter.begin( &finalPixmap );
+ painter.fillRect( 0, 0, finalPixmap.width(), finalPixmap.height(),
+ palette().brush(
+ isEnabled() ? QPalette::Active : QPalette::Disabled,
+ QColorGroup::Background ) );
+ painter.end();
+
+ /*!
+ Copy the part of the background the shadow will be on
+ to another pixmap.
+ */
+ tempPixmap.resize( m_shadowRect.size() );
+ if (!finalPixmap.isNull()) {
+ bitBlt( &tempPixmap, 0, 0, &finalPixmap,
+ m_shadowRect.x() + SHADOW_OFFSET_X,
+ m_shadowRect.y() + SHADOW_OFFSET_Y,
+ m_shadowRect.width(),
+ m_shadowRect.height() );
+ }
+ /*!
+ Replace the big background pixmap with the
+ part we could out just before.
+ */
+ finalPixmap = tempPixmap;
+
+ /*!
+ Copy the "interesting" part of the shadow image
+ to a new image.
+ I tried to copy this to a pixmap directly,
+ but it didn't work correctly.
+ Maybe a Qt bug?
+ */
+ tempImage = shadowImage.copy( m_shadowRect );
+ tempPixmap.convertFromImage( tempImage );
+ /*!
+ Anyways, merge the shadow with the background.
+ */
+ if (!tempPixmap.isNull()) {
+ bitBlt( &finalPixmap, 0, 0, &tempPixmap );
+ }
+
+ /**
+ Now move the rect.
+ Don't do this before the shadow is copied from shadowImage!
+ */
+ m_shadowRect.moveBy( SHADOW_OFFSET_X, SHADOW_OFFSET_Y );
+
+ return finalPixmap;
+}
+
+QRect KexiDBInternalLabel::getBounding( const QImage &image, const QRect& startRect ) {
+ QPoint topLeft;
+ QPoint bottomRight;
+
+ const int startX = startRect.x();
+ const int startY = startRect.y();
+ /*!
+ * Ugly beast to get the correct width and height
+ */
+ const int width = QMIN( ( startRect.bottomRight().x() > 0
+ ? startRect.bottomRight().x() : QCOORD_MAX ),
+ image.width() );
+ const int height = QMIN( ( startRect.bottomRight().y() > 0
+ ? startRect.bottomRight().y() : QCOORD_MAX ),
+ image.height() );
+
+ /*!
+ Assume the first pixel has the color of the
+ background that has to be cut away.
+ Qt uses the four corner pixels to guess the
+ correct color, but in this case the topleft
+ pixel should be enough.
+ */
+ QRgb trans = image.pixel( 0, 0 );
+
+ for ( int y = startY; y < height; y++ ) {
+ for ( int x = startX; x < width; x++ ) {
+ if ( image.pixel( x, y ) != trans ) {
+ topLeft.setY( y );
+ y = height;
+ break;
+ }
+ }
+ }
+
+ for ( int x = startX; x < width; x++ ) {
+ for ( int y = startY; y < height; y++ ) {
+ if ( image.pixel( x, y ) != trans ) {
+ topLeft.setX( x );
+ x = width;
+ break;
+ }
+ }
+ }
+
+ for ( int y = height - 1; y > topLeft.y(); y-- ) {
+ for ( int x = width - 1; x > topLeft.x(); x-- ) {
+ if ( image.pixel( x, y ) != trans ) {
+ bottomRight.setY( y + 1 );
+ y = 0;
+ break;
+ }
+ }
+ }
+
+ for ( int x = width - 1; x > topLeft.x(); x-- ) {
+ for ( int y = height - 1; y > topLeft.y(); y-- ) {
+ if ( image.pixel( x, y ) != trans ) {
+ bottomRight.setX( x + 1 );
+ x = 0;
+ break;
+ }
+ }
+ }
+
+ return QRect(
+ topLeft.x(),
+ topLeft.y(),
+ bottomRight.x() - topLeft.x(),
+ bottomRight.y() - topLeft.y() );
+}
+
+//=========================================================
+
+//! @internal
+class KexiDBLabel::Private
+{
+ public:
+ Private()
+ : timer(0)
+// , autonumberDisplayParameters(0)
+ , pixmapDirty( true )
+ , shadowEnabled( false )
+ , resizeEvent( false )
+ {
+ }
+ ~Private() {}
+ KPixmap shadowPixmap;
+ QPoint shadowPosition;
+ KexiDBInternalLabel* internalLabel;
+ QTimer* timer;
+ QColor frameColor;
+ bool pixmapDirty : 1;
+ bool shadowEnabled : 1;
+ bool resizeEvent : 1;
+};
+
+//=========================================================
+
+KexiDBLabel::KexiDBLabel( QWidget *parent, const char *name, WFlags f )
+ : QLabel( parent, name, f )
+ , KexiDBTextWidgetInterface()
+ , KexiFormDataItemInterface()
+ , d( new Private() )
+{
+ init();
+}
+
+KexiDBLabel::KexiDBLabel( const QString& text, QWidget *parent, const char *name, WFlags f )
+ : QLabel( parent, name, f )
+ , KexiDBTextWidgetInterface()
+ , KexiFormDataItemInterface()
+ , d( new Private() )
+{
+ init();
+ setText( text );
+}
+
+KexiDBLabel::~KexiDBLabel()
+{
+ delete d;
+}
+
+void KexiDBLabel::init()
+{
+ m_hasFocusableWidget = false;
+ d->internalLabel = new KexiDBInternalLabel( this );
+ d->internalLabel->hide();
+ d->frameColor = palette().active().foreground();
+
+ setAlignment( d->internalLabel->alignment() );
+}
+
+void KexiDBLabel::updatePixmapLater() {
+ if (d->resizeEvent) {
+ if (!d->timer) {
+ d->timer = new QTimer(this, "KexiDBLabelTimer");
+ connect(d->timer, SIGNAL(timeout()), this, SLOT(updatePixmap()));
+ }
+ d->timer->start(100, true);
+ d->resizeEvent = false;
+ return;
+ }
+ if (d->timer && d->timer->isActive())
+ return;
+ updatePixmap();
+}
+
+void KexiDBLabel::updatePixmap() {
+ /*!
+ Whatever has changed in KexiDBLabel,
+ every parameter is set to our private-label.
+ Just in case...
+ */
+ d->internalLabel->setText( text() );
+ d->internalLabel->setFixedSize( size() );
+ d->internalLabel->setPalette( palette() );
+ d->internalLabel->setAlignment( alignment() );
+// d->shadowPixmap = KPixmap(); //parallel repaints won't hurt us cause incomplete pixmap
+ KPixmap shadowPixmap = d->internalLabel->getShadowPixmap();
+ if (shadowPixmap.isNull())
+ return;
+ d->shadowPixmap = shadowPixmap;
+ d->shadowPosition = d->internalLabel->m_shadowRect.topLeft();
+ d->pixmapDirty = false;
+ repaint();
+}
+
+void KexiDBLabel::paintEvent( QPaintEvent* e )
+{
+ QPainter p( this );
+ if ( d->shadowEnabled ) {
+ /*!
+ If required, update the pixmap-cache.
+ */
+ if ( d->pixmapDirty ) {
+ updatePixmapLater();
+ }
+
+ /*!
+ If the part that should be redrawn intersects with our shadow,
+ redraw the shadow where it intersects with e->rect().
+ Have to move the clipping rect around a bit because
+ the shadow has to be drawn using an offset relative to
+ the widgets border.
+ */
+ if ( !d->pixmapDirty && e->rect().contains( d->shadowPosition ) && !d->shadowPixmap.isNull()) {
+ QRect clipRect = QRect(
+ QMAX( e->rect().x() - d->shadowPosition.x(), 0 ),
+ QMAX( e->rect().y() - d->shadowPosition.y(), 0 ),
+ QMIN( e->rect().width() + d->shadowPosition.x(), d->shadowPixmap.width() ),
+ QMIN( e->rect().height() + d->shadowPosition.y(), d->shadowPixmap.height() ) );
+ p.drawPixmap( d->internalLabel->m_shadowRect.topLeft(), d->shadowPixmap, clipRect );
+ }
+ }
+ KexiDBTextWidgetInterface::paint( this, &p, text().isEmpty(), alignment(), false );
+ QLabel::paintEvent( e );
+}
+
+void KexiDBLabel::setValueInternal( const QVariant& add, bool removeOld ) {
+ if (removeOld)
+ setText(add.toString());
+ else
+ setText( m_origValue.toString() + add.toString() );
+}
+
+QVariant KexiDBLabel::value() {
+ return text();
+}
+
+void KexiDBLabel::setInvalidState( const QString& displayText )
+{
+ setText( displayText );
+}
+
+bool KexiDBLabel::valueIsNull()
+{
+ return text().isNull();
+}
+
+bool KexiDBLabel::valueIsEmpty()
+{
+ return text().isEmpty();
+}
+
+bool KexiDBLabel::isReadOnly() const
+{
+ return true;
+}
+
+void KexiDBLabel::setReadOnly( bool readOnly )
+{
+ Q_UNUSED(readOnly);
+}
+
+QWidget* KexiDBLabel::widget()
+{
+ return this;
+}
+
+bool KexiDBLabel::cursorAtStart()
+{
+ return false;
+}
+
+bool KexiDBLabel::cursorAtEnd()
+{
+ return false;
+}
+
+void KexiDBLabel::clear()
+{
+ setText(QString::null);
+}
+
+bool KexiDBLabel::setProperty( const char * name, const QVariant & value )
+{
+ const bool ret = QLabel::setProperty(name, value);
+ if (d->shadowEnabled) {
+ if (0==qstrcmp("indent", name) || 0==qstrcmp("font", name) || 0==qstrcmp("margin", name)
+ || 0==qstrcmp("frameShadow", name) || 0==qstrcmp("frameShape", name)
+ || 0==qstrcmp("frameStyle", name) || 0==qstrcmp("midLineWidth", name)
+ || 0==qstrcmp("lineWidth", name)) {
+ d->internalLabel->setProperty(name, value);
+ updatePixmap();
+ }
+ }
+ return ret;
+}
+
+void KexiDBLabel::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ KexiFormDataItemInterface::setColumnInfo(cinfo);
+ KexiDBTextWidgetInterface::setColumnInfo(cinfo, this);
+}
+
+void KexiDBLabel::setShadowEnabled( bool state ) {
+ d->shadowEnabled = state;
+ d->pixmapDirty = true;
+ if (state)
+ d->internalLabel->updateFrame();
+ repaint();
+}
+
+void KexiDBLabel::resizeEvent( QResizeEvent* e ) {
+ if (isVisible())
+ d->resizeEvent = true;
+ d->pixmapDirty = true;
+ QLabel::resizeEvent( e );
+}
+
+void KexiDBLabel::fontChange( const QFont& font ) {
+ d->pixmapDirty = true;
+ d->internalLabel->setFont( font );
+ QLabel::fontChange( font );
+}
+
+void KexiDBLabel::styleChange( QStyle& style ) {
+ d->pixmapDirty = true;
+ QLabel::styleChange( style );
+}
+
+void KexiDBLabel::enabledChange( bool enabled ) {
+ d->pixmapDirty = true;
+ d->internalLabel->setEnabled( enabled );
+ QLabel::enabledChange( enabled );
+}
+
+void KexiDBLabel::paletteChange( const QPalette& oldPal ) {
+ Q_UNUSED(oldPal);
+ d->pixmapDirty = true;
+ d->internalLabel->setPalette( palette() );
+}
+
+/*const QColor & KexiDBLabel::paletteForegroundColor () const
+{
+ return d->foregroundColor;
+}
+
+void KexiDBLabel::setPaletteForegroundColor ( const QColor& color )
+{
+ d->foregroundColor = color;
+}*/
+
+void KexiDBLabel::frameChanged() {
+ d->pixmapDirty = true;
+ d->internalLabel->updateFrame();
+ QFrame::frameChanged();
+}
+
+void KexiDBLabel::showEvent( QShowEvent* e ) {
+ d->pixmapDirty = true;
+ QLabel::showEvent( e );
+}
+
+void KexiDBLabel::setText( const QString& text ) {
+ d->pixmapDirty = true;
+ QLabel::setText( text );
+ //This is necessary for KexiFormDataItemInterface
+ valueChanged();
+ repaint();
+}
+
+bool KexiDBLabel::shadowEnabled() const
+{
+ return d->shadowEnabled;
+}
+
+#define ClassName KexiDBLabel
+#define SuperClassName QLabel
+#include "kexiframeutils_p.cpp"
+#include "kexidblabel.moc"
diff --git a/kexi/plugins/forms/widgets/kexidblabel.h b/kexi/plugins/forms/widgets/kexidblabel.h
new file mode 100644
index 00000000..ec4e626a
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidblabel.h
@@ -0,0 +1,140 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Christian Nitschkowski <segfault_ii@web.de>
+ Copyright (C) 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 KEXIDBLABEL_H
+#define KEXIDBLABEL_H
+
+#include <qimage.h>
+#include <qlabel.h>
+
+#include <kpixmap.h>
+
+#include "../kexiformdataiteminterface.h"
+#include "../kexidbtextwidgetinterface.h"
+#include <widget/utils/kexidisplayutils.h>
+
+class QPainter;
+class QTimer;
+class KexiDBInternalLabel;
+
+//! @short An extended, data-aware, read-only text label.
+/*! It's text may have a drop-shadow.
+
+ @author Christian Nitschkowski, Jaroslaw Staniek
+*/
+class KEXIFORMUTILS_EXPORT KexiDBLabel : public QLabel, protected KexiDBTextWidgetInterface, public KexiFormDataItemInterface {
+ Q_OBJECT
+ Q_PROPERTY( QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true )
+ Q_PROPERTY( QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true )
+ Q_PROPERTY( bool shadowEnabled READ shadowEnabled WRITE setShadowEnabled DESIGNABLE true )
+ Q_OVERRIDE( QPixmap pixmap DESIGNABLE false )
+ Q_OVERRIDE( bool scaledContents DESIGNABLE false )
+// Q_OVERRIDE( QColor paletteForegroundColor READ paletteForegroundColor WRITE setPaletteForegroundColor DESIGNABLE true )
+ Q_PROPERTY( QColor frameColor READ frameColor WRITE setFrameColor DESIGNABLE true )
+
+ public:
+ KexiDBLabel( QWidget *parent, const char *name = 0, WFlags f = 0 );
+ KexiDBLabel( const QString& text, QWidget *parent, const char *name = 0, WFlags f = 0 );
+ virtual ~KexiDBLabel();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+
+ virtual QVariant value();
+
+ bool shadowEnabled() const;
+
+ virtual void setInvalidState( const QString& displayText );
+
+ virtual bool valueIsNull();
+
+ virtual bool valueIsEmpty();
+
+ //! always true
+ virtual bool isReadOnly() const;
+
+ virtual QWidget* widget();
+
+ //! always false
+ virtual bool cursorAtStart();
+
+ //! always false
+ virtual bool cursorAtEnd();
+
+ virtual void clear();
+
+ //! used to catch setIndent(), etc.
+ virtual bool setProperty ( const char * name, const QVariant & value );
+
+ virtual const QColor& frameColor() const;
+
+// const QColor & paletteForegroundColor() const;
+
+ public slots:
+ //! Sets the datasource to \a ds
+ inline void setDataSource( const QString &ds ) { KexiFormDataItemInterface::setDataSource( ds ); }
+
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+
+ virtual void setText( const QString& text );
+
+ /*! Enable/Disable the shadow effect.
+ KexiDBLabel acts just like a normal QLabel when shadow is disabled. */
+ void setShadowEnabled( bool state );
+
+ virtual void setPalette( const QPalette &pal );
+
+ virtual void setFrameColor(const QColor& color);
+
+// void setPaletteForegroundColor( const QColor& color );
+
+ protected slots:
+ //! empty
+ virtual void setReadOnly( bool readOnly );
+ void updatePixmap();
+
+ protected:
+ void init();
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+ virtual void paintEvent( QPaintEvent* );
+ virtual void resizeEvent( QResizeEvent* e );
+
+ //! Sets value \a value for a widget.
+ virtual void setValueInternal( const QVariant& add, bool removeOld );
+
+ virtual void fontChange( const QFont& font );
+ virtual void styleChange( QStyle& style );
+ virtual void enabledChange( bool enabled );
+
+ virtual void paletteChange( const QPalette& oldPal );
+ virtual void frameChanged();
+ virtual void showEvent( QShowEvent* e );
+
+ //! Reimplemented to paint using real frame color instead of froeground.
+ //! Also allows to paint more types of frame.
+ virtual void drawFrame( QPainter * );
+
+ void updatePixmapLater();
+
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidblineedit.cpp b/kexi/plugins/forms/widgets/kexidblineedit.cpp
new file mode 100644
index 00000000..3897a8cb
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidblineedit.cpp
@@ -0,0 +1,417 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 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 "kexidblineedit.h"
+#include "kexidbautofield.h"
+
+#include <kdebug.h>
+#include <knumvalidator.h>
+#include <kdatetbl.h>
+
+#include <qpopupmenu.h>
+#include <qpainter.h>
+
+#include <kexiutils/utils.h>
+#include <kexidb/queryschema.h>
+#include <kexidb/fieldvalidator.h>
+#include <kexiutils/utils.h>
+
+//! @todo reenable as an app aption
+//#define USE_KLineEdit_setReadOnly
+
+//! @internal A validator used for read only flag to disable editing
+class KexiDBLineEdit_ReadOnlyValidator : public QValidator
+{
+ public:
+ KexiDBLineEdit_ReadOnlyValidator( QObject * parent )
+ : QValidator(parent)
+ {
+ }
+ ~KexiDBLineEdit_ReadOnlyValidator() {}
+ virtual State validate( QString &, int & ) const { return Invalid; }
+};
+
+//-----
+
+KexiDBLineEdit::KexiDBLineEdit(QWidget *parent, const char *name)
+ : KLineEdit(parent, name)
+ , KexiDBTextWidgetInterface()
+ , KexiFormDataItemInterface()
+//moved , m_dateFormatter(0)
+//moved , m_timeFormatter(0)
+ , m_menuExtender(this, this)
+ , m_internalReadOnly(false)
+ , m_slotTextChanged_enabled(true)
+{
+#ifdef USE_KLineEdit_setReadOnly
+//! @todo reenable as an app aption
+ QPalette p(widget->palette());
+ p.setColor( lighterGrayBackgroundColor(palette()) );
+ widget->setPalette(p);
+#endif
+
+ connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged(const QString&)));
+}
+
+KexiDBLineEdit::~KexiDBLineEdit()
+{
+//moved delete m_dateFormatter;
+//moved delete m_timeFormatter;
+}
+
+void KexiDBLineEdit::setInvalidState( const QString& displayText )
+{
+ KLineEdit::setReadOnly(true);
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+ setText(displayText);
+}
+
+void KexiDBLineEdit::setValueInternal(const QVariant& add, bool removeOld)
+{
+#if 0 //moved to KexiTextFormatter
+ QVariant value;
+ if (removeOld)
+ value = add;
+ else {
+ if (add.toString().isEmpty())
+ value = m_origValue;
+ else
+ value = m_origValue.toString() + add.toString();
+ }
+
+ if (m_columnInfo) {
+ const KexiDB::Field::Type t = m_columnInfo->field->type();
+ if (t == KexiDB::Field::Boolean) {
+ //! @todo temporary solution for booleans!
+ setText( value.toBool() ? "1" : "0" );
+ return;
+ }
+ else if (t == KexiDB::Field::Date) {
+ setText( dateFormatter()->dateToString( value.toString().isEmpty() ? QDate() : value.toDate() ) );
+ setCursorPosition(0); //ok?
+ return;
+ }
+ else if (t == KexiDB::Field::Time) {
+ setText(
+ timeFormatter()->timeToString(
+ //hack to avoid converting null variant to valid QTime(0,0,0)
+ value.toString().isEmpty() ? value.toTime() : QTime(99,0,0)
+ )
+ );
+ setCursorPosition(0); //ok?
+ return;
+ }
+ else if (t == KexiDB::Field::DateTime) {
+ if (value.toString().isEmpty() ) {
+ setText( QString::null );
+ }
+ else {
+ setText(
+ dateFormatter()->dateToString( value.toDateTime().date() ) + " " +
+ timeFormatter()->timeToString( value.toDateTime().time() )
+ );
+ }
+ setCursorPosition(0); //ok?
+ return;
+ }
+ }
+#endif
+ m_slotTextChanged_enabled = false;
+ setText( m_textFormatter.valueToText(removeOld ? QVariant() : m_origValue, add.toString()) );
+// setText( value.toString() );
+ setCursorPosition(0); //ok?
+ m_slotTextChanged_enabled = true;
+}
+
+QVariant KexiDBLineEdit::value()
+{
+ return m_textFormatter.textToValue( text() );
+#if 0 // moved to KexiTextFormatter
+ if (! m_columnInfo)
+ return QVariant();
+ const KexiDB::Field::Type t = m_columnInfo->field->type();
+ switch (t) {
+ case KexiDB::Field::Text:
+ case KexiDB::Field::LongText:
+ return text();
+ case KexiDB::Field::Byte:
+ case KexiDB::Field::ShortInteger:
+ return text().toShort();
+//! @todo uint, etc?
+ case KexiDB::Field::Integer:
+ return text().toInt();
+ case KexiDB::Field::BigInteger:
+ return text().toLongLong();
+ case KexiDB::Field::Boolean:
+ //! @todo temporary solution for booleans!
+ return text() == "1" ? QVariant(true,1) : QVariant(false,0);
+ case KexiDB::Field::Date:
+ return dateFormatter()->stringToVariant( text() );
+ case KexiDB::Field::Time:
+ return timeFormatter()->stringToVariant( text() );
+ case KexiDB::Field::DateTime:
+ return stringToDateTime(*dateFormatter(), *timeFormatter(), text());
+ case KexiDB::Field::Float:
+ return text().toFloat();
+ case KexiDB::Field::Double:
+ return text().toDouble();
+ default:
+ return QVariant();
+ }
+//! @todo more data types!
+ return text();
+#endif
+}
+
+void KexiDBLineEdit::slotTextChanged(const QString&)
+{
+ if (!m_slotTextChanged_enabled)
+ return;
+ signalValueChanged();
+}
+
+bool KexiDBLineEdit::valueIsNull()
+{
+ return valueIsEmpty(); //ok??? text().isNull();
+}
+
+bool KexiDBLineEdit::valueIsEmpty()
+{
+ return m_textFormatter.valueIsEmpty( text() );
+#if 0 // moved to KexiTextFormatter
+ if (text().isEmpty())
+ return true;
+
+ if (m_columnInfo) {
+ const KexiDB::Field::Type t = m_columnInfo->field->type();
+ if (t == KexiDB::Field::Date || )
+ return dateFormatter()->isEmpty( text() );
+ else if (t == KexiDB::Field::Time)
+ return timeFormatter()->isEmpty( text() );
+ else if (t == KexiDB::Field::Time)
+ return dateTimeIsEmpty( *dateFormatter(), *timeFormatter(), text() );
+ }
+
+//! @todo
+ return text().isEmpty();
+#endif
+}
+
+bool KexiDBLineEdit::valueIsValid()
+{
+ return m_textFormatter.valueIsValid( text() );
+#if 0 // moved to KexiTextFormatter
+ if (!m_columnInfo)
+ return true;
+//! @todo fix for fields with "required" property = true
+ if (valueIsEmpty()/*ok?*/)
+ return true;
+
+ const KexiDB::Field::Type t = m_columnInfo->field->type();
+ if (t == KexiDB::Field::Date)
+ return dateFormatter()->stringToVariant( text() ).isValid();
+ else if (t == KexiDB::Field::Time)
+ return timeFormatter()->stringToVariant( text() ).isValid();
+ else if (t == KexiDB::Field::DateTime)
+ return dateTimeIsValid( *dateFormatter(), *timeFormatter(), text() );
+
+//! @todo
+ return true;
+#endif
+}
+
+bool KexiDBLineEdit::isReadOnly() const
+{
+ return m_internalReadOnly;
+}
+
+void KexiDBLineEdit::setReadOnly( bool readOnly )
+{
+#ifdef USE_KLineEdit_setReadOnly
+//! @todo reenable as an app aption
+ return KLineEdit::setReadOnly( readOnly );
+#else
+ m_internalReadOnly = readOnly;
+ if (m_internalReadOnly) {
+ m_readWriteValidator = validator();
+ if (!m_readOnlyValidator)
+ m_readOnlyValidator = new KexiDBLineEdit_ReadOnlyValidator(this);
+ setValidator( m_readOnlyValidator );
+ }
+ else {
+ //revert to r/w validator
+ setValidator( m_readWriteValidator );
+ }
+ m_menuExtender.updatePopupMenuActions();
+#endif
+}
+
+QPopupMenu * KexiDBLineEdit::createPopupMenu()
+{
+ QPopupMenu *contextMenu = KLineEdit::createPopupMenu();
+ m_menuExtender.createTitle(contextMenu);
+ return contextMenu;
+}
+
+
+QWidget* KexiDBLineEdit::widget()
+{
+ return this;
+}
+
+bool KexiDBLineEdit::cursorAtStart()
+{
+ return cursorPosition()==0;
+}
+
+bool KexiDBLineEdit::cursorAtEnd()
+{
+ return cursorPosition()==(int)text().length();
+}
+
+void KexiDBLineEdit::clear()
+{
+ if (!m_internalReadOnly)
+ KLineEdit::clear();
+}
+
+
+void KexiDBLineEdit::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ KexiFormDataItemInterface::setColumnInfo(cinfo);
+ m_textFormatter.setField( cinfo ? cinfo->field : 0 );
+
+ if (!cinfo)
+ return;
+
+//! @todo handle input mask (via QLineEdit::setInputMask()) using a special KexiDB::FieldInputMask class
+ setValidator( new KexiDB::FieldValidator(*cinfo->field, this) );
+
+#if 0 // moved to KexiTextFormatter
+ if (t==KexiDB::Field::Date) {
+//! @todo use KDateWidget?
+ setInputMask( dateFormatter()->inputMask() );
+ }
+ else if (t==KexiDB::Field::Time) {
+//! @todo use KTimeWidget
+// setInputMask("00:00:00");
+ setInputMask( timeFormatter()->inputMask() );
+ }
+ else if (t==KexiDB::Field::DateTime) {
+ setInputMask(
+ dateTimeInputMask( *dateFormatter(), *timeFormatter() ) );
+ }
+#endif
+ const QString inputMask( m_textFormatter.inputMask() );
+ if (!inputMask.isEmpty())
+ setInputMask( inputMask );
+
+ KexiDBTextWidgetInterface::setColumnInfo(cinfo, this);
+}
+
+/*todo
+void KexiDBLineEdit::paint( QPainter *p )
+{
+ KexiDBTextWidgetInterface::paint( this, &p, text().isEmpty(), alignment(), hasFocus() );
+}*/
+
+void KexiDBLineEdit::paintEvent ( QPaintEvent *pe )
+{
+ KLineEdit::paintEvent( pe );
+ QPainter p(this);
+ KexiDBTextWidgetInterface::paint( this, &p, text().isEmpty(), alignment(), hasFocus() );
+}
+
+bool KexiDBLineEdit::event( QEvent * e )
+{
+ const bool ret = KLineEdit::event( e );
+ KexiDBTextWidgetInterface::event(e, this, text().isEmpty());
+ if (e->type()==QEvent::FocusOut) {
+ QFocusEvent *fe = static_cast<QFocusEvent *>(e);
+// if (fe->reason()!=QFocusEvent::ActiveWindow && fe->reason()!=QFocusEvent::Popup) {
+ if (fe->reason()==QFocusEvent::Tab || fe->reason()==QFocusEvent::Backtab) {
+ //display aligned to left after loosing the focus (only if this is tab/backtab event)
+//! @todo add option to set cursor at the beginning
+ setCursorPosition(0); //ok?
+ }
+ }
+ return ret;
+}
+
+bool KexiDBLineEdit::appendStretchRequired(KexiDBAutoField* autoField) const
+{
+ return KexiDBAutoField::Top == autoField->labelPosition();
+}
+
+void KexiDBLineEdit::handleAction(const QString& actionName)
+{
+ if (actionName=="edit_copy") {
+ copy();
+ }
+ else if (actionName=="edit_paste") {
+ paste();
+ }
+ else if (actionName=="edit_cut") {
+ cut();
+ }
+ //! @todo ?
+}
+
+void KexiDBLineEdit::setDisplayDefaultValue(QWidget *widget, bool displayDefaultValue)
+{
+ KexiFormDataItemInterface::setDisplayDefaultValue(widget, displayDefaultValue);
+ // initialize display parameters for default / entered value
+ KexiDisplayUtils::DisplayParameters * const params
+ = displayDefaultValue ? m_displayParametersForDefaultValue : m_displayParametersForEnteredValue;
+ setFont(params->font);
+ QPalette pal(palette());
+ pal.setColor(QPalette::Active, QColorGroup::Text, params->textColor);
+ setPalette(pal);
+}
+
+void KexiDBLineEdit::undo()
+{
+ cancelEditor();
+}
+
+void KexiDBLineEdit::moveCursorToEnd()
+{
+ KLineEdit::end(false/*!mark*/);
+}
+
+void KexiDBLineEdit::moveCursorToStart()
+{
+ KLineEdit::home(false/*!mark*/);
+}
+
+void KexiDBLineEdit::selectAll()
+{
+ KLineEdit::selectAll();
+}
+
+bool KexiDBLineEdit::keyPressed(QKeyEvent *ke)
+{
+ Q_UNUSED(ke);
+ return false;
+}
+
+#include "kexidblineedit.moc"
diff --git a/kexi/plugins/forms/widgets/kexidblineedit.h b/kexi/plugins/forms/widgets/kexidblineedit.h
new file mode 100644
index 00000000..5f0262b2
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidblineedit.h
@@ -0,0 +1,170 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 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 KexiDBLineEdit_H
+#define KexiDBLineEdit_H
+
+#include <klineedit.h>
+#include <qvalidator.h>
+
+#include "kexiformdataiteminterface.h"
+#include "kexidbtextwidgetinterface.h"
+#include "kexidbutils.h"
+#include <widget/tableview/kexitextformatter.h>
+#include <widget/utils/kexidatetimeformatter.h>
+
+class KexiDBWidgetContextMenuExtender;
+
+/*! @internal Utility: alter background color to be a blended color
+ of the background and base (usually lighter gray). Used for read-only mode. */
+void setLighterGrayBackgroundColor(QWidget* widget);
+
+//! @short Line edit widget for Kexi forms
+/*! Handles many data types. User input is validated by using validators
+ and/or input masks.
+*/
+class KEXIFORMUTILS_EXPORT KexiDBLineEdit :
+ public KLineEdit,
+ protected KexiDBTextWidgetInterface,
+ public KexiFormDataItemInterface,
+ public KexiSubwidgetInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_OVERRIDE(bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true)
+
+ public:
+ KexiDBLineEdit(QWidget *parent, const char *name=0);
+ virtual ~KexiDBLineEdit();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return true if the value is valid */
+ virtual bool valueIsValid();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! If \a displayDefaultValue is true, the value set by KexiDataItemInterface::setValue()
+ is displayed in a special way. Used by KexiFormDataProvider::fillDataItems().
+ \a widget is equal to 'this'.
+ Reimplemented after KexiFormDataItemInterface. */
+ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue);
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+
+ /*! Handles action having standard name \a actionName.
+ Action could be: "edit_copy", "edit_paste", etc.
+ Reimplemented after KexiDataItemChangesListener. */
+ virtual void handleAction(const QString& actionName);
+
+ /*! Called by top-level form on key press event to consume widget-specific shortcuts. */
+ virtual bool keyPressed(QKeyEvent *ke);
+
+ public slots:
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ virtual void setReadOnly( bool readOnly );
+
+ //! Reimplemented, so "undo" means the same as "cancelEditor" action
+ virtual void undo();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void moveCursorToEnd();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void moveCursorToStart();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void selectAll();
+
+ protected slots:
+ void slotTextChanged(const QString&);
+
+ protected:
+ virtual void paintEvent ( QPaintEvent * );
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+ virtual bool event ( QEvent * );
+
+#if 0
+//moved to KexiTextFormatter
+ inline KexiDateFormatter* dateFormatter() {
+ return m_dateFormatter ? m_dateFormatter : m_dateFormatter = new KexiDateFormatter();
+ }
+
+ inline KexiTimeFormatter* timeFormatter() {
+ return m_timeFormatter ? m_timeFormatter : m_timeFormatter = new KexiTimeFormatter();
+ }
+#endif
+
+ virtual QPopupMenu * createPopupMenu();
+
+ //! Implemented for KexiSubwidgetInterface
+ virtual bool appendStretchRequired(KexiDBAutoField* autoField) const;
+
+#if 0
+//moved to KexiTextFormatter
+ //! Used for date and date/time types
+ KexiDateFormatter* m_dateFormatter;
+ //! Used for time and date/time types
+ KexiTimeFormatter* m_timeFormatter;
+#endif
+ //! Used to format text
+ KexiTextFormatter m_textFormatter;
+
+ //! Used for read only flag to disable editing
+ QGuardedPtr<const QValidator> m_readOnlyValidator;
+
+ //! Used to remember the previous validator used forf r/w mode, after setting the read only flag
+ QGuardedPtr<const QValidator> m_readWriteValidator;
+
+ //! Used for extending context menu
+ KexiDBWidgetContextMenuExtender m_menuExtender;
+
+ //! Used in isReadOnly, as sometimes we want to have the flag set tot true when KLineEdit::isReadOnly
+ //! is still false.
+ bool m_internalReadOnly : 1;
+
+ //! Used in slotTextChanged()
+ bool m_slotTextChanged_enabled : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbsubform.cpp b/kexi/plugins/forms/widgets/kexidbsubform.cpp
new file mode 100644
index 00000000..8d1971a9
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbsubform.cpp
@@ -0,0 +1,131 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbsubform.h"
+
+#include "kexidbform.h"
+#include "../kexiformview.h"
+#include <kexidb/utils.h>
+#include <formeditor/formIO.h>
+#include <formeditor/objecttree.h>
+#include <formeditor/utils.h>
+#include <formeditor/container.h>
+#include <formeditor/formmanager.h>
+
+KexiDBSubForm::KexiDBSubForm(KFormDesigner::Form *parentForm, QWidget *parent, const char *name)
+: QScrollView(parent, name), m_parentForm(parentForm), m_form(0), m_widget(0)
+{
+ setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+ viewport()->setPaletteBackgroundColor(colorGroup().mid());
+}
+/*
+void
+KexiDBSubForm::paintEvent(QPaintEvent *ev)
+{
+ QScrollView::paintEvent(ev);
+ QPainter p;
+
+ setWFlags(WPaintUnclipped);
+
+ QString txt("Subform");
+ QFont f = font();
+ f.setPointSize(f.pointSize() * 3);
+ QFontMetrics fm(f);
+ const int txtw = fm.width(txt), txth = fm.height();
+
+ p.begin(this, true);
+ p.setPen(black);
+ p.setFont(f);
+ p.drawText(width()/2, height()/2, txt, Qt::AlignCenter|Qt::AlignVCenter);
+ p.end();
+
+ clearWFlags( WPaintUnclipped );
+}
+*/
+void
+KexiDBSubForm::setFormName(const QString &name)
+{
+ if(m_formName==name)
+ return;
+
+ m_formName = name; //assign, even if the name points to nowhere
+
+ if(name.isEmpty()) {
+ delete m_widget;
+ m_widget = 0;
+ updateScrollBars();
+ return;
+ }
+
+ QWidget *pw = parentWidget();
+ KexiFormView *view = 0;
+ QStringList list;
+ while(pw) {
+ if(pw->isA("KexiDBSubForm")) {
+ if(list.contains(pw->name())) {
+//! @todo error message
+ return; // Be sure to don't run into a endless-loop cause of recursive subforms.
+ }
+ list.append(pw->name());
+ }
+ else if(! view && pw->isA("KexiFormView"))
+ view = static_cast<KexiFormView*>(pw); // we need a KexiFormView*
+ pw = pw->parentWidget();
+ }
+
+ if (!view || !view->parentDialog() || !view->parentDialog()->mainWin()
+ || !view->parentDialog()->mainWin()->project()->dbConnection())
+ return;
+
+ KexiDB::Connection *conn = view->parentDialog()->mainWin()->project()->dbConnection();
+
+ // we check if there is a form with this name
+ int id = KexiDB::idForObjectName(*conn, name, KexiPart::FormObjectType);
+ if((id == 0) || (id == view->parentDialog()->id())) // == our form
+ return; // because of recursion when loading
+
+ // we create the container widget
+ delete m_widget;
+ m_widget = new KexiDBFormBase(viewport(), "KexiDBSubForm_widget");
+ m_widget->show();
+ addChild(m_widget);
+ m_form = new KFormDesigner::Form(KexiFormPart::library(), this->name());
+ m_form->createToplevel(m_widget);
+
+ // and load the sub form
+ QString data;
+ tristate res = conn->loadDataBlock(id, data, QString::null);
+ if (res == true)
+ res = KFormDesigner::FormIO::loadFormFromString(m_form, m_widget, data);
+ if(res != true) {
+ delete m_widget;
+ m_widget = 0;
+ updateScrollBars();
+ m_formName = QString::null;
+ return;
+ }
+ m_form->setDesignMode(false);
+
+ // Install event filters on the whole newly created form
+ KFormDesigner::ObjectTreeItem *tree = m_parentForm->objectTree()->lookup(QObject::name());
+ KFormDesigner::installRecursiveEventFilter(this, tree->eventEater());
+}
+
+#include "kexidbsubform.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbsubform.h b/kexi/plugins/forms/widgets/kexidbsubform.h
new file mode 100644
index 00000000..5b73f860
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbsubform.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBSubForm_H
+#define KexiDBSubForm_H
+
+#include <qscrollview.h>
+#include <formeditor/form.h>
+
+//! @short A form embedded as a widget inside other form
+class KEXIFORMUTILS_EXPORT KexiDBSubForm : public QScrollView
+{
+ Q_OBJECT
+ Q_PROPERTY(QString formName READ formName WRITE setFormName DESIGNABLE true)
+
+ public:
+ KexiDBSubForm(KFormDesigner::Form *parentForm, QWidget *parent, const char *name);
+ ~KexiDBSubForm() {}
+
+ //! \return the name of the subform to display inside this widget
+ QString formName() const { return m_formName; }
+
+ //! Sets the name of the subform to display inside this widget
+ void setFormName(const QString &name);
+
+ //void paintEvent(QPaintEvent *ev);
+
+ private:
+ KFormDesigner::Form *m_parentForm;
+ KFormDesigner::Form *m_form;
+ QWidget *m_widget;
+ QString m_formName;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbtextedit.cpp b/kexi/plugins/forms/widgets/kexidbtextedit.cpp
new file mode 100644
index 00000000..8541fc01
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbtextedit.cpp
@@ -0,0 +1,209 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbtextedit.h"
+#include "kexidblineedit.h"
+#include <kexidb/queryschema.h>
+
+#include <kapplication.h>
+#include <kstdaccel.h>
+#include <kdebug.h>
+
+#include <qpainter.h>
+
+KexiDBTextEdit::KexiDBTextEdit(QWidget *parent, const char *name)
+ : KTextEdit(parent, name)
+ , KexiDBTextWidgetInterface()
+ , KexiFormDataItemInterface()
+ , m_menuExtender(this, this)
+ , m_slotTextChanged_enabled(true)
+{
+ connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));
+ installEventFilter(this);
+}
+
+KexiDBTextEdit::~KexiDBTextEdit()
+{
+}
+
+void KexiDBTextEdit::setInvalidState( const QString& displayText )
+{
+ setReadOnly(true);
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+ KTextEdit::setText(displayText);
+}
+
+void KexiDBTextEdit::setValueInternal(const QVariant& add, bool removeOld)
+{
+ if (m_columnInfo && m_columnInfo->field->type()==KexiDB::Field::Boolean) {
+//! @todo temporary solution for booleans!
+ KTextEdit::setText( add.toBool() ? "1" : "0" );
+ }
+ else {
+ if (removeOld)
+ KTextEdit::setText( add.toString() );
+ else
+ KTextEdit::setText( m_origValue.toString() + add.toString() );
+ }
+}
+
+QVariant KexiDBTextEdit::value()
+{
+ return text();
+}
+
+void KexiDBTextEdit::slotTextChanged()
+{
+ if (!m_slotTextChanged_enabled)
+ return;
+ signalValueChanged();
+}
+
+bool KexiDBTextEdit::valueIsNull()
+{
+ return text().isNull();
+}
+
+bool KexiDBTextEdit::valueIsEmpty()
+{
+ return text().isEmpty();
+}
+
+bool KexiDBTextEdit::isReadOnly() const
+{
+ return KTextEdit::isReadOnly();
+}
+
+void KexiDBTextEdit::setReadOnly( bool readOnly )
+{
+ KTextEdit::setReadOnly( readOnly );
+ QPalette p = palette();
+ QColor c(readOnly ? lighterGrayBackgroundColor(kapp->palette()) : p.color(QPalette::Normal, QColorGroup::Base));
+ setPaper( c );
+ p.setColor(QColorGroup::Base, c);
+ p.setColor(QColorGroup::Background, c);
+ setPalette( p );
+}
+
+void KexiDBTextEdit::setText( const QString & text, const QString & context )
+{
+ KTextEdit::setText(text, context);
+}
+
+QWidget* KexiDBTextEdit::widget()
+{
+ return this;
+}
+
+bool KexiDBTextEdit::cursorAtStart()
+{
+ int para, index;
+ getCursorPosition ( &para, &index );
+ return para==0 && index==0;
+}
+
+bool KexiDBTextEdit::cursorAtEnd()
+{
+ int para, index;
+ getCursorPosition ( &para, &index );
+ return (paragraphs()-1)==para && (paragraphLength(paragraphs()-1)-1)==index;
+}
+
+void KexiDBTextEdit::clear()
+{
+ setText(QString::null, QString::null);
+}
+
+void KexiDBTextEdit::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
+{
+ KexiFormDataItemInterface::setColumnInfo(cinfo);
+ if (!cinfo)
+ return;
+ KexiDBTextWidgetInterface::setColumnInfo(m_columnInfo, this);
+}
+
+void KexiDBTextEdit::paintEvent ( QPaintEvent *pe )
+{
+ KTextEdit::paintEvent( pe );
+ QPainter p(this);
+ KexiDBTextWidgetInterface::paint( this, &p, text().isEmpty(), alignment(), hasFocus() );
+}
+
+QPopupMenu * KexiDBTextEdit::createPopupMenu(const QPoint & pos)
+{
+ QPopupMenu *contextMenu = KTextEdit::createPopupMenu(pos);
+ m_menuExtender.createTitle(contextMenu);
+ return contextMenu;
+}
+
+void KexiDBTextEdit::undo()
+{
+ cancelEditor();
+}
+
+void KexiDBTextEdit::setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue)
+{
+ KexiFormDataItemInterface::setDisplayDefaultValue(widget, displayDefaultValue);
+ // initialize display parameters for default / entered value
+ KexiDisplayUtils::DisplayParameters * const params
+ = displayDefaultValue ? m_displayParametersForDefaultValue : m_displayParametersForEnteredValue;
+ QPalette pal(palette());
+ pal.setColor(QPalette::Active, QColorGroup::Text, params->textColor);
+ setPalette(pal);
+ setFont(params->font);
+//! @todo support rich text...
+/* m_slotTextChanged_enabled = false;
+ //for rich text...
+ const QString origText( text() );
+ KTextEdit::setText(QString::null);
+ setCurrentFont(params->font);
+ setColor(params->textColor);
+ KTextEdit::setText(origText);
+ m_slotTextChanged_enabled = true;*/
+}
+
+void KexiDBTextEdit::moveCursorToEnd()
+{
+ KTextEdit::setCursorPosition(paragraphs()-1, paragraphLength( paragraphs()-1 ));
+}
+
+void KexiDBTextEdit::moveCursorToStart()
+{
+ KTextEdit::setCursorPosition(0 /*para*/, 0 /*index*/);
+}
+
+void KexiDBTextEdit::selectAll()
+{
+ KTextEdit::selectAll();
+}
+
+void KexiDBTextEdit::keyPressEvent( QKeyEvent *ke )
+{
+ // for instance, Windows uses Ctrl+Tab for moving between tabs, so do not steal this shortcut
+ if (KStdAccel::tabNext().contains( KKey(ke) ) || KStdAccel::tabPrev().contains( KKey(ke) )) {
+ ke->ignore();
+ return;
+ }
+ KTextEdit::keyPressEvent(ke);
+}
+
+#include "kexidbtextedit.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbtextedit.h b/kexi/plugins/forms/widgets/kexidbtextedit.h
new file mode 100644
index 00000000..a380b070
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbtextedit.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-2007 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 KexiDBTextEdit_H
+#define KexiDBTextEdit_H
+
+#include "kexiformdataiteminterface.h"
+#include "kexidbtextwidgetinterface.h"
+#include "kexidbutils.h"
+#include <ktextedit.h>
+
+//! @short Multiline edit widget for Kexi forms
+class KEXIFORMUTILS_EXPORT KexiDBTextEdit :
+ public KTextEdit,
+ protected KexiDBTextWidgetInterface,
+ public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+
+ public:
+ KexiDBTextEdit(QWidget *parent, const char *name=0);
+ virtual ~KexiDBTextEdit();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setColumnInfo(KexiDB::QueryColumnInfo* cinfo);
+
+ /*! If \a displayDefaultValue is true, the value set by KexiDataItemInterface::setValue()
+ is displayed in a special way. Used by KexiFormDataProvider::fillDataItems().
+ \a widget is equal to 'this'.
+ Reimplemented after KexiFormDataItemInterface. */
+ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue);
+
+ //! Windows uses Ctrl+Tab for moving between tabs, so do not steal this shortcut
+ virtual void keyPressEvent( QKeyEvent *ke );
+
+ public slots:
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ virtual void setReadOnly( bool readOnly );
+ virtual void setText( const QString & text, const QString & context );
+
+ //! Reimplemented, so "undo" means the same as "cancelEditor" action
+//! @todo enable "real" undo internally so user can use ctrl+z while editing
+ virtual void undo();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void moveCursorToEnd();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void moveCursorToStart();
+
+ //! Implemented for KexiDataItemInterface
+ virtual void selectAll();
+
+ protected slots:
+ void slotTextChanged();
+
+ protected:
+ virtual void paintEvent ( QPaintEvent * );
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+ QPopupMenu * createPopupMenu(const QPoint & pos);
+
+ //! Used for extending context menu
+ KexiDBWidgetContextMenuExtender m_menuExtender;
+
+ //! Used to disable slotTextChanged()
+ bool m_slotTextChanged_enabled : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbtimeedit.cpp b/kexi/plugins/forms/widgets/kexidbtimeedit.cpp
new file mode 100644
index 00000000..82e61b83
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbtimeedit.cpp
@@ -0,0 +1,156 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexidbtimeedit.h"
+
+#include <qtoolbutton.h>
+#include <qlayout.h>
+#include <qpainter.h>
+
+#include <kpopupmenu.h>
+#include <kdatepicker.h>
+#include <kdatetbl.h>
+#include <kexiutils/utils.h>
+
+KexiDBTimeEdit::KexiDBTimeEdit(const QTime &time, QWidget *parent, const char *name)
+ : QTimeEdit(time, parent, name), KexiFormDataItemInterface()
+{
+ m_invalidState = false;
+ setAutoAdvance(true);
+ m_cleared = false;
+
+#ifdef QDateTimeEditor_HACK
+ m_dte_time = KexiUtils::findFirstChild<QDateTimeEditor>(this, "QDateTimeEditor");
+#else
+ m_dte_time = 0;
+#endif
+
+ connect(this, SIGNAL(valueChanged(const QTime&)), this, SLOT(slotValueChanged(const QTime&)));
+}
+
+KexiDBTimeEdit::~KexiDBTimeEdit()
+{
+}
+
+void KexiDBTimeEdit::setInvalidState( const QString&)
+{
+ setEnabled(false);
+ setReadOnly(true);
+ m_invalidState = true;
+//! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
+ if (focusPolicy() & TabFocus)
+ setFocusPolicy(QWidget::ClickFocus);
+}
+
+void
+KexiDBTimeEdit::setEnabled(bool enabled)
+{
+ // prevent the user from reenabling the widget when it is in invalid state
+ if(enabled && m_invalidState)
+ return;
+ QTimeEdit::setEnabled(enabled);
+}
+
+void KexiDBTimeEdit::setValueInternal(const QVariant &add, bool removeOld)
+{
+ m_cleared = !m_origValue.isValid();
+
+ int setNumberOnFocus = -1;
+ QTime t;
+ QString addString(add.toString());
+ if (removeOld) {
+ if (!addString.isEmpty() && addString[0].latin1()>='0' && addString[0].latin1() <='9') {
+ setNumberOnFocus = addString[0].latin1()-'0';
+ t = QTime(setNumberOnFocus, 0, 0);
+ }
+ }
+ else
+ t = m_origValue.toTime();
+
+ setTime(t);
+}
+
+QVariant
+KexiDBTimeEdit::value()
+{
+ //QDateTime - a hack needed because QVariant(QTime) has broken isNull()
+ return QVariant(QDateTime( m_cleared ? QDate() : QDate(0,1,2)/*nevermind*/, time()));
+}
+
+bool KexiDBTimeEdit::valueIsNull()
+{
+ return !time().isValid() || time().isNull();
+}
+
+bool KexiDBTimeEdit::valueIsEmpty()
+{
+ return m_cleared;
+}
+
+bool KexiDBTimeEdit::isReadOnly() const
+{
+ //! @todo: data/time edit API has no readonly flag,
+ //! so use event filter to avoid changes made by keyboard or mouse when m_readOnly==true
+ return m_readOnly; //!isEnabled();
+}
+
+void KexiDBTimeEdit::setReadOnly(bool set)
+{
+ m_readOnly = set;
+}
+
+QWidget*
+KexiDBTimeEdit::widget()
+{
+ return this;
+}
+
+bool KexiDBTimeEdit::cursorAtStart()
+{
+#ifdef QDateTimeEditor_HACK
+ return m_dte_time && hasFocus() && m_dte_time->focusSection()==0;
+#else
+ return false;
+#endif
+}
+
+bool KexiDBTimeEdit::cursorAtEnd()
+{
+#ifdef QDateTimeEditor_HACK
+ return m_dte_time && hasFocus()
+ && m_dte_time->focusSection()==int(m_dte_time->sectionCount()-1);
+#else
+ return false;
+#endif
+}
+
+void KexiDBTimeEdit::clear()
+{
+ setTime(QTime());
+ m_cleared = true;
+}
+
+void
+KexiDBTimeEdit::slotValueChanged(const QTime&)
+{
+ m_cleared = false;
+}
+
+#include "kexidbtimeedit.moc"
diff --git a/kexi/plugins/forms/widgets/kexidbtimeedit.h b/kexi/plugins/forms/widgets/kexidbtimeedit.h
new file mode 100644
index 00000000..9665b1f9
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbtimeedit.h
@@ -0,0 +1,87 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiDBTimeEdit_H
+#define KexiDBTimeEdit_H
+
+#include "kexiformdataiteminterface.h"
+#include "kexidbtextwidgetinterface.h"
+#include <qdatetimeedit.h>
+
+class QDateTimeEditor;
+
+//! @short A db-aware time editor
+class KEXIFORMUTILS_EXPORT KexiDBTimeEdit : public QTimeEdit, public KexiFormDataItemInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource DESIGNABLE true)
+ Q_PROPERTY(QCString dataSourceMimeType READ dataSourceMimeType WRITE setDataSourceMimeType DESIGNABLE true)
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true )
+
+ public:
+ KexiDBTimeEdit(const QTime &time, QWidget *parent, const char *name=0);
+ virtual ~KexiDBTimeEdit();
+
+ inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); }
+ inline QCString dataSourceMimeType() const { return KexiFormDataItemInterface::dataSourceMimeType(); }
+ virtual QVariant value();
+ virtual void setInvalidState( const QString& displayText );
+
+ //! \return true if editor's value is null (not empty)
+ //! Used for checking if a given constraint within table of form is met.
+ virtual bool valueIsNull();
+
+ //! \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 or form is met.
+ virtual bool valueIsEmpty();
+
+ /*! \return 'readOnly' flag for this widget. */
+ virtual bool isReadOnly() const;
+
+ /*! \return the view widget of this item, e.g. line edit widget. */
+ virtual QWidget* widget();
+
+ virtual bool cursorAtStart();
+ virtual bool cursorAtEnd();
+ virtual void clear();
+
+ virtual void setEnabled(bool enabled);
+
+ public slots:
+ inline void setDataSource(const QString &ds) { KexiFormDataItemInterface::setDataSource(ds); }
+ inline void setDataSourceMimeType(const QCString &ds) { KexiFormDataItemInterface::setDataSourceMimeType(ds); }
+ virtual void setReadOnly(bool set);
+
+ protected slots:
+ void slotValueChanged(const QTime&);
+
+ protected:
+ virtual void setValueInternal(const QVariant& add, bool removeOld);
+
+ private:
+ QDateTimeEditor* m_dte_time;
+ bool m_invalidState : 1;
+ bool m_cleared : 1;
+ bool m_readOnly : 1;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexidbutils.cpp b/kexi/plugins/forms/widgets/kexidbutils.cpp
new file mode 100644
index 00000000..0c08d64c
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbutils.cpp
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-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 "kexidbutils.h"
+
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+
+#include <kexidb/queryschema.h>
+#include <kexidb/utils.h>
+#include <formeditor/widgetlibrary.h>
+#include <kexiutils/utils.h>
+#include "../kexiformpart.h"
+#include <widget/utils/kexicontextmenuutils.h>
+
+
+QColor lighterGrayBackgroundColor(const QPalette& palette)
+{
+ return KexiUtils::blendedColors(palette.active().background(), palette.active().base(), 1, 2);
+}
+
+//-------
+
+KexiDBWidgetContextMenuExtender::KexiDBWidgetContextMenuExtender( QObject* parent, KexiDataItemInterface* iface )
+ : QObject(parent)
+ , m_iface(iface)
+ , m_contextMenuHasTitle(false)
+{
+}
+
+KexiDBWidgetContextMenuExtender::~KexiDBWidgetContextMenuExtender()
+{
+}
+
+void KexiDBWidgetContextMenuExtender::createTitle(QPopupMenu *menu)
+{
+ if (!menu)
+ return;
+ m_contextMenu = menu;
+ KPopupTitle *titleItem = new KPopupTitle();
+ const int id = m_contextMenu->insertItem(titleItem, -1, 0);
+ m_contextMenu->setItemEnabled(id, false);
+ QString icon;
+ if (dynamic_cast<QWidget*>(m_iface))
+ icon = KexiFormPart::library()->iconName(dynamic_cast<QWidget*>(m_iface)->className());
+
+ m_contextMenuHasTitle = m_iface->columnInfo() ?
+ KexiContextMenuUtils::updateTitle(m_contextMenu,
+ m_iface->columnInfo()->captionOrAliasOrName(),
+ KexiDB::simplifiedTypeName(*m_iface->columnInfo()->field), icon)
+ : false;
+
+ if (!m_contextMenuHasTitle)
+ m_contextMenu->removeItem(id);
+ updatePopupMenuActions();
+}
+
+void KexiDBWidgetContextMenuExtender::updatePopupMenuActions()
+{
+ if (m_contextMenu) {
+ enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll }; //from qlineedit.h
+ const bool readOnly = m_iface->isReadOnly();
+ const int id = m_contextMenu->idAt(m_contextMenuHasTitle ? 1 : 0);
+
+//! @todo maybe redo will be enabled one day?
+ m_contextMenu->removeItem(id-(int)IdRedo);
+
+ // update cut/copy/paste
+ m_contextMenu->setItemEnabled(id-(int)IdCut, !readOnly);
+ m_contextMenu->setItemEnabled(id-(int)IdPaste, !readOnly);
+ m_contextMenu->setItemEnabled(id-(int)IdClear, !readOnly);
+ }
+}
+
+//------------------
+
+KexiSubwidgetInterface::KexiSubwidgetInterface()
+{
+}
+
+KexiSubwidgetInterface::~KexiSubwidgetInterface()
+{
+}
diff --git a/kexi/plugins/forms/widgets/kexidbutils.h b/kexi/plugins/forms/widgets/kexidbutils.h
new file mode 100644
index 00000000..386f1ee5
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexidbutils.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-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 KDBWIDGETS_UTILS_H
+#define KDBWIDGETS_UTILS_H
+
+#include <qpopupmenu.h>
+#include <kexidataiteminterface.h>
+
+QColor lighterGrayBackgroundColor(const QPalette& palette);
+
+//! @short Used for extending editor widgets' context menu.
+/*! @internal This is performed by adding a title and disabling editing
+ actions when "read only" flag is true. */
+class KexiDBWidgetContextMenuExtender : public QObject
+{
+ public:
+ KexiDBWidgetContextMenuExtender( QObject* parent, KexiDataItemInterface* iface );
+ ~KexiDBWidgetContextMenuExtender();
+
+ //! Creates title for context menu \a menu
+ void createTitle(QPopupMenu *menu);
+
+ //! Enables or disables context menu actions that can modify the value.
+ //! The menu has to be previously provided by createTitle().
+ void updatePopupMenuActions();
+
+ /*! Updates title for context menu based on data item \a iface caption or name
+ Used in createTitle(QPopupMenu *menu) and KexiDBImageBox.
+ \return true is the title has been added. */
+ static bool updateContextMenuTitleForDataItem(QPopupMenu *menu, KexiDataItemInterface* iface,
+ const QString& icon = QString::null);
+
+ protected:
+ KexiDataItemInterface* m_iface;
+ QGuardedPtr<QPopupMenu> m_contextMenu;
+ bool m_contextMenuHasTitle; //!< true if KPopupTitle has been added to the context menu.
+};
+
+class KexiDBAutoField;
+
+//! An interface allowing to define custom behaviour for subwidget of the KexiDBAutoField
+class KexiSubwidgetInterface
+{
+ public:
+ KexiSubwidgetInterface();
+ virtual ~KexiSubwidgetInterface();
+
+ virtual bool appendStretchRequired(KexiDBAutoField* autoField) const
+ { Q_UNUSED(autoField); return false; }
+ virtual bool subwidgetStretchRequired(KexiDBAutoField* autoField) const
+ { Q_UNUSED(autoField); return false; }
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexiframe.cpp b/kexi/plugins/forms/widgets/kexiframe.cpp
new file mode 100644
index 00000000..b49386da
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexiframe.cpp
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 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 "kexiframe.h"
+
+#include <qpainter.h>
+#include <qdrawutil.h>
+#include <kexiutils/utils.h>
+
+//! @internal
+class KexiFrame::Private
+{
+ public:
+ Private()
+ {
+ }
+ ~Private()
+ {
+ }
+ QColor frameColor;
+#if 0
+//todo
+ KexiFrame::Shape frameShape;
+ KexiFrame::Shadow frameShadow;
+#endif
+};
+
+//=========================================================
+
+KexiFrame::KexiFrame( QWidget * parent, const char * name, WFlags f )
+ : QFrame(parent, name, f)
+ , d( new Private() )
+{
+ //defaults
+ d->frameColor = palette().active().foreground();
+//! @todo obtain these defaults from current template's style...
+ setLineWidth(2);
+ setFrameStyle(QFrame::StyledPanel|QFrame::Raised);
+}
+
+KexiFrame::~KexiFrame()
+{
+ delete d;
+}
+
+void KexiFrame::dragMoveEvent( QDragMoveEvent *e )
+{
+ QFrame::dragMoveEvent(e);
+ emit handleDragMoveEvent(e);
+}
+
+void KexiFrame::dropEvent( QDropEvent *e )
+{
+ QFrame::dropEvent(e);
+ emit handleDropEvent(e);
+}
+
+#define ClassName KexiFrame
+#define SuperClassName QFrame
+#include "kexiframeutils_p.cpp"
+#include "kexiframe.moc"
diff --git a/kexi/plugins/forms/widgets/kexiframe.h b/kexi/plugins/forms/widgets/kexiframe.h
new file mode 100644
index 00000000..8d60d597
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexiframe.h
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 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 KexiFrame_H
+#define KexiFrame_H
+
+#include <qframe.h>
+
+//! @short Frame widget for Kexi forms
+class KEXIFORMUTILS_EXPORT KexiFrame : public QFrame
+{
+ Q_OBJECT
+//todo Q_ENUMS( Shape Shadow )
+ Q_PROPERTY( QColor frameColor READ frameColor WRITE setFrameColor DESIGNABLE true )
+//todo Q_OVERRIDE( Shape frameShape READ frameShape WRITE setFrameShape )
+//todo Q_OVERRIDE( Shadow frameShadow READ frameShadow WRITE setFrameShadow )
+
+ public:
+ KexiFrame( QWidget * parent, const char * name = 0, WFlags f = 0 );
+ virtual ~KexiFrame();
+
+ virtual const QColor& frameColor() const;
+
+#if 0
+//! @todo more options
+ enum Shadow {
+ NoShadow = QFrame::Plain,
+ Raised = QFrame::Raised,
+ Sunken = QFrame::Sunken
+ };
+//! @todo more options
+ enum Shape { NoFrame = QFrame::NoFrame, //!< no frame
+ Box = QFrame::Box, //!< rectangular box
+ Panel = QFrame::Panel, //!< rectangular panel
+ StyledPanel = QFrame::StyledPanel, //!< rectangular panel depending on the GUI style
+ GroupBoxPanel = QFrame::GroupBoxPanel //!< rectangular group-box-like panel depending on the GUI style
+ };
+ Shape frameShape() const;
+ void setFrameShape( KexiFrame::Shape shape );
+ Shadow frameShadow() const;
+ void setFrameShadow( KexiFrame::Shadow shadow );
+#endif
+
+ //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface
+ virtual void dragMoveEvent( QDragMoveEvent *e );
+
+ //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface
+ virtual void dropEvent( QDropEvent *e );
+
+ public slots:
+ virtual void setPalette( const QPalette &pal );
+ virtual void setFrameColor(const QColor& color);
+
+ signals:
+ //! Needed to control dragging over the container's surface
+ void handleDragMoveEvent(QDragMoveEvent *e);
+
+ //! Needed to control dropping on the container's surface
+ void handleDropEvent(QDropEvent *e);
+
+ protected:
+ virtual void drawFrame( QPainter * );
+
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexiframeutils_p.cpp b/kexi/plugins/forms/widgets/kexiframeutils_p.cpp
new file mode 100644
index 00000000..11b8650a
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexiframeutils_p.cpp
@@ -0,0 +1,232 @@
+/* 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.
+*/
+
+/* This file is included by KexiDBLabel and KexiFrame */
+
+//! @todo add more frame types
+void ClassName::drawFrame( QPainter *p )
+{
+ if (frameShape() == QFrame::Box) {
+ if ( frameShadow() == Plain )
+ qDrawPlainRect( p, frameRect(), d->frameColor, lineWidth() );
+ else
+ qDrawShadeRect( p, frameRect(), colorGroup(), frameShadow() == QFrame::Sunken,
+ lineWidth(), midLineWidth() );
+ }
+ else {
+ SuperClassName::drawFrame(p);
+ }
+}
+
+void ClassName::setPalette( const QPalette &pal )
+{
+ QPalette pal2(pal);
+ QColorGroup cg( pal2.active() );
+ cg.setColor(QColorGroup::Light, KexiUtils::bleachedColor( d->frameColor, 150 ));
+ cg.setColor(QColorGroup::Mid, d->frameColor);
+ cg.setColor(QColorGroup::Dark, d->frameColor.dark(150));
+ pal2.setActive(cg);
+ QColorGroup cg2( pal2.inactive() );
+ cg2.setColor(QColorGroup::Light, cg.light() );
+ cg2.setColor(QColorGroup::Mid, cg.mid());
+ cg2.setColor(QColorGroup::Dark, cg.dark());
+ pal2.setInactive(cg2);
+ SuperClassName::setPalette(pal2);
+}
+
+const QColor& ClassName::frameColor() const
+{
+ return d->frameColor;
+}
+
+void ClassName::setFrameColor(const QColor& color)
+{
+ d->frameColor = color;
+ //update light and dark colors
+ setPalette( palette() );
+}
+
+#if 0
+//todo
+ClassName::Shape ClassName::frameShape() const
+{
+ return d->frameShape;
+}
+
+void ClassName::setFrameShape( ClassName::Shape shape )
+{
+ d->frameShape = shape;
+ update();
+}
+
+ClassName::Shadow ClassName::frameShadow() const
+{
+ return d->frameShadow;
+}
+
+void ClassName::setFrameShadow( ClassName::Shadow shadow )
+{
+ d->frameShadow = shadow;
+ update();
+}
+#endif
+
+#if 0
+void QFrame::drawFrame( QPainter *p )
+{
+ QPoint p1, p2;
+ QRect r = frameRect();
+ int type = fstyle & MShape;
+ int cstyle = fstyle & MShadow;
+#ifdef QT_NO_DRAWUTIL
+ p->setPen( black ); // ####
+ p->drawRect( r ); //### a bit too simple
+#else
+ const QColorGroup & g = colorGroup();
+
+#ifndef QT_NO_STYLE
+ QStyleOption opt(lineWidth(),midLineWidth());
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (cstyle == Sunken)
+ flags |= QStyle::Style_Sunken;
+ else if (cstyle == Raised)
+ flags |= QStyle::Style_Raised;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (hasMouse())
+ flags |= QStyle::Style_MouseOver;
+#endif // QT_NO_STYLE
+
+ switch ( type ) {
+
+ case Box:
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ qDrawShadeRect( p, r, g, cstyle == Sunken, lwidth,
+ midLineWidth() );
+ break;
+
+ case LineEditPanel:
+ style().drawPrimitive( QStyle::PE_PanelLineEdit, p, r, g, flags, opt );
+ break;
+
+ case GroupBoxPanel:
+ style().drawPrimitive( QStyle::PE_PanelGroupBox, p, r, g, flags, opt );
+ break;
+
+ case TabWidgetPanel:
+ style().drawPrimitive( QStyle::PE_PanelTabWidget, p, r, g, flags, opt );
+ break;
+
+ case MenuBarPanel:
+#ifndef QT_NO_STYLE
+ style().drawPrimitive(QStyle::PE_PanelMenuBar, p, r, g, flags, opt);
+ break;
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case ToolBarPanel:
+#ifndef QT_NO_STYLE
+ style().drawPrimitive( QStyle::PE_PanelDockWindow, p, rect(), g, flags, opt);
+ break;
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case StyledPanel:
+#ifndef QT_NO_STYLE
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ style().drawPrimitive(QStyle::PE_Panel, p, r, g, flags, opt);
+ break;
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case PopupPanel:
+#ifndef QT_NO_STYLE
+ {
+ int vextra = style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this),
+ hextra = style().pixelMetric(QStyle::PM_PopupMenuFrameHorizontalExtra, this);
+ if(vextra > 0 || hextra > 0) {
+ QRect fr = frameRect();
+ int fw = frameWidth();
+ if(vextra > 0) {
+ style().drawControl(QStyle::CE_PopupMenuVerticalExtra, p, this,
+ QRect(fr.x() + fw, fr.y() + fw, fr.width() - (fw*2), vextra),
+ g, flags, opt);
+ style().drawControl(QStyle::CE_PopupMenuVerticalExtra, p, this,
+ QRect(fr.x() + fw, fr.bottom() - fw - vextra, fr.width() - (fw*2), vextra),
+ g, flags, opt);
+ }
+ if(hextra > 0) {
+ style().drawControl(QStyle::CE_PopupMenuHorizontalExtra, p, this,
+ QRect(fr.x() + fw, fr.y() + fw + vextra, hextra, fr.height() - (fw*2) - vextra),
+ g, flags, opt);
+ style().drawControl(QStyle::CE_PopupMenuHorizontalExtra, p, this,
+ QRect(fr.right() - fw - hextra, fr.y() + fw + vextra, hextra, fr.height() - (fw*2) - vextra),
+ g, flags, opt);
+ }
+ }
+
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ style().drawPrimitive(QStyle::PE_PanelPopup, p, r, g, flags, opt);
+ break;
+ }
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case Panel:
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ qDrawShadePanel( p, r, g, cstyle == Sunken, lwidth );
+ break;
+
+ case WinPanel:
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), wpwidth );
+ else
+ qDrawWinPanel( p, r, g, cstyle == Sunken );
+ break;
+ case HLine:
+ case VLine:
+ if ( type == HLine ) {
+ p1 = QPoint( r.x(), r.height()/2 );
+ p2 = QPoint( r.x()+r.width(), p1.y() );
+ }
+ else {
+ p1 = QPoint( r.x()+r.width()/2, 0 );
+ p2 = QPoint( p1.x(), r.height() );
+ }
+ if ( cstyle == Plain ) {
+ QPen oldPen = p->pen();
+ p->setPen( QPen(g.foreground(),lwidth) );
+ p->drawLine( p1, p2 );
+ p->setPen( oldPen );
+ }
+ else
+ qDrawShadeLine( p, p1, p2, g, cstyle == Sunken,
+ lwidth, midLineWidth() );
+ break;
+ }
+#endif // QT_NO_DRAWUTIL
+
+#endif
diff --git a/kexi/plugins/forms/widgets/kexipushbutton.cpp b/kexi/plugins/forms/widgets/kexipushbutton.cpp
new file mode 100644
index 00000000..acfda0a4
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexipushbutton.cpp
@@ -0,0 +1,32 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 "kexipushbutton.h"
+
+KexiPushButton::KexiPushButton( const QString & text, QWidget * parent, const char * name )
+: KPushButton(text, parent, name)
+{
+}
+
+KexiPushButton::~KexiPushButton()
+{
+}
+
+#include "kexipushbutton.moc"
diff --git a/kexi/plugins/forms/widgets/kexipushbutton.h b/kexi/plugins/forms/widgets/kexipushbutton.h
new file mode 100644
index 00000000..12c01631
--- /dev/null
+++ b/kexi/plugins/forms/widgets/kexipushbutton.h
@@ -0,0 +1,55 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
+ Copyright (C) 2004-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 KexiPushButton_H
+#define KexiPushButton_H
+
+#include <kpushbutton.h>
+#include "../kexiformeventhandler.h"
+
+//! @short Push Button widget for Kexi forms
+class KEXIFORMUTILS_EXPORT KexiPushButton : public KPushButton
+{
+ Q_OBJECT
+ Q_PROPERTY(QString onClickAction READ onClickAction WRITE setOnClickAction DESIGNABLE true)
+ Q_PROPERTY(QString onClickActionOption READ onClickActionOption WRITE setOnClickActionOption DESIGNABLE true)
+
+ public:
+ KexiPushButton( const QString & text, QWidget * parent, const char * name = 0 );
+ ~KexiPushButton();
+
+ public slots:
+ //! action string for "on click" event
+ //! @see KexiFormPart::slotAssignAction()
+ //! @see KexiFormEventAction::ActionData
+ QString onClickAction() const { return m_onClickActionData.string; }
+ void setOnClickAction(const QString& actionString) { m_onClickActionData.string = actionString; }
+
+ //! action option allowing to select whether the object should be opened in data view mode or printed, etc.
+ //! @see KexiFormPart::slotAssignAction()
+ //! @see KexiFormEventAction::ActionData
+ QString onClickActionOption() const { return m_onClickActionData.option; }
+ void setOnClickActionOption(const QString& option) { m_onClickActionData.option = option; }
+
+ protected:
+ KexiFormEventAction::ActionData m_onClickActionData;
+};
+
+#endif