Qt 4.8
qsqltablemodel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
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 
57 
65 {
66  QSqlRecord r = rec;
67  for (int i = 0; i < r.count() && i < values.count(); ++i)
68  r.setValue(i, values.at(i));
69  return r;
70 }
71 
79 {
81  bool isOk = true;
82 
84 
85  // FieldChange strategy makes no sense when setting an entire row
88  for (int i = 0; i < record.count(); ++i) {
89  if (!record.isGenerated(i))
90  continue;
91  int idx = nameToIndex(record.fieldName(i));
92  if (idx == -1)
93  continue;
94  QModelIndex cIndex = q->createIndex(row, idx);
95  QVariant value = record.value(i);
96  QVariant oldValue = q->data(cIndex);
97  if (oldValue.isNull() || oldValue != value)
98  isOk &= q->setData(cIndex, value, Qt::EditRole);
99  }
100  if (isOk && oldStrategy == QSqlTableModel::OnFieldChange)
101  q->submitAll();
102  strategy = oldStrategy;
103 
104  return isOk;
105 }
106 
108 {
109  QString fieldname = name;
111  fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName);
112  return rec.indexOf(fieldname);
113 }
114 
116 {
117  rec = db.record(tableName);
119 }
120 
122 {
123  editIndex = -1;
124  sortColumn = -1;
126  tableName.clear();
127  editQuery.clear();
128  editBuffer.clear();
129  cache.clear();
131  rec.clear();
132  filter.clear();
133 }
134 
136 {
138  if (insertIndex == -1)
139  return;
140 
141  q->beginRemoveRows(QModelIndex(), insertIndex, insertIndex);
142  insertIndex = -1;
143  q->endRemoveRows();
144 }
145 
147 {
148  editBuffer = rec;
150 }
151 
153 {
154  cache.clear();
155 }
156 
158 {
159  for (int i = rec.count() - 1; i >= 0; i--)
160  rec.setGenerated(i, false);
161 }
162 
164 {
165  rec.setValue(c, v);
166  rec.setGenerated(c, true);
167 }
168 
170 {
172  ModifiedRow r = cache.value(row);
173  switch (r.op) {
175  Q_ASSERT_X(false, "QSqlTableModelPrivate::revertCachedRow()", "Invalid entry in cache map");
176  return;
179  cache.remove(row);
180  emit q->dataChanged(q->createIndex(row, 0),
181  q->createIndex(row, q->columnCount() - 1));
182  break;
185  if (it == cache.end())
186  return;
187  q->beginRemoveRows(QModelIndex(), row, row);
188  it = cache.erase(it);
189  while (it != cache.end()) {
190  int oldKey = it.key();
191  const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
192  cache.erase(it);
193  it = cache.insert(oldKey - 1, oldValue);
194  ++it;
195  }
196  q->endRemoveRows();
197  break; }
198  }
199 }
200 
201 bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
202  const QSqlRecord &rec, const QSqlRecord &whereValues)
203 {
204  if (stmt.isEmpty())
205  return false;
206 
207  // lazy initialization of editQuery
208  if (editQuery.driver() != db.driver())
210 
211  // workaround for In-Process databases - remove all read locks
212  // from the table to make sure the editQuery succeeds
214  const_cast<QSqlResult *>(query.result())->detachFromResultSet();
215 
216  if (prepStatement) {
217  if (editQuery.lastQuery() != stmt) {
218  if (!editQuery.prepare(stmt)) {
220  return false;
221  }
222  }
223  int i;
224  for (i = 0; i < rec.count(); ++i) {
225  if (rec.isGenerated(i))
226  editQuery.addBindValue(rec.value(i));
227  }
228  for (i = 0; i < whereValues.count(); ++i) {
229  if (whereValues.isGenerated(i) && !whereValues.isNull(i))
230  editQuery.addBindValue(whereValues.value(i));
231  }
232 
233  if (!editQuery.exec()) {
235  return false;
236  }
237  } else {
238  if (!editQuery.exec(stmt)) {
240  return false;
241  }
242  }
243  return true;
244 }
245 
247 {
249  if (!query.seek(row)) {
250  error = query.lastError();
251  return record;
252  }
253  if (primaryIndex.isEmpty()) {
254  record = rec;
255  for (int i = 0; i < record.count(); ++i)
256  record.setValue(i, query.value(i));
257  } else {
258  record = primaryIndex;
259  for (int i = 0; i < record.count(); ++i)
260  record.setValue(i, query.value(rec.indexOf(record.fieldName(i))));
261  }
262  return record;
263 }
264 
371  : QSqlQueryModel(*new QSqlTableModelPrivate, parent)
372 {
374  d->db = db.isValid() ? db : QSqlDatabase::database();
375 }
376 
380  : QSqlQueryModel(dd, parent)
381 {
383  d->db = db.isValid() ? db : QSqlDatabase::database();
384 }
385 
390 {
391 }
392 
405 {
407  clear();
408  d->tableName = tableName;
409  d->initRecordAndPrimaryIndex();
410  d->initColOffsets(d->rec.count());
411 
412  if (d->rec.count() == 0)
413  d->error = QSqlError(QLatin1String("Unable to find table ") + d->tableName, QString(),
415 }
416 
421 {
422  Q_D(const QSqlTableModel);
423  return d->tableName;
424 }
425 
436 {
439  if (query.isEmpty())
440  return false;
441 
442  revertAll();
443  QSqlQuery qu(query, d->db);
444  setQuery(qu);
445 
446  if (!qu.isActive() || lastError().isValid()) {
447  // something went wrong - revert to non-select state
448  d->initRecordAndPrimaryIndex();
449  return false;
450  }
451  return true;
452 }
453 
458 {
459  Q_D(const QSqlTableModel);
460  if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole))
461  return QVariant();
462 
463  // Problem.. we need to use QSQM::indexInQuery to handle inserted columns
464  // but inserted rows we need to handle
465  // and indexInQuery is not virtual (grrr) so any values we pass to QSQM need
466  // to handle the insertedRows
467  QModelIndex item = indexInQuery(index);
468 
469  switch (d->strategy) {
470  case OnFieldChange:
471  case OnRowChange:
472  if (index.row() == d->insertIndex) {
473  if (item.column() < 0 || item.column() >= d->rec.count())
474  return QVariant();
475  return d->editBuffer.value(index.column());
476  }
477  if (d->editIndex == item.row()) {
478  if (d->editBuffer.isGenerated(item.column()))
479  return d->editBuffer.value(item.column());
480  }
481  break;
482  case OnManualSubmit:
483  if (d->cache.contains(index.row())) {
484  const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
485  if (row.rec.isGenerated(item.column()) || row.op == QSqlTableModelPrivate::Insert)
486  return row.rec.value(item.column());
487  }
488  break;
489  }
490 
491  // We need to handle row mapping here, but not column mapping
492  return QSqlQueryModel::data(index.sibling(item.row(), index.column()), role);
493 }
494 
498 QVariant QSqlTableModel::headerData(int section, Qt::Orientation orientation, int role) const
499 {
500  Q_D(const QSqlTableModel);
501  if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
502  switch (d->strategy) {
503  case OnFieldChange:
504  case OnRowChange:
505  if (d->insertIndex == section)
506  return QLatin1String("*");
507  break;
508  case OnManualSubmit:
509  QSqlTableModelPrivate::Op op = d->cache.value(section).op;
511  return QLatin1String("*");
512  else if (op == QSqlTableModelPrivate::Delete)
513  return QLatin1String("!");
514  break;
515  }
516  }
517  return QSqlQueryModel::headerData(section, orientation, role);
518 }
519 
528 {
529  Q_D(const QSqlTableModel);
530  if (!index.isValid())
531  return false;
532 
533  switch (d->strategy) {
534  case OnFieldChange:
535  return false;
536  case OnRowChange:
537  return index.row() == d->editIndex && d->editBuffer.isGenerated(index.column());
538  case OnManualSubmit: {
539  const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
540  return row.op == QSqlTableModelPrivate::Insert
543  && row.rec.isGenerated(index.column()));
544  }
545  }
546  return false;
547 }
548 
559 bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
560 {
562  if (role != Qt::EditRole)
563  return QSqlQueryModel::setData(index, value, role);
564 
565  if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount())
566  return false;
567 
568  bool isOk = true;
569  switch (d->strategy) {
570  case OnFieldChange: {
571  if (index.row() == d->insertIndex) {
572  QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
573  return true;
574  }
575  d->clearEditBuffer();
576  QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
577  isOk = updateRowInTable(index.row(), d->editBuffer);
578  if (isOk)
579  select();
580  emit dataChanged(index, index);
581  break; }
582  case OnRowChange:
583  if (index.row() == d->insertIndex) {
584  QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
585  return true;
586  }
587  if (d->editIndex != index.row()) {
588  if (d->editIndex != -1)
589  submit();
590  d->clearEditBuffer();
591  }
592  QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
593  d->editIndex = index.row();
594  emit dataChanged(index, index);
595  break;
596  case OnManualSubmit: {
597  QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
598  if (row.op == QSqlTableModelPrivate::None) {
600  row.rec = d->rec;
602  row.primaryValues = d->primaryValues(indexInQuery(index).row());
603  }
605  emit dataChanged(index, index);
606  break; }
607  }
608  return isOk;
609 }
610 
619 {
621 }
622 
640 {
642  QSqlRecord rec(values);
643  emit beforeUpdate(row, rec);
644 
645  const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row);
646  bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
647  QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName,
648  rec, prepStatement);
649  QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, d->tableName,
650  whereValues, prepStatement);
651 
652  if (stmt.isEmpty() || where.isEmpty() || row < 0 || row >= rowCount()) {
653  d->error = QSqlError(QLatin1String("No Fields to update"), QString(),
655  return false;
656  }
657  stmt.append(QLatin1Char(' ')).append(where);
658 
659  return d->exec(stmt, prepStatement, rec, whereValues);
660 }
661 
662 
677 {
679  QSqlRecord rec = values;
680  emit beforeInsert(rec);
681 
682  bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
683  QString stmt = d->db.driver()->sqlStatement(QSqlDriver::InsertStatement, d->tableName,
684  rec, prepStatement);
685 
686  if (stmt.isEmpty()) {
687  d->error = QSqlError(QLatin1String("No Fields to update"), QString(),
689  return false;
690  }
691 
692  return d->exec(stmt, prepStatement, rec, QSqlRecord() /* no where values */);
693 }
694 
708 {
710  emit beforeDelete(row);
711 
712  const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row);
713  bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
714  QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement,
715  d->tableName,
716  QSqlRecord(),
717  prepStatement);
718  QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement,
719  d->tableName,
720  whereValues,
721  prepStatement);
722 
723  if (stmt.isEmpty() || where.isEmpty()) {
724  d->error = QSqlError(QLatin1String("Unable to delete row"), QString(),
726  return false;
727  }
728  stmt.append(QLatin1Char(' ')).append(where);
729 
730  return d->exec(stmt, prepStatement, QSqlRecord() /* no new values */, whereValues);
731 }
732 
749 {
751 
752  switch (d->strategy) {
753  case OnFieldChange:
754  if (d->insertIndex == -1)
755  return true;
756  // else fall through
757  case OnRowChange:
758  if (d->editBuffer.isEmpty())
759  return true;
760  if (d->insertIndex != -1) {
761  if (!insertRowIntoTable(d->editBuffer))
762  return false;
763  d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column());
764  } else {
765  if (!updateRowInTable(d->editIndex, d->editBuffer))
766  return false;
767  }
768  d->clearEditBuffer();
769  d->editIndex = -1;
770  d->insertIndex = -1;
771  return select();
772  case OnManualSubmit:
773  for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
774  it != d->cache.constEnd(); ++it) {
775  switch (it.value().op) {
777  if (!insertRowIntoTable(it.value().rec))
778  return false;
779  d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column());
780  break;
782  if (!updateRowInTable(it.key(), it.value().rec))
783  return false;
784  break;
786  if (!deleteRowFromTable(it.key()))
787  return false;
788  break;
790  Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation");
791  break;
792  }
793  }
794  d->clearCache();
795  return select();
796  }
797  return false;
798 }
799 
820 {
822  if (d->strategy == OnRowChange || d->strategy == OnFieldChange)
823  return submitAll();
824  return true;
825 }
826 
840 {
842  if (d->strategy == OnRowChange)
843  revertAll();
844 }
845 
875 {
877  revertAll();
878  d->strategy = strategy;
879 }
880 
887 {
888  Q_D(const QSqlTableModel);
889  return d->strategy;
890 }
891 
898 {
900  switch (d->strategy) {
901  case OnFieldChange:
902  break;
903  case OnRowChange:
904  if (d->editIndex != -1)
905  revertRow(d->editIndex);
906  else if (d->insertIndex != -1)
907  revertRow(d->insertIndex);
908  break;
909  case OnManualSubmit:
910  while (!d->cache.isEmpty())
911  revertRow(d->cache.constBegin().key());
912  break;
913  }
914 }
915 
922 {
923  if (row < 0)
924  return;
925 
927  switch (d->strategy) {
928  case OnFieldChange:
929  break;
930  case OnRowChange: {
931  if (d->editIndex == row) {
932  d->editBuffer.clear();
933  int oldIndex = d->editIndex;
934  d->editIndex = -1;
935  emit dataChanged(createIndex(oldIndex, 0), createIndex(oldIndex, columnCount() - 1));
936  } else if (d->insertIndex == row) {
937  d->revertInsertedRow();
938  }
939  break; }
940  case OnManualSubmit:
941  d->revertCachedRow(row);
942  break;
943  }
944 }
945 
953 {
954  Q_D(const QSqlTableModel);
955  return d->primaryIndex;
956 }
957 
968 {
970  d->primaryIndex = key;
971 }
972 
977 {
978  Q_D(const QSqlTableModel);
979  return d->db;
980 }
981 
989 void QSqlTableModel::sort(int column, Qt::SortOrder order)
990 {
991  setSort(column, order);
992  select();
993 }
994 
1003 {
1005  d->sortColumn = column;
1006  d->sortOrder = order;
1007 }
1008 
1016 {
1017  Q_D(const QSqlTableModel);
1018  QString s;
1019  QSqlField f = d->rec.field(d->sortColumn);
1020  if (!f.isValid())
1021  return s;
1022 
1023  QString table = d->tableName;
1024  //we can safely escape the field because it would have been obtained from the database
1025  //and have the correct case
1026  QString field = d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
1027  s.append(QLatin1String("ORDER BY ")).append(table).append(QLatin1Char('.')).append(field);
1028  s += d->sortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC");
1029 
1030  return s;
1031 }
1032 
1037 int QSqlTableModel::fieldIndex(const QString &fieldName) const
1038 {
1039  Q_D(const QSqlTableModel);
1040  return d->rec.indexOf(fieldName);
1041 }
1042 
1051 {
1052  Q_D(const QSqlTableModel);
1053  QString query;
1054  if (d->tableName.isEmpty()) {
1055  d->error = QSqlError(QLatin1String("No table name given"), QString(),
1057  return query;
1058  }
1059  if (d->rec.isEmpty()) {
1060  d->error = QSqlError(QLatin1String("Unable to find table ") + d->tableName, QString(),
1062  return query;
1063  }
1064 
1065  query = d->db.driver()->sqlStatement(QSqlDriver::SelectStatement,
1066  d->tableName,
1067  d->rec,
1068  false);
1069  if (query.isEmpty()) {
1070  d->error = QSqlError(QLatin1String("Unable to select fields from table ") + d->tableName,
1072  return query;
1073  }
1074  if (!d->filter.isEmpty())
1075  query.append(QLatin1String(" WHERE ")).append(d->filter);
1076  QString orderBy(orderByClause());
1077  if (!orderBy.isEmpty())
1078  query.append(QLatin1Char(' ')).append(orderBy);
1079 
1080  return query;
1081 }
1082 
1092 bool QSqlTableModel::removeColumns(int column, int count, const QModelIndex &parent)
1093 {
1095  if (parent.isValid() || column < 0 || column + count > d->rec.count())
1096  return false;
1097  for (int i = 0; i < count; ++i)
1098  d->rec.remove(column);
1099  if (d->query.isActive())
1100  return select();
1101  return true;
1102 }
1103 
1119 bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
1120 {
1122  if (parent.isValid() || row < 0 || count <= 0)
1123  return false;
1124 
1125  int i;
1126  switch (d->strategy) {
1127  case OnFieldChange:
1128  case OnRowChange:
1129  for (i = 0; i < count; ++i) {
1130  if (row + i == d->insertIndex)
1131  d->revertInsertedRow();
1132  else if (!deleteRowFromTable(row + i))
1133  return false;
1134  }
1135  select();
1136  break;
1137  case OnManualSubmit:
1138  for (i = 0; i < count; ++i) {
1139  int idx = row + i;
1140  if (idx >= rowCount())
1141  return false;
1142  if (d->cache.value(idx).op == QSqlTableModelPrivate::Insert) {
1143  revertRow(idx);
1144  // Reverting a row means all the other cache entries have been adjusted downwards
1145  // so fake this by adjusting row
1146  --row;
1147  } else {
1148  d->cache[idx].op = QSqlTableModelPrivate::Delete;
1149  d->cache[idx].primaryValues = d->primaryValues(indexInQuery(createIndex(idx, 0)).row());
1150  emit headerDataChanged(Qt::Vertical, idx, idx);
1151  }
1152  }
1153  break;
1154  }
1155  return true;
1156 }
1157 
1175 bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
1176 {
1178  if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
1179  return false;
1180 
1181  switch (d->strategy) {
1182  case OnFieldChange:
1183  case OnRowChange:
1184  if (count != 1)
1185  return false;
1186  beginInsertRows(parent, row, row);
1187  d->insertIndex = row;
1188  // ### apply dangling changes...
1189  d->clearEditBuffer();
1190  emit primeInsert(row, d->editBuffer);
1191  break;
1192  case OnManualSubmit:
1193  beginInsertRows(parent, row, row + count - 1);
1194  if (!d->cache.isEmpty()) {
1196  while (it != d->cache.begin() && (--it).key() >= row) {
1197  int oldKey = it.key();
1198  const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
1199  d->cache.erase(it);
1200  it = d->cache.insert(oldKey + count, oldValue);
1201  }
1202  }
1203 
1204  for (int i = 0; i < count; ++i) {
1206  d->rec);
1207  emit primeInsert(row + i, d->cache[row + i].rec);
1208  }
1209  break;
1210  }
1211  endInsertRows();
1212  return true;
1213 }
1214 
1225 {
1227  if (row < 0)
1228  row = rowCount();
1229  if (!insertRow(row, QModelIndex()))
1230  return false;
1231  if (!setRecord(row, record))
1232  return false;
1233  if (d->strategy == OnFieldChange || d->strategy == OnRowChange)
1234  return submit();
1235  return true;
1236 }
1237 
1241 {
1242  Q_D(const QSqlTableModel);
1243 
1244  if (parent.isValid())
1245  return 0;
1246 
1247  int rc = QSqlQueryModel::rowCount();
1248  if (d->strategy == OnManualSubmit) {
1249  for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
1250  it != d->cache.constEnd(); ++it) {
1251  if (it.value().op == QSqlTableModelPrivate::Insert)
1252  ++rc;
1253  }
1254  } else if (d->insertIndex >= 0) {
1255  ++rc;
1256  }
1257  return rc;
1258 }
1259 
1273 {
1274  Q_D(const QSqlTableModel);
1275  const QModelIndex it = QSqlQueryModel::indexInQuery(item); // this adjusts columns only
1276  if (d->strategy == OnManualSubmit) {
1277  int rowOffset = 0;
1278  QSqlTableModelPrivate::CacheMap::ConstIterator i = d->cache.constBegin();
1279  while (i != d->cache.constEnd() && i.key() <= it.row()) {
1280  if (i.value().op == QSqlTableModelPrivate::Insert)
1281  ++rowOffset;
1282  ++i;
1283  }
1284  return createIndex(it.row() - rowOffset, it.column(), it.internalPointer());
1285  } else {
1286  if (d->insertIndex >= 0 && it.row() >= d->insertIndex)
1287  return createIndex(it.row() - 1, it.column(), it.internalPointer());
1288  }
1289  return it;
1290 }
1291 
1298 {
1299  Q_D(const QSqlTableModel);
1300  return d->filter;
1301 }
1302 
1316 {
1318  d->filter = filter;
1319  if (d->query.isActive())
1320  select();
1321 }
1322 
1326 {
1328  d->clear();
1330 }
1331 
1334 Qt::ItemFlags QSqlTableModel::flags(const QModelIndex &index) const
1335 {
1336  Q_D(const QSqlTableModel);
1337  if (index.internalPointer() || index.column() < 0 || index.column() >= d->rec.count()
1338  || index.row() < 0)
1339  return 0;
1340  if (d->rec.field(index.column()).isReadOnly())
1343 }
1344 
1353 {
1355  Q_ASSERT_X(row >= 0, "QSqlTableModel::setRecord()", "Cannot set a record to a row less than 0");
1356  if (row >= rowCount())
1357  return false;
1358 
1359  bool isOk = true;
1360  switch (d->strategy) {
1361  case OnFieldChange:
1362  case OnRowChange:
1363  return d->setRecord(row, record);
1364  case OnManualSubmit: {
1365  QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
1366  if (mrow.op == QSqlTableModelPrivate::None) {
1368  mrow.rec = d->rec;
1370  mrow.primaryValues = d->primaryValues(indexInQuery(createIndex(row, 0)).row());
1371  }
1372  QString fieldName;
1373  for (int i = 0; i < record.count(); ++i) {
1374  fieldName = record.fieldName(i);
1375  if (d->db.driver()->isIdentifierEscaped(fieldName, QSqlDriver::FieldName))
1376  fieldName = d->db.driver()->stripDelimiters(fieldName, QSqlDriver::FieldName);
1377  int idx = mrow.rec.indexOf(fieldName);
1378  if (idx == -1) {
1379  isOk = false;
1380  } else {
1381  mrow.rec.setValue(idx, record.value(i));
1382  mrow.rec.setGenerated(idx, record.isGenerated(i));
1383  }
1384  }
1385 
1386  if (isOk)
1387  emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1));
1388  return isOk; }
1389  }
1390  return false;
1391 }
1392 
static void clearGenerated(QSqlRecord &rec)
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
The QSqlError class provides SQL database error information.
Definition: qsqlerror.h:53
The QSqlIndex class provides functions to manipulate and describe database indexes.
Definition: qsqlindex.h:55
QModelIndex indexInQuery(const QModelIndex &item) const
Returns the index of the value in the database result set for the given item in the model...
double d
Definition: qnumeric_p.h:62
void * internalPointer() const
Returns a void * pointer used by the model to associate the index with the internal data structure...
const Key & key() const
Returns the current item&#39;s key as a const reference.
Definition: qmap.h:250
EditStrategy
This enum type describes which strategy to choose when editing values in the database.
const QSqlDriver * driver() const
Returns the database driver associated with the query.
Definition: qsqlquery.cpp:441
virtual QString selectStatement() const
Returns the SQL SELECT statement used internally to populate the model.
virtual void setEditStrategy(EditStrategy strategy)
Sets the strategy for editing values in the database to strategy.
bool isValid() const
Returns true if the field&#39;s variant type is valid; otherwise returns false.
Definition: qsqlfield.cpp:517
static void setGeneratedValue(QSqlRecord &rec, int c, QVariant v)
virtual int nameToIndex(const QString &name) const
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex())
Inserts count empty rows at position row.
int rowCount(const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
unsigned char c[8]
Definition: qnumeric_p.h:62
void beforeInsert(QSqlRecord &record)
This signal is emitted by insertRowIntoTable() before a new row is inserted into the currently active...
QSqlError lastError() const
Returns information about the last error that occurred on the database.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
int rowCount(const QModelIndex &parent=QModelIndex()) const
If the database supports returning the size of a query (see QSqlDriver::hasFeature()), the number of rows of the current query is returned.
bool prepare(const QString &query)
Prepares the SQL query query for execution.
Definition: qsqlquery.cpp:903
QModelIndex sibling(int row, int column) const
Returns the sibling at row and column.
bool isNull() const
Returns true if this is a NULL variant, false otherwise.
Definition: qvariant.cpp:3102
virtual bool hasFeature(DriverFeature f) const =0
Returns true if the driver supports feature feature; otherwise returns false.
#define it(className, varName)
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
QString filter() const
Returns the currently set filter.
bool setRecord(int row, const QSqlRecord &record)
Set a record for OnFieldChange and OnRowChange.
virtual void setFilter(const QString &filter)
Sets the current filter to filter.
QSqlDatabase database() const
Returns a pointer to the used QSqlDatabase or 0 if no database was set.
bool isValid() const
Returns true if the QSqlDatabase has a valid driver.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition: qsqlquery.h:63
EditStrategy editStrategy() const
Returns the current edit strategy.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Returns the index of the data in row and column with parent.
virtual void clearCache()
The QSqlDatabase class represents a connection to a database.
Definition: qsqldatabase.h:78
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Sets the role data for the item at index to value.
QModelIndex createIndex(int row, int column, void *data=0) const
Creates a model index for the given row and column with the internal pointer ptr. ...
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool isEmpty() const
Returns true if there are no fields in the record; otherwise returns false.
Definition: qsqlrecord.cpp:380
iterator find(const Key &key)
Returns an iterator pointing to the item with key key in the map.
Definition: qmap.h:618
bool isNull(int i) const
Returns true if the field index is null or if there is no field at position index; otherwise returns ...
Definition: qsqlrecord.cpp:453
The QSqlRecord class encapsulates a database record.
Definition: qsqlrecord.h:58
void endInsertRows()
Ends a row insertion operation.
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool isActive() const
Returns true if the query is active.
Definition: qsqlquery.cpp:785
QSqlIndex primaryKey() const
Returns the primary key for the current table, or an empty QSqlIndex if the table is not set or has n...
QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const
Returns the value for the specified item and role.
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
const QSqlResult * result() const
Returns the result associated with the query.
Definition: qsqlquery.cpp:450
#define Q_D(Class)
Definition: qglobal.h:2482
virtual ~QSqlTableModel()
Destroys the object and frees any allocated resources.
bool setRecord(int row, const QSqlRecord &record)
Sets the values at the specified row to the values of record.
QSqlDriver * driver() const
Returns the database driver used to access the database connection.
void setPrimaryKey(const QSqlIndex &key)
Protected method that allows subclasses to set the primary key to key.
QString lastQuery() const
Returns the text of the current query being used, or an empty string if there is no current query tex...
Definition: qsqlquery.cpp:432
QSqlIndex primaryIndex(const QString &tablename) const
Returns the primary index for table tablename.
bool isDirty(const QModelIndex &index) const
Returns true if the value at the index index is dirty, otherwise false.
#define Q_Q(Class)
Definition: qglobal.h:2483
QString name() const
Returns the name of the field.
Definition: qsqlfield.cpp:380
bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const
Returns whether identifier is escaped according to the database rules.
Definition: qsqldriver.cpp:429
void primeInsert(int row, QSqlRecord &record)
This signal is emitted by insertRows(), when an insertion is initiated in the given row of the curren...
T & value() const
Returns a modifiable reference to the current item&#39;s value.
Definition: qmap.h:251
bool isGenerated(int i) const
Returns true if the record has a field at position index and this field is to be generated (the defau...
Definition: qsqlrecord.cpp:519
void clear()
Reimplemented Function
SortOrder
Definition: qnamespace.h:189
void clear()
Clears the result set and releases any resources held by the query.
Definition: qsqlquery.cpp:874
void * data()
Definition: qvariant.cpp:3077
QSqlRecord primaryValues(int index)
int columnCount(const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
The QSqlQueryModel class provides a read-only data model for SQL result sets.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QSqlRecord record(const QString &tablename) const
Returns a QSqlRecord populated with the names of all the fields in the table (or view) called tablena...
virtual void setTable(const QString &tableName)
Sets the database table on which the model operates to tableName.
const_iterator ConstIterator
Qt-style synonym for QMap::const_iterator.
Definition: qmap.h:389
virtual bool insertRowIntoTable(const QSqlRecord &values)
Inserts the values values into the currently active database table.
QSqlQuery query() const
Returns the QSqlQuery associated with this model.
void revert()
This reimplemented slot is called by the item delegates when the user canceled editing the current ro...
bool insertRow(int row, const QModelIndex &parent=QModelIndex())
Inserts a single row before the given row in the child items of the parent specified.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
virtual void clearEditBuffer()
QSqlTableModel::EditStrategy strategy
int row() const
Returns the row this model index refers to.
const char * name
static QSqlDatabase database(const QString &connectionName=QLatin1String(defaultConnection), bool open=true)
Returns the database connection called connectionName.
const T value(const Key &key) const
Returns the value associated with the key key.
Definition: qmap.h:499
#define emit
Definition: qobjectdefs.h:76
void setQuery(const QSqlQuery &query)
This function simply calls QSqlQueryModel::setQuery(query).
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
virtual void revertCachedRow(int row)
bool insertRecord(int row, const QSqlRecord &record)
Inserts the record after row.
virtual bool updateRowInTable(int row, const QSqlRecord &values)
Updates the given row in the currently active database table with the specified values.
quint16 values[128]
virtual QString orderByClause() const
Returns an SQL ORDER BY clause based on the currently set sort order.
bool isValid() const
Returns true if this model index is valid; otherwise returns false.
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
Qt::ItemFlags flags(const QModelIndex &index) const
Reimplemented Function
void sort(int column, Qt::SortOrder order)
Sorts the data by column with the sort order order.
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex())
Removes count columns from the parent model, starting at index column.
void setQuery(const QSqlQuery &query)
Resets the model and sets the data provider to be the given query.
bool submit()
This reimplemented slot is called by the item delegates when the user stopped editing the current row...
int remove(const Key &key)
Removes all the items that have the key key from the map.
Definition: qmap.h:662
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
int count() const
Returns the number of fields in the record.
Definition: qsqlrecord.cpp:573
void addBindValue(const QVariant &val, QSql::ParamType type=QSql::In)
Adds the value val to the list of values when using positional value binding.
Definition: qsqlquery.cpp:1060
QSqlError lastError() const
Returns error information about the last error (if any) that occurred with this query.
Definition: qsqlquery.cpp:754
QString & append(QChar c)
Definition: qstring.cpp:1777
The QMap::iterator class provides an STL-style non-const iterator for QMap and QMultiMap.
Definition: qmap.h:233
virtual void clear()
Clears the model and releases any acquired resource.
void headerDataChanged(Qt::Orientation orientation, int first, int last)
This signal is emitted whenever a header is changed.
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the map...
Definition: qmap.h:375
virtual bool deleteRowFromTable(int row)
Deletes the given row from the currently active database table.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Sets the data for the item index for the role role to value.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key key and a value of value.
Definition: qmap.h:559
QString tableName() const
Returns the name of the currently selected table.
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Returns the header data for the given role in the section of the header with the specified orientatio...
QSqlRecord record(const QVector< QVariant > &values) const
Populates our record with values.
int key
The QModelIndex class is used to locate data in a data model.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Reimplemented Function
QModelIndex indexInQuery(const QModelIndex &item) const
Returns the index of the value in the database result set for the given item in the model...
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
This signal is emitted whenever the data in an existing item changes.
QSqlRecord record() const
Returns an empty record containing information about the fields of the current query.
void beforeUpdate(int row, QSqlRecord &record)
This signal is emitted by updateRowInTable() before the row is updated in the currently active databa...
void clear()
Removes all the record&#39;s fields.
Definition: qsqlrecord.cpp:367
QSqlTableModel(QObject *parent=0, QSqlDatabase db=QSqlDatabase())
Creates an empty QSqlTableModel and sets the parent to parent and the database connection to db...
QObject * parent
Definition: qobject.h:92
The QSqlTableModel class provides an editable data model for a single database table.
iterator erase(iterator it)
Removes the (key, value) pair pointed to by the iterator pos from the map, and returns an iterator to...
Definition: qmap.h:717
bool isValid() const
Returns true if an error is set, otherwise false.
Definition: qsqlerror.cpp:254
virtual bool select()
Populates the model with data from the table that was set via setTable(), using the specified filter ...
bool seek(int i, bool relative=false)
Retrieves the record at position index, if available, and positions the query on the retrieved record...
Definition: qsqlquery.cpp:502
bool submitAll()
Submits all pending changes and returns true on success.
virtual void revertRow(int row)
Reverts all changes for the specified row.
void setValue(int i, const QVariant &val)
Sets the value of the field at position index to val.
Definition: qsqlrecord.cpp:585
The QSqlField class manipulates the fields in SQL database tables and views.
Definition: qsqlfield.h:56
bool exec(const QString &query)
Executes the SQL in query.
Definition: qsqlquery.cpp:355
QString stripDelimiters(const QString &identifier, IdentifierType type) const
Returns the identifier with the leading and trailing delimiters removed, identifier can either be a t...
Definition: qsqldriver.cpp:455
void revertAll()
Reverts all pending changes.
int fieldIndex(const QString &fieldName) const
Returns the index of the field fieldName, or -1 if no corresponding field exists in the model...
Orientation
Definition: qnamespace.h:174
QString fieldName(int i) const
Returns the name of the field at position index.
Definition: qsqlrecord.cpp:232
QVariant value(int i) const
Returns the value of field index in the current record.
Definition: qsqlquery.cpp:403
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
bool exec(const QString &stmt, bool prepStatement, const QSqlRecord &rec, const QSqlRecord &whereValues)
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
Removes count rows starting at row.
QVariant data(const QModelIndex &idx, int role=Qt::DisplayRole) const
Reimplemented Function
void clear()
Removes all items from the map.
Definition: qmap.h:444
int indexOf(const QString &name) const
Returns the position of the field called name within the record, or -1 if it cannot be found...
Definition: qsqlrecord.cpp:246
QVariant value(int i) const
Returns the value of the field located at position index in the record.
Definition: qsqlrecord.cpp:203
void beginInsertRows(const QModelIndex &parent, int first, int last)
Begins a row insertion operation.
int column() const
Returns the column this model index refers to.
void setGenerated(const QString &name, bool generated)
Sets the generated flag for the field called name to generated.
Definition: qsqlrecord.cpp:420
void beforeDelete(int row)
This signal is emitted by deleteRowFromTable() before the row is deleted from the currently active da...
virtual void setSort(int column, Qt::SortOrder order)
Sets the sort order for column to order.