kexi

kexitableviewdata.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002   Lucijan Busch <lucijan@gmx.at>
00003    Copyright (C) 2003   Daniel Molkentin <molkentin@kde.org>
00004    Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
00005 
00006    This program is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this program; see the file COPYING.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  
00021    Original Author:  Till Busch <till@bux.at>
00022    Original Project: buX (www.bux.at)
00023 */
00024 
00025 #include "kexitableviewdata.h"
00026 
00027 #include <kexiutils/validator.h>
00028 
00029 #include <kexidb/field.h>
00030 #include <kexidb/queryschema.h>
00031 #include <kexidb/roweditbuffer.h>
00032 #include <kexidb/cursor.h>
00033 #include <kexidb/utils.h>
00034 #include <kexi.h>
00035 
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038 
00039 #include <qapplication.h>
00040 
00041 unsigned short KexiTableViewData::charTable[]=
00042 {
00043     #include "chartable.txt"
00044 };
00045 
00046 KexiTableViewColumn::KexiTableViewColumn(KexiDB::Field& f, bool owner)
00047 : fieldinfo(0)
00048 , m_field(&f)
00049 {
00050     isDBAware = false;
00051     m_fieldOwned = owner;
00052     m_captionAliasOrName = m_field->captionOrName();
00053     init();
00054 }
00055 
00056 KexiTableViewColumn::KexiTableViewColumn(const QString& name, KexiDB::Field::Type ctype,
00057     uint cconst,
00058     uint options,
00059     uint length, uint precision,
00060     QVariant defaultValue,
00061     const QString& caption, const QString& description, uint width
00062 )
00063 : fieldinfo(0)
00064 {
00065     m_field = new KexiDB::Field(
00066         name, ctype,
00067         cconst,
00068         options,
00069         length, precision,
00070         defaultValue,
00071         caption, description, width);
00072 
00073     isDBAware = false;
00074     m_fieldOwned = true;
00075     m_captionAliasOrName = m_field->captionOrName();
00076     init();
00077 }
00078 
00079 KexiTableViewColumn::KexiTableViewColumn(const QString& name, KexiDB::Field::Type ctype, const QString& caption,
00080     const QString& description)
00081 : fieldinfo(0)
00082 {
00083     m_field = new KexiDB::Field(
00084         name, ctype,
00085         KexiDB::Field::NoConstraints,
00086         KexiDB::Field::NoOptions,
00087         0, 0,
00088         QVariant(),
00089         caption, description);
00090 
00091     isDBAware = false;
00092     m_fieldOwned = true;
00093     m_captionAliasOrName = m_field->captionOrName();
00094     init();
00095 }
00096 
00097 KexiTableViewColumn::KexiTableViewColumn(
00098     const KexiDB::QuerySchema &query, KexiDB::QueryColumnInfo& fi)
00099 //  const KexiDB::QuerySchema &query, KexiDB::Field& f)
00100 : fieldinfo(&fi)
00101 , m_field(fi.field)
00102 {
00103     isDBAware = true;
00104     m_fieldOwned = false;
00105 
00106     //setup column's caption:
00107     if (!fieldinfo->field->caption().isEmpty()) {
00108         m_captionAliasOrName = fieldinfo->field->caption();
00109     }
00110     else {
00111         //reuse alias if available:
00112         m_captionAliasOrName = fieldinfo->alias;
00113         //last hance: use field name
00114         if (m_captionAliasOrName.isEmpty())
00115             m_captionAliasOrName = fieldinfo->field->name();
00116         //todo: compute other auto-name?
00117     }
00118     init();
00119     //setup column's readonly flag: 
00120     // true if it's not from parent table's field or if the query itself is coming read-only connection
00121     m_readOnly = (query.masterTable()!=fieldinfo->field->table())
00122         || (query.connection() && query.connection()->isReadOnly());
00123 //  kdDebug() << "KexiTableViewColumn: query.masterTable()==" 
00124 //      << (query.masterTable() ? query.masterTable()->name() : "notable") << ", fieldinfo->field->table()=="
00125 //      << (fieldinfo->field->table() ? fieldinfo->field->table()->name()  : "notable") << endl;
00126 
00127 //  m_visible = query.isFieldVisible(&f);
00128 }
00129 
00130 KexiTableViewColumn::KexiTableViewColumn(bool)
00131 : fieldinfo(0)
00132 , m_field(0)
00133 {
00134     isDBAware = false;
00135     init();
00136 }
00137 
00138 KexiTableViewColumn::~KexiTableViewColumn()
00139 {
00140     if (m_fieldOwned)
00141         delete m_field;
00142     setValidator( 0 );
00143     delete m_relatedData;
00144 }
00145 
00146 void KexiTableViewColumn::init()
00147 {
00148     m_relatedData = 0;
00149     m_readOnly = false;
00150     m_visible = true;
00151     m_data = 0;
00152     m_validator = 0;
00153     m_relatedDataEditable = false;
00154 }
00155 
00156 void KexiTableViewColumn::setValidator( KexiUtils::Validator* v )
00157 {
00158     if (m_validator) {//remove old one
00159         if (!m_validator->parent()) //destroy if has no parent
00160             delete m_validator;
00161     }
00162     m_validator = v;
00163 }
00164 
00165 void KexiTableViewColumn::setRelatedData(KexiTableViewData *data)
00166 {
00167     if (isDBAware)
00168         return;
00169     if (m_relatedData)
00170         delete m_relatedData;
00171     m_relatedData = 0;
00172     if (!data)
00173         return;
00174     //find a primary key
00175     KexiTableViewColumn::ListIterator it( data->columns );
00176     for (int id = 0;it.current();++it, id++) {
00177         if (it.current()->field()->isPrimaryKey()) {
00178             //found, remember
00179             m_relatedDataPKeyID = id;
00180             m_relatedData = data;
00181             return;
00182         }
00183     }
00184 }
00185 
00186 void KexiTableViewColumn::setRelatedDataEditable(bool set)
00187 {
00188     m_relatedDataEditable = set;
00189 }
00190 
00191 bool KexiTableViewColumn::acceptsFirstChar(const QChar& ch) const
00192 {
00193     if (m_field->isNumericType()) {
00194         if (ch=="-")
00195              return !m_field->isUnsigned();
00196         if (ch=="+" || (ch>="0" && ch<="9"))
00197             return true;
00198         return false;
00199     }
00200 
00201     switch (m_field->type()) {
00202     case KexiDB::Field::Boolean:
00203         return false;
00204     case KexiDB::Field::Date:
00205     case KexiDB::Field::DateTime:
00206     case KexiDB::Field::Time:
00207         return ch>="0" && ch<="9";
00208     default:;
00209     }
00210     return true;
00211 }
00212 
00213 
00214 //------------------------------------------------------
00215 
00216 KexiTableViewData::KexiTableViewData()
00217     : QObject()
00218     , KexiTableViewDataBase()
00219 {
00220     init();
00221 }
00222 
00223 KexiTableViewData::KexiTableViewData(KexiDB::Cursor *c)
00224     : QObject()
00225     , KexiTableViewDataBase()
00226 {
00227     init();
00228     m_cursor = c;
00229     m_containsROWIDInfo = m_cursor->containsROWIDInfo();
00230 
00231     KexiDB::QueryColumnInfo::Vector vector 
00232         = m_cursor->query()->fieldsExpanded();
00233     KexiTableViewColumn* col;
00234     const uint count = vector.count();
00235     for (uint i=0;i<count;i++) {
00236         KexiDB::QueryColumnInfo *fi = vector[i];
00237         if (fi->visible) {
00238             col=new KexiTableViewColumn(*m_cursor->query(), *fi);
00239             //col->setVisible( detailedVisibility[i] );
00240             addColumn( col );
00241         }
00242     }
00243 }
00244 
00245 KexiTableViewData::KexiTableViewData(
00246     const QValueList<QVariant> &keys, const QValueList<QVariant> &values,
00247     KexiDB::Field::Type keyType, KexiDB::Field::Type valueType)
00248     : QObject()
00249     , KexiTableViewDataBase()
00250 {
00251     init(keys, values, keyType, valueType);
00252 }
00253 
00254 KexiTableViewData::KexiTableViewData(
00255     KexiDB::Field::Type keyType, KexiDB::Field::Type valueType)
00256 {
00257     const QValueList<QVariant> empty;
00258     init(empty, empty, keyType, valueType);
00259 }
00260 
00261 KexiTableViewData::~KexiTableViewData()
00262 {
00263     emit destroying();
00264     clearInternal();
00265 }
00266 
00267 void KexiTableViewData::init(
00268     const QValueList<QVariant> &keys, const QValueList<QVariant> &values,
00269     KexiDB::Field::Type keyType, KexiDB::Field::Type valueType)
00270 {
00271     init();
00272     KexiDB::Field *keyField = new KexiDB::Field("key", keyType);
00273     keyField->setPrimaryKey(true);
00274     KexiTableViewColumn *keyColumn = new KexiTableViewColumn(*keyField, true);
00275     keyColumn->setVisible(false);
00276     addColumn(keyColumn);
00277 
00278     KexiDB::Field *valueField = new KexiDB::Field("value", valueType);
00279     KexiTableViewColumn *valueColumn = new KexiTableViewColumn(*valueField, true);
00280     addColumn(valueColumn);
00281 
00282     uint cnt = QMIN(keys.count(), values.count());
00283     QValueList<QVariant>::ConstIterator it_keys = keys.constBegin();
00284     QValueList<QVariant>::ConstIterator it_values = values.constBegin();
00285     for (;cnt>0;++it_keys, ++it_values, cnt--) {
00286         KexiTableItem *item = new KexiTableItem(2);
00287         (*item)[0] = (*it_keys);
00288         (*item)[1] = (*it_values);
00289         append( item );
00290     }
00291 }
00292 
00293 /*
00294 KexiTableViewData::KexiTableViewData(KexiTableViewColumnList& cols) 
00295     : KexiTableViewDataBase()
00296     , columns(cols)
00297     , m_key(0)
00298     , m_order(1)
00299     , m_type(1)
00300     , m_pRowEditBuffer(0)
00301     , m_readOnly(false)
00302     , m_insertingEnabled(true)
00303 {
00304     setAutoDelete(true);
00305     columns.setAutoDelete(true);
00306 }*/
00307 
00308 void KexiTableViewData::init()
00309 {
00310     m_key = 0;
00311 //  m_order = 1;
00312     m_order = 0;
00313     m_type = 1;
00314     m_pRowEditBuffer = 0;
00315     m_cursor = 0;
00316     m_readOnly = false;
00317     m_insertingEnabled = true;
00318 
00319     setAutoDelete(true);
00320     columns.setAutoDelete(true);
00321     m_visibleColumnsCount=0;
00322     m_visibleColumnsIDs.resize(100);
00323     m_globalColumnsIDs.resize(100);
00324 
00325     m_autoIncrementedColumn = -2;
00326     m_containsROWIDInfo = false;
00327 }
00328 
00329 void KexiTableViewData::addColumn( KexiTableViewColumn* col )
00330 {
00331 //  if (!col->isDBAware) {
00332 //      if (!m_simpleColumnsByName)
00333 //          m_simpleColumnsByName = new QDict<KexiTableViewColumn>(101);
00334 //      m_simpleColumnsByName->insert(col->caption,col);//for faster lookup
00335 //  }
00336     columns.append( col );
00337     col->m_data = this;
00338     if (m_globalColumnsIDs.size() < columns.count()) {//sanity
00339         m_globalColumnsIDs.resize( m_globalColumnsIDs.size()*2 );
00340     }
00341     if (col->visible()) {
00342         m_visibleColumnsCount++;
00343         if (m_visibleColumnsIDs.size() < m_visibleColumnsCount) {//sanity
00344             m_visibleColumnsIDs.resize( m_visibleColumnsIDs.size()*2 );
00345         }
00346         m_visibleColumnsIDs[ columns.count()-1 ] = m_visibleColumnsCount-1;
00347         m_globalColumnsIDs[ m_visibleColumnsCount-1 ] = columns.count()-1;
00348     }
00349     else {
00350         m_visibleColumnsIDs[ columns.count()-1 ] = -1;
00351     }
00352     m_autoIncrementedColumn = -2; //clear cache;
00353 }
00354 
00355 /*void KexiTableViewData::addColumns( KexiDB::QuerySchema *query, KexiDB::Field *field )
00356 {
00357     field->isQueryAsterisk
00358 }*/
00359 
00360 QString KexiTableViewData::dbTableName() const
00361 {
00362     if (m_cursor && m_cursor->query() && m_cursor->query()->masterTable())
00363         return m_cursor->query()->masterTable()->name();
00364     return QString::null;
00365 }
00366 
00367 void KexiTableViewData::setSorting(int column, bool ascending)
00368 {
00369 //  m_order = (ascending ? 1 : -1);
00370 
00371     if (column>=0 && column<(int)columns.count()) {
00372         m_order = (ascending ? 1 : -1);
00373         m_key = column;
00374     } 
00375     else {
00376         m_order = 0;
00377         m_key = -1;
00378         return;
00379     }
00380 
00381     const KexiDB::Field *field = columns.at(m_key)->field();
00382     const int t = field->type();
00383     if (KexiDB::Field::isFPNumericType(t))
00384         cmpFunc = &KexiTableViewData::cmpDouble;
00385     else if (t==KexiDB::Field::BigInteger) {
00386         if (field->isUnsigned())
00387             cmpFunc = &KexiTableViewData::cmpULongLong;
00388         else
00389             cmpFunc = &KexiTableViewData::cmpLongLong;
00390     }
00391     else if (t == KexiDB::Field::Integer && field->isUnsigned())
00392         cmpFunc = &KexiTableViewData::cmpUInt;
00393     else if (t == KexiDB::Field::Boolean || KexiDB::Field::isNumericType(t))
00394         cmpFunc = &KexiTableViewData::cmpInt; //other integers
00395     else if (t == KexiDB::Field::Date)
00396         cmpFunc = &KexiTableViewData::cmpDate;
00397     else if (t == KexiDB::Field::Time)
00398         cmpFunc = &KexiTableViewData::cmpTime;
00399     else if (t == KexiDB::Field::DateTime)
00400         cmpFunc = &KexiTableViewData::cmpDateTime;
00401     else
00402         cmpFunc = &KexiTableViewData::cmpStr; //text or anything else
00403 }
00404 
00405 int KexiTableViewData::compareItems(Item item1, Item item2)
00406 {
00407     return ((this->*cmpFunc) (item1, item2));
00408 }
00409 
00411 #define CMP_NULLS(item1, item2) \
00412     m_leftTmp = ((KexiTableItem *)item1)->at(m_key); \
00413     if (m_leftTmp.isNull()) \
00414         return -m_order; \
00415     m_rightTmp = ((KexiTableItem *)item2)->at(m_key); \
00416     if (m_rightTmp.isNull()) \
00417         return m_order
00418 
00419 #define CAST_AND_COMPARE(casting, item1, item2) \
00420     CMP_NULLS(item1, item2); \
00421     if (m_leftTmp.casting() < m_rightTmp.casting()) \
00422         return -m_order; \
00423     if (m_leftTmp.casting() > m_rightTmp.casting()) \
00424         return m_order; \
00425     return 0
00426 
00427 int KexiTableViewData::cmpInt(Item item1, Item item2)
00428 {
00429     CAST_AND_COMPARE(toInt, item1, item2);
00430 }
00431 
00432 int KexiTableViewData::cmpUInt(Item item1, Item item2)
00433 {
00434     CAST_AND_COMPARE(toUInt, item1, item2);
00435 }
00436 
00437 int KexiTableViewData::cmpLongLong(Item item1, Item item2)
00438 {
00439     CAST_AND_COMPARE(toLongLong, item1, item2);
00440 }
00441 
00442 int KexiTableViewData::cmpULongLong(Item item1, Item item2)
00443 {
00444     CAST_AND_COMPARE(toULongLong, item1, item2);
00445 }
00446 
00447 int KexiTableViewData::cmpDouble(Item item1, Item item2)
00448 {
00449     CAST_AND_COMPARE(toDouble, item1, item2);
00450 }
00451 
00452 int KexiTableViewData::cmpDate(Item item1, Item item2)
00453 {
00454     CAST_AND_COMPARE(toDate, item1, item2);
00455 }
00456 
00457 int KexiTableViewData::cmpDateTime(Item item1, Item item2)
00458 {
00459     CAST_AND_COMPARE(toDateTime, item1, item2);
00460 }
00461 
00462 int KexiTableViewData::cmpTime(Item item1, Item item2)
00463 {
00464     CAST_AND_COMPARE(toDate, item1, item2);
00465 }
00466 
00467 int KexiTableViewData::cmpStr(Item item1, Item item2)
00468 {
00469     CMP_NULLS(item1, item2);
00470     const QString &as = m_leftTmp.toString();
00471     const QString &bs = m_rightTmp.toString();
00472 
00473     const QChar *a = as.unicode();
00474     const QChar *b = bs.unicode();
00475 
00476     if ( a == b )
00477         return 0;
00478     if ( a == 0 )
00479         return -1;
00480     if ( b == 0 )
00481         return 1;
00482 
00483     unsigned short au;
00484     unsigned short bu;
00485 
00486     int l=QMIN(as.length(),bs.length());
00487 
00488     au = a->unicode();
00489     bu = b->unicode();
00490     au = (au <= 0x17e ? charTable[au] : 0xffff);
00491     bu = (bu <= 0x17e ? charTable[bu] : 0xffff);
00492 
00493     while (l-- && au == bu)
00494     {
00495         a++,b++;
00496         au = a->unicode();
00497         bu = b->unicode();
00498         au = (au <= 0x17e ? charTable[au] : 0xffff);
00499         bu = (bu <= 0x17e ? charTable[bu] : 0xffff);
00500     }
00501 
00502     if ( l==-1 )
00503         return m_order*(as.length()-bs.length());
00504 
00505     return m_order*(au-bu);
00506 }
00507 
00508 void KexiTableViewData::setReadOnly(bool set)
00509 {
00510     if (m_readOnly == set)
00511         return;
00512     m_readOnly = set;
00513     if (m_readOnly)
00514         setInsertingEnabled(false);
00515 }
00516 
00517 void KexiTableViewData::setInsertingEnabled(bool set)
00518 {
00519     if (m_insertingEnabled == set)
00520         return;
00521     m_insertingEnabled = set;
00522     if (m_insertingEnabled)
00523         setReadOnly(false);
00524 }
00525 
00526 void KexiTableViewData::clearRowEditBuffer()
00527 {
00528     //init row edit buffer
00529     if (!m_pRowEditBuffer)
00530         m_pRowEditBuffer = new KexiDB::RowEditBuffer(isDBAware());
00531     else
00532         m_pRowEditBuffer->clear();
00533 }
00534 
00535 bool KexiTableViewData::updateRowEditBufferRef(KexiTableItem *item, 
00536     int colnum, KexiTableViewColumn* col, QVariant& newval, bool allowSignals)
00537 {
00538     m_result.clear();
00539     if (allowSignals)
00540         emit aboutToChangeCell(item, colnum, newval, &m_result);
00541     if (!m_result.success)
00542         return false;
00543 
00544     kdDebug() << "KexiTableViewData::updateRowEditBufferRef() column #" 
00545         << colnum << " = " << newval.toString() << endl;
00546 //  KexiTableViewColumn* col = columns.at(colnum);
00547     if (!col) {
00548         kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" 
00549             << colnum << " not found! col==0" << endl;
00550         return false;
00551     }
00552     if (m_pRowEditBuffer->isDBAware()) {
00553         if (!(col->fieldinfo)) {
00554             kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" 
00555                 << colnum << " not found!" << endl;
00556             return false;
00557         }
00558 //      if (!(static_cast<KexiDBTableViewColumn*>(col)->field)) {
00559         m_pRowEditBuffer->insert( *col->fieldinfo, newval);
00560         return true;
00561     }
00562     if (!(col->field())) {
00563         kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" << colnum<<" not found!" << endl;
00564         return false;
00565     }
00566     //not db-aware:
00567     const QString colname = col->field()->name();
00568     if (colname.isEmpty()) {
00569         kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" << colnum<<" not found!" << endl;
00570         return false;
00571     }
00572     m_pRowEditBuffer->insert(colname, newval);
00573     return true;
00574 }
00575 
00576 //get a new value (of present in the buffer), or the old one, otherwise
00577 //(taken here for optimization)
00578 #define GET_VALUE if (!val) { \
00579     val = m_cursor ? m_pRowEditBuffer->at( *it_f.current()->fieldinfo ) : m_pRowEditBuffer->at( *f ); \
00580     if (!val) \
00581         val = &(*it_r); /* get old value */ \
00582     }
00583 
00584 //js TODO: if there can be multiple views for this data, we need multiple buffers!
00585 bool KexiTableViewData::saveRow(KexiTableItem& item, bool insert, bool repaint)
00586 {
00587     if (!m_pRowEditBuffer)
00588         return true; //nothing to do
00589 
00590     //check constraints:
00591     //-check if every NOT NULL and NOT EMPTY field is filled
00592     KexiTableViewColumn::ListIterator it_f(columns);
00593     KexiDB::RowData::ConstIterator it_r = item.constBegin();
00594     int col = 0;
00595     const QVariant *val;
00596     for (;it_f.current() && it_r!=item.constEnd();++it_f,++it_r,col++) {
00597         KexiDB::Field *f = it_f.current()->field();
00598         val = 0;
00599         if (f->isNotNull()) {
00600             GET_VALUE;
00601             //check it
00602             if (val->isNull() && !f->isAutoIncrement()) {
00603                 //NOT NULL violated
00604                 m_result.msg = i18n("\"%1\" column requires a value to be entered.")
00605                     .arg(f->captionOrName()) + "\n\n" + Kexi::msgYouCanImproveData();
00606                 m_result.desc = i18n("The column's constraint is declared as NOT NULL.");
00607                 m_result.column = col;
00608                 return false;
00609             }
00610         }
00611         if (f->isNotEmpty()) {
00612             GET_VALUE;
00613             if (!f->isAutoIncrement() && (val->isNull() || KexiDB::isEmptyValue( f, *val ))) {
00614                 //NOT EMPTY violated
00615                 m_result.msg = i18n("\"%1\" column requires a value to be entered.")
00616                     .arg(f->captionOrName()) + "\n\n" + Kexi::msgYouCanImproveData();
00617                 m_result.desc = i18n("The column's constraint is declared as NOT EMPTY.");
00618                 m_result.column = col;
00619                 return false;
00620             }
00621         }
00622     }
00623 
00624     if (m_cursor) {//db-aware
00625         if (insert) {
00626             if (!m_cursor->insertRow( static_cast<KexiDB::RowData&>(item), *m_pRowEditBuffer, 
00627                 m_containsROWIDInfo/*also retrieve ROWID*/ )) 
00628             {
00629                 m_result.msg = i18n("Row inserting failed.") + "\n\n" 
00630                     + Kexi::msgYouCanImproveData();
00631                 KexiDB::getHTMLErrorMesage(m_cursor, &m_result);
00632 
00633 /*          if (desc)
00634             *desc = 
00635 js: TODO: use KexiMainWindowImpl::showErrorMessage(const QString &title, KexiDB::Object *obj)
00636     after it will be moved somewhere to kexidb (this will require moving other 
00637       showErrorMessage() methods from KexiMainWindowImpl to libkexiutils....)
00638     then: just call: *desc = KexiDB::errorMessage(m_cursor);
00639 */
00640                 return false;
00641             }
00642         }
00643         else {
00644 //          if (m_containsROWIDInfo)
00645 //              ROWID = item[columns.count()].toULongLong();
00646             if (!m_cursor->updateRow( static_cast<KexiDB::RowData&>(item), *m_pRowEditBuffer,
00647                     m_containsROWIDInfo/*use ROWID*/))
00648             {
00649                 m_result.msg = i18n("Row changing failed.") + "\n\n" + Kexi::msgYouCanImproveData();
00651                 KexiDB::getHTMLErrorMesage(m_cursor, m_result.desc);
00652                 return false;
00653             }
00654         }
00655     }
00656     else {//js UNTESTED!!! - not db-aware version
00657         KexiDB::RowEditBuffer::SimpleMap b = m_pRowEditBuffer->simpleBuffer();
00658         for (KexiDB::RowEditBuffer::SimpleMap::ConstIterator it = b.constBegin();it!=b.constEnd();++it) {
00659             uint i=0;
00660             for (KexiTableViewColumn::ListIterator it2(columns);it2.current();++it2, i++) {
00661                 if (it2.current()->field()->name()==it.key()) {
00662                     kdDebug() << it2.current()->field()->name()<< ": "<<item[i].toString()<<" -> "<<it.data().toString()<<endl;
00663                     item[i] = it.data();
00664                 }
00665             }
00666         }
00667     }
00668     
00669     m_pRowEditBuffer->clear();
00670 
00671     if (repaint)
00672         emit rowRepaintRequested(item);
00673     return true;
00674 }
00675 
00676 bool KexiTableViewData::saveRowChanges(KexiTableItem& item, bool repaint)
00677 {
00678     kdDebug() << "KexiTableViewData::saveRowChanges()..." << endl;
00679     m_result.clear();
00680     emit aboutToUpdateRow(&item, m_pRowEditBuffer, &m_result);
00681     if (!m_result.success)
00682         return false;
00683 
00684     if (saveRow(item, false /*update*/, repaint)) {
00685         emit rowUpdated(&item);
00686         return true;
00687     }
00688     return false;
00689 }
00690 
00691 bool KexiTableViewData::saveNewRow(KexiTableItem& item, bool repaint)
00692 {
00693     kdDebug() << "KexiTableViewData::saveNewRow()..." << endl;
00694     m_result.clear();
00695     emit aboutToInsertRow(&item, &m_result, repaint);
00696     if (!m_result.success)
00697         return false;
00698     
00699     if (saveRow(item, true /*insert*/, repaint)) {
00700         emit rowInserted(&item, repaint);
00701         return true;
00702     }
00703     return false;
00704 }
00705 
00706 bool KexiTableViewData::deleteRow(KexiTableItem& item, bool repaint)
00707 {
00708     m_result.clear();
00709     emit aboutToDeleteRow(item, &m_result, repaint);
00710     if (!m_result.success)
00711         return false;
00712 
00713     if (m_cursor) {//db-aware
00714         m_result.success = false;
00715         if (!m_cursor->deleteRow( static_cast<KexiDB::RowData&>(item), m_containsROWIDInfo/*use ROWID*/ )) {
00716             m_result.msg = i18n("Row deleting failed.");
00717 /*js: TODO: use KexiDB::errorMessage() for description (desc) as in KexiTableViewData::saveRow() */
00718             KexiDB::getHTMLErrorMesage(m_cursor, &m_result);
00719             m_result.success = false;
00720             return false;
00721         }
00722     }
00723 
00724     if (!removeRef(&item)) {
00725         //aah - this shouldn't be!
00726         kdWarning() << "KexiTableViewData::deleteRow(): !removeRef() - IMPL. ERROR?" << endl;
00727         m_result.success = false;
00728         return false;
00729     }
00730     emit rowDeleted();
00731     return true;
00732 }
00733 
00734 void KexiTableViewData::deleteRows( const QValueList<int> &rowsToDelete, bool repaint )
00735 {
00736     Q_UNUSED( repaint );
00737 
00738     if (rowsToDelete.isEmpty())
00739         return;
00740     int last_r=0;
00741     first();
00742     for (QValueList<int>::ConstIterator r_it = rowsToDelete.constBegin(); r_it!=rowsToDelete.constEnd(); ++r_it) {
00743         for (; last_r<(*r_it); last_r++) {
00744             next();
00745         }
00746         remove();
00747         last_r++;
00748     }
00749 //DON'T CLEAR BECAUSE KexiTableViewPropertyBuffer will clear BUFFERS!
00750 //-->   emit reloadRequested(); //! \todo more effective?
00751     emit rowsDeleted( rowsToDelete );
00752 }
00753 
00754 void KexiTableViewData::insertRow(KexiTableItem& item, uint index, bool repaint)
00755 {
00756     if (!insert( index = QMIN(index, count()), &item ))
00757         return;
00758     emit rowInserted(&item, index, repaint);
00759 }
00760 
00761 //void KexiTableViewData::clear()
00762 void KexiTableViewData::clearInternal()
00763 {
00764     clearRowEditBuffer();
00765 //  qApp->processEvents( 1 );
00766 //TODO: this is time consuming: find better data model
00767 //  KexiTableViewDataBase::clear();
00768     const uint c = count();
00769     for (uint i=0; i<c; i++) {
00770         removeLast();
00771 #ifndef KEXI_NO_PROCESS_EVENTS
00772         if (i % 1000 == 0)
00773             qApp->processEvents( 1 );
00774 #endif
00775     }
00776 }
00777 
00778 bool KexiTableViewData::deleteAllRows(bool repaint)
00779 {
00780     clearInternal();
00781 
00782     bool res = true;
00783     if (m_cursor) {
00784         //db-aware
00785         res = m_cursor->deleteAllRows();
00786     }
00787 
00788     if (repaint)
00789         emit reloadRequested();
00790     return res;
00791 }
00792 
00793 int KexiTableViewData::autoIncrementedColumn()
00794 {
00795     if (m_autoIncrementedColumn==-2) {
00796         //find such a column
00797         m_autoIncrementedColumn = 0;
00798         KexiTableViewColumn::ListIterator it(columns);
00799         for (; it.current(); ++it, m_autoIncrementedColumn++) {
00800             if (it.current()->field()->isAutoIncrement())
00801                 break;
00802         }
00803         if (!it.current())
00804             m_autoIncrementedColumn = -1;
00805     }
00806     return m_autoIncrementedColumn;
00807 }
00808 
00809 void KexiTableViewData::preloadAllRows()
00810 {
00811     if (!m_cursor)
00812         return;
00813 
00814     const uint fcount = m_cursor->fieldCount() + (m_containsROWIDInfo ? 1 : 0);
00815     m_cursor->moveFirst();
00816     for (int i=0;!m_cursor->eof();i++) {
00817         KexiTableItem *item = new KexiTableItem(fcount);
00818         m_cursor->storeCurrentRow(*item);
00819         append( item );
00820         m_cursor->moveNext();
00821 #ifndef KEXI_NO_PROCESS_EVENTS
00822         if ((i % 1000) == 0)
00823             qApp->processEvents( 1 );
00824 #endif
00825     }
00826 }
00827 
00828 bool KexiTableViewData::isReadOnly() const
00829 {
00830     return m_readOnly || (m_cursor && m_cursor->connection()->isReadOnly());
00831 }
00832 
00833 #include "kexitableviewdata.moc"
00834 
KDE Home | KDE Accessibility Home | Description of Access Keys