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