kexi

kexidataprovider.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kexidataprovider.h"
00021 
00022 #include <qwidget.h>
00023 #include <qobjectlist.h>
00024 
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027 
00028 #include <tableview/kexitableitem.h>
00029 #include <tableview/kexitableviewdata.h>
00030 #include <kexidb/queryschema.h>
00031 #include <kexiutils/utils.h>
00032 
00033 #include "widgets/kexidbform.h"
00034 
00035 KexiFormDataProvider::KexiFormDataProvider()
00036  : KexiDataItemChangesListener()
00037  , m_mainWidget(0)
00038  , m_duplicatedItems(0)
00039  , m_disableFillDuplicatedDataItems(false)
00040 {
00041 }
00042 
00043 KexiFormDataProvider::~KexiFormDataProvider()
00044 {
00045     delete m_duplicatedItems;
00046 }
00047 
00048 void KexiFormDataProvider::setMainDataSourceWidget(QWidget* mainWidget)
00049 {
00050     m_mainWidget = mainWidget;
00051     m_dataItems.clear();
00052     m_usedDataSources.clear();
00053     m_fieldNumbersForDataItems.clear();
00054     if (!m_mainWidget)
00055         return;
00056 
00057     //find widgets whose will work as data items
00058     QObjectList *l = m_mainWidget->queryList( "QWidget" );
00059     QObjectListIt it( *l );
00060     QObject *obj;
00061     QDict<char> tmpSources;
00062     for ( ; (obj = it.current()) != 0; ++it ) {
00063         KexiFormDataItemInterface* const formDataItem = dynamic_cast<KexiFormDataItemInterface*>(obj);
00064         if (!formDataItem)
00065             continue;
00066         if (formDataItem->parentInterface()) //item with parent interface: collect parent instead...
00067             continue;
00068 #if 0 
00069         KexiDBForm *dbForm = KexiUtils::findParent<KexiDBForm>(obj, "KexiDBForm"); //form's surface...
00070         if (dbForm!=m_mainWidget) //only set data for this form's data items
00071             continue;
00072 #else
00073         //tmp: reject widgets within subforms
00074         if (KexiUtils::findParent<KexiDBForm>(obj, "KexiDBSubForm"))
00075             continue;
00076 #endif
00077         QString dataSource( formDataItem->dataSource().lower() );
00078         if (dataSource.isEmpty())
00079             continue;
00080         kexipluginsdbg << obj->name() << endl;
00081         m_dataItems.append( formDataItem );
00082         formDataItem->installListener( this );
00083         tmpSources.replace( dataSource, (char*)1 );
00084     }
00085     delete l;
00086     //now we've got a set (unique list) of field names in tmpSources
00087     //remember it in m_usedDataSources
00088     for (QDictIterator<char> it(tmpSources); it.current(); ++it) {
00089         m_usedDataSources += it.currentKey();
00090     }
00091 }
00092 
00093 void KexiFormDataProvider::fillDataItems(KexiTableItem& row)
00094 {
00095     kexidbg << "KexiFormDataProvider::fillDataItems() cnt=" << row.count() << endl;
00096     for (KexiFormDataItemInterfaceToIntMap::ConstIterator it = m_fieldNumbersForDataItems.constBegin(); 
00097         it!=m_fieldNumbersForDataItems.constEnd(); ++it)
00098     {
00099         kexipluginsdbg << "fill data of '" << it.key()->dataSource() <<  "' at idx=" << it.data() 
00100             << " data=" << row.at(it.data()) << endl;
00101         it.key()->setValue( row.at(it.data()) );
00102     }
00103 }
00104 
00105 void KexiFormDataProvider::fillDuplicatedDataItems(
00106     KexiFormDataItemInterface* item, const QVariant& value)
00107 {
00108     if (m_disableFillDuplicatedDataItems)
00109         return;
00110     if (!m_duplicatedItems) {
00111         //build (once) a set of duplicated data items (having the same fields assigned)
00112         //so we can later check if an item is duplicated with a cost of o(1)
00113         QMap<KexiDB::Field*,int> tmpDuplicatedItems;
00114         QMapIterator<KexiDB::Field*,int> it_dup;
00115         for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
00116             if (!it.current()->columnInfo()->field)
00117                 continue;
00118             kdDebug() << " ** " << it.current()->columnInfo()->field->name() << endl;
00119             it_dup = tmpDuplicatedItems.find( it.current()->columnInfo()->field );
00120             uint count;
00121             if (it_dup==tmpDuplicatedItems.end())
00122                 count = 0;
00123             else
00124                 count = it_dup.data();
00125             tmpDuplicatedItems.insert( it.current()->columnInfo()->field, ++count );
00126         }
00127         m_duplicatedItems = new QPtrDict<char>(101);
00128         for (it_dup = tmpDuplicatedItems.begin(); it_dup!=tmpDuplicatedItems.end(); ++it_dup) {
00129             if (it_dup.data() > 1) {
00130                 m_duplicatedItems->insert( it_dup.key(), (char*)1 );
00131                 kexipluginsdbg << "duplicated item: " << static_cast<KexiDB::Field*>(it_dup.key())->name() 
00132                     << " (" << it_dup.data() << " times)" << endl;
00133             }
00134         }
00135     }
00136     if (m_duplicatedItems->find( item->columnInfo()->field )) {
00137         for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
00138             if (it.current()!=item && item->columnInfo()->field == it.current()->columnInfo()->field) {
00139                 kexipluginsdbg << "- setting a copy of value for item '" 
00140                     << dynamic_cast<QObject*>(it.current())->name() << "' == " << value << endl;
00141                 it.current()->setValue( value );
00142             }
00143         }
00144     }
00145 }
00146 
00147 void KexiFormDataProvider::valueChanged(KexiDataItemInterface* item)
00148 {
00149     Q_UNUSED( item );
00150 }
00151 
00152 bool KexiFormDataProvider::cursorAtNewRow()
00153 {
00154     return false;
00155 }
00156 
00157 void KexiFormDataProvider::invalidateDataSources( const QValueList<uint>& invalidSources,
00158  KexiDB::QuerySchema* query)
00159 {
00160     //fill m_fieldNumbersForDataItems mapping from data item to field number
00161     //(needed for fillDataItems)
00162     KexiDB::QueryColumnInfo::Vector fieldsExpanded;
00163     uint dataFieldsCount; // == fieldsExpanded.count() if query is available or else == m_dataItems.count()
00164     if (query) {
00165         fieldsExpanded = query->fieldsExpanded();
00166         dataFieldsCount = fieldsExpanded.count();
00167         QMap<KexiDB::QueryColumnInfo*,int> fieldsOrder( query->fieldsOrder() );
00168         for (QMapConstIterator<KexiDB::QueryColumnInfo*,int> it = fieldsOrder.constBegin(); it!=fieldsOrder.constEnd(); ++it) {
00169             kexipluginsdbg << "query->fieldsOrder()[ " << it.key()->field->name() << " ] = " << it.data() << endl;
00170         }
00171         for (QPtrListIterator<KexiFormDataItemInterface> it(m_dataItems); it.current(); ++it) {
00172             KexiFormDataItemInterface *item = it.current();
00173             KexiDB::QueryColumnInfo* ci = query->columnInfo( it.current()->dataSource() );
00174             int index = ci ? query->fieldsOrder()[ ci ] : -1;
00175             kexipluginsdbg << "query->fieldsOrder()[ " << (ci ? ci->field->name() : "") << " ] = " << index 
00176                 << " (dataSource: " << item->dataSource() << ", name=" << dynamic_cast<QObject*>(item)->name() << ")" << endl;
00177             if (index!=-1)
00178                 m_fieldNumbersForDataItems.insert( item, index );
00179     //todo
00180     //WRONG: not only used data sources can be fetched!
00181     //          m_fieldNumbersForDataItems.insert( it.current(), 
00182     //              m_usedDataSources.findIndex(it.current()->dataSource().lower()) );
00183         }
00184     }
00185     else {
00186         dataFieldsCount = m_dataItems.count();
00187     }
00188 
00189     //in 'newIndices' let's collect new indices for every data source
00190     foreach(QValueList<uint>::ConstIterator, it, invalidSources) {
00191         //all previous indices have corresponding data source
00192 //      for (; i < (*it); i++) {
00193 //          newIndices[i] = number++;
00194             //kexidbg << "invalidateDataSources(): " << i << " -> " << number-1 << endl;
00195 //      }
00196         //this index have no corresponding data source
00197 //      newIndices[i]=-1;
00198         KexiFormDataItemInterface *item = m_dataItems.at( *it );
00199         if (item)
00200             item->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
00201         m_dataItems.remove(*it);
00202         kexidbg << "invalidateDataSources(): " << (*it) << " -> " << -1 << endl;
00203 //      i++;
00204     }
00205     //fill remaining part of the vector
00206 //  for (; i < dataFieldsCount; i++) { //m_dataItems.count(); i++) {
00207         //newIndices[i] = number++;
00208         //kexidbg << "invalidateDataSources(): " << i << " -> " << number-1 << endl;
00209     //}
00210 
00211 #if 0
00212     //recreate m_fieldNumbersForDataItems and mark widgets with invalid data sources
00213     KexiFormDataItemInterfaceToIntMap newFieldNumbersForDataItems;
00214     foreach(KexiFormDataItemInterfaceToIntMap::ConstIterator, it, m_fieldNumbersForDataItems) {
00215         bool ok;
00216         const int newIndex = newIndices.at( it.data(), &ok );
00217         if (ok && newIndex!=-1) {
00218             kexidbg << "invalidateDataSources(): " << it.key()->dataSource() << ": " << it.data() << " -> " << newIndex << endl;
00219             newFieldNumbersForDataItems.replace(it.key(), newIndex);
00220         }
00221         else {
00222             kexidbg << "invalidateDataSources(): removing " << it.key()->dataSource() << endl;
00223             m_dataItems.remove(it.key());
00224             it.key()->setInvalidState( QString::fromLatin1("#") + i18n("NAME") + QString::fromLatin1("?") );
00225         }
00226     }
00227 #endif
00228 //  m_fieldNumbersForDataItems = newFieldNumbersForDataItems;
00229 
00230     //update data sources set (some of them may be removed)
00231     QDict<char> tmpUsedDataSources(1013);
00232 
00233     if (query)
00234         query->debug();
00235 
00236     //if (query && m_dataItems.count()!=query->fieldCount()) {
00237     //  kdWarning() << "KexiFormDataProvider::invalidateDataSources(): m_dataItems.count()!=query->fieldCount() ("
00238     //   << m_dataItems.count() << "," << query->fieldCount() << ")" << endl;
00239     //}
00240     //i = 0;
00241     m_disableFillDuplicatedDataItems = true; // temporary disable fillDuplicatedDataItems()
00242                                              // because setColumnInfo() can activate it
00243     foreach_list(QPtrListIterator<KexiFormDataItemInterface>, it, m_dataItems) {
00244         KexiFormDataItemInterface * item = it.current();
00245         uint fieldNumber = m_fieldNumbersForDataItems[ item ];
00246         if (query) {
00247             KexiDB::QueryColumnInfo *ci = fieldsExpanded[fieldNumber];
00248 //          KexiDB::Field *f = ci->field;
00249             it.current()->setColumnInfo(ci);
00250             kexipluginsdbg << "- item=" << dynamic_cast<QObject*>(it.current())->name() 
00251                 << " dataSource=" << it.current()->dataSource()
00252                 << " field=" << ci->field->name() << endl;
00253         }
00254         tmpUsedDataSources.replace( it.current()->dataSource().lower(), (char*)1 );
00255     }
00256     m_disableFillDuplicatedDataItems = false;
00257     m_usedDataSources.clear();
00258     foreach_list(QDictIterator<char>, it, tmpUsedDataSources) {
00259         m_usedDataSources += it.currentKey();
00260     }
00261 }
KDE Home | KDE Accessibility Home | Description of Access Keys