source: trunk/src/sql/models/qsqltablemodel.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 41.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtSql module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qsqltablemodel.h"
43
44#include "qsqldriver.h"
45#include "qsqlerror.h"
46#include "qsqlfield.h"
47#include "qsqlindex.h"
48#include "qsqlquery.h"
49#include "qsqlrecord.h"
50#include "qsqlresult.h"
51
52#include "qsqltablemodel_p.h"
53
54#include <qdebug.h>
55
56QT_BEGIN_NAMESPACE
57
58/*! \internal
59 Populates our record with values.
60*/
61QSqlRecord QSqlTableModelPrivate::record(const QVector<QVariant> &values) const
62{
63 QSqlRecord r = rec;
64 for (int i = 0; i < r.count() && i < values.count(); ++i)
65 r.setValue(i, values.at(i));
66 return r;
67}
68
69/*! \internal
70 Set a record for OnFieldChange and OnRowChange.
71*/
72bool QSqlTableModelPrivate::setRecord(int row, const QSqlRecord &record)
73{
74 Q_Q(QSqlTableModel);
75 bool isOk = true;
76
77 QSqlTableModel::EditStrategy oldStrategy = strategy;
78
79 // FieldChange strategy makes no sense when setting an entire row
80 if (strategy == QSqlTableModel::OnFieldChange)
81 strategy = QSqlTableModel::OnRowChange;
82 for (int i = 0; i < record.count(); ++i) {
83 int idx = nameToIndex(record.fieldName(i));
84 if (idx == -1)
85 continue;
86 QModelIndex cIndex = q->createIndex(row, idx);
87 QVariant value = record.value(i);
88 QVariant oldValue = q->data(cIndex);
89 if (oldValue.isNull() || oldValue != value)
90 isOk &= q->setData(cIndex, value, Qt::EditRole);
91 }
92 if (isOk && oldStrategy == QSqlTableModel::OnFieldChange)
93 q->submitAll();
94 strategy = oldStrategy;
95
96 return isOk;
97}
98
99int QSqlTableModelPrivate::nameToIndex(const QString &name) const
100{
101 QString fieldname = name;
102 if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName))
103 fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName);
104 return rec.indexOf(fieldname);
105}
106
107void QSqlTableModelPrivate::initRecordAndPrimaryIndex()
108{
109 rec = db.record(tableName);
110 primaryIndex = db.primaryIndex(tableName);
111}
112
113void QSqlTableModelPrivate::clear()
114{
115 editIndex = -1;
116 sortColumn = -1;
117 sortOrder = Qt::AscendingOrder;
118 tableName.clear();
119 editQuery.clear();
120 editBuffer.clear();
121 cache.clear();
122 primaryIndex.clear();
123 rec.clear();
124 filter.clear();
125}
126
127void QSqlTableModelPrivate::revertInsertedRow()
128{
129 Q_Q(QSqlTableModel);
130 if (insertIndex == -1)
131 return;
132
133 q->beginRemoveRows(QModelIndex(), insertIndex, insertIndex);
134 insertIndex = -1;
135 q->endRemoveRows();
136}
137
138void QSqlTableModelPrivate::clearEditBuffer()
139{
140 editBuffer = rec;
141}
142
143void QSqlTableModelPrivate::clearCache()
144{
145 cache.clear();
146}
147
148void QSqlTableModelPrivate::revertCachedRow(int row)
149{
150 Q_Q(QSqlTableModel);
151 ModifiedRow r = cache.value(row);
152 switch (r.op) {
153 case QSqlTableModelPrivate::None:
154 Q_ASSERT_X(false, "QSqlTableModelPrivate::revertCachedRow()", "Invalid entry in cache map");
155 return;
156 case QSqlTableModelPrivate::Update:
157 case QSqlTableModelPrivate::Delete:
158 cache.remove(row);
159 emit q->dataChanged(q->createIndex(row, 0),
160 q->createIndex(row, q->columnCount() - 1));
161 break;
162 case QSqlTableModelPrivate::Insert: {
163 QMap<int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = cache.find(row);
164 if (it == cache.end())
165 return;
166 q->beginRemoveRows(QModelIndex(), row, row);
167 it = cache.erase(it);
168 while (it != cache.end()) {
169 int oldKey = it.key();
170 const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
171 cache.erase(it);
172 it = cache.insert(oldKey - 1, oldValue);
173 ++it;
174 }
175 q->endRemoveRows();
176 break; }
177 }
178}
179
180bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
181 const QSqlRecord &rec, const QSqlRecord &whereValues)
182{
183 if (stmt.isEmpty())
184 return false;
185
186 // lazy initialization of editQuery
187 if (editQuery.driver() != db.driver())
188 editQuery = QSqlQuery(db);
189
190 // workaround for In-Process databases - remove all read locks
191 // from the table to make sure the editQuery succeeds
192 if (db.driver()->hasFeature(QSqlDriver::SimpleLocking))
193 const_cast<QSqlResult *>(query.result())->detachFromResultSet();
194
195 if (prepStatement) {
196 if (editQuery.lastQuery() != stmt) {
197 if (!editQuery.prepare(stmt)) {
198 error = editQuery.lastError();
199 return false;
200 }
201 }
202 int i;
203 for (i = 0; i < rec.count(); ++i) {
204 if (rec.isGenerated(i) && rec.value(i).type() != QVariant::Invalid)
205 editQuery.addBindValue(rec.value(i));
206 }
207 for (i = 0; i < whereValues.count(); ++i) {
208 if (whereValues.isGenerated(i) && !whereValues.isNull(i))
209 editQuery.addBindValue(whereValues.value(i));
210 }
211
212 if (!editQuery.exec()) {
213 error = editQuery.lastError();
214 return false;
215 }
216 } else {
217 if (!editQuery.exec(stmt)) {
218 error = editQuery.lastError();
219 return false;
220 }
221 }
222 return true;
223}
224
225QSqlRecord QSqlTableModelPrivate::primaryValues(int row)
226{
227 QSqlRecord record;
228 if (!query.seek(row)) {
229 error = query.lastError();
230 return record;
231 }
232 if (primaryIndex.isEmpty()) {
233 record = rec;
234 for (int i = 0; i < record.count(); ++i)
235 record.setValue(i, query.value(i));
236 } else {
237 record = primaryIndex;
238 for (int i = 0; i < record.count(); ++i)
239 record.setValue(i, query.value(rec.indexOf(record.fieldName(i))));
240 }
241 return record;
242}
243
244/*!
245 \class QSqlTableModel
246 \brief The QSqlTableModel class provides an editable data model
247 for a single database table.
248
249 \ingroup database
250 \inmodule QtSql
251
252 QSqlTableModel is a high-level interface for reading and writing
253 database records from a single table. It is build on top of the
254 lower-level QSqlQuery and can be used to provide data to view
255 classes such as QTableView. For example:
256
257 \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 24
258
259 We set the SQL table's name and the edit strategy, then we set up
260 the labels displayed in the view header. The edit strategy
261 dictates when the changes done by the user in the view are
262 actually applied to the database. The possible values are \l
263 OnFieldChange, \l OnRowChange, and \l OnManualSubmit.
264
265 QSqlTableModel can also be used to access a database
266 programmatically, without binding it to a view:
267
268 \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 21
269
270 The code snippet above extracts the \c salary field from record 4 in
271 the result set of the query \c{SELECT * from employee}.
272
273 It is possible to set filters using setFilter(), or modify the
274 sort order using setSort(). At the end, you must call select() to
275 populate the model with data.
276
277 The \l{sql/tablemodel} example illustrates how to use
278 QSqlTableModel as the data source for a QTableView.
279
280 QSqlTableModel provides no direct support for foreign keys. Use
281 the QSqlRelationalTableModel and QSqlRelationalDelegate if you
282 want to resolve foreign keys.
283
284 \sa QSqlRelationalTableModel, QSqlQuery, {Model/View Programming},
285 {Table Model Example}, {Cached Table Example}
286*/
287
288/*!
289 \fn QSqlTableModel::beforeDelete(int row)
290
291 This signal is emitted by deleteRowFromTable() before the \a row
292 is deleted from the currently active database table.
293*/
294
295/*!
296 \fn void QSqlTableModel::primeInsert(int row, QSqlRecord &record)
297
298 This signal is emitted by insertRows(), when an insertion is
299 initiated in the given \a row of the currently active database
300 table. The \a record parameter can be written to (since it is a
301 reference), for example to populate some fields with default
302 values.
303*/
304
305/*!
306 \fn QSqlTableModel::beforeInsert(QSqlRecord &record)
307
308 This signal is emitted by insertRowIntoTable() before a new row is
309 inserted into the currently active database table. The values that
310 are about to be inserted are stored in \a record and can be
311 modified before they will be inserted.
312*/
313
314/*!
315 \fn QSqlTableModel::beforeUpdate(int row, QSqlRecord &record)
316
317 This signal is emitted by updateRowInTable() before the \a row is
318 updated in the currently active database table with the values
319 from \a record.
320
321 Note that only values that are marked as generated will be updated.
322 The generated flag can be set with \l QSqlRecord::setGenerated()
323 and checked with \l QSqlRecord::isGenerated().
324
325 \sa QSqlRecord::isGenerated()
326*/
327
328/*!
329 Creates an empty QSqlTableModel and sets the parent to \a parent
330 and the database connection to \a db. If \a db is not valid, the
331 default database connection will be used.
332
333 The default edit strategy is \l OnRowChange.
334*/
335QSqlTableModel::QSqlTableModel(QObject *parent, QSqlDatabase db)
336 : QSqlQueryModel(*new QSqlTableModelPrivate, parent)
337{
338 Q_D(QSqlTableModel);
339 d->db = db.isValid() ? db : QSqlDatabase::database();
340}
341
342/*! \internal
343*/
344QSqlTableModel::QSqlTableModel(QSqlTableModelPrivate &dd, QObject *parent, QSqlDatabase db)
345 : QSqlQueryModel(dd, parent)
346{
347 Q_D(QSqlTableModel);
348 d->db = db.isValid() ? db : QSqlDatabase::database();
349}
350
351/*!
352 Destroys the object and frees any allocated resources.
353*/
354QSqlTableModel::~QSqlTableModel()
355{
356}
357
358/*!
359 Sets the database table on which the model operates to \a
360 tableName. Does not select data from the table, but fetches its
361 field information.
362
363 To populate the model with the table's data, call select().
364
365 Error information can be retrieved with \l lastError().
366
367 \sa select(), setFilter(), lastError()
368*/
369void QSqlTableModel::setTable(const QString &tableName)
370{
371 Q_D(QSqlTableModel);
372 clear();
373 d->tableName = tableName;
374 d->initRecordAndPrimaryIndex();
375 d->initColOffsets(d->rec.count());
376
377 if (d->rec.count() == 0)
378 d->error = QSqlError(QLatin1String("Unable to find table ") + d->tableName, QString(),
379 QSqlError::StatementError);
380}
381
382/*!
383 Returns the name of the currently selected table.
384*/
385QString QSqlTableModel::tableName() const
386{
387 Q_D(const QSqlTableModel);
388 return d->tableName;
389}
390
391/*!
392 Populates the model with data from the table that was set via setTable(), using the
393 specified filter and sort condition, and returns true if successful; otherwise
394 returns false.
395
396 \note Calling select() will revert any unsubmitted changes and remove any inserted columns.
397
398 \sa setTable(), setFilter(), selectStatement()
399*/
400bool QSqlTableModel::select()
401{
402 Q_D(QSqlTableModel);
403 QString query = selectStatement();
404 if (query.isEmpty())
405 return false;
406
407 revertAll();
408 QSqlQuery qu(query, d->db);
409 setQuery(qu);
410
411 if (!qu.isActive() || lastError().isValid()) {
412 // something went wrong - revert to non-select state
413 d->initRecordAndPrimaryIndex();
414 return false;
415 }
416 return true;
417}
418
419/*!
420 \reimp
421*/
422QVariant QSqlTableModel::data(const QModelIndex &index, int role) const
423{
424 Q_D(const QSqlTableModel);
425 if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole))
426 return QVariant();
427
428 // Problem.. we need to use QSQM::indexInQuery to handle inserted columns
429 // but inserted rows we need to handle
430 // and indexInQuery is not virtual (grrr) so any values we pass to QSQM need
431 // to handle the insertedRows
432 QModelIndex item = indexInQuery(index);
433
434 switch (d->strategy) {
435 case OnFieldChange:
436 case OnRowChange:
437 if (index.row() == d->insertIndex) {
438 QVariant val;
439 if (item.column() < 0 || item.column() >= d->rec.count())
440 return val;
441 val = d->editBuffer.value(index.column());
442 if (val.type() == QVariant::Invalid)
443 val = QVariant(d->rec.field(item.column()).type());
444 return val;
445 }
446 if (d->editIndex == item.row()) {
447 QVariant var = d->editBuffer.value(item.column());
448 if (var.isValid())
449 return var;
450 }
451 break;
452 case OnManualSubmit: {
453 const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
454 const QVariant var = row.rec.value(item.column());
455 if (var.isValid() || row.op == QSqlTableModelPrivate::Insert)
456 return var;
457 break; }
458 }
459
460 // We need to handle row mapping here, but not column mapping
461 return QSqlQueryModel::data(index.sibling(item.row(), index.column()), role);
462}
463
464/*!
465 \reimp
466*/
467QVariant QSqlTableModel::headerData(int section, Qt::Orientation orientation, int role) const
468{
469 Q_D(const QSqlTableModel);
470 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
471 switch (d->strategy) {
472 case OnFieldChange:
473 case OnRowChange:
474 if (d->insertIndex == section)
475 return QLatin1String("*");
476 break;
477 case OnManualSubmit:
478 QSqlTableModelPrivate::Op op = d->cache.value(section).op;
479 if (op == QSqlTableModelPrivate::Insert)
480 return QLatin1String("*");
481 else if (op == QSqlTableModelPrivate::Delete)
482 return QLatin1String("!");
483 break;
484 }
485 }
486 return QSqlQueryModel::headerData(section, orientation, role);
487}
488
489/*!
490 Returns true if the value at the index \a index is dirty, otherwise false.
491 Dirty values are values that were modified in the model
492 but not yet written into the database.
493
494 If \a index is invalid or points to a non-existing row, false is returned.
495*/
496bool QSqlTableModel::isDirty(const QModelIndex &index) const
497{
498 Q_D(const QSqlTableModel);
499 if (!index.isValid())
500 return false;
501
502 switch (d->strategy) {
503 case OnFieldChange:
504 return false;
505 case OnRowChange:
506 return index.row() == d->editIndex && d->editBuffer.value(index.column()).isValid();
507 case OnManualSubmit: {
508 const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
509 return row.op == QSqlTableModelPrivate::Insert
510 || row.op == QSqlTableModelPrivate::Delete
511 || (row.op == QSqlTableModelPrivate::Update
512 && row.rec.value(index.column()).isValid());
513 }
514 }
515 return false;
516}
517
518/*!
519 Sets the data for the item \a index for the role \a role to \a
520 value. Depending on the edit strategy, the value might be applied
521 to the database at once or cached in the model.
522
523 Returns true if the value could be set or false on error, for
524 example if \a index is out of bounds.
525
526 \sa editStrategy(), data(), submit(), submitAll(), revertRow()
527*/
528bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
529{
530 Q_D(QSqlTableModel);
531 if (role != Qt::EditRole)
532 return QSqlQueryModel::setData(index, value, role);
533
534 if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount())
535 return false;
536
537 bool isOk = true;
538 switch (d->strategy) {
539 case OnFieldChange: {
540 if (index.row() == d->insertIndex) {
541 d->editBuffer.setValue(index.column(), value);
542 return true;
543 }
544 d->clearEditBuffer();
545 d->editBuffer.setValue(index.column(), value);
546 isOk = updateRowInTable(index.row(), d->editBuffer);
547 if (isOk)
548 select();
549 emit dataChanged(index, index);
550 break; }
551 case OnRowChange:
552 if (index.row() == d->insertIndex) {
553 d->editBuffer.setValue(index.column(), value);
554 return true;
555 }
556 if (d->editIndex != index.row()) {
557 if (d->editIndex != -1)
558 submit();
559 d->clearEditBuffer();
560 }
561 d->editBuffer.setValue(index.column(), value);
562 d->editIndex = index.row();
563 emit dataChanged(index, index);
564 break;
565 case OnManualSubmit: {
566 QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
567 if (row.op == QSqlTableModelPrivate::None) {
568 row.op = QSqlTableModelPrivate::Update;
569 row.rec = d->rec;
570 row.primaryValues = d->primaryValues(indexInQuery(index).row());
571 }
572 row.rec.setValue(index.column(), value);
573 emit dataChanged(index, index);
574 break; }
575 }
576 return isOk;
577}
578
579/*!
580 This function simply calls QSqlQueryModel::setQuery(\a query).
581 You should normally not call it on a QSqlTableModel. Instead, use
582 setTable(), setSort(), setFilter(), etc., to set up the query.
583
584 \sa selectStatement()
585*/
586void QSqlTableModel::setQuery(const QSqlQuery &query)
587{
588 QSqlQueryModel::setQuery(query);
589}
590
591/*!
592 Updates the given \a row in the currently active database table
593 with the specified \a values. Returns true if successful; otherwise
594 returns false.
595
596 This is a low-level method that operates directly on the database
597 and should not be called directly. Use setData() to update values.
598 The model will decide depending on its edit strategy when to modify
599 the database.
600
601 Note that only values that have the generated-flag set are updated.
602 The generated-flag can be set with QSqlRecord::setGenerated() and
603 tested with QSqlRecord::isGenerated().
604
605 \sa QSqlRecord::isGenerated(), setData()
606*/
607bool QSqlTableModel::updateRowInTable(int row, const QSqlRecord &values)
608{
609 Q_D(QSqlTableModel);
610 QSqlRecord rec(values);
611 emit beforeUpdate(row, rec);
612
613 const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row);
614 bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
615 QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName,
616 rec, prepStatement);
617 QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, d->tableName,
618 whereValues, prepStatement);
619
620 if (stmt.isEmpty() || where.isEmpty() || row < 0 || row >= rowCount()) {
621 d->error = QSqlError(QLatin1String("No Fields to update"), QString(),
622 QSqlError::StatementError);
623 return false;
624 }
625 stmt.append(QLatin1Char(' ')).append(where);
626
627 return d->exec(stmt, prepStatement, rec, whereValues);
628}
629
630
631/*!
632 Inserts the values \a values into the currently active database table.
633
634 This is a low-level method that operates directly on the database
635 and should not be called directly. Use insertRow() and setData()
636 to insert values. The model will decide depending on its edit strategy
637 when to modify the database.
638
639 Returns true if the values could be inserted, otherwise false.
640 Error information can be retrieved with \l lastError().
641
642 \sa lastError(), insertRow(), insertRows()
643*/
644bool QSqlTableModel::insertRowIntoTable(const QSqlRecord &values)
645{
646 Q_D(QSqlTableModel);
647 QSqlRecord rec = values;
648 emit beforeInsert(rec);
649
650 bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
651 QString stmt = d->db.driver()->sqlStatement(QSqlDriver::InsertStatement, d->tableName,
652 rec, prepStatement);
653
654 if (stmt.isEmpty()) {
655 d->error = QSqlError(QLatin1String("No Fields to update"), QString(),
656 QSqlError::StatementError);
657 return false;
658 }
659
660 return d->exec(stmt, prepStatement, rec);
661}
662
663/*!
664 Deletes the given \a row from the currently active database table.
665
666 This is a low-level method that operates directly on the database
667 and should not be called directly. Use removeRow() or removeRows()
668 to delete values. The model will decide depending on its edit strategy
669 when to modify the database.
670
671 Returns true if the row was deleted; otherwise returns false.
672
673 \sa removeRow(), removeRows()
674*/
675bool QSqlTableModel::deleteRowFromTable(int row)
676{
677 Q_D(QSqlTableModel);
678 emit beforeDelete(row);
679
680 const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row);
681 bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
682 QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement,
683 d->tableName,
684 QSqlRecord(),
685 prepStatement);
686 QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement,
687 d->tableName,
688 whereValues,
689 prepStatement);
690
691 if (stmt.isEmpty() || where.isEmpty()) {
692 d->error = QSqlError(QLatin1String("Unable to delete row"), QString(),
693 QSqlError::StatementError);
694 return false;
695 }
696 stmt.append(QLatin1Char(' ')).append(where);
697
698 return d->exec(stmt, prepStatement, whereValues);
699}
700
701/*!
702 Submits all pending changes and returns true on success.
703 Returns false on error, detailed error information can be
704 obtained with lastError().
705
706 On success the model will be repopulated. Any views
707 presenting it will lose their selections.
708
709 Note: In OnManualSubmit mode, already submitted changes won't
710 be cleared from the cache when submitAll() fails. This allows
711 transactions to be rolled back and resubmitted again without
712 losing data.
713
714 \sa revertAll(), lastError()
715*/
716bool QSqlTableModel::submitAll()
717{
718 Q_D(QSqlTableModel);
719
720 switch (d->strategy) {
721 case OnFieldChange:
722 if (d->insertIndex == -1)
723 return true;
724 // else fall through
725 case OnRowChange:
726 if (d->editBuffer.isEmpty())
727 return true;
728 if (d->insertIndex != -1) {
729 if (!insertRowIntoTable(d->editBuffer))
730 return false;
731 d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column());
732 } else {
733 if (!updateRowInTable(d->editIndex, d->editBuffer))
734 return false;
735 }
736 d->clearEditBuffer();
737 d->editIndex = -1;
738 d->insertIndex = -1;
739 return select();
740 case OnManualSubmit:
741 for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
742 it != d->cache.constEnd(); ++it) {
743 switch (it.value().op) {
744 case QSqlTableModelPrivate::Insert:
745 if (!insertRowIntoTable(it.value().rec))
746 return false;
747 d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column());
748 break;
749 case QSqlTableModelPrivate::Update:
750 if (!updateRowInTable(it.key(), it.value().rec))
751 return false;
752 break;
753 case QSqlTableModelPrivate::Delete:
754 if (!deleteRowFromTable(it.key()))
755 return false;
756 break;
757 case QSqlTableModelPrivate::None:
758 Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation");
759 break;
760 }
761 }
762 d->clearCache();
763 return select();
764 }
765 return false;
766}
767
768/*!
769 This reimplemented slot is called by the item delegates when the
770 user stopped editing the current row.
771
772 Submits the currently edited row if the model's strategy is set
773 to OnRowChange or OnFieldChange. Does nothing for the OnManualSubmit
774 strategy.
775
776 Use submitAll() to submit all pending changes for the
777 OnManualSubmit strategy.
778
779 Returns true on success; otherwise returns false. Use lastError()
780 to query detailed error information.
781
782 On success the model will be repopulated. Any views
783 presenting it will lose their selections.
784
785 \sa revert(), revertRow(), submitAll(), revertAll(), lastError()
786*/
787bool QSqlTableModel::submit()
788{
789 Q_D(QSqlTableModel);
790 if (d->strategy == OnRowChange || d->strategy == OnFieldChange)
791 return submitAll();
792 return true;
793}
794
795/*!
796 This reimplemented slot is called by the item delegates when the
797 user canceled editing the current row.
798
799 Reverts the changes if the model's strategy is set to
800 OnRowChange. Does nothing for the other edit strategies.
801
802 Use revertAll() to revert all pending changes for the
803 OnManualSubmit strategy or revertRow() to revert a specific row.
804
805 \sa submit(), submitAll(), revertRow(), revertAll()
806*/
807void QSqlTableModel::revert()
808{
809 Q_D(QSqlTableModel);
810 if (d->strategy == OnRowChange)
811 revertAll();
812}
813
814/*!
815 \enum QSqlTableModel::EditStrategy
816
817 This enum type describes which strategy to choose when editing values in the database.
818
819 \value OnFieldChange All changes to the model will be applied immediately to the database.
820 \value OnRowChange Changes to a row will be applied when the user selects a different row.
821 \value OnManualSubmit All changes will be cached in the model until either submitAll()
822 or revertAll() is called.
823
824 Note: To prevent inserting only partly initialized rows into the database,
825 \c OnFieldChange will behave like \c OnRowChange for newly inserted rows.
826
827 \sa setEditStrategy()
828*/
829
830
831/*!
832 Sets the strategy for editing values in the database to \a
833 strategy.
834
835 This will revert any pending changes.
836
837 \sa editStrategy(), revertAll()
838*/
839void QSqlTableModel::setEditStrategy(EditStrategy strategy)
840{
841 Q_D(QSqlTableModel);
842 revertAll();
843 d->strategy = strategy;
844}
845
846/*!
847 Returns the current edit strategy.
848
849 \sa setEditStrategy()
850*/
851QSqlTableModel::EditStrategy QSqlTableModel::editStrategy() const
852{
853 Q_D(const QSqlTableModel);
854 return d->strategy;
855}
856
857/*!
858 Reverts all pending changes.
859
860 \sa revert(), revertRow(), submitAll()
861*/
862void QSqlTableModel::revertAll()
863{
864 Q_D(QSqlTableModel);
865 switch (d->strategy) {
866 case OnFieldChange:
867 break;
868 case OnRowChange:
869 if (d->editIndex != -1)
870 revertRow(d->editIndex);
871 else if (d->insertIndex != -1)
872 revertRow(d->insertIndex);
873 break;
874 case OnManualSubmit:
875 while (!d->cache.isEmpty())
876 revertRow(d->cache.constBegin().key());
877 break;
878 }
879}
880
881/*!
882 Reverts all changes for the specified \a row.
883
884 \sa revert(), revertAll(), submit(), submitAll()
885*/
886void QSqlTableModel::revertRow(int row)
887{
888 if (row < 0)
889 return;
890
891 Q_D(QSqlTableModel);
892 switch (d->strategy) {
893 case OnFieldChange:
894 break;
895 case OnRowChange: {
896 if (d->editIndex == row) {
897 d->editBuffer.clear();
898 int oldIndex = d->editIndex;
899 d->editIndex = -1;
900 emit dataChanged(createIndex(oldIndex, 0), createIndex(oldIndex, columnCount()));
901 } else if (d->insertIndex == row) {
902 d->revertInsertedRow();
903 }
904 break; }
905 case OnManualSubmit:
906 d->revertCachedRow(row);
907 break;
908 }
909}
910
911/*!
912 Returns the primary key for the current table, or an empty
913 QSqlIndex if the table is not set or has no primary key.
914
915 \sa setTable(), setPrimaryKey(), QSqlDatabase::primaryIndex()
916*/
917QSqlIndex QSqlTableModel::primaryKey() const
918{
919 Q_D(const QSqlTableModel);
920 return d->primaryIndex;
921}
922
923/*!
924 Protected method that allows subclasses to set the primary key to
925 \a key.
926
927 Normally, the primary index is set automatically whenever you
928 call setTable().
929
930 \sa primaryKey(), QSqlDatabase::primaryIndex()
931*/
932void QSqlTableModel::setPrimaryKey(const QSqlIndex &key)
933{
934 Q_D(QSqlTableModel);
935 d->primaryIndex = key;
936}
937
938/*!
939 Returns a pointer to the used QSqlDatabase or 0 if no database was set.
940*/
941QSqlDatabase QSqlTableModel::database() const
942{
943 Q_D(const QSqlTableModel);
944 return d->db;
945}
946
947/*!
948 Sorts the data by \a column with the sort order \a order.
949 This will immediately select data, use setSort()
950 to set a sort order without populating the model with data.
951
952 \sa setSort(), select(), orderByClause()
953*/
954void QSqlTableModel::sort(int column, Qt::SortOrder order)
955{
956 setSort(column, order);
957 select();
958}
959
960/*!
961 Sets the sort order for \a column to \a order. This does not
962 affect the current data, to refresh the data using the new
963 sort order, call select().
964
965 \sa select(), orderByClause()
966*/
967void QSqlTableModel::setSort(int column, Qt::SortOrder order)
968{
969 Q_D(QSqlTableModel);
970 d->sortColumn = column;
971 d->sortOrder = order;
972}
973
974/*!
975 Returns an SQL \c{ORDER BY} clause based on the currently set
976 sort order.
977
978 \sa setSort(), selectStatement()
979*/
980QString QSqlTableModel::orderByClause() const
981{
982 Q_D(const QSqlTableModel);
983 QString s;
984 QSqlField f = d->rec.field(d->sortColumn);
985 if (!f.isValid())
986 return s;
987
988 QString table = d->tableName;
989 //we can safely escape the field because it would have been obtained from the database
990 //and have the correct case
991 QString field = d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
992 s.append(QLatin1String("ORDER BY ")).append(table).append(QLatin1Char('.')).append(field);
993 s += d->sortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC");
994
995 return s;
996}
997
998/*!
999 Returns the index of the field \a fieldName.
1000*/
1001int QSqlTableModel::fieldIndex(const QString &fieldName) const
1002{
1003 Q_D(const QSqlTableModel);
1004 return d->rec.indexOf(fieldName);
1005}
1006
1007/*!
1008 Returns the SQL \c SELECT statement used internally to populate
1009 the model. The statement includes the filter and the \c{ORDER BY}
1010 clause.
1011
1012 \sa filter(), orderByClause()
1013*/
1014QString QSqlTableModel::selectStatement() const
1015{
1016 Q_D(const QSqlTableModel);
1017 QString query;
1018 if (d->tableName.isEmpty()) {
1019 d->error = QSqlError(QLatin1String("No table name given"), QString(),
1020 QSqlError::StatementError);
1021 return query;
1022 }
1023 if (d->rec.isEmpty()) {
1024 d->error = QSqlError(QLatin1String("Unable to find table ") + d->tableName, QString(),
1025 QSqlError::StatementError);
1026 return query;
1027 }
1028
1029 query = d->db.driver()->sqlStatement(QSqlDriver::SelectStatement,
1030 d->tableName,
1031 d->rec,
1032 false);
1033 if (query.isEmpty()) {
1034 d->error = QSqlError(QLatin1String("Unable to select fields from table ") + d->tableName,
1035 QString(), QSqlError::StatementError);
1036 return query;
1037 }
1038 if (!d->filter.isEmpty())
1039 query.append(QLatin1String(" WHERE ")).append(d->filter);
1040 QString orderBy(orderByClause());
1041 if (!orderBy.isEmpty())
1042 query.append(QLatin1Char(' ')).append(orderBy);
1043
1044 return query;
1045}
1046
1047/*!
1048 Removes \a count columns from the \a parent model, starting at
1049 index \a column.
1050
1051 Returns if the columns were successfully removed; otherwise
1052 returns false.
1053
1054 \sa removeRows()
1055*/
1056bool QSqlTableModel::removeColumns(int column, int count, const QModelIndex &parent)
1057{
1058 Q_D(QSqlTableModel);
1059 if (parent.isValid() || column < 0 || column + count > d->rec.count())
1060 return false;
1061 for (int i = 0; i < count; ++i)
1062 d->rec.remove(column);
1063 if (d->query.isActive())
1064 return select();
1065 return true;
1066}
1067
1068/*!
1069 Removes \a count rows starting at \a row. Since this model
1070 does not support hierarchical structures, \a parent must be
1071 an invalid model index.
1072
1073 Emits the beforeDelete() signal before a row is deleted. When
1074 the edit strategy is OnManualSubmit signal emission is delayed
1075 until submitAll() is called.
1076
1077 Returns true if all rows could be removed; otherwise returns
1078 false. Detailed error information can be retrieved using
1079 lastError().
1080
1081 \sa removeColumns(), insertRows()
1082*/
1083bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
1084{
1085 Q_D(QSqlTableModel);
1086 if (parent.isValid() || row < 0 || count <= 0)
1087 return false;
1088
1089 int i;
1090 switch (d->strategy) {
1091 case OnFieldChange:
1092 case OnRowChange:
1093 for (i = 0; i < count; ++i) {
1094 if (row + i == d->insertIndex)
1095 d->revertInsertedRow();
1096 else if (!deleteRowFromTable(row + i))
1097 return false;
1098 }
1099 select();
1100 break;
1101 case OnManualSubmit:
1102 for (i = 0; i < count; ++i) {
1103 int idx = row + i;
1104 if (idx >= rowCount())
1105 return false;
1106 if (d->cache.value(idx).op == QSqlTableModelPrivate::Insert) {
1107 revertRow(idx);
1108 // Reverting a row means all the other cache entries have been adjusted downwards
1109 // so fake this by adjusting row
1110 --row;
1111 } else {
1112 d->cache[idx].op = QSqlTableModelPrivate::Delete;
1113 d->cache[idx].primaryValues = d->primaryValues(indexInQuery(createIndex(idx, 0)).row());
1114 emit headerDataChanged(Qt::Vertical, idx, idx);
1115 }
1116 }
1117 break;
1118 }
1119 return true;
1120}
1121
1122/*!
1123 Inserts \a count empty rows at position \a row. Note that \a
1124 parent must be invalid, since this model does not support
1125 parent-child relations.
1126
1127 Only one row at a time can be inserted when using the
1128 OnFieldChange or OnRowChange update strategies.
1129
1130 The primeInsert() signal will be emitted for each new row.
1131 Connect to it if you want to initialize the new row with default
1132 values.
1133
1134 Returns false if the parameters are out of bounds; otherwise
1135 returns true.
1136
1137 \sa primeInsert(), insertRecord()
1138*/
1139bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
1140{
1141 Q_D(QSqlTableModel);
1142 if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
1143 return false;
1144
1145 switch (d->strategy) {
1146 case OnFieldChange:
1147 case OnRowChange:
1148 if (count != 1)
1149 return false;
1150 beginInsertRows(parent, row, row);
1151 d->insertIndex = row;
1152 // ### apply dangling changes...
1153 d->clearEditBuffer();
1154 emit primeInsert(row, d->editBuffer);
1155 break;
1156 case OnManualSubmit:
1157 beginInsertRows(parent, row, row + count - 1);
1158 if (!d->cache.isEmpty()) {
1159 QMap<int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = d->cache.end();
1160 while (it != d->cache.begin() && (--it).key() >= row) {
1161 int oldKey = it.key();
1162 const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
1163 d->cache.erase(it);
1164 it = d->cache.insert(oldKey + count, oldValue);
1165 }
1166 }
1167
1168 for (int i = 0; i < count; ++i) {
1169 d->cache[row + i] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Insert,
1170 d->rec);
1171 emit primeInsert(row + i, d->cache[row + i].rec);
1172 }
1173 break;
1174 }
1175 endInsertRows();
1176 return true;
1177}
1178
1179/*!
1180 Inserts the \a record after \a row. If \a row is negative, the
1181 record will be appended to the end. Calls insertRows() and
1182 setRecord() internally.
1183
1184 Returns true if the row could be inserted, otherwise false.
1185
1186 \sa insertRows(), removeRows()
1187*/
1188bool QSqlTableModel::insertRecord(int row, const QSqlRecord &record)
1189{
1190 Q_D(QSqlTableModel);
1191 if (row < 0)
1192 row = rowCount();
1193 if (!insertRow(row, QModelIndex()))
1194 return false;
1195 if (!setRecord(row, record))
1196 return false;
1197 if (d->strategy == OnFieldChange || d->strategy == OnRowChange)
1198 return submit();
1199 return true;
1200}
1201
1202/*! \reimp
1203*/
1204int QSqlTableModel::rowCount(const QModelIndex &parent) const
1205{
1206 Q_D(const QSqlTableModel);
1207
1208 if (parent.isValid())
1209 return 0;
1210
1211 int rc = QSqlQueryModel::rowCount();
1212 if (d->strategy == OnManualSubmit) {
1213 for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
1214 it != d->cache.constEnd(); ++it) {
1215 if (it.value().op == QSqlTableModelPrivate::Insert)
1216 ++rc;
1217 }
1218 } else if (d->insertIndex >= 0) {
1219 ++rc;
1220 }
1221 return rc;
1222}
1223
1224/*!
1225 Returns the index of the value in the database result set for the
1226 given \a item in the model.
1227
1228 The return value is identical to \a item if no columns or rows
1229 have been inserted, removed, or moved around.
1230
1231 Returns an invalid model index if \a item is out of bounds or if
1232 \a item does not point to a value in the result set.
1233
1234 \sa QSqlQueryModel::indexInQuery()
1235*/
1236QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const
1237{
1238 Q_D(const QSqlTableModel);
1239 const QModelIndex it = QSqlQueryModel::indexInQuery(item); // this adjusts columns only
1240 if (d->strategy == OnManualSubmit) {
1241 int rowOffset = 0;
1242 QSqlTableModelPrivate::CacheMap::ConstIterator i = d->cache.constBegin();
1243 while (i != d->cache.constEnd() && i.key() <= it.row()) {
1244 if (i.value().op == QSqlTableModelPrivate::Insert)
1245 ++rowOffset;
1246 ++i;
1247 }
1248 return createIndex(it.row() - rowOffset, it.column(), it.internalPointer());
1249 } else {
1250 if (d->insertIndex >= 0 && it.row() >= d->insertIndex)
1251 return createIndex(it.row() - 1, it.column(), it.internalPointer());
1252 }
1253 return it;
1254}
1255
1256/*!
1257 Returns the currently set filter.
1258
1259 \sa setFilter(), select()
1260*/
1261QString QSqlTableModel::filter() const
1262{
1263 Q_D(const QSqlTableModel);
1264 return d->filter;
1265}
1266
1267/*!
1268 Sets the current filter to \a filter.
1269
1270 The filter is a SQL \c WHERE clause without the keyword \c WHERE
1271 (for example, \c{name='Josephine')}.
1272
1273 If the model is already populated with data from a database,
1274 the model re-selects it with the new filter. Otherwise, the filter
1275 will be applied the next time select() is called.
1276
1277 \sa filter(), select(), selectStatement(), orderByClause()
1278*/
1279void QSqlTableModel::setFilter(const QString &filter)
1280{
1281 Q_D(QSqlTableModel);
1282 d->filter = filter;
1283 if (d->query.isActive())
1284 select();
1285}
1286
1287/*! \reimp
1288*/
1289void QSqlTableModel::clear()
1290{
1291 Q_D(QSqlTableModel);
1292 d->clear();
1293 QSqlQueryModel::clear();
1294}
1295
1296/*! \reimp
1297*/
1298Qt::ItemFlags QSqlTableModel::flags(const QModelIndex &index) const
1299{
1300 Q_D(const QSqlTableModel);
1301 if (index.internalPointer() || index.column() < 0 || index.column() >= d->rec.count()
1302 || index.row() < 0)
1303 return 0;
1304 if (d->rec.field(index.column()).isReadOnly())
1305 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
1306 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
1307}
1308
1309/*!
1310 Sets the values at the specified \a row to the values of \a
1311 record. Returns true if all the values could be set; otherwise
1312 returns false.
1313
1314 \sa record()
1315*/
1316bool QSqlTableModel::setRecord(int row, const QSqlRecord &record)
1317{
1318 Q_D(QSqlTableModel);
1319 Q_ASSERT_X(row >= 0, "QSqlTableModel::setRecord()", "Cannot set a record to a row less than 0");
1320 if (row >= rowCount())
1321 return false;
1322
1323 bool isOk = true;
1324 switch (d->strategy) {
1325 case OnFieldChange:
1326 case OnRowChange:
1327 return d->setRecord(row, record);
1328 case OnManualSubmit: {
1329 QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
1330 if (mrow.op == QSqlTableModelPrivate::None) {
1331 mrow.op = QSqlTableModelPrivate::Update;
1332 mrow.rec = d->rec;
1333 mrow.primaryValues = d->primaryValues(indexInQuery(createIndex(row, 0)).row());
1334 }
1335 QString fieldName;
1336 for (int i = 0; i < record.count(); ++i) {
1337 fieldName = record.fieldName(i);
1338 if (d->db.driver()->isIdentifierEscaped(fieldName, QSqlDriver::FieldName))
1339 fieldName = d->db.driver()->stripDelimiters(fieldName, QSqlDriver::FieldName);
1340 int idx = mrow.rec.indexOf(fieldName);
1341 if (idx == -1)
1342 isOk = false;
1343 else
1344 mrow.rec.setValue(idx, record.value(i));
1345 }
1346
1347 if (isOk)
1348 emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1));
1349 return isOk; }
1350 }
1351 return false;
1352}
1353
1354QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.