summaryrefslogtreecommitdiffstats
path: root/kexi/plugins/forms/kexidataprovider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kexi/plugins/forms/kexidataprovider.cpp')
-rw-r--r--kexi/plugins/forms/kexidataprovider.cpp315
1 files changed, 315 insertions, 0 deletions
diff --git a/kexi/plugins/forms/kexidataprovider.cpp b/kexi/plugins/forms/kexidataprovider.cpp
new file mode 100644
index 00000000..6706f838
--- /dev/null
+++ b/kexi/plugins/forms/kexidataprovider.cpp
@@ -0,0 +1,315 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Jaroslaw Staniek <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "kexidataprovider.h"
+
+#include <qwidget.h>
+#include <qobjectlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <widget/tableview/kexitableitem.h>
+#include <widget/tableview/kexitableviewdata.h>
+#include <widget/tableview/kexicomboboxbase.h>
+#include <kexidb/queryschema.h>
+#include <kexiutils/utils.h>
+
+#include "widgets/kexidbform.h"
+
+KexiFormDataProvider::KexiFormDataProvider()
+ : KexiDataItemChangesListener()
+ , m_mainWidget(0)
+ , m_duplicatedItems(0)
+ , m_disableFillDuplicatedDataItems(false)
+{
+}
+
+KexiFormDataProvider::~KexiFormDataProvider()
+{
+ delete m_duplicatedItems;
+}
+
+void KexiFormDataProvider::setMainDataSourceWidget(QWidget* mainWidget)
+{
+ m_mainWidget = mainWidget;
+ m_dataItems.clear();
+ m_usedDataSources.clear();
+ m_fieldNumbersForDataItems.clear();
+ if (!m_mainWidget)
+ return;
+
+ //find widgets whose will work as data items
+ QObjectList *l = m_mainWidget->queryList( "QWidget" );
+ QObjectListIt it( *l );
+ QObject *obj;
+ QDict<char> tmpSources;
+ for ( ; (obj = it.current()) != 0; ++it ) {
+ KexiFormDataItemInterface* const formDataItem = dynamic_cast<KexiFormDataItemInterface*>(obj);
+ if (!formDataItem)
+ continue;
+ if (formDataItem->parentInterface()) //item with parent interface: collect parent instead...
+ continue;
+#if 0 //! @todo reenable when subform is moved to KexiDBForm
+ KexiDBForm *dbForm = KexiUtils::findParent<KexiDBForm>(obj, "KexiDBForm"); //form's surface...
+ if (dbForm!=m_mainWidget) //only set data for this form's data items
+ continue;
+#else
+ //tmp: reject widgets within subforms
+ if (KexiUtils::findParent<KexiDBForm>(obj, "KexiDBSubForm"))
+ continue;
+#endif
+ QString dataSource( formDataItem->dataSource().lower() );
+ if (dataSource.isEmpty())
+ continue;
+ kexipluginsdbg << obj->name() << endl;
+ m_dataItems.append( formDataItem );
+ formDataItem->installListener( this );
+ tmpSources.replace( dataSource, (char*)1 );
+ }
+ delete l;
+ //now we've got a set (unique list) of field names in tmpSources
+ //remember it in m_usedDataSources
+ for (QDictIterator<char> it(tmpSources); it.current(); ++it) {
+ m_usedDataSources += it.currentKey();
+ }
+}
+
+void KexiFormDataProvider::fillDataItems(KexiTableItem& row, bool cursorAtNewRow)
+{
+ kexipluginsdbg << "KexiFormDataProvider::fillDataItems() cnt=" << row.count() << endl;
+ for (KexiFormDataItemInterfaceToIntMap::ConstIterator it = m_fieldNumbersForDataItems.constBegin();
+ it!=m_fieldNumbersForDataItems.constEnd(); ++it)
+ {
+ KexiFormDataItemInterface *itemIface = it.key();
+ if (!itemIface->columnInfo()) {
+ kexipluginsdbg << "KexiFormDataProvider::fillDataItems(): itemIface->columnInfo() == 0" << endl;
+ continue;
+ }
+ //1. Is this a value with a combo box (lookup)?
+ int indexForVisibleLookupValue = itemIface->columnInfo()->indexForVisibleLookupValue();
+ if (indexForVisibleLookupValue<0 && indexForVisibleLookupValue>=(int)row.count()) //sanity
+ indexForVisibleLookupValue = -1; //no
+ const QVariant value(row.at(it.data()));
+ QVariant visibleLookupValue;
+ if (indexForVisibleLookupValue!=-1 && (int)row.size()>indexForVisibleLookupValue)
+ visibleLookupValue = row.at(indexForVisibleLookupValue);
+ kexipluginsdbg << "fill data of '" << itemIface->dataSource() << "' at idx=" << it.data()
+ << " data=" << value << (indexForVisibleLookupValue!=-1
+ ? QString(" SPECIAL: indexForVisibleLookupValue=%1 visibleValue=%2")
+ .arg(indexForVisibleLookupValue).arg(visibleLookupValue.toString())
+ : QString::null)
+ << endl;
+ const bool displayDefaultValue = cursorAtNewRow && (value.isNull() && visibleLookupValue.isNull())
+ && !itemIface->columnInfo()->field->defaultValue().isNull()
+ && !itemIface->columnInfo()->field->isAutoIncrement(); //no value to set but there is default value defined
+ itemIface->setValue(
+ displayDefaultValue ? itemIface->columnInfo()->field->defaultValue() : value,
+ QVariant(), /*add*/
+ /*!remove old*/false,
+ indexForVisibleLookupValue==-1 ? 0 : &visibleLookupValue //pass visible value if available
+ );
+ // now disable/enable "display default value" if needed (do it after setValue(), before setValue() turns it off)
+ if (itemIface->hasDisplayedDefaultValue() != displayDefaultValue)
+ itemIface->setDisplayDefaultValue( dynamic_cast<QWidget*>(itemIface), displayDefaultValue );
+ }
+}
+
+void KexiFormDataProvider::fillDuplicatedDataItems(
+ KexiFormDataItemInterface* item, const QVariant& value)
+{
+ if (m_disableFillDuplicatedDataItems)
+ return;
+ if (!m_duplicatedItems) {
+ //build (once) a set of duplicated data items (having the same fields assigned)
+ //so we can later check if an item is duplicated with a cost of o(1)
+ QMap<KexiDB::Field*,int> tmpDuplicatedItems;
+ QMapIterator<KexiDB::Field*,int> it_dup;
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ if (!it.current()->columnInfo() || !it.current()->columnInfo()->field)
+ continue;
+ kdDebug() << " ** " << it.current()->columnInfo()->field->name() << endl;
+ it_dup = tmpDuplicatedItems.find( it.current()->columnInfo()->field );
+ uint count;
+ if (it_dup==tmpDuplicatedItems.end())
+ count = 0;
+ else
+ count = it_dup.data();
+ tmpDuplicatedItems.insert( it.current()->columnInfo()->field, ++count );
+ }
+ m_duplicatedItems = new QPtrDict<char>(101);
+ for (it_dup = tmpDuplicatedItems.begin(); it_dup!=tmpDuplicatedItems.end(); ++it_dup) {
+ if (it_dup.data() > 1) {
+ m_duplicatedItems->insert( it_dup.key(), (char*)1 );
+ kexipluginsdbg << "duplicated item: " << static_cast<KexiDB::Field*>(it_dup.key())->name()
+ << " (" << it_dup.data() << " times)" << endl;
+ }
+ }
+ }
+ if (item->columnInfo() && m_duplicatedItems->find( item->columnInfo()->field )) {
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ if (it.current()!=item && item->columnInfo()->field == it.current()->columnInfo()->field) {
+ kexipluginsdbg << "- setting a copy of value for item '"
+ << dynamic_cast<QObject*>(it.current())->name() << "' == " << value << endl;
+ it.current()->setValue( value );
+ }
+ }
+ }
+}
+
+void KexiFormDataProvider::valueChanged(KexiDataItemInterface* item)
+{
+ Q_UNUSED( item );
+}
+
+bool KexiFormDataProvider::cursorAtNewRow() const
+{
+ return false;
+}
+
+void KexiFormDataProvider::invalidateDataSources( const QDict<char>& invalidSources,
+ KexiDB::QuerySchema* query)
+{
+ //fill m_fieldNumbersForDataItems mapping from data item to field number
+ //(needed for fillDataItems)
+ KexiDB::QueryColumnInfo::Vector fieldsExpanded;
+// uint dataFieldsCount; // == fieldsExpanded.count() if query is available or else == m_dataItems.count()
+
+ if (query) {
+ fieldsExpanded = query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields );
+// dataFieldsCount = fieldsExpanded.count();
+ QMap<KexiDB::QueryColumnInfo*,int> columnsOrder( query->columnsOrder() );
+ for (QMapConstIterator<KexiDB::QueryColumnInfo*,int> it = columnsOrder.constBegin(); it!=columnsOrder.constEnd(); ++it) {
+ kexipluginsdbg << "query->columnsOrder()[ " << it.key()->field->name() << " ] = " << it.data() << endl;
+ }
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
+ KexiFormDataItemInterface *item = it.current();
+ KexiDB::QueryColumnInfo* ci = query->columnInfo( it.current()->dataSource() );
+ int index = ci ? columnsOrder[ ci ] : -1;
+ kexipluginsdbg << "query->columnsOrder()[ " << (ci ? ci->field->name() : "") << " ] = " << index
+ << " (dataSource: " << item->dataSource() << ", name=" << dynamic_cast<QObject*>(item)->name() << ")" << endl;
+ if (index!=-1 && !m_fieldNumbersForDataItems[ item ])
+ m_fieldNumbersForDataItems.insert( item, index );
+ //todo
+ //WRONG: not only used data sources can be fetched!
+ // m_fieldNumbersForDataItems.insert( it.current(),
+ // m_usedDataSources.findIndex(it.current()->dataSource().lower()) );
+ }
+ }
+ else {//!query
+// dataFieldsCount = m_dataItems.count();
+ }
+
+#if 0 //moved down
+ //in 'newIndices' let's collect new indices for every data source
+ foreach(QValueList<uint>::ConstIterator, it, invalidSources) {
+ //all previous indices have corresponding data source
+// for (; i < (*it); i++) {
+// newIndices[i] = number++;
+ //kexipluginsdbg << "invalidateDataSources(): " << i << " -> " << number-1 << endl;
+// }
+ //this index have no corresponding data source
+// newIndices[i]=-1;
+ KexiFormDataItemInterface *item = m_dataItems.at( *it );
+ if (item)
+ item->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
+ m_dataItems.remove(*it);
+ kexipluginsdbg << "invalidateDataSources(): " << (*it) << " -> " << -1 << endl;
+// i++;
+ }
+#endif
+ //fill remaining part of the vector
+// for (; i < dataFieldsCount; i++) { //m_dataItems.count(); i++) {
+ //newIndices[i] = number++;
+ //kexipluginsdbg << "invalidateDataSources(): " << i << " -> " << number-1 << endl;
+ //}
+
+#if 0
+ //recreate m_fieldNumbersForDataItems and mark widgets with invalid data sources
+ KexiFormDataItemInterfaceToIntMap newFieldNumbersForDataItems;
+ foreach(KexiFormDataItemInterfaceToIntMap::ConstIterator, it, m_fieldNumbersForDataItems) {
+ bool ok;
+ const int newIndex = newIndices.at( it.data(), &ok );
+ if (ok && newIndex!=-1) {
+ kexipluginsdbg << "invalidateDataSources(): " << it.key()->dataSource() << ": " << it.data() << " -> " << newIndex << endl;
+ newFieldNumbersForDataItems.replace(it.key(), newIndex);
+ }
+ else {
+ kexipluginsdbg << "invalidateDataSources(): removing " << it.key()->dataSource() << endl;
+ m_dataItems.remove(it.key());
+ it.key()->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
+ }
+ }
+#endif
+// m_fieldNumbersForDataItems = newFieldNumbersForDataItems;
+
+ //update data sources set (some of them may be removed)
+ QDict<char> tmpUsedDataSources(1013);
+
+ if (query)
+ query->debug();
+
+ //if (query && m_dataItems.count()!=query->fieldCount()) {
+ // kdWarning() << "KexiFormDataProvider::invalidateDataSources(): m_dataItems.count()!=query->fieldCount() ("
+ // << m_dataItems.count() << "," << query->fieldCount() << ")" << endl;
+ //}
+ //i = 0;
+ m_disableFillDuplicatedDataItems = true; // temporary disable fillDuplicatedDataItems()
+ // because setColumnInfo() can activate it
+ for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current();) {
+ KexiFormDataItemInterface * item = it.current();
+ if (invalidSources[ item->dataSource().lower() ]) {
+ item->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
+ m_dataItems.remove(item);
+ continue;
+ }
+ uint fieldNumber = m_fieldNumbersForDataItems[ item ];
+ if (query) {
+ KexiDB::QueryColumnInfo *ci = fieldsExpanded[fieldNumber];
+ item->setColumnInfo(ci);
+ kexipluginsdbg << "- item=" << dynamic_cast<QObject*>(item)->name()
+ << " dataSource=" << item->dataSource()
+ << " field=" << ci->field->name() << endl;
+ const int indexForVisibleLookupValue = ci->indexForVisibleLookupValue();
+ if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)fieldsExpanded.count()) {
+ //there's lookup column defined: set visible column as well
+ KexiDB::QueryColumnInfo *visibleColumnInfo = fieldsExpanded[ indexForVisibleLookupValue ];
+ if (visibleColumnInfo) {
+ item->setVisibleColumnInfo( visibleColumnInfo );
+ if (dynamic_cast<KexiComboBoxBase*>(item) && m_mainWidget
+ && dynamic_cast<KexiComboBoxBase*>(item)->internalEditor())
+ {
+ // m_mainWidget (dbform) should filter the (just created using setVisibleColumnInfo())
+ // combo box' internal editor (actually, only if the combo is in 'editable' mode)
+ dynamic_cast<KexiComboBoxBase*>(item)->internalEditor()->installEventFilter(m_mainWidget);
+ }
+ kexipluginsdbg << " ALSO SET visibleColumn=" << visibleColumnInfo->debugString()
+ << "\n at position " << indexForVisibleLookupValue << endl;
+ }
+ }
+ }
+ tmpUsedDataSources.replace( item->dataSource().lower(), (char*)1 );
+ ++it;
+ }
+ m_disableFillDuplicatedDataItems = false;
+ m_usedDataSources.clear();
+ foreach_list(QDictIterator<char>, it, tmpUsedDataSources) {
+ m_usedDataSources += it.currentKey();
+ }
+}