diff options
Diffstat (limited to 'kexi/plugins/forms/kexidataprovider.cpp')
-rw-r--r-- | kexi/plugins/forms/kexidataprovider.cpp | 315 |
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(); + } +} |