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

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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