summaryrefslogtreecommitdiffstats
path: root/kexi/plugins/forms/widgets
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/widgets
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/widgets')
-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
36 files changed, 7945 insertions, 0 deletions
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