summaryrefslogtreecommitdiffstats
path: root/src/sql/models/qsqltablemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql/models/qsqltablemodel.cpp')
-rw-r--r--src/sql/models/qsqltablemodel.cpp487
1 files changed, 186 insertions, 301 deletions
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index d2b9427287..ff32533440 100644
--- a/src/sql/models/qsqltablemodel.cpp
+++ b/src/sql/models/qsqltablemodel.cpp
@@ -1,8 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Contact: http://www.qt-project.org/
**
** This file is part of the QtSql module of the Qt Toolkit.
**
@@ -35,6 +34,7 @@
**
**
**
+**
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -66,36 +66,6 @@ QSqlRecord QSqlTableModelPrivate::record(const QVector<QVariant> &values) const
return r;
}
-/*! \internal
- Set a record for OnFieldChange and OnRowChange.
-*/
-bool QSqlTableModelPrivate::setRecord(int row, const QSqlRecord &record)
-{
- Q_Q(QSqlTableModel);
- bool isOk = true;
-
- QSqlTableModel::EditStrategy oldStrategy = strategy;
-
- // FieldChange strategy makes no sense when setting an entire row
- if (strategy == QSqlTableModel::OnFieldChange)
- strategy = QSqlTableModel::OnRowChange;
- for (int i = 0; i < record.count(); ++i) {
- int idx = nameToIndex(record.fieldName(i));
- if (idx == -1)
- continue;
- QModelIndex cIndex = q->createIndex(row, idx);
- QVariant value = record.value(i);
- QVariant oldValue = q->data(cIndex);
- if (oldValue.isNull() || oldValue != value)
- isOk &= q->setData(cIndex, value, Qt::EditRole);
- }
- if (isOk && oldStrategy == QSqlTableModel::OnFieldChange)
- q->submitAll();
- strategy = oldStrategy;
-
- return isOk;
-}
-
int QSqlTableModelPrivate::nameToIndex(const QString &name) const
{
QString fieldname = name;
@@ -112,52 +82,21 @@ void QSqlTableModelPrivate::initRecordAndPrimaryIndex()
void QSqlTableModelPrivate::clear()
{
- editIndex = -1;
sortColumn = -1;
sortOrder = Qt::AscendingOrder;
tableName.clear();
editQuery.clear();
- editBuffer.clear();
cache.clear();
primaryIndex.clear();
rec.clear();
filter.clear();
}
-void QSqlTableModelPrivate::revertInsertedRow()
-{
- Q_Q(QSqlTableModel);
- if (insertIndex == -1)
- return;
-
- q->beginRemoveRows(QModelIndex(), insertIndex, insertIndex);
- insertIndex = -1;
- q->endRemoveRows();
-}
-
-void QSqlTableModelPrivate::clearEditBuffer()
-{
- editBuffer = rec;
- clearGenerated(editBuffer);
-}
-
void QSqlTableModelPrivate::clearCache()
{
cache.clear();
}
-void QSqlTableModelPrivate::clearGenerated(QSqlRecord &rec)
-{
- for (int i = rec.count() - 1; i >= 0; i--)
- rec.setGenerated(i, false);
-}
-
-void QSqlTableModelPrivate::setGeneratedValue(QSqlRecord &rec, int c, QVariant v)
-{
- rec.setValue(c, v);
- rec.setGenerated(c, true);
-}
-
void QSqlTableModelPrivate::revertCachedRow(int row)
{
Q_Q(QSqlTableModel);
@@ -444,26 +383,28 @@ QVariant QSqlTableModel::data(const QModelIndex &index, int role) const
// to handle the insertedRows
QModelIndex item = indexInQuery(index);
- switch (d->strategy) {
- case OnFieldChange:
- case OnRowChange:
- if (index.row() == d->insertIndex) {
- if (item.column() < 0 || item.column() >= d->rec.count())
- return QVariant();
- return d->editBuffer.value(index.column());
- }
- if (d->editIndex == item.row()) {
- if (d->editBuffer.isGenerated(item.column()))
- return d->editBuffer.value(item.column());
- }
- break;
- case OnManualSubmit:
- if (d->cache.contains(index.row())) {
- const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
- if (row.rec.isGenerated(item.column()) || row.op == QSqlTableModelPrivate::Insert)
+ 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())
+ 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());
+ }
+ break;
+ case OnManualSubmit:
+ if (row.op == QSqlTableModelPrivate::Insert
+ || (row.op != QSqlTableModelPrivate::None
+ && row.rec.isGenerated(item.column())))
+ return row.rec.value(item.column());
+ break;
}
- break;
}
// We need to handle row mapping here, but not column mapping
@@ -477,19 +418,12 @@ QVariant QSqlTableModel::headerData(int section, Qt::Orientation orientation, in
{
Q_D(const QSqlTableModel);
if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
- switch (d->strategy) {
- case OnFieldChange:
- case OnRowChange:
- if (d->insertIndex == section)
- return QLatin1String("*");
- break;
- case OnManualSubmit:
- QSqlTableModelPrivate::Op op = d->cache.value(section).op;
+ if (d->cache.contains(section)) {
+ const QSqlTableModelPrivate::Op op = d->cache.value(section).op;
if (op == QSqlTableModelPrivate::Insert)
return QLatin1String("*");
else if (op == QSqlTableModelPrivate::Delete)
return QLatin1String("!");
- break;
}
}
return QSqlQueryModel::headerData(section, orientation, role);
@@ -511,8 +445,11 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const
switch (d->strategy) {
case OnFieldChange:
return false;
- case OnRowChange:
- return index.row() == d->editIndex && d->editBuffer.isGenerated(index.column());
+ case OnRowChange: {
+ const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
+ 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
@@ -543,46 +480,47 @@ bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, in
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) {
+ d->cache.clear();
+ } else if (d->strategy == OnRowChange && !d->cache.isEmpty() && !d->cache.contains(index.row())) {
+ submit();
+ d->cache.clear();
+ }
+
+ QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
+
+ if (row.op == QSqlTableModelPrivate::None) {
+ row = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
+ d->rec,
+ d->primaryValues(indexInQuery(index).row()));
+ }
+
+ row.setValue(index.column(), value);
+
bool isOk = true;
- switch (d->strategy) {
- case OnFieldChange: {
- if (index.row() == d->insertIndex) {
- QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
- return true;
- }
- d->clearEditBuffer();
- QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
- isOk = updateRowInTable(index.row(), d->editBuffer);
+ 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();
- emit dataChanged(index, index);
- break; }
- case OnRowChange:
- if (index.row() == d->insertIndex) {
- QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
- return true;
- }
- if (d->editIndex != index.row()) {
- if (d->editIndex != -1)
- submit();
- d->clearEditBuffer();
- }
- QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
- d->editIndex = index.row();
- emit dataChanged(index, index);
- break;
- case OnManualSubmit: {
- QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
- if (row.op == QSqlTableModelPrivate::None) {
- row.op = QSqlTableModelPrivate::Update;
- row.rec = d->rec;
- QSqlTableModelPrivate::clearGenerated(row.rec);
- row.primaryValues = d->primaryValues(indexInQuery(index).row());
- }
- QSqlTableModelPrivate::setGeneratedValue(row.rec, index.column(), value);
- emit dataChanged(index, index);
- break; }
}
+
+ // 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;
}
@@ -727,52 +665,29 @@ bool QSqlTableModel::submitAll()
{
Q_D(QSqlTableModel);
- switch (d->strategy) {
- case OnFieldChange:
- if (d->insertIndex == -1)
- return true;
- // else fall through
- case OnRowChange:
- if (d->editBuffer.isEmpty())
- return true;
- if (d->insertIndex != -1) {
- if (!insertRowIntoTable(d->editBuffer))
+ for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
+ it != d->cache.constEnd(); ++it) {
+ switch (it.value().op) {
+ case QSqlTableModelPrivate::Insert:
+ if (!insertRowIntoTable(it.value().rec))
return false;
d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column());
- } else {
- if (!updateRowInTable(d->editIndex, d->editBuffer))
+ break;
+ case QSqlTableModelPrivate::Update:
+ if (!updateRowInTable(it.key(), it.value().rec))
return false;
+ break;
+ case QSqlTableModelPrivate::Delete:
+ if (!deleteRowFromTable(it.key()))
+ return false;
+ break;
+ case QSqlTableModelPrivate::None:
+ Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation");
+ break;
}
- d->clearEditBuffer();
- d->editIndex = -1;
- d->insertIndex = -1;
- return select();
- case OnManualSubmit:
- for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
- it != d->cache.constEnd(); ++it) {
- switch (it.value().op) {
- case QSqlTableModelPrivate::Insert:
- 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))
- return false;
- break;
- case QSqlTableModelPrivate::Delete:
- if (!deleteRowFromTable(it.key()))
- return false;
- break;
- case QSqlTableModelPrivate::None:
- Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation");
- break;
- }
- }
- d->clearCache();
- return select();
}
- return false;
+ d->clearCache();
+ return select();
}
/*!
@@ -872,20 +787,9 @@ QSqlTableModel::EditStrategy QSqlTableModel::editStrategy() const
void QSqlTableModel::revertAll()
{
Q_D(QSqlTableModel);
- switch (d->strategy) {
- case OnFieldChange:
- break;
- case OnRowChange:
- if (d->editIndex != -1)
- revertRow(d->editIndex);
- else if (d->insertIndex != -1)
- revertRow(d->insertIndex);
- break;
- case OnManualSubmit:
- while (!d->cache.isEmpty())
- revertRow(d->cache.constBegin().key());
- break;
- }
+
+ while (!d->cache.isEmpty())
+ revertRow(d->cache.constBegin().key());
}
/*!
@@ -899,23 +803,7 @@ void QSqlTableModel::revertRow(int row)
return;
Q_D(QSqlTableModel);
- switch (d->strategy) {
- case OnFieldChange:
- break;
- case OnRowChange: {
- if (d->editIndex == row) {
- d->editBuffer.clear();
- int oldIndex = d->editIndex;
- d->editIndex = -1;
- emit dataChanged(createIndex(oldIndex, 0), createIndex(oldIndex, columnCount()));
- } else if (d->insertIndex == row) {
- d->revertInsertedRow();
- }
- break; }
- case OnManualSubmit:
- d->revertCachedRow(row);
- break;
- }
+ d->revertCachedRow(row);
}
/*!
@@ -1097,36 +985,37 @@ bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
if (parent.isValid() || row < 0 || count <= 0)
return false;
+ int initialRowCount = rowCount();
+
int i;
- switch (d->strategy) {
- case OnFieldChange:
- case OnRowChange:
- for (i = 0; i < count; ++i) {
- if (row + i == d->insertIndex)
- d->revertInsertedRow();
- else if (!deleteRowFromTable(row + i))
- return false;
- }
- select();
- break;
- case OnManualSubmit:
- for (i = 0; i < count; ++i) {
- int idx = row + i;
- if (idx >= rowCount())
- return false;
- 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].op = QSqlTableModelPrivate::Delete;
- d->cache[idx].primaryValues = d->primaryValues(indexInQuery(createIndex(idx, 0)).row());
+ for (i = 0; i < count && row + i < rowCount(); ++i) {
+ int idx = row + i;
+ 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()));
+ if (d->strategy == OnManualSubmit)
emit headerDataChanged(Qt::Vertical, idx, idx);
- }
}
- break;
}
+
+ 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;
+
return true;
}
@@ -1153,36 +1042,30 @@ bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
return false;
- switch (d->strategy) {
- case OnFieldChange:
- case OnRowChange:
- if (count != 1)
- return false;
- beginInsertRows(parent, row, row);
- d->insertIndex = row;
- // ### apply dangling changes...
- d->clearEditBuffer();
- emit primeInsert(row, d->editBuffer);
- break;
- case OnManualSubmit:
- beginInsertRows(parent, row, row + count - 1);
- if (!d->cache.isEmpty()) {
- QMap<int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = d->cache.end();
- while (it != d->cache.begin() && (--it).key() >= row) {
- int oldKey = it.key();
- const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
- d->cache.erase(it);
- it = d->cache.insert(oldKey + count, oldValue);
- }
- }
+ if (d->strategy != OnManualSubmit && count != 1)
+ return false;
- 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);
+ beginInsertRows(parent, row, row + count - 1);
+
+ if (d->strategy != OnManualSubmit)
+ d->cache.empty();
+
+ if (!d->cache.isEmpty()) {
+ QMap<int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = d->cache.end();
+ while (it != d->cache.begin() && (--it).key() >= row) {
+ int oldKey = it.key();
+ const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
+ d->cache.erase(it);
+ it = d->cache.insert(oldKey + count, oldValue);
}
- break;
}
+
+ 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);
+ }
+
endInsertRows();
return true;
}
@@ -1220,14 +1103,10 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const
return 0;
int rc = QSqlQueryModel::rowCount();
- if (d->strategy == OnManualSubmit) {
- for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
- it != d->cache.constEnd(); ++it) {
- if (it.value().op == QSqlTableModelPrivate::Insert)
- ++rc;
- }
- } else if (d->insertIndex >= 0) {
- ++rc;
+ for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
+ it != d->cache.constEnd(); ++it) {
+ if (it.value().op == QSqlTableModelPrivate::Insert)
+ ++rc;
}
return rc;
}
@@ -1248,20 +1127,14 @@ QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const
{
Q_D(const QSqlTableModel);
const QModelIndex it = QSqlQueryModel::indexInQuery(item); // this adjusts columns only
- if (d->strategy == OnManualSubmit) {
- 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());
- } else {
- if (d->insertIndex >= 0 && it.row() >= d->insertIndex)
- return createIndex(it.row() - 1, it.column(), it.internalPointer());
+ 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 it;
+ return createIndex(it.row() - rowOffset, it.column(), it.internalPointer());
}
/*!
@@ -1331,37 +1204,49 @@ bool QSqlTableModel::setRecord(int row, const QSqlRecord &record)
if (row >= rowCount())
return false;
+ 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;
- switch (d->strategy) {
- case OnFieldChange:
- case OnRowChange:
- return d->setRecord(row, record);
- case OnManualSubmit: {
- QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
- if (mrow.op == QSqlTableModelPrivate::None) {
- mrow.op = QSqlTableModelPrivate::Update;
- mrow.rec = d->rec;
- QSqlTableModelPrivate::clearGenerated(mrow.rec);
- mrow.primaryValues = d->primaryValues(indexInQuery(createIndex(row, 0)).row());
- }
- QString fieldName;
- for (int i = 0; i < record.count(); ++i) {
- fieldName = record.fieldName(i);
- if (d->db.driver()->isIdentifierEscaped(fieldName, QSqlDriver::FieldName))
- fieldName = d->db.driver()->stripDelimiters(fieldName, QSqlDriver::FieldName);
- int idx = mrow.rec.indexOf(fieldName);
- if (idx == -1) {
- isOk = false;
- } else {
- QSqlTableModelPrivate::setGeneratedValue(mrow.rec, idx, record.value(i));
+ 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 (isOk)
- emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1));
- return isOk; }
}
- return false;
+
+ if (d->strategy == OnManualSubmit && isOk)
+ emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1));
+ else if (d->strategy == OnFieldChange)
+ return submitAll();
+ else if (d->strategy == OnManualSubmit)
+ return isOk;
+
+ return true;
}
QT_END_NAMESPACE