diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/widget/tableview/kexitableviewdata.cpp | |
download | koffice-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/widget/tableview/kexitableviewdata.cpp')
-rw-r--r-- | kexi/widget/tableview/kexitableviewdata.cpp | 886 |
1 files changed, 886 insertions, 0 deletions
diff --git a/kexi/widget/tableview/kexitableviewdata.cpp b/kexi/widget/tableview/kexitableviewdata.cpp new file mode 100644 index 00000000..62259db3 --- /dev/null +++ b/kexi/widget/tableview/kexitableviewdata.cpp @@ -0,0 +1,886 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Lucijan Busch <[email protected]> + Copyright (C) 2003 Daniel Molkentin <[email protected]> + Copyright (C) 2003-2006 Jaroslaw Staniek <[email protected]> + + 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. + + Original Author: Till Busch <[email protected]> + Original Project: buX (www.bux.at) +*/ + +#include "kexitableviewdata.h" + +#include <kexiutils/validator.h> + +#include <kexidb/field.h> +#include <kexidb/queryschema.h> +#include <kexidb/roweditbuffer.h> +#include <kexidb/cursor.h> +#include <kexidb/utils.h> +#include <kexi.h> + +#include <kdebug.h> +#include <klocale.h> + +#include <qapplication.h> + +unsigned short KexiTableViewData::charTable[]= +{ + #include "chartable.txt" +}; + +KexiTableViewColumn::KexiTableViewColumn(KexiDB::Field& f, bool owner) +: columnInfo(0) +, visibleLookupColumnInfo(0) +, m_field(&f) +{ + isDBAware = false; + m_fieldOwned = owner; + m_captionAliasOrName = m_field->captionOrName(); + init(); +} + +KexiTableViewColumn::KexiTableViewColumn(const QString& name, KexiDB::Field::Type ctype, + uint cconst, + uint options, + uint length, uint precision, + QVariant defaultValue, + const QString& caption, const QString& description, uint width +) +: columnInfo(0) +, visibleLookupColumnInfo(0) +{ + m_field = new KexiDB::Field( + name, ctype, + cconst, + options, + length, precision, + defaultValue, + caption, description, width); + + isDBAware = false; + m_fieldOwned = true; + m_captionAliasOrName = m_field->captionOrName(); + init(); +} + +KexiTableViewColumn::KexiTableViewColumn(const QString& name, KexiDB::Field::Type ctype, + const QString& caption, const QString& description) +: columnInfo(0) +, visibleLookupColumnInfo(0) +{ + m_field = new KexiDB::Field( + name, ctype, + KexiDB::Field::NoConstraints, + KexiDB::Field::NoOptions, + 0, 0, + QVariant(), + caption, description); + + isDBAware = false; + m_fieldOwned = true; + m_captionAliasOrName = m_field->captionOrName(); + init(); +} + +// db-aware +KexiTableViewColumn::KexiTableViewColumn( + const KexiDB::QuerySchema &query, KexiDB::QueryColumnInfo& aColumnInfo, + KexiDB::QueryColumnInfo* aVisibleLookupColumnInfo) +: columnInfo(&aColumnInfo) +, visibleLookupColumnInfo(aVisibleLookupColumnInfo) +, m_field(aColumnInfo.field) +{ + isDBAware = true; + m_fieldOwned = false; + + //setup column's caption: + if (!columnInfo->field->caption().isEmpty()) { + m_captionAliasOrName = columnInfo->field->caption(); + } + else { + //reuse alias if available: + m_captionAliasOrName = columnInfo->alias; + //last hance: use field name + if (m_captionAliasOrName.isEmpty()) + m_captionAliasOrName = columnInfo->field->name(); + //todo: compute other auto-name? + } + init(); + //setup column's readonly flag: true, if + // - it's not from parent table's field, or + // - if the query itself is coming from read-only connection, or + // - if the query itself is stored (i.e. has connection) and lookup column is defined + const bool columnFromMasterTable = query.masterTable()==columnInfo->field->table(); + m_readOnly = !columnFromMasterTable + || (query.connection() && query.connection()->isReadOnly()); +// || (query.connection() && (query.connection()->isReadOnly() || visibleLookupColumnInfo)); +//! @todo 2.0: remove this when queries become editable ^^^^^^^^^^^^^^ +// kdDebug() << "KexiTableViewColumn: query.masterTable()==" +// << (query.masterTable() ? query.masterTable()->name() : "notable") << ", columnInfo->field->table()==" +// << (columnInfo->field->table() ? columnInfo->field->table()->name() : "notable") << endl; + +// m_visible = query.isFieldVisible(&f); +} + +KexiTableViewColumn::KexiTableViewColumn(bool) +: columnInfo(0) +, visibleLookupColumnInfo(0) +, m_field(0) +{ + isDBAware = false; + init(); +} + +KexiTableViewColumn::~KexiTableViewColumn() +{ + if (m_fieldOwned) + delete m_field; + setValidator( 0 ); + delete m_relatedData; +} + +void KexiTableViewColumn::init() +{ + m_relatedData = 0; + m_readOnly = false; + m_visible = true; + m_data = 0; + m_validator = 0; + m_relatedDataEditable = false; + m_headerTextVisible = true; +} + +void KexiTableViewColumn::setValidator( KexiUtils::Validator* v ) +{ + if (m_validator) {//remove old one + if (!m_validator->parent()) //destroy if has no parent + delete m_validator; + } + m_validator = v; +} + +void KexiTableViewColumn::setRelatedData(KexiTableViewData *data) +{ + if (isDBAware) + return; + if (m_relatedData) + delete m_relatedData; + m_relatedData = 0; + if (!data) + return; + //find a primary key + KexiTableViewColumn::ListIterator it( data->columns ); + for (int id = 0;it.current();++it, id++) { + if (it.current()->field()->isPrimaryKey()) { + //found, remember + m_relatedDataPKeyID = id; + m_relatedData = data; + return; + } + } +} + +void KexiTableViewColumn::setRelatedDataEditable(bool set) +{ + m_relatedDataEditable = set; +} + +bool KexiTableViewColumn::isReadOnly() const +{ + return m_readOnly || (m_data && m_data->isReadOnly()); +} + +bool KexiTableViewColumn::acceptsFirstChar(const QChar& ch) const +{ + // the field we're looking at can be related to "visible lookup column" + // if lookup column is present + KexiDB::Field *visibleField = visibleLookupColumnInfo + ? visibleLookupColumnInfo->field : m_field; + if (visibleField->isNumericType()) { + if (ch=='.' || ch==',') + return visibleField->isFPNumericType(); + if (ch=='-') + return !visibleField->isUnsigned(); + if (ch=='+' || (ch>='0' && ch<='9')) + return true; + return false; + } + + switch (visibleField->type()) { + case KexiDB::Field::Boolean: + return false; + case KexiDB::Field::Date: + case KexiDB::Field::DateTime: + case KexiDB::Field::Time: + return ch>='0' && ch<='9'; + default:; + } + return true; +} + + +//------------------------------------------------------ + +KexiTableViewData::KexiTableViewData() + : QObject() + , KexiTableViewDataBase() +{ + init(); +} + +// db-aware ctor +KexiTableViewData::KexiTableViewData(KexiDB::Cursor *c) + : QObject() + , KexiTableViewDataBase() +{ + init(); + m_cursor = c; + m_containsROWIDInfo = m_cursor->containsROWIDInfo(); + if (m_cursor && m_cursor->query()) { + const KexiDB::QuerySchema::FieldsExpandedOptions fieldsExpandedOptions + = m_containsROWIDInfo ? KexiDB::QuerySchema::WithInternalFieldsAndRowID + : KexiDB::QuerySchema::WithInternalFields; + m_itemSize = m_cursor->query()->fieldsExpanded( fieldsExpandedOptions ).count(); + } + else + m_itemSize = columns.count()+(m_containsROWIDInfo?1:0); + + // Allocate KexiTableViewColumn objects for each visible query column + const KexiDB::QueryColumnInfo::Vector fields = m_cursor->query()->fieldsExpanded(); + const uint fieldsCount = fields.count(); + for (uint i=0;i < fieldsCount;i++) { + KexiDB::QueryColumnInfo *ci = fields[i]; + if (ci->visible) { + KexiDB::QueryColumnInfo *visibleLookupColumnInfo = 0; + if (ci->indexForVisibleLookupValue() != -1) { + //Lookup field is defined + visibleLookupColumnInfo = m_cursor->query()->expandedOrInternalField( ci->indexForVisibleLookupValue() ); + /* not needed + if (visibleLookupColumnInfo) { + // 2. Create a KexiTableViewData object for each found lookup field + }*/ + } + KexiTableViewColumn* col = new KexiTableViewColumn(*m_cursor->query(), *ci, visibleLookupColumnInfo); + addColumn( col ); + } + } +} + +KexiTableViewData::KexiTableViewData( + const QValueList<QVariant> &keys, const QValueList<QVariant> &values, + KexiDB::Field::Type keyType, KexiDB::Field::Type valueType) + : QObject() + , KexiTableViewDataBase() +{ + init(keys, values, keyType, valueType); +} + +KexiTableViewData::KexiTableViewData( + KexiDB::Field::Type keyType, KexiDB::Field::Type valueType) +{ + const QValueList<QVariant> empty; + init(empty, empty, keyType, valueType); +} + +KexiTableViewData::~KexiTableViewData() +{ + emit destroying(); + clearInternal(); +} + +void KexiTableViewData::init( + const QValueList<QVariant> &keys, const QValueList<QVariant> &values, + KexiDB::Field::Type keyType, KexiDB::Field::Type valueType) +{ + init(); + KexiDB::Field *keyField = new KexiDB::Field("key", keyType); + keyField->setPrimaryKey(true); + KexiTableViewColumn *keyColumn = new KexiTableViewColumn(*keyField, true); + keyColumn->setVisible(false); + addColumn(keyColumn); + + KexiDB::Field *valueField = new KexiDB::Field("value", valueType); + KexiTableViewColumn *valueColumn = new KexiTableViewColumn(*valueField, true); + addColumn(valueColumn); + + uint cnt = QMIN(keys.count(), values.count()); + QValueList<QVariant>::ConstIterator it_keys = keys.constBegin(); + QValueList<QVariant>::ConstIterator it_values = values.constBegin(); + for (;cnt>0;++it_keys, ++it_values, cnt--) { + KexiTableItem *item = new KexiTableItem(2); + (*item)[0] = (*it_keys); + (*item)[1] = (*it_values); + append( item ); + } +} + +void KexiTableViewData::init() +{ + m_sortedColumn = 0; + m_realSortedColumn = 0; +// m_order = 1; + m_order = 0; + m_type = 1; + m_pRowEditBuffer = 0; + m_cursor = 0; + m_readOnly = false; + m_insertingEnabled = true; + + setAutoDelete(true); + columns.setAutoDelete(true); + m_visibleColumnsCount=0; + m_visibleColumnsIDs.resize(100); + m_globalColumnsIDs.resize(100); + + m_autoIncrementedColumn = -2; + m_containsROWIDInfo = false; + m_itemSize = 0; +} + +void KexiTableViewData::deleteLater() +{ + m_cursor = 0; + QObject::deleteLater(); +} + +void KexiTableViewData::addColumn( KexiTableViewColumn* col ) +{ +// if (!col->isDBAware) { +// if (!m_simpleColumnsByName) +// m_simpleColumnsByName = new QDict<KexiTableViewColumn>(101); +// m_simpleColumnsByName->insert(col->caption,col);//for faster lookup +// } + columns.append( col ); + col->m_data = this; + if (m_globalColumnsIDs.size() < columns.count()) {//sanity + m_globalColumnsIDs.resize( m_globalColumnsIDs.size()*2 ); + } + if (col->visible()) { + m_visibleColumnsCount++; + if (m_visibleColumnsIDs.size() < m_visibleColumnsCount) {//sanity + m_visibleColumnsIDs.resize( m_visibleColumnsIDs.size()*2 ); + } + m_visibleColumnsIDs[ columns.count()-1 ] = m_visibleColumnsCount-1; + m_globalColumnsIDs[ m_visibleColumnsCount-1 ] = columns.count()-1; + } + else { + m_visibleColumnsIDs[ columns.count()-1 ] = -1; + } + m_autoIncrementedColumn = -2; //clear cache; + if (!m_cursor || !m_cursor->query()) + m_itemSize = columns.count()+(m_containsROWIDInfo?1:0); +} + +QString KexiTableViewData::dbTableName() const +{ + if (m_cursor && m_cursor->query() && m_cursor->query()->masterTable()) + return m_cursor->query()->masterTable()->name(); + return QString::null; +} + +void KexiTableViewData::setSorting(int column, bool ascending) +{ + if (column>=0 && column<(int)columns.count()) { + m_order = (ascending ? 1 : -1); + } + else { + m_order = 0; + m_sortedColumn = -1; + m_realSortedColumn = -1; + return; + } + // find proper column information for sorting (lookup column points to alternate column with visible data) + const KexiTableViewColumn *tvcol = columns.at(column); + KexiDB::QueryColumnInfo* visibleLookupColumnInfo = tvcol->visibleLookupColumnInfo; + const KexiDB::Field *field = visibleLookupColumnInfo ? visibleLookupColumnInfo->field : tvcol->field(); + m_sortedColumn = column; + m_realSortedColumn = tvcol->columnInfo->indexForVisibleLookupValue()!=-1 + ? tvcol->columnInfo->indexForVisibleLookupValue() : m_sortedColumn; + + // setup compare function + const int t = field->type(); + if (field->isTextType()) + cmpFunc = &KexiTableViewData::cmpStr; + else if (KexiDB::Field::isFPNumericType(t)) + cmpFunc = &KexiTableViewData::cmpDouble; + else if (t==KexiDB::Field::BigInteger) { + if (field->isUnsigned()) + cmpFunc = &KexiTableViewData::cmpULongLong; + else + cmpFunc = &KexiTableViewData::cmpLongLong; + } + else if (t == KexiDB::Field::Integer && field->isUnsigned()) + cmpFunc = &KexiTableViewData::cmpUInt; + else if (t == KexiDB::Field::Boolean || KexiDB::Field::isNumericType(t)) + cmpFunc = &KexiTableViewData::cmpInt; //other integers + else if (t == KexiDB::Field::Date) + cmpFunc = &KexiTableViewData::cmpDate; + else if (t == KexiDB::Field::Time) + cmpFunc = &KexiTableViewData::cmpTime; + else if (t == KexiDB::Field::DateTime) + cmpFunc = &KexiTableViewData::cmpDateTime; + else if (t == KexiDB::Field::BLOB) +//! TODO allow users to define BLOB sorting function? + cmpFunc = &KexiTableViewData::cmpBLOB; + else + cmpFunc = &KexiTableViewData::cmpStr; //anything else +} + +int KexiTableViewData::compareItems(Item item1, Item item2) +{ + return ((this->*cmpFunc) (item1, item2)); +} + +//! compare NULLs : NULL is smaller than everything +#define CMP_NULLS(item1, item2) \ + m_leftTmp = ((KexiTableItem *)item1)->at(m_realSortedColumn); \ + if (m_leftTmp.isNull()) \ + return -m_order; \ + m_rightTmp = ((KexiTableItem *)item2)->at(m_realSortedColumn); \ + if (m_rightTmp.isNull()) \ + return m_order + +#define CAST_AND_COMPARE(casting, item1, item2) \ + CMP_NULLS(item1, item2); \ + if (m_leftTmp.casting() < m_rightTmp.casting()) \ + return -m_order; \ + if (m_leftTmp.casting() > m_rightTmp.casting()) \ + return m_order; \ + return 0 + +int KexiTableViewData::cmpInt(Item item1, Item item2) +{ + CAST_AND_COMPARE(toInt, item1, item2); +} + +int KexiTableViewData::cmpUInt(Item item1, Item item2) +{ + CAST_AND_COMPARE(toUInt, item1, item2); +} + +int KexiTableViewData::cmpLongLong(Item item1, Item item2) +{ + CAST_AND_COMPARE(toLongLong, item1, item2); +} + +int KexiTableViewData::cmpULongLong(Item item1, Item item2) +{ + CAST_AND_COMPARE(toULongLong, item1, item2); +} + +int KexiTableViewData::cmpDouble(Item item1, Item item2) +{ + CAST_AND_COMPARE(toDouble, item1, item2); +} + +int KexiTableViewData::cmpDate(Item item1, Item item2) +{ + CAST_AND_COMPARE(toDate, item1, item2); +} + +int KexiTableViewData::cmpDateTime(Item item1, Item item2) +{ + CAST_AND_COMPARE(toDateTime, item1, item2); +} + +int KexiTableViewData::cmpTime(Item item1, Item item2) +{ + CAST_AND_COMPARE(toDate, item1, item2); +} + +int KexiTableViewData::cmpStr(Item item1, Item item2) +{ + CMP_NULLS(item1, item2); + const QString &as = m_leftTmp.toString(); + const QString &bs = m_rightTmp.toString(); + + const QChar *a = as.unicode(); + const QChar *b = bs.unicode(); + + if ( a == b ) + return 0; + if ( a == 0 ) + return -1; + if ( b == 0 ) + return 1; + + unsigned short au; + unsigned short bu; + + int l=QMIN(as.length(),bs.length()); + + au = a->unicode(); + bu = b->unicode(); + au = (au <= 0x17e ? charTable[au] : 0xffff); + bu = (bu <= 0x17e ? charTable[bu] : 0xffff); + + while (l-- && au == bu) + { + a++,b++; + au = a->unicode(); + bu = b->unicode(); + au = (au <= 0x17e ? charTable[au] : 0xffff); + bu = (bu <= 0x17e ? charTable[bu] : 0xffff); + } + + if ( l==-1 ) + return m_order*(as.length()-bs.length()); + + return m_order*(au-bu); +} + +int KexiTableViewData::cmpBLOB(Item item1, Item item2) +{ + CMP_NULLS(item1, item2); + return m_leftTmp.toByteArray().size() - m_rightTmp.toByteArray().size(); +} + +void KexiTableViewData::setReadOnly(bool set) +{ + if (m_readOnly == set) + return; + m_readOnly = set; + if (m_readOnly) + setInsertingEnabled(false); +} + +void KexiTableViewData::setInsertingEnabled(bool set) +{ + if (m_insertingEnabled == set) + return; + m_insertingEnabled = set; + if (m_insertingEnabled) + setReadOnly(false); +} + +void KexiTableViewData::clearRowEditBuffer() +{ + //init row edit buffer + if (!m_pRowEditBuffer) + m_pRowEditBuffer = new KexiDB::RowEditBuffer(isDBAware()); + else + m_pRowEditBuffer->clear(); +} + +bool KexiTableViewData::updateRowEditBufferRef(KexiTableItem *item, + int colnum, KexiTableViewColumn* col, QVariant& newval, bool allowSignals, + QVariant *visibleValueForLookupField) +{ + m_result.clear(); + if (allowSignals) + emit aboutToChangeCell(item, colnum, newval, &m_result); + if (!m_result.success) + return false; + + kdDebug() << "KexiTableViewData::updateRowEditBufferRef() column #" + << colnum << " = " << newval.toString() << endl; + if (!col) { + kdWarning() << "KexiTableViewData::updateRowEditBufferRef(): column #" + << colnum << " not found! col==0" << endl; + return false; + } + if (!m_pRowEditBuffer) + m_pRowEditBuffer = new KexiDB::RowEditBuffer(isDBAware()); + if (m_pRowEditBuffer->isDBAware()) { + if (!(col->columnInfo)) { + kdWarning() << "KexiTableViewData::updateRowEditBufferRef(): column #" + << colnum << " not found!" << endl; + return false; + } + m_pRowEditBuffer->insert( *col->columnInfo, newval); + + if (col->visibleLookupColumnInfo && visibleValueForLookupField) { + //this is value for lookup table: update visible value as well + m_pRowEditBuffer->insert( *col->visibleLookupColumnInfo, *visibleValueForLookupField); + } + return true; + } + if (!(col->field())) { + kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" << colnum<<" not found!" << endl; + return false; + } + //not db-aware: + const QString colname = col->field()->name(); + if (colname.isEmpty()) { + kdDebug() << "KexiTableViewData::updateRowEditBufferRef(): column #" << colnum<<" not found!" << endl; + return false; + } + m_pRowEditBuffer->insert(colname, newval); + return true; +} + +//get a new value (if present in the buffer), or the old one, otherwise +//(taken here for optimization) +#define GET_VALUE if (!val) { \ + val = m_cursor \ + ? m_pRowEditBuffer->at( *it_f.current()->columnInfo, true /* useDefaultValueIfPossible */ ) \ + : m_pRowEditBuffer->at( *f ); \ + if (!val) \ + val = &(*it_r); /* get old value */ \ + } + +//! @todo if there're multiple views for this data, we need multiple buffers! +bool KexiTableViewData::saveRow(KexiTableItem& item, bool insert, bool repaint) +{ + if (!m_pRowEditBuffer) + return true; //nothing to do + + //check constraints: + //-check if every NOT NULL and NOT EMPTY field is filled + KexiTableViewColumn::ListIterator it_f(columns); + KexiDB::RowData::ConstIterator it_r = item.constBegin(); + int col = 0; + const QVariant *val; + for (;it_f.current() && it_r!=item.constEnd();++it_f,++it_r,col++) { + KexiDB::Field *f = it_f.current()->field(); + val = 0; + if (f->isNotNull()) { + GET_VALUE; + //check it + if (val->isNull() && !f->isAutoIncrement()) { + //NOT NULL violated + m_result.msg = i18n("\"%1\" column requires a value to be entered.") + .arg(f->captionOrName()) + "\n\n" + Kexi::msgYouCanImproveData(); + m_result.desc = i18n("The column's constraint is declared as NOT NULL."); + m_result.column = col; + return false; + } + } + if (f->isNotEmpty()) { + GET_VALUE; + if (!f->isAutoIncrement() && (val->isNull() || KexiDB::isEmptyValue( f, *val ))) { + //NOT EMPTY violated + m_result.msg = i18n("\"%1\" column requires a value to be entered.") + .arg(f->captionOrName()) + "\n\n" + Kexi::msgYouCanImproveData(); + m_result.desc = i18n("The column's constraint is declared as NOT EMPTY."); + m_result.column = col; + return false; + } + } + } + + if (m_cursor) {//db-aware + if (insert) { + if (!m_cursor->insertRow( static_cast<KexiDB::RowData&>(item), *m_pRowEditBuffer, + m_containsROWIDInfo/*also retrieve ROWID*/ )) + { + m_result.msg = i18n("Row inserting failed.") + "\n\n" + + Kexi::msgYouCanImproveData(); + KexiDB::getHTMLErrorMesage(m_cursor, &m_result); + +/* if (desc) + *desc = +js: TODO: use KexiMainWindowImpl::showErrorMessage(const QString &title, KexiDB::Object *obj) + after it will be moved somewhere to kexidb (this will require moving other + showErrorMessage() methods from KexiMainWindowImpl to libkexiutils....) + then: just call: *desc = KexiDB::errorMessage(m_cursor); +*/ + return false; + } + } + else { // row updating +// if (m_containsROWIDInfo) +// ROWID = item[columns.count()].toULongLong(); + if (!m_cursor->updateRow( static_cast<KexiDB::RowData&>(item), *m_pRowEditBuffer, + m_containsROWIDInfo/*use ROWID*/)) + { + m_result.msg = i18n("Row changing failed.") + "\n\n" + Kexi::msgYouCanImproveData(); +//! @todo set m_result.column if possible + KexiDB::getHTMLErrorMesage(m_cursor, m_result.desc); + return false; + } + } + } + else {//not db-aware version + KexiDB::RowEditBuffer::SimpleMap b = m_pRowEditBuffer->simpleBuffer(); + for (KexiDB::RowEditBuffer::SimpleMap::ConstIterator it = b.constBegin();it!=b.constEnd();++it) { + uint i=0; + for (KexiTableViewColumn::ListIterator it2(columns);it2.current();++it2, i++) { + if (it2.current()->field()->name()==it.key()) { + kdDebug() << it2.current()->field()->name()<< ": "<<item[i].toString()<<" -> "<<it.data().toString()<<endl; + item[i] = it.data(); + } + } + } + } + + m_pRowEditBuffer->clear(); + + if (repaint) + emit rowRepaintRequested(item); + return true; +} + +bool KexiTableViewData::saveRowChanges(KexiTableItem& item, bool repaint) +{ + kdDebug() << "KexiTableViewData::saveRowChanges()..." << endl; + m_result.clear(); + emit aboutToUpdateRow(&item, m_pRowEditBuffer, &m_result); + if (!m_result.success) + return false; + + if (saveRow(item, false /*update*/, repaint)) { + emit rowUpdated(&item); + return true; + } + return false; +} + +bool KexiTableViewData::saveNewRow(KexiTableItem& item, bool repaint) +{ + kdDebug() << "KexiTableViewData::saveNewRow()..." << endl; + m_result.clear(); + emit aboutToInsertRow(&item, &m_result, repaint); + if (!m_result.success) + return false; + + if (saveRow(item, true /*insert*/, repaint)) { + emit rowInserted(&item, repaint); + return true; + } + return false; +} + +bool KexiTableViewData::deleteRow(KexiTableItem& item, bool repaint) +{ + m_result.clear(); + emit aboutToDeleteRow(item, &m_result, repaint); + if (!m_result.success) + return false; + + if (m_cursor) {//db-aware + m_result.success = false; + if (!m_cursor->deleteRow( static_cast<KexiDB::RowData&>(item), m_containsROWIDInfo/*use ROWID*/ )) { + m_result.msg = i18n("Row deleting failed."); +/*js: TODO: use KexiDB::errorMessage() for description (desc) as in KexiTableViewData::saveRow() */ + KexiDB::getHTMLErrorMesage(m_cursor, &m_result); + m_result.success = false; + return false; + } + } + + if (!removeRef(&item)) { + //aah - this shouldn't be! + kdWarning() << "KexiTableViewData::deleteRow(): !removeRef() - IMPL. ERROR?" << endl; + m_result.success = false; + return false; + } + emit rowDeleted(); + return true; +} + +void KexiTableViewData::deleteRows( const QValueList<int> &rowsToDelete, bool repaint ) +{ + Q_UNUSED( repaint ); + + if (rowsToDelete.isEmpty()) + return; + int last_r=0; + first(); + for (QValueList<int>::ConstIterator r_it = rowsToDelete.constBegin(); r_it!=rowsToDelete.constEnd(); ++r_it) { + for (; last_r<(*r_it); last_r++) { + next(); + } + remove(); + last_r++; + } +//DON'T CLEAR BECAUSE KexiTableViewPropertyBuffer will clear BUFFERS! +//--> emit reloadRequested(); //! \todo more effective? + emit rowsDeleted( rowsToDelete ); +} + +void KexiTableViewData::insertRow(KexiTableItem& item, uint index, bool repaint) +{ + if (!insert( index = QMIN(index, count()), &item )) + return; + emit rowInserted(&item, index, repaint); +} + +void KexiTableViewData::clearInternal() +{ + clearRowEditBuffer(); +// qApp->processEvents( 1 ); +//TODO: this is time consuming: find better data model +// KexiTableViewDataBase::clear(); + const uint c = count(); + for (uint i=0; i<c; i++) { + removeLast(); +#ifndef KEXI_NO_PROCESS_EVENTS + if (i % 1000 == 0) + qApp->processEvents( 1 ); +#endif + } +} + +bool KexiTableViewData::deleteAllRows(bool repaint) +{ + clearInternal(); + + bool res = true; + if (m_cursor) { + //db-aware + res = m_cursor->deleteAllRows(); + } + + if (repaint) + emit reloadRequested(); + return res; +} + +int KexiTableViewData::autoIncrementedColumn() +{ + if (m_autoIncrementedColumn==-2) { + //find such a column + m_autoIncrementedColumn = 0; + KexiTableViewColumn::ListIterator it(columns); + for (; it.current(); ++it, m_autoIncrementedColumn++) { + if (it.current()->field()->isAutoIncrement()) + break; + } + if (!it.current()) + m_autoIncrementedColumn = -1; + } + return m_autoIncrementedColumn; +} + +void KexiTableViewData::preloadAllRows() +{ + if (!m_cursor) + return; + + //const uint fcount = m_cursor->fieldCount() + (m_containsROWIDInfo ? 1 : 0); + m_cursor->moveFirst(); + for (int i=0;!m_cursor->eof();i++) { + KexiTableItem *item = new KexiTableItem(0); + m_cursor->storeCurrentRow(*item); +// item->debug(); + append( item ); + m_cursor->moveNext(); +#ifndef KEXI_NO_PROCESS_EVENTS + if ((i % 1000) == 0) + qApp->processEvents( 1 ); +#endif + } +} + +bool KexiTableViewData::isReadOnly() const +{ + return m_readOnly || (m_cursor && m_cursor->connection()->isReadOnly()); +} + +#include "kexitableviewdata.moc" |