Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmltablemodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmltablemodel_p.h"
5
6#include <QtCore/qloggingcategory.h>
7#include <QtQml/qqmlinfo.h>
8#include <QtQml/qqmlengine.h>
9
11
12Q_LOGGING_CATEGORY(lcTableModel, "qt.qml.tablemodel")
13
14
17
138
142
153{
154 return mRows;
155}
156
158{
159 if (rows.userType() != qMetaTypeId<QJSValue>()) {
160 qmlWarning(this) << "setRows(): \"rows\" must be an array; actual type is " << rows.typeName();
161 return;
162 }
163
164 const QJSValue rowsAsJSValue = rows.value<QJSValue>();
165 const QVariantList rowsAsVariantList = rowsAsJSValue.toVariant().toList();
166 if (rowsAsVariantList == mRows) {
167 // No change.
168 return;
169 }
170
171 if (!componentCompleted) {
172 // Store the rows until we can call doSetRows() after component completion.
173 mRows = rowsAsVariantList;
174 return;
175 }
176
177 doSetRows(rowsAsVariantList);
178}
179
180void QQmlTableModel::doSetRows(const QVariantList &rowsAsVariantList)
181{
182 Q_ASSERT(componentCompleted);
183
184 // By now, all TableModelColumns should have been set.
185 if (mColumns.isEmpty()) {
186 qmlWarning(this) << "No TableModelColumns were set; model will be empty";
187 return;
188 }
189
190 const bool firstTimeValidRowsHaveBeenSet = mColumnMetadata.isEmpty();
191 if (!firstTimeValidRowsHaveBeenSet) {
192 // This is not the first time rows have been set; validate each one.
193 for (int rowIndex = 0; rowIndex < rowsAsVariantList.size(); ++rowIndex) {
194 // validateNewRow() expects a QVariant wrapping a QJSValue, so to
195 // simplify the code, just create one here.
196 const QVariant row = QVariant::fromValue(rowsAsVariantList.at(rowIndex));
197 if (!validateNewRow("setRows()", row, rowIndex, SetRowsOperation))
198 return;
199 }
200 }
201
202 const int oldRowCount = mRowCount;
203 const int oldColumnCount = mColumnCount;
204
206
207 // We don't clear the column or role data, because a TableModel should not be reused in that way.
208 // Once it has valid data, its columns and roles are fixed.
209 mRows = rowsAsVariantList;
210 mRowCount = mRows.size();
211
212 // Gather metadata the first time rows is set.
213 if (firstTimeValidRowsHaveBeenSet && !mRows.isEmpty())
214 fetchColumnMetadata();
215
217
219
220 if (mRowCount != oldRowCount)
222 if (mColumnCount != oldColumnCount)
224}
225
226QQmlTableModel::ColumnRoleMetadata QQmlTableModel::fetchColumnRoleData(const QString &roleNameKey,
227 QQmlTableModelColumn *tableModelColumn, int columnIndex) const
228{
229 const QVariant firstRow = mRows.first();
230 ColumnRoleMetadata roleData;
231
232 QJSValue columnRoleGetter = tableModelColumn->getterAtRole(roleNameKey);
233 if (columnRoleGetter.isUndefined()) {
234 // This role is not defined, which is fine; just skip it.
235 return roleData;
236 }
237
238 if (columnRoleGetter.isString()) {
239 // The role is set as a string, so we assume the row is a simple object.
240 if (firstRow.userType() != QMetaType::QVariantMap) {
241 qmlWarning(this).quote() << "expected row for role "
242 << roleNameKey << " of TableModelColumn at index "
243 << columnIndex << " to be a simple object, but it's "
244 << firstRow.typeName() << " instead: " << firstRow;
245 return roleData;
246 }
247 const QVariantMap firstRowAsMap = firstRow.toMap();
248 const QString rolePropertyName = columnRoleGetter.toString();
249 const QVariant roleProperty = firstRowAsMap.value(rolePropertyName);
250
251 roleData.isStringRole = true;
252 roleData.name = rolePropertyName;
253 roleData.type = roleProperty.userType();
254 roleData.typeName = QString::fromLatin1(roleProperty.typeName());
255 } else if (columnRoleGetter.isCallable()) {
256 // The role is provided via a function, which means the row is complex and
257 // the user needs to provide the data for it.
258 const auto modelIndex = index(0, columnIndex);
259 const auto args = QJSValueList() << qmlEngine(this)->toScriptValue(modelIndex);
260 const QVariant cellData = columnRoleGetter.call(args).toVariant();
261
262 // We don't know the property name since it's provided through the function.
263 // roleData.name = ???
264 roleData.isStringRole = false;
265 roleData.type = cellData.userType();
266 roleData.typeName = QString::fromLatin1(cellData.typeName());
267 } else {
268 // Invalid role.
269 qmlWarning(this) << "TableModelColumn role for column at index "
270 << columnIndex << " must be either a string or a function; actual type is: "
271 << columnRoleGetter.toString();
272 }
273
274 return roleData;
275}
276
277void QQmlTableModel::fetchColumnMetadata()
278{
279 qCDebug(lcTableModel) << "gathering metadata for" << mColumnCount << "columns from first row:";
280
281 static const auto supportedRoleNames = QQmlTableModelColumn::supportedRoleNames();
282
283 // Since we support different data structures at the row level, we require that there
284 // is a TableModelColumn for each column.
285 // Collect and cache metadata for each column. This makes data lookup faster.
286 for (int columnIndex = 0; columnIndex < mColumns.size(); ++columnIndex) {
287 QQmlTableModelColumn *column = mColumns.at(columnIndex);
288 qCDebug(lcTableModel).nospace() << "- column " << columnIndex << ":";
289
290 ColumnMetadata metaData;
291 const auto builtInRoleKeys = supportedRoleNames.keys();
292 for (const int builtInRoleKey : builtInRoleKeys) {
293 const QString builtInRoleName = supportedRoleNames.value(builtInRoleKey);
294 ColumnRoleMetadata roleData = fetchColumnRoleData(builtInRoleName, column, columnIndex);
295 if (roleData.type == QMetaType::UnknownType) {
296 // This built-in role was not specified in this column.
297 continue;
298 }
299
300 qCDebug(lcTableModel).nospace() << " - added metadata for built-in role "
301 << builtInRoleName << " at column index " << columnIndex
302 << ": name=" << roleData.name << " typeName=" << roleData.typeName
303 << " type=" << roleData.type;
304
305 // This column now supports this specific built-in role.
306 metaData.roles.insert(builtInRoleName, roleData);
307 // Add it if it doesn't already exist.
308 mRoleNames[builtInRoleKey] = builtInRoleName.toLatin1();
309 }
310 mColumnMetadata.insert(columnIndex, metaData);
311 }
312}
313
333{
334 if (!validateNewRow("appendRow()", row, -1, AppendOperation))
335 return;
336
337 doInsert(mRowCount, row);
338}
339
353
376{
377 if (!validateRowIndex("getRow()", "rowIndex", rowIndex))
378 return QVariant();
379
380 return mRows.at(rowIndex);
381}
382
404void QQmlTableModel::insertRow(int rowIndex, const QVariant &row)
405{
406 if (!validateNewRow("insertRow()", row, rowIndex))
407 return;
408
409 doInsert(rowIndex, row);
410}
411
412void QQmlTableModel::doInsert(int rowIndex, const QVariant &row)
413{
414 beginInsertRows(QModelIndex(), rowIndex, rowIndex);
415
416 // Adding rowAsVariant.toList() will add each invidual variant in the list,
417 // which is definitely not what we want.
418 const QVariant rowAsVariant = row.value<QJSValue>().toVariant();
419 mRows.insert(rowIndex, rowAsVariant);
420 ++mRowCount;
421
422 qCDebug(lcTableModel).nospace() << "inserted the following row to the model at index "
423 << rowIndex << ":\n" << rowAsVariant.toMap();
424
425 // Gather metadata the first time a row is added.
426 if (mColumnMetadata.isEmpty())
427 fetchColumnMetadata();
428
431}
432
436
438{
439 componentCompleted = true;
440
441 mColumnCount = mColumns.size();
442 if (mColumnCount > 0)
444
445 doSetRows(mRows);
446}
447
463void QQmlTableModel::moveRow(int fromRowIndex, int toRowIndex, int rows)
464{
465 if (fromRowIndex == toRowIndex) {
466 qmlWarning(this) << "moveRow(): \"fromRowIndex\" cannot be equal to \"toRowIndex\"";
467 return;
468 }
469
470 if (rows <= 0) {
471 qmlWarning(this) << "moveRow(): \"rows\" is less than or equal to 0";
472 return;
473 }
474
475 if (!validateRowIndex("moveRow()", "fromRowIndex", fromRowIndex))
476 return;
477
478 if (!validateRowIndex("moveRow()", "toRowIndex", toRowIndex))
479 return;
480
481 if (fromRowIndex + rows > mRowCount) {
482 qmlWarning(this) << "moveRow(): \"fromRowIndex\" (" << fromRowIndex
483 << ") + \"rows\" (" << rows << ") = " << (fromRowIndex + rows)
484 << ", which is greater than rowCount() of " << mRowCount;
485 return;
486 }
487
488 if (toRowIndex + rows > mRowCount) {
489 qmlWarning(this) << "moveRow(): \"toRowIndex\" (" << toRowIndex
490 << ") + \"rows\" (" << rows << ") = " << (toRowIndex + rows)
491 << ", which is greater than rowCount() of " << mRowCount;
492 return;
493 }
494
495 qCDebug(lcTableModel).nospace() << "moving " << rows
496 << " row(s) from index " << fromRowIndex
497 << " to index " << toRowIndex;
498
499 // Based on the same call in QQmlListModel::moveRow().
500 beginMoveRows(QModelIndex(), fromRowIndex, fromRowIndex + rows - 1, QModelIndex(),
501 toRowIndex > fromRowIndex ? toRowIndex + rows : toRowIndex);
502
503 // Based on ListModel::moveRow().
504 if (fromRowIndex > toRowIndex) {
505 // Only move forwards - flip if moving backwards.
506 const int from = fromRowIndex;
507 const int to = toRowIndex;
508 fromRowIndex = to;
509 toRowIndex = to + rows;
510 rows = from - to;
511 }
512
513 QVector<QVariant> store;
514 store.reserve(rows);
515 for (int i = 0; i < (toRowIndex - fromRowIndex); ++i)
516 store.append(mRows.at(fromRowIndex + rows + i));
517 for (int i = 0; i < rows; ++i)
518 store.append(mRows.at(fromRowIndex + i));
519 for (int i = 0; i < store.size(); ++i)
520 mRows[fromRowIndex + i] = store[i];
521
522 qCDebug(lcTableModel).nospace() << "after moving, rows are:\n" << mRows;
523
524 endMoveRows();
525}
526
534void QQmlTableModel::removeRow(int rowIndex, int rows)
535{
536 if (!validateRowIndex("removeRow()", "rowIndex", rowIndex))
537 return;
538
539 if (rows <= 0) {
540 qmlWarning(this) << "removeRow(): \"rows\" is less than or equal to zero";
541 return;
542 }
543
544 if (rowIndex + rows - 1 >= mRowCount) {
545 qmlWarning(this) << "removeRow(): \"rows\" " << rows
546 << " exceeds available rowCount() of " << mRowCount
547 << " when removing from \"rowIndex\" " << rowIndex;
548 return;
549 }
550
551 beginRemoveRows(QModelIndex(), rowIndex, rowIndex + rows - 1);
552
553 auto firstIterator = mRows.begin() + rowIndex;
554 // The "last" argument to erase() is exclusive, so we go one past the last item.
555 auto lastIterator = firstIterator + rows;
556 mRows.erase(firstIterator, lastIterator);
557 mRowCount -= rows;
558
561
562 qCDebug(lcTableModel).nospace() << "removed " << rows
563 << " items from the model, starting at index " << rowIndex;
564}
565
588void QQmlTableModel::setRow(int rowIndex, const QVariant &row)
589{
590 if (!validateNewRow("setRow()", row, rowIndex))
591 return;
592
593 if (rowIndex != mRowCount) {
594 // Setting an existing row.
595 mRows[rowIndex] = row;
596
597 // For now we just assume the whole row changed, as it's simpler.
598 const QModelIndex topLeftModelIndex(createIndex(rowIndex, 0));
599 const QModelIndex bottomRightModelIndex(createIndex(rowIndex, mColumnCount - 1));
600 emit dataChanged(topLeftModelIndex, bottomRightModelIndex);
601 } else {
602 // Appending a row.
603 doInsert(rowIndex, row);
604 }
605}
606
607QQmlListProperty<QQmlTableModelColumn> QQmlTableModel::columns()
608{
609 return QQmlListProperty<QQmlTableModelColumn>(this, nullptr,
616}
617
618void QQmlTableModel::columns_append(QQmlListProperty<QQmlTableModelColumn> *property,
620{
621 QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
622 QQmlTableModelColumn *column = qobject_cast<QQmlTableModelColumn*>(value);
623 if (column)
624 model->mColumns.append(column);
625}
626
627qsizetype QQmlTableModel::columns_count(QQmlListProperty<QQmlTableModelColumn> *property)
628{
629 const QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
630 return model->mColumns.size();
631}
632
634{
635 const QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
636 return model->mColumns.at(index);
637}
638
639void QQmlTableModel::columns_clear(QQmlListProperty<QQmlTableModelColumn> *property)
640{
641 QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
642 return model->mColumns.clear();
643}
644
646{
647 QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
648 if (QQmlTableModelColumn *column = qobject_cast<QQmlTableModelColumn*>(value))
649 return model->mColumns.replace(index, column);
650}
651
652void QQmlTableModel::columns_removeLast(QQmlListProperty<QQmlTableModelColumn> *property)
653{
654 QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
655 model->mColumns.removeLast();
656}
657
691// Note: we don't document the parent argument, because you never need it, because
692// cells in a TableModel don't have parents. But it is there because this function is an override.
694{
695 return row >= 0 && row < rowCount() && column >= 0 && column < columnCount() && !parent.isValid()
697 : QModelIndex();
698}
699
708int QQmlTableModel::rowCount(const QModelIndex &parent) const
709{
710 if (parent.isValid())
711 return 0;
712
713 return mRowCount;
714}
715
727{
728 if (parent.isValid())
729 return 0;
730
731 return mColumnCount;
732}
733
743{
744 const int iRole = mRoleNames.key(role.toUtf8(), -1);
745 if (iRole >= 0)
746 return data(index, iRole);
747 return QVariant();
748}
749
751{
752 const int row = index.row();
753 if (row < 0 || row >= rowCount())
754 return QVariant();
755
756 const int column = index.column();
757 if (column < 0 || column >= columnCount())
758 return QVariant();
759
760 const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
761 const QString roleName = QString::fromUtf8(mRoleNames.value(role));
762 if (!columnMetadata.roles.contains(roleName)) {
763 qmlWarning(this) << "setData(): no role named " << roleName
764 << " at column index " << column << ". The available roles for that column are: "
765 << columnMetadata.roles.keys();
766 return QVariant();
767 }
768
769 const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
770 if (roleData.isStringRole) {
771 // We know the data structure, so we can get the data for the user.
772 const QVariantMap rowData = mRows.at(row).toMap();
773 const QString propertyName = columnMetadata.roles.value(roleName).name;
774 const QVariant value = rowData.value(propertyName);
775 return value;
776 }
777
778 // We don't know the data structure, so the user has to modify their data themselves.
779 // First, find the getter for this column and role.
780 QJSValue getter = mColumns.at(column)->getterAtRole(roleName);
781
782 // Then, call it and return what it returned.
783 const auto args = QJSValueList() << qmlEngine(this)->toScriptValue(index);
784 return getter.call(args).toVariant();
785}
786
796{
797 const int intRole = mRoleNames.key(role.toUtf8(), -1);
798 if (intRole >= 0)
799 return setData(index, value, intRole);
800 return false;
801}
802
804{
805 const int row = index.row();
806 if (row < 0 || row >= rowCount())
807 return false;
808
809 const int column = index.column();
810 if (column < 0 || column >= columnCount())
811 return false;
812
813 const QString roleName = QString::fromUtf8(mRoleNames.value(role));
814
815 qCDebug(lcTableModel).nospace() << "setData() called with index "
816 << index << ", value " << value << " and role " << roleName;
817
818 // Verify that the role exists for this column.
819 const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
820 if (!columnMetadata.roles.contains(roleName)) {
821 qmlWarning(this) << "setData(): no role named \"" << roleName
822 << "\" at column index " << column << ". The available roles for that column are: "
823 << columnMetadata.roles.keys();
824 return false;
825 }
826
827 // Verify that the type of the value is what we expect.
828 // If the value set is not of the expected type, we can try to convert it automatically.
829 const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
830 QVariant effectiveValue = value;
831 if (value.userType() != roleData.type) {
832 if (!value.canConvert(QMetaType(roleData.type))) {
833 qmlWarning(this).nospace() << "setData(): the value " << value
834 << " set at row " << row << " column " << column << " with role " << roleName
835 << " cannot be converted to " << roleData.typeName;
836 return false;
837 }
838
839 if (!effectiveValue.convert(QMetaType(roleData.type))) {
840 qmlWarning(this).nospace() << "setData(): failed converting value " << value
841 << " set at row " << row << " column " << column << " with role " << roleName
842 << " to " << roleData.typeName;
843 return false;
844 }
845 }
846
847 if (roleData.isStringRole) {
848 // We know the data structure, so we can set it for the user.
849 QVariantMap modifiedRow = mRows.at(row).toMap();
850 modifiedRow[roleData.name] = value;
851
852 mRows[row] = modifiedRow;
853 } else {
854 // We don't know the data structure, so the user has to modify their data themselves.
855 auto engine = qmlEngine(this);
856 auto args = QJSValueList()
857 // arg 0: modelIndex.
859 // arg 1: cellData.
861 // Do the actual setting.
862 QJSValue setter = mColumns.at(column)->setterAtRole(roleName);
863 setter.call(args);
864
865 /*
866 The chain of events so far:
867
868 - User did e.g.: model.edit = textInput.text
869 - setData() is called
870 - setData() calls the setter
871 (remember that we need to emit the dataChanged() signal,
872 which is why the user can't just set the data directly in the delegate)
873
874 Now the user's setter function has modified *their* copy of the
875 data, but *our* copy of the data is old. Imagine the getters and setters looked like this:
876
877 display: function(modelIndex) { return rows[modelIndex.row][1].amount }
878 setDisplay: function(modelIndex, cellData) { rows[modelIndex.row][1].amount = cellData }
879
880 We don't know the structure of the user's data, so we can't just do
881 what we do above for the isStringRole case:
882
883 modifiedRow[column][roleName] = value
884
885 This means that, besides getting the implicit row count when rows is initially set,
886 our copy of the data is unused when it comes to complex columns.
887
888 Another point to note is that we can't pass rowData in to the getter as a convenience,
889 because we would be passing in *our* copy of the row, which is not up-to-date.
890 Since the user already has access to the data, it's not a big deal for them to do:
891
892 display: function(modelIndex) { return rows[modelIndex.row][1].amount }
893
894 instead of:
895
896 display: function(modelIndex, rowData) { return rowData[1].amount }
897 */
898 }
899
900 QVector<int> rolesChanged;
901 rolesChanged.append(role);
902 emit dataChanged(index, index, rolesChanged);
903
904 return true;
905}
906
907QHash<int, QByteArray> QQmlTableModel::roleNames() const
908{
909 return mRoleNames;
910}
911
912QQmlTableModel::ColumnRoleMetadata::ColumnRoleMetadata()
913{
914}
915
916QQmlTableModel::ColumnRoleMetadata::ColumnRoleMetadata(
917 bool isStringRole, const QString &name, int type, const QString &typeName) :
918 isStringRole(isStringRole),
919 name(name),
920 type(type),
922{
923}
924
925bool QQmlTableModel::ColumnRoleMetadata::isValid() const
926{
927 return !name.isEmpty();
928}
929
930bool QQmlTableModel::validateRowType(const char *functionName, const QVariant &row) const
931{
932 if (!row.canConvert<QJSValue>()) {
933 qmlWarning(this) << functionName << ": expected \"row\" argument to be a QJSValue,"
934 << " but got " << row.typeName() << " instead:\n" << row;
935 return false;
936 }
937
938 const QJSValue rowAsJSValue = row.value<QJSValue>();
939 if (!rowAsJSValue.isObject() && !rowAsJSValue.isArray()) {
940 qmlWarning(this) << functionName << ": expected \"row\" argument "
941 << "to be an object or array, but got:\n" << rowAsJSValue.toString();
942 return false;
943 }
944
945 return true;
946}
947
948bool QQmlTableModel::validateNewRow(const char *functionName, const QVariant &row,
949 int rowIndex, NewRowOperationFlag operation) const
950{
951 if (mColumnMetadata.isEmpty()) {
952 // There is no column metadata, so we have nothing to validate the row against.
953 // Rows have to be added before we can gather metadata from them, so just this
954 // once we'll return true to allow the rows to be added.
955 return true;
956 }
957
958 // Don't require each row to be a QJSValue when setting all rows,
959 // as they won't be; they'll be QVariantMap.
960 if (operation != SetRowsOperation && !validateRowType(functionName, row))
961 return false;
962
963 if (operation == OtherOperation) {
964 // Inserting/setting.
965 if (rowIndex < 0) {
966 qmlWarning(this) << functionName << ": \"rowIndex\" cannot be negative";
967 return false;
968 }
969
970 if (rowIndex > mRowCount) {
971 qmlWarning(this) << functionName << ": \"rowIndex\" " << rowIndex
972 << " is greater than rowCount() of " << mRowCount;
973 return false;
974 }
975 }
976
977 const QVariant rowAsVariant = operation == SetRowsOperation
978 ? row : row.value<QJSValue>().toVariant();
979 if (rowAsVariant.userType() != QMetaType::QVariantMap) {
980 qmlWarning(this) << functionName << ": row manipulation functions "
981 << "do not support complex rows (row index: " << rowIndex << ")";
982 return false;
983 }
984
985 const QVariantMap rowAsMap = rowAsVariant.toMap();
986 const int columnCount = rowAsMap.size();
987 if (columnCount < mColumnCount) {
988 qmlWarning(this) << functionName << ": expected " << mColumnCount
989 << " columns, but only got " << columnCount;
990 return false;
991 }
992
993 // We can't validate complex structures, but we can make sure that
994 // each simple string-based role in each column is correct.
995 for (int columnIndex = 0; columnIndex < mColumns.size(); ++columnIndex) {
996 QQmlTableModelColumn *column = mColumns.at(columnIndex);
997 const QHash<QString, QJSValue> getters = column->getters();
998 const auto roleNames = getters.keys();
999 const ColumnMetadata columnMetadata = mColumnMetadata.at(columnIndex);
1000 for (const QString &roleName : roleNames) {
1001 const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
1002 if (!roleData.isStringRole)
1003 continue;
1004
1005 if (!rowAsMap.contains(roleData.name)) {
1006 qmlWarning(this).quote() << functionName << ": expected a property named "
1007 << roleData.name << " in row at index " << rowIndex << ", but couldn't find one";
1008 return false;
1009 }
1010
1011 const QVariant rolePropertyValue = rowAsMap.value(roleData.name);
1012
1013 if (rolePropertyValue.userType() != roleData.type) {
1014 if (!rolePropertyValue.canConvert(QMetaType(roleData.type))) {
1015 qmlWarning(this).quote() << functionName << ": expected the property named "
1016 << roleData.name << " to be of type " << roleData.typeName
1017 << ", but got " << QString::fromLatin1(rolePropertyValue.typeName())
1018 << " instead";
1019 return false;
1020 }
1021
1022 QVariant effectiveValue = rolePropertyValue;
1023 if (!effectiveValue.convert(QMetaType(roleData.type))) {
1024 qmlWarning(this).nospace() << functionName << ": failed converting value "
1025 << rolePropertyValue << " set at column " << columnIndex << " with role "
1026 << QString::fromLatin1(rolePropertyValue.typeName()) << " to "
1027 << roleData.typeName;
1028 return false;
1029 }
1030 }
1031 }
1032 }
1033
1034 return true;
1035}
1036
1037bool QQmlTableModel::validateRowIndex(const char *functionName, const char *argumentName, int rowIndex) const
1038{
1039 if (rowIndex < 0) {
1040 qmlWarning(this) << functionName << ": \"" << argumentName << "\" cannot be negative";
1041 return false;
1042 }
1043
1044 if (rowIndex >= mRowCount) {
1045 qmlWarning(this) << functionName << ": \"" << argumentName
1046 << "\" " << rowIndex << " is greater than or equal to rowCount() of " << mRowCount;
1047 return false;
1048 }
1049
1050 return true;
1051}
1052
1058
1060
1061#include "moc_qqmltablemodel_p.cpp"
void endResetModel()
Completes a model reset operation.
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationRow)
void endRemoveRows()
Ends a row removal operation.
void endMoveRows()
Ends a row move operation.
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This signal is emitted whenever the data in an existing item changes.
void endInsertRows()
Ends a row insertion operation.
void beginResetModel()
Begins a model reset operation.
QModelIndex createIndex(int row, int column, const void *data=nullptr) const
Creates a model index for the given row and column with the internal pointer ptr.
void beginRemoveRows(const QModelIndex &parent, int first, int last)
Begins a row removal operation.
void beginInsertRows(const QModelIndex &parent, int first, int last)
Begins a row insertion operation.
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
T value(const Key &key) const noexcept
Definition qhash.h:1054
Key key(const T &value) const noexcept
Definition qhash.h:1034
QJSValue newArray(uint length=0)
Creates a JavaScript object of class Array with the given length.
QJSValue toScriptValue(const T &value)
Creates a QJSValue with the given value.
Definition qjsengine.h:58
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
iterator erase(const_iterator begin, const_iterator end)
Definition qlist.h:889
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
QList< T > toList() const noexcept
Definition qlist.h:723
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
iterator begin()
Definition qlist.h:625
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
size_type size() const
Definition qmap.h:267
\inmodule QtCore
Definition qmetatype.h:341
\inmodule QtCore
\inmodule QtCore
Definition qobject.h:103
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QJSValue setterAtRole(const QString &roleName)
static const QHash< int, QString > supportedRoleNames()
const QHash< QString, QJSValue > getters() const
QJSValue getterAtRole(const QString &roleName)
Q_INVOKABLE void moveRow(int fromRowIndex, int toRowIndex, int rows=1)
\qmlmethod TableModel::moveRow(int fromRowIndex, int toRowIndex, int rows)
static void columns_clear(QQmlListProperty< QQmlTableModelColumn > *property)
static void columns_append(QQmlListProperty< QQmlTableModelColumn > *property, QQmlTableModelColumn *value)
static qsizetype columns_count(QQmlListProperty< QQmlTableModelColumn > *property)
~QQmlTableModel() override
Q_INVOKABLE void appendRow(const QVariant &row)
\qmlmethod TableModel::appendRow(object row)
static void columns_replace(QQmlListProperty< QQmlTableModelColumn > *property, qsizetype index, QQmlTableModelColumn *value)
void columnCountChanged()
Q_INVOKABLE void clear()
\qmlmethod TableModel::clear()
Q_INVOKABLE QVariant getRow(int rowIndex)
\qmlmethod object TableModel::getRow(int rowIndex)
void setRows(const QVariant &rows)
Q_INVOKABLE void setRow(int rowIndex, const QVariant &row)
\qmlmethod TableModel::setRow(int rowIndex, object row)
Q_INVOKABLE QVariant data(const QModelIndex &index, const QString &role) const
\qmlmethod variant TableModel::data(QModelIndex index, string role)
Qt::ItemFlags flags(const QModelIndex &index) const override
\reimp
static void columns_removeLast(QQmlListProperty< QQmlTableModelColumn > *property)
Q_INVOKABLE bool setData(const QModelIndex &index, const QString &role, const QVariant &value)
\qmlmethod bool TableModel::setData(QModelIndex index, string role, variant value)
static QQmlTableModelColumn * columns_at(QQmlListProperty< QQmlTableModelColumn > *property, qsizetype index)
Q_INVOKABLE void removeRow(int rowIndex, int rows=1)
\qmlmethod TableModel::removeRow(int rowIndex, int rows = 1)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void classBegin() override
Invoked after class creation, but before any properties have been set.
void rowsChanged()
Q_INVOKABLE void insertRow(int rowIndex, const QVariant &row)
\qmlmethod TableModel::insertRow(int rowIndex, object row)
QQmlListProperty< QQmlTableModelColumn > columns
void rowCountChanged()
QHash< int, QByteArray > roleNames() const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
\qmlmethod QModelIndex TableModel::index(int row, int column)
virtual void clear()
Clears the model and releases any acquired resource.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
Definition qvariant.h:65
T value() const &
Definition qvariant.h:516
QMap< QString, QVariant > toMap() const
Returns the variant as a QVariantMap if the variant has type() \l QMetaType::QVariantMap.
int userType() const
Definition qvariant.h:339
const char * typeName() const
Returns the name of the type stored in the variant.
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
Combined button and popup list for selecting options.
@ ItemIsEditable
@ ItemIsSelectable
@ ItemIsEnabled
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QList< QJSValue > QJSValueList
Definition qjsvalue.h:22
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
const char * typeName
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLuint name
GLenum GLenum GLsizei void GLsizei void * column
GLenum GLenum GLsizei void * row
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, JSToQVariantConversionBehavior conversionBehavior, V4ObjectSet *visitedObjects)
const char property[13]
Definition qwizard.cpp:101
QSqlQueryModel * model
[16]
std::array< QModelRoleData, 3 > roleData
[13]
QJSValueList args
QJSEngine engine
[0]