diff options
author | João Abecasis <joao.abecasis@nokia.com> | 2012-02-21 14:58:57 +0100 |
---|---|---|
committer | João Abecasis <joao.abecasis@nokia.com> | 2012-02-21 14:58:57 +0100 |
commit | 31a0358afb4fde998d1eeeaa80fc32e4420266c7 (patch) | |
tree | 938455353474196c1f49b0529b5b644e19c21f3e /src/sql | |
parent | 4c8a4058c359c8d163c643120426079fc80c8214 (diff) | |
parent | 69da8588d41bbf5ab785f5ad7c1fce76deefc7d0 (diff) |
Merge remote-tracking branch 'gerrit/master' into containers
Conflicts:
src/corelib/tools/qbytearray.h
Change-Id: I03b1f3e05c9b7a45130887c522fcd9b7aa387129
Diffstat (limited to 'src/sql')
-rw-r--r-- | src/sql/drivers/psql/qsql_psql.cpp | 12 | ||||
-rw-r--r-- | src/sql/drivers/sqlite/qsql_sqlite.cpp | 12 | ||||
-rw-r--r-- | src/sql/drivers/sqlite2/qsql_sqlite2.cpp | 11 | ||||
-rw-r--r-- | src/sql/drivers/tds/qsql_tds.cpp | 15 | ||||
-rw-r--r-- | src/sql/kernel/qsqldatabase.cpp | 5 | ||||
-rw-r--r-- | src/sql/models/qsqlquerymodel.h | 2 | ||||
-rw-r--r-- | src/sql/models/qsqlrelationaltablemodel.cpp | 25 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel.cpp | 327 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel_p.h | 35 |
9 files changed, 213 insertions, 231 deletions
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index e3533581ba..ec31d54f0f 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -107,18 +107,10 @@ template <typename T> inline void PQfreemem(T *t, int = 0) { free(t); } -QT_BEGIN_NAMESPACE namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<PGconn*> { - enum { Value = false }; -}; -} QT_END_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(PGconn*) Q_DECLARE_METATYPE(PGconn*) -QT_BEGIN_NAMESPACE namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<PGresult*> { - enum { Value = false }; -}; -} QT_END_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(PGresult*) Q_DECLARE_METATYPE(PGresult*) QT_BEGIN_NAMESPACE diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp index 962fc97dfc..d2dc5af070 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.cpp +++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -59,18 +59,10 @@ #include <sqlite3.h> -QT_BEGIN_NAMESPACE namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<sqlite3*> { - enum { Value = false }; -}; -} QT_END_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(sqlite3*) Q_DECLARE_METATYPE(sqlite3*) -QT_BEGIN_NAMESPACE namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<sqlite3_stmt*> { - enum { Value = false }; -}; -} QT_END_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*) Q_DECLARE_METATYPE(sqlite3_stmt*) QT_BEGIN_NAMESPACE diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp index 46127923bf..b42f82e800 100644 --- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp +++ b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp @@ -60,15 +60,10 @@ typedef struct sqlite_vm sqlite_vm; -QT_BEGIN_NAMESPACE namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<sqlite_vm*> { - enum { Value = false }; -}; -template <> struct IsPointerToTypeDerivedFromQObject<sqlite*> { - enum { Value = false }; -}; -} QT_END_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(sqlite_vm*) Q_DECLARE_METATYPE(sqlite_vm*) + +Q_DECLARE_OPAQUE_POINTER(sqlite*) Q_DECLARE_METATYPE(sqlite*) QT_BEGIN_NAMESPACE diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp index 2a97a3c392..b9414499d8 100644 --- a/src/sql/drivers/tds/qsql_tds.cpp +++ b/src/sql/drivers/tds/qsql_tds.cpp @@ -63,6 +63,9 @@ #include <stdlib.h> +Q_DECLARE_OPAQUE_POINTER(LOGINREC*) +Q_DECLARE_OPAQUE_POINTER(DBPROCESS*) + QT_BEGIN_NAMESPACE #ifdef DBNTWIN32 @@ -127,18 +130,6 @@ QT_BEGIN_NAMESPACE #define CS_PUBLIC #endif -namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<LOGINREC*> { - enum { Value = false }; -}; -} - -namespace QtPrivate { -template <> struct IsPointerToTypeDerivedFromQObject<DBPROCESS*> { - enum { Value = false }; -}; -} - QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = -1) { return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo); diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index d260588dd5..7b6a2b8c12 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -138,10 +138,7 @@ public: driver(dr), port(-1) { - if(driver) - precisionPolicy = driver->numericalPrecisionPolicy(); - else - precisionPolicy= QSql::LowPrecisionDouble; + precisionPolicy = QSql::LowPrecisionDouble; } QSqlDatabasePrivate(const QSqlDatabasePrivate &other); ~QSqlDatabasePrivate(); diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h index 7db973b0d4..b5e1a7a746 100644 --- a/src/sql/models/qsqlquerymodel.h +++ b/src/sql/models/qsqlquerymodel.h @@ -92,7 +92,7 @@ public: protected: virtual void queryChange(); - QModelIndex indexInQuery(const QModelIndex &item) const; + virtual QModelIndex indexInQuery(const QModelIndex &item) const; void setLastError(const QSqlError &error); QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = 0); }; diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index e12976ef24..8dd18ca1d0 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -268,7 +268,7 @@ public: void clearCache(); void revertCachedRow(int row); - void translateFieldNames(int row, QSqlRecord &values) const; + void translateFieldNames(QSqlRecord &values) const; QSqlRelationalTableModel::JoinMode joinMode; }; @@ -299,9 +299,7 @@ void QSqlRelationalTableModelPrivate::revertCachedRow(int row) int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const { - QString fieldname = name; - if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName)) - fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName); + QString fieldname = strippedFieldName(name); int idx = baseRec.indexOf(fieldname); if (idx == -1) { // If the name is an alias we can find it here. @@ -440,9 +438,9 @@ QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) cons //already have the correct display value. if (d->strategy != OnFieldChange) { const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row()); - if (row.op != QSqlTableModelPrivate::None && row.rec.isGenerated(index.column())) { - if (d->strategy == OnManualSubmit || row.op != QSqlTableModelPrivate::Delete) { - QVariant v = row.rec.value(index.column()); + if (row.op() != QSqlTableModelPrivate::None && row.rec().isGenerated(index.column())) { + if (d->strategy == OnManualSubmit || row.op() != QSqlTableModelPrivate::Delete) { + QVariant v = row.rec().value(index.column()); if (v.isValid()) return relation.dictionary[v.toString()]; } @@ -746,16 +744,13 @@ void QSqlRelationalTableModel::setTable(const QString &table) /*! \internal */ -void QSqlRelationalTableModelPrivate::translateFieldNames(int row, QSqlRecord &values) const +void QSqlRelationalTableModelPrivate::translateFieldNames(QSqlRecord &values) const { - Q_Q(const QSqlRelationalTableModel); - for (int i = 0; i < values.count(); ++i) { - int realCol = q->indexInQuery(q->createIndex(row, i)).column(); - if (realCol != -1 && relations.value(realCol).isValid()) { + if (relations.value(i).isValid()) { QVariant v = values.value(i); bool gen = values.isGenerated(i); - values.replace(i, baseRec.field(realCol)); + values.replace(i, baseRec.field(i)); values.setValue(i, v); values.setGenerated(i, gen); } @@ -770,7 +765,7 @@ bool QSqlRelationalTableModel::updateRowInTable(int row, const QSqlRecord &value Q_D(QSqlRelationalTableModel); QSqlRecord rec = values; - d->translateFieldNames(row, rec); + d->translateFieldNames(rec); return QSqlTableModel::updateRowInTable(row, rec); } @@ -783,7 +778,7 @@ bool QSqlRelationalTableModel::insertRowIntoTable(const QSqlRecord &values) Q_D(QSqlRelationalTableModel); QSqlRecord rec = values; - d->translateFieldNames(0, rec); + d->translateFieldNames(rec); return QSqlTableModel::insertRowIntoTable(rec); } diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index ff32533440..932bbbfd6b 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -68,10 +68,30 @@ QSqlRecord QSqlTableModelPrivate::record(const QVector<QVariant> &values) const int QSqlTableModelPrivate::nameToIndex(const QString &name) const { + return rec.indexOf(strippedFieldName(name)); +} + +QString QSqlTableModelPrivate::strippedFieldName(const QString &name) const +{ QString fieldname = name; if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName)) fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName); - return rec.indexOf(fieldname); + return fieldname; +} + +int QSqlTableModelPrivate::insertCount(int maxRow) const +{ + int cnt = 0; + CacheMap::ConstIterator i = cache.constBegin(); + const CacheMap::ConstIterator e = cache.constEnd(); + for (; + i != e && (maxRow < 0 || i.key() <= maxRow); + ++i) { + if (i.value().op() == Insert) + ++cnt; + } + + return cnt; } void QSqlTableModelPrivate::initRecordAndPrimaryIndex() @@ -101,7 +121,12 @@ void QSqlTableModelPrivate::revertCachedRow(int row) { Q_Q(QSqlTableModel); ModifiedRow r = cache.value(row); - switch (r.op) { + + // cannot revert a committed change + if (r.submitted()) + return; + + switch (r.op()) { case QSqlTableModelPrivate::None: Q_ASSERT_X(false, "QSqlTableModelPrivate::revertCachedRow()", "Invalid entry in cache map"); return; @@ -174,23 +199,18 @@ bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement, return true; } -QSqlRecord QSqlTableModelPrivate::primaryValues(int row) +QSqlRecord QSqlTableModelPrivate::primaryValues(int row) const { - QSqlRecord record; - if (!query.seek(row)) { - error = query.lastError(); - return record; - } - if (primaryIndex.isEmpty()) { - record = rec; - for (int i = 0; i < record.count(); ++i) - record.setValue(i, query.value(i)); - } else { - record = primaryIndex; - for (int i = 0; i < record.count(); ++i) - record.setValue(i, query.value(rec.indexOf(record.fieldName(i)))); - } - return record; + Q_Q(const QSqlTableModel); + if (cache.value(row).op() == Insert) + return QSqlRecord(); + + QSqlRecord values(primaryIndex.isEmpty() ? rec : primaryIndex); + + for (int i = 0; i < values.count(); ++i) + values.setValue(i, q->QSqlQueryModel::data(createIndex(row, rec.indexOf(values.fieldName(i))), Qt::EditRole)); + + return values; } /*! @@ -251,7 +271,9 @@ QSqlRecord QSqlTableModelPrivate::primaryValues(int row) initiated in the given \a row of the currently active database table. The \a record parameter can be written to (since it is a reference), for example to populate some fields with default - values. + values and set the generated flags of the fields. Do not try to + edit the record via other means such as setData() or setRecord() + while handling this signal. */ /*! @@ -356,6 +378,12 @@ bool QSqlTableModel::select() if (query.isEmpty()) return false; + // clear the submitted flags so revertAll can do its job + for (QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.begin(); + it != d->cache.constEnd(); + ++it) + it.value().setSubmitted(false); + revertAll(); QSqlQuery qu(query, d->db); setQuery(qu); @@ -377,38 +405,31 @@ QVariant QSqlTableModel::data(const QModelIndex &index, int role) const if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole)) return QVariant(); - // Problem.. we need to use QSQM::indexInQuery to handle inserted columns - // but inserted rows we need to handle - // and indexInQuery is not virtual (grrr) so any values we pass to QSQM need - // to handle the insertedRows - QModelIndex item = indexInQuery(index); - if (d->cache.contains(index.row())) { const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row()); switch (d->strategy) { case OnFieldChange: case OnRowChange: - if (row.op == QSqlTableModelPrivate::Insert) { - if (item.column() < 0 || item.column() >= row.rec.count()) + if (row.op() == QSqlTableModelPrivate::Insert) { + if (index.column() < 0 || index.column() >= row.rec().count()) return QVariant(); - return row.rec.value(item.column()); - } else if (row.op == QSqlTableModelPrivate::Update) { - if (row.rec.isGenerated(item.column())) - return row.rec.value(item.column()); + return row.rec().value(index.column()); + } else if (row.op() == QSqlTableModelPrivate::Update) { + if (row.rec().isGenerated(index.column())) + return row.rec().value(index.column()); } break; case OnManualSubmit: - if (row.op == QSqlTableModelPrivate::Insert - || (row.op != QSqlTableModelPrivate::None - && row.rec.isGenerated(item.column()))) - return row.rec.value(item.column()); + if (row.op() == QSqlTableModelPrivate::Insert + || (row.op() != QSqlTableModelPrivate::None + && row.rec().isGenerated(index.column()))) + return row.rec().value(index.column()); break; } } - // We need to handle row mapping here, but not column mapping - return QSqlQueryModel::data(index.sibling(item.row(), index.column()), role); + return QSqlQueryModel::data(index, role); } /*! @@ -419,7 +440,7 @@ QVariant QSqlTableModel::headerData(int section, Qt::Orientation orientation, in Q_D(const QSqlTableModel); if (orientation == Qt::Vertical && role == Qt::DisplayRole) { if (d->cache.contains(section)) { - const QSqlTableModelPrivate::Op op = d->cache.value(section).op; + const QSqlTableModelPrivate::Op op = d->cache.value(section).op(); if (op == QSqlTableModelPrivate::Insert) return QLatin1String("*"); else if (op == QSqlTableModelPrivate::Delete) @@ -447,15 +468,15 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const return false; case OnRowChange: { const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row()); - return row.op == QSqlTableModelPrivate::Update - && row.rec.isGenerated(index.column()); + return row.op() == QSqlTableModelPrivate::Update + && row.rec().isGenerated(index.column()); } case OnManualSubmit: { const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row()); - return row.op == QSqlTableModelPrivate::Insert - || row.op == QSqlTableModelPrivate::Delete - || (row.op == QSqlTableModelPrivate::Update - && row.rec.isGenerated(index.column())); + return row.op() == QSqlTableModelPrivate::Insert + || row.op() == QSqlTableModelPrivate::Delete + || (row.op() == QSqlTableModelPrivate::Update + && row.rec().isGenerated(index.column())); } } return false; @@ -474,13 +495,16 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { Q_D(QSqlTableModel); + if (d->busyInsertingRows) + return false; + if (role != Qt::EditRole) return QSqlQueryModel::setData(index, value, role); if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount()) return false; - if (d->strategy == OnFieldChange && d->cache.value(index.row()).op != QSqlTableModelPrivate::Insert) { + if (d->strategy == OnFieldChange && d->cache.value(index.row()).op() != QSqlTableModelPrivate::Insert) { d->cache.clear(); } else if (d->strategy == OnRowChange && !d->cache.isEmpty() && !d->cache.contains(index.row())) { submit(); @@ -489,39 +513,18 @@ bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, in QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()]; - if (row.op == QSqlTableModelPrivate::None) { + if (row.op() == QSqlTableModelPrivate::None) { row = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update, - d->rec, - d->primaryValues(indexInQuery(index).row())); + d->rec); } row.setValue(index.column(), value); + emit dataChanged(index, index); - bool isOk = true; - if (d->strategy == OnFieldChange && row.op != QSqlTableModelPrivate::Insert) { - // historical bug: bad style to call updateRowInTable. - // Should call submit(), but maybe the author wanted to avoid - // clearing the cache on failure. - isOk = updateRowInTable(index.row(), row.rec); - if (isOk) - select(); - } + if (d->strategy == OnFieldChange && row.op() != QSqlTableModelPrivate::Insert) + return submit(); - // historical bug: dataChanged() is suppressed for OnFieldChange and OnRowChange - // when operating on an "insert" record. This is to accomodate - // applications that call setData() while handling primeInsert(). - // Otherwise dataChanged() would be emitted between beginInsert() - // and endInsert(). - // The price of this workaround is that, although the view making - // the change will already display the new value, other views connected - // to the model probably will not. - // It's not clear why OnManualSubmit is excluded from this workaround. - // Calling setData() while handling primeInsert() is arguably very wrong anyway. - // primeInsert() provides a ref to the record for settings values. - if (d->strategy == OnManualSubmit || row.op != QSqlTableModelPrivate::Insert) - emit dataChanged(index, index); - - return isOk; + return true; } /*! @@ -558,7 +561,7 @@ bool QSqlTableModel::updateRowInTable(int row, const QSqlRecord &values) QSqlRecord rec(values); emit beforeUpdate(row, rec); - const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row); + const QSqlRecord whereValues = d->primaryValues(row); bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName, rec, prepStatement); @@ -625,7 +628,7 @@ bool QSqlTableModel::deleteRowFromTable(int row) Q_D(QSqlTableModel); emit beforeDelete(row); - const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row); + const QSqlRecord whereValues = d->primaryValues(row); bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement, d->tableName, @@ -665,16 +668,18 @@ bool QSqlTableModel::submitAll() { Q_D(QSqlTableModel); - for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin(); + for (QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.begin(); it != d->cache.constEnd(); ++it) { - switch (it.value().op) { + if (it.value().submitted()) + continue; + + switch (it.value().op()) { case QSqlTableModelPrivate::Insert: - if (!insertRowIntoTable(it.value().rec)) + if (!insertRowIntoTable(it.value().rec())) return false; - d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column()); break; case QSqlTableModelPrivate::Update: - if (!updateRowInTable(it.key(), it.value().rec)) + if (!updateRowInTable(it.key(), it.value().rec())) return false; break; case QSqlTableModelPrivate::Delete: @@ -685,6 +690,20 @@ bool QSqlTableModel::submitAll() Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation"); break; } + it.value().setSubmitted(true); + } + + // all changes have been committed + + // clean up inserted rows + QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.end(); + while (it != d->cache.constBegin()) { + --it; + if (it.value().op() == QSqlTableModelPrivate::Insert) { + beginRemoveRows(QModelIndex(), it.key(), it.key()); + it = d->cache.erase(it); + endRemoveRows(); + } } d->clearCache(); return select(); @@ -969,13 +988,20 @@ bool QSqlTableModel::removeColumns(int column, int count, const QModelIndex &par does not support hierarchical structures, \a parent must be an invalid model index. - Emits the beforeDelete() signal before a row is deleted. When - the edit strategy is OnManualSubmit signal emission is delayed - until submitAll() is called. + When the edit strategy is OnManualSubmit, deletion of rows from + the database is delayed until submitAll() is called; otherwise, + deletions are immediate. + + Inserted but not yet submitted rows in the range to be removed + are immediately removed from the model. - Returns true if all rows could be removed; otherwise returns - false. Detailed error information can be retrieved using - lastError(). + Before a row is deleted from the database, the beforeDelete() + signal is emitted. + + If row < 0 or row + count > rowCount(), no action is taken and + false is returned. Returns true if all rows could be removed; + otherwise returns false. Detailed database error information + can be retrieved using lastError(). \sa removeColumns(), insertRows() */ @@ -984,37 +1010,27 @@ bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent) Q_D(QSqlTableModel); if (parent.isValid() || row < 0 || count <= 0) return false; + else if (row + count > rowCount()) + return false; + else if (!count) + return true; - int initialRowCount = rowCount(); - - int i; - for (i = 0; i < count && row + i < rowCount(); ++i) { + for (int i = 0; i < count; ++i) { int idx = row + i; - if (d->cache.value(idx).op == QSqlTableModelPrivate::Insert) { + if (d->cache.value(idx).op() == QSqlTableModelPrivate::Insert) { revertRow(idx); // Reverting a row means all the other cache entries have been adjusted downwards // so fake this by adjusting row --row; } else { - d->cache[idx] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Delete, - QSqlRecord(), - d->primaryValues(indexInQuery(createIndex(idx, 0)).row())); + d->cache[idx] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Delete); if (d->strategy == OnManualSubmit) emit headerDataChanged(Qt::Vertical, idx, idx); } } - if (d->strategy != OnManualSubmit && i > 0) - submit(); - - // historical bug: emit beforeDelete for 1st row beyond end - if (d->strategy != OnManualSubmit) { - if (row + count > initialRowCount) - emit beforeDelete(qMax(initialRowCount, row)); - } - - if (i < count) - return false; + if (d->strategy != OnManualSubmit) + return submit(); return true; } @@ -1045,6 +1061,7 @@ bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent) if (d->strategy != OnManualSubmit && count != 1) return false; + d->busyInsertingRows = true; beginInsertRows(parent, row, row + count - 1); if (d->strategy != OnManualSubmit) @@ -1063,19 +1080,22 @@ bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent) for (int i = 0; i < count; ++i) { d->cache[row + i] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Insert, d->rec); - emit primeInsert(row + i, d->cache[row + i].rec); + emit primeInsert(row + i, d->cache[row + i].recRef()); } endInsertRows(); + d->busyInsertingRows = false; return true; } /*! - Inserts the \a record after \a row. If \a row is negative, the - record will be appended to the end. Calls insertRows() and + Inserts the \a record at position \a row. If \a row is negative, + the record will be appended to the end. Calls insertRows() and setRecord() internally. - Returns true if the row could be inserted, otherwise false. + Only fields where the generated flag is true will be included. + + Returns true if the record could be inserted, otherwise false. \sa insertRows(), removeRows() */ @@ -1086,8 +1106,11 @@ bool QSqlTableModel::insertRecord(int row, const QSqlRecord &record) row = rowCount(); if (!insertRow(row, QModelIndex())) return false; - if (!setRecord(row, record)) + if (!setRecord(row, record)) { + if (d->strategy == OnManualSubmit) + revertRow(row); return false; + } if (d->strategy == OnFieldChange || d->strategy == OnRowChange) return submit(); return true; @@ -1102,13 +1125,7 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const if (parent.isValid()) return 0; - int rc = QSqlQueryModel::rowCount(); - for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin(); - it != d->cache.constEnd(); ++it) { - if (it.value().op == QSqlTableModelPrivate::Insert) - ++rc; - } - return rc; + return QSqlQueryModel::rowCount() + d->insertCount(); } /*! @@ -1126,15 +1143,11 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const { Q_D(const QSqlTableModel); - const QModelIndex it = QSqlQueryModel::indexInQuery(item); // this adjusts columns only - int rowOffset = 0; - QSqlTableModelPrivate::CacheMap::ConstIterator i = d->cache.constBegin(); - while (i != d->cache.constEnd() && i.key() <= it.row()) { - if (i.value().op == QSqlTableModelPrivate::Insert) - ++rowOffset; - ++i; - } - return createIndex(it.row() - rowOffset, it.column(), it.internalPointer()); + if (d->cache.value(item.row()).op() == QSqlTableModelPrivate::Insert) + return QModelIndex(); + + const int rowOffset = d->insertCount(item.row()); + return QSqlQueryModel::indexInQuery(createIndex(item.row() - rowOffset, item.column(), item.internalPointer())); } /*! @@ -1192,8 +1205,10 @@ Qt::ItemFlags QSqlTableModel::flags(const QModelIndex &index) const /*! Sets the values at the specified \a row to the values of \a - record. Returns true if all the values could be set; otherwise - returns false. + record for fields where generated flag is true. + + Returns true if all the values could be set; otherwise returns + false. \sa record() */ @@ -1201,50 +1216,44 @@ bool QSqlTableModel::setRecord(int row, const QSqlRecord &record) { Q_D(QSqlTableModel); Q_ASSERT_X(row >= 0, "QSqlTableModel::setRecord()", "Cannot set a record to a row less than 0"); + if (d->busyInsertingRows) + return false; + if (row >= rowCount()) return false; - if (d->strategy == OnFieldChange && d->cache.value(row).op != QSqlTableModelPrivate::Insert) + if (d->strategy == OnFieldChange && d->cache.value(row).op() != QSqlTableModelPrivate::Insert) d->cache.clear(); else if (d->strategy == OnRowChange && !d->cache.isEmpty() && !d->cache.contains(row)) submit(); - QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row]; - if (mrow.op == QSqlTableModelPrivate::None) - mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update, - d->rec, - d->primaryValues(indexInQuery(createIndex(row, 0)).row())); - - bool isOk = true; + // Check field names and remember mapping + typedef QMap<int, int> Map; + Map map; for (int i = 0; i < record.count(); ++i) { - int idx = d->nameToIndex(record.fieldName(i)); - if (idx == -1) { - isOk = false; - } else if (d->strategy != OnManualSubmit) { - // historical bug: this could all be simple like OnManualSubmit, but isn't - const QModelIndex cIndex = createIndex(row, idx); - // historical bug: comparing EditRole with DisplayRole values here - const QVariant oldValue = data(cIndex); - const QVariant value = record.value(i); - // historical bug: it's a bad idea to check for change here - // historical bug: should test oldValue.isNull() != value.isNull() - if (oldValue.isNull() || oldValue != value) { - // historical bug: dataChanged() is suppressed for Insert. See also setData(). - mrow.setValue(idx, record.value(i)); - if (mrow.op != QSqlTableModelPrivate::Insert) - emit dataChanged(cIndex, cIndex); - } - } else { - mrow.setValue(idx, record.value(i)); + if (record.isGenerated(i)) { + int idx = d->nameToIndex(record.fieldName(i)); + if (idx == -1) + return false; + map[i] = idx; } } - if (d->strategy == OnManualSubmit && isOk) + QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row]; + if (mrow.op() == QSqlTableModelPrivate::None) + mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update, + d->rec); + + Map::const_iterator i = map.constBegin(); + const Map::const_iterator e = map.constEnd(); + for ( ; i != e; ++i) + mrow.setValue(i.value(), record.value(i.key())); + + if (columnCount()) emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1)); - else if (d->strategy == OnFieldChange) - return submitAll(); - else if (d->strategy == OnManualSubmit) - return isOk; + + if (d->strategy == OnFieldChange) + return submit(); return true; } diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h index 56fd839a0c..0ae6b53742 100644 --- a/src/sql/models/qsqltablemodel_p.h +++ b/src/sql/models/qsqltablemodel_p.h @@ -66,10 +66,11 @@ public: QSqlTableModelPrivate() : sortColumn(-1), sortOrder(Qt::AscendingOrder), - strategy(QSqlTableModel::OnRowChange) + strategy(QSqlTableModel::OnRowChange), + busyInsertingRows(false) {} void clear(); - QSqlRecord primaryValues(int index); + QSqlRecord primaryValues(int index) const; virtual void clearCache(); QSqlRecord record(const QVector<QVariant> &values) const; @@ -77,6 +78,8 @@ public: const QSqlRecord &rec, const QSqlRecord &whereValues); virtual void revertCachedRow(int row); virtual int nameToIndex(const QString &name) const; + QString strippedFieldName(const QString &name) const; + int insertCount(int maxRow = -1) const; void initRecordAndPrimaryIndex(); QSqlDatabase db; @@ -85,6 +88,7 @@ public: Qt::SortOrder sortOrder; QSqlTableModel::EditStrategy strategy; + bool busyInsertingRows; QSqlQuery editQuery; QSqlIndex primaryIndex; @@ -93,22 +97,29 @@ public: enum Op { None, Insert, Update, Delete }; - struct ModifiedRow + class ModifiedRow { - inline ModifiedRow(Op o = None, const QSqlRecord &r = QSqlRecord(), const QSqlRecord &pVals = QSqlRecord()) - : op(o), rec(r), primaryValues(pVals) + public: + inline ModifiedRow(Op o = None, const QSqlRecord &r = QSqlRecord()) + : m_op(o), m_rec(r), m_submitted(false) { - for (int i = rec.count() - 1; i >= 0; --i) - rec.setGenerated(i, false); + for (int i = m_rec.count() - 1; i >= 0; --i) + m_rec.setGenerated(i, false); } + inline Op op() const { return m_op; } + inline QSqlRecord rec() const { return m_rec; } + inline QSqlRecord& recRef() { return m_rec; } inline void setValue(int c, const QVariant &v) { - rec.setValue(c, v); - rec.setGenerated(c, true); + m_rec.setValue(c, v); + m_rec.setGenerated(c, true); } - Op op; - QSqlRecord rec; - QSqlRecord primaryValues; + inline bool submitted() const { return m_submitted; } + inline void setSubmitted(bool b) { m_submitted = b; } + private: + Op m_op; + QSqlRecord m_rec; + bool m_submitted; }; typedef QMap<int, ModifiedRow> CacheMap; |