8#include <QtCore/qdir.h>
9#include <QtCore/qmimedata.h>
10#include <QtCore/qtimer.h>
11#include <QtQml/private/qqmlincubator_p.h>
12#include <QtQml/qqmlinfo.h>
13#include <QtQmlModels/private/qqmlchangeset_p.h>
14#include <QtQmlModels/private/qqmldelegatecomponent_p.h>
15#include <QtQmlModels/private/qqmldelegatemodel_p.h>
16#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
17#include <QtQuick/qquickitemgrabresult.h>
19#include <QtQuick/private/qquickflickable_p_p.h>
20#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
21#include <QtQuick/private/qquicktaphandler_p.h>
23#include <QtCore/qtyperevision.h>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
387
388
389
390
391
392
393
394
395
396
399
400
401
402
403
404
405
406
407
408
409
410
413
414
415
416
417
418
421
422
423
424
425
426
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
477
478
479
480
481
482
483
484
485
486
487
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
543
544
545
546
547
548
549
550
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
627
628
629
630
631
632
635
636
637
638
639
640
643
644
645
646
647
648
651
652
653
654
655
656
659
660
661
662
663
664
665
666
667
668
669
672
673
674
675
676
677
678
679
680
681
682
685
686
687
688
689
690
691
692
693
694
695
696
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
720
721
722
723
724
725
726
727
728
729
730
731
732
735
736
737
738
739
740
741
742
743
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
793
794
795
796
797
798
801
802
803
804
805
806
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1044
1045
1046
1047
1048
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1075
1076
1077
1078
1079
1080
1081
1082
1083
1086
1087
1088
1089
1090
1091
1092
1093
1096
1097
1098
1099
1100
1101
1102
1103
1104
1107
1108
1109
1110
1111
1112
1113
1114
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1148
1149
1150
1151
1152
1153
1154
1155
1156
1159
1160
1161
1162
1163
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1184
1185
1186
1187
1188
1191
1192
1193
1194
1195
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1217
1218
1219
1220
1223
1224
1225
1226
1227
1228
1229
1230
1233
1234
1235
1236
1237
1238
1239
1240
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1315
1316
1317
1318
1319
1320
1321
1322
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1387
1388
1389
1390
1391
1392
1393
1394
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1459
1460
1461
1462
1463
1464
1465
1468
1469
1470
1471
1472
1473
1474
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1513
1514
1515
1516
1517
1518
1519
1520
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1539
1540
1541
1542
1543
1544
1545
1548
1549
1550
1551
1552
1553
1554
1557
1558
1559
1560
1561
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1679QQuickSelectable::~QQuickSelectable() { }
1683#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
1684#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
1697 return (order == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder;
1702#define TV_REBUILDSTATE(STATE)
1703 case QQuickTableViewPrivate::RebuildState::STATE:
1704 dbg << QStringLiteral(#STATE); break;
1724#define TV_REBUILDOPTION(OPTION)
1725 if (options & QQuickTableViewPrivate::RebuildOption::OPTION)
1726 dbg << QStringLiteral(#OPTION)
1728 if (options == QQuickTableViewPrivate::RebuildOption::None) {
1729 dbg << QStringLiteral(
"None");
1745QQuickTableViewPrivate::EdgeRange::EdgeRange()
1746 : startIndex(kEdgeIndexNotSet)
1747 , endIndex(kEdgeIndexNotSet)
1751bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge,
int index)
1753 if (startIndex == kEdgeIndexNotSet)
1756 if (endIndex == kEdgeIndexAtEnd) {
1760 return index <= startIndex;
1762 case Qt::BottomEdge:
1763 return index >= startIndex;
1767 const int s = std::min(startIndex, endIndex);
1768 const int e = std::max(startIndex, endIndex);
1769 return index >= s && index <= e;
1772QQuickTableViewPrivate::QQuickTableViewPrivate()
1773 : QQuickFlickablePrivate()
1777QQuickTableViewPrivate::~QQuickTableViewPrivate()
1780 QQuickItem *cellItem = editItem->parentItem();
1782 editModel->dispose(editItem);
1783 tableModel->release(cellItem, QQmlInstanceModel::NotReusable);
1789 for (
auto *fxTableItem : loadedItems) {
1790 if (
auto item = fxTableItem->item) {
1791 if (fxTableItem->ownItem)
1793 else if (tableModel)
1794 tableModel->dispose(item);
1803QString QQuickTableViewPrivate::tableLayoutToString()
const
1805 if (loadedItems.isEmpty())
1806 return QLatin1String(
"table is empty!");
1807 return QString(QLatin1String(
"table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
1808 .arg(leftColumn()).arg(topRow())
1809 .arg(rightColumn()).arg(bottomRow())
1810 .arg(loadedItems.size())
1811 .arg(loadedTableOuterRect.x())
1812 .arg(loadedTableOuterRect.y())
1813 .arg(loadedTableOuterRect.width())
1814 .arg(loadedTableOuterRect.height());
1817void QQuickTableViewPrivate::dumpTable()
const
1819 auto listCopy = loadedItems.values();
1820 std::stable_sort(listCopy.begin(), listCopy.end(),
1821 [](
const FxTableItem *lhs,
const FxTableItem *rhs)
1822 {
return lhs->index < rhs->index; });
1824 qWarning() << QStringLiteral(
"******* TABLE DUMP *******");
1825 for (
int i = 0; i < listCopy.size(); ++i)
1826 qWarning() <<
static_cast<FxTableItem *>(listCopy.at(i))->cell;
1827 qWarning() << tableLayoutToString();
1829 const QString filename = QStringLiteral(
"QQuickTableView_dumptable_capture.png");
1830 const QString path = QDir::current().absoluteFilePath(filename);
1831 if (q_func()->window() && q_func()->window()->grabWindow().save(path))
1832 qWarning() <<
"Window capture saved to:" << path;
1835void QQuickTableViewPrivate::setRequiredProperty(
const char *property,
1836 const QVariant &value,
int serializedModelIndex, QObject *object,
bool init)
1838 Q_Q(QQuickTableView);
1840 QQmlTableInstanceModel *tableInstanceModel = qobject_cast<QQmlTableInstanceModel *>(model);
1841 if (!tableInstanceModel) {
1851 const QString propertyName = QString::fromUtf8(property);
1854 bool wasRequired =
false;
1855 if (object == editItem) {
1858 wasRequired = editModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1860 wasRequired = tableInstanceModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1863 QStringList propertyList = object->property(kRequiredProperties).toStringList();
1864 object->setProperty(kRequiredProperties, propertyList << propertyName);
1868 const QStringList propertyList = object->property(kRequiredProperties).toStringList();
1869 if (propertyList.contains(propertyName)) {
1870 const auto metaObject = object->metaObject();
1871 const int propertyIndex = metaObject->indexOfProperty(property);
1872 const auto metaProperty = metaObject->property(propertyIndex);
1873 metaProperty.write(object, value);
1883 const QModelIndex modelIndex = q->modelIndex(cellAtModelIndex(serializedModelIndex));
1884 if (modelIndex == editIndex) {
1885 const QStringList propertyList = editItem->property(kRequiredProperties).toStringList();
1886 if (propertyList.contains(propertyName)) {
1887 const auto metaObject = editItem->metaObject();
1888 const int propertyIndex = metaObject->indexOfProperty(property);
1889 const auto metaProperty = metaObject->property(propertyIndex);
1890 metaProperty.write(editItem, value);
1898QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget()
const
1900 return const_cast<QQuickTableView *>(q_func())->contentItem();
1903bool QQuickTableViewPrivate::hasSelection()
const
1905 return selectionModel && selectionModel->hasSelection();
1908bool QQuickTableViewPrivate::startSelection(
const QPointF &pos, Qt::KeyboardModifiers modifiers)
1910 Q_Q(QQuickTableView);
1911 if (!selectionModel) {
1912 if (warnNoSelectionModel)
1913 qmlWarning(q_func()) <<
"Cannot start selection: no SelectionModel assigned!";
1914 warnNoSelectionModel =
false;
1918 if (selectionBehavior == QQuickTableView::SelectionDisabled) {
1919 qmlWarning(q) <<
"Cannot start selection: TableView.selectionBehavior == TableView.SelectionDisabled";
1924 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
1930 if (selectionMode == QQuickTableView::SingleSelection
1931 || selectionMode == QQuickTableView::ContiguousSelection
1932 || modifiers == Qt::NoModifier)
1934 else if (selectionModel)
1935 existingSelection = selectionModel->selection();
1941 selectionFlag = QItemSelectionModel::Select;
1942 if (modifiers & Qt::ControlModifier) {
1943 QPoint startCell = clampedCellAtPos(pos);
1944 if (!cellIsValid(startCell))
1946 const QModelIndex startIndex = q->index(startCell.y(), startCell.x());
1947 if (selectionModel->isSelected(startIndex))
1948 selectionFlag = QItemSelectionModel::Deselect;
1951 selectionStartCell = QPoint(-1, -1);
1952 selectionEndCell = QPoint(-1, -1);
1953 closeEditorAndCommit();
1957void QQuickTableViewPrivate::setSelectionStartPos(
const QPointF &pos)
1959 Q_Q(QQuickTableView);
1960 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1961 if (loadedItems.isEmpty())
1963 if (!selectionModel) {
1964 if (warnNoSelectionModel)
1965 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1966 warnNoSelectionModel =
false;
1969 const QAbstractItemModel *qaim = selectionModel->model();
1973 if (selectionMode == QQuickTableView::SingleSelection
1974 && cellIsValid(selectionStartCell)) {
1978 const QRect prevSelection = selection();
1980 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1983 if (pos.x() == -1) {
1985 clampedCell = q->cellAtIndex(selectionModel->currentIndex());
1987 clampedCell = clampedCellAtPos(pos);
1988 if (cellIsValid(clampedCell))
1989 setCurrentIndex(clampedCell);
1992 if (!cellIsValid(clampedCell))
1995 switch (selectionBehavior) {
1996 case QQuickTableView::SelectCells:
1997 selectionStartCell = clampedCell;
1999 case QQuickTableView::SelectRows:
2000 selectionStartCell = QPoint(0, clampedCell.y());
2002 case QQuickTableView::SelectColumns:
2003 selectionStartCell = QPoint(clampedCell.x(), 0);
2005 case QQuickTableView::SelectionDisabled:
2009 if (!cellIsValid(selectionEndCell))
2013 updateSelection(prevSelection, selection());
2016void QQuickTableViewPrivate::setSelectionEndPos(
const QPointF &pos)
2018 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
2019 if (loadedItems.isEmpty())
2021 if (!selectionModel) {
2022 if (warnNoSelectionModel)
2023 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
2024 warnNoSelectionModel =
false;
2027 const QAbstractItemModel *qaim = selectionModel->model();
2031 const QRect prevSelection = selection();
2034 if (selectionMode == QQuickTableView::SingleSelection) {
2035 clampedCell = selectionStartCell;
2037 clampedCell = clampedCellAtPos(pos);
2038 if (!cellIsValid(clampedCell))
2042 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2044 setCurrentIndex(clampedCell);
2046 switch (selectionBehavior) {
2047 case QQuickTableView::SelectCells:
2048 selectionEndCell = clampedCell;
2050 case QQuickTableView::SelectRows:
2051 selectionEndCell = QPoint(tableSize.width() - 1, clampedCell.y());
2053 case QQuickTableView::SelectColumns:
2054 selectionEndCell = QPoint(clampedCell.x(), tableSize.height() - 1);
2056 case QQuickTableView::SelectionDisabled:
2060 if (!cellIsValid(selectionStartCell))
2064 updateSelection(prevSelection, selection());
2067QPoint QQuickTableViewPrivate::clampedCellAtPos(
const QPointF &pos)
const
2069 Q_Q(
const QQuickTableView);
2072 QPoint cell = q->cellAtPosition(pos,
true);
2073 if (cellIsValid(cell))
2076 if (loadedTableOuterRect.width() == 0 || loadedTableOuterRect.height() == 0)
2077 return QPoint(-1, -1);
2081 qBound(loadedTableOuterRect.x(), pos.x(), loadedTableOuterRect.right() - 1),
2082 qBound(loadedTableOuterRect.y(), pos.y(), loadedTableOuterRect.bottom() - 1));
2083 QPointF clampedPosInView = q->mapFromItem(selectionPointerHandlerTarget(), clampedPos);
2084 clampedPosInView.rx() = qBound(0., clampedPosInView.x(), viewportRect.width());
2085 clampedPosInView.ry() = qBound(0., clampedPosInView.y(), viewportRect.height());
2086 clampedPos = q->mapToItem(selectionPointerHandlerTarget(), clampedPosInView);
2088 return q->cellAtPosition(clampedPos,
true);
2091void QQuickTableViewPrivate::updateSelection(
const QRect &oldSelection,
const QRect &newSelection)
2093 if (oldSelection == newSelection)
2096 const QAbstractItemModel *qaim = selectionModel->model();
2097 const QRect oldRect = oldSelection.normalized();
2098 const QRect newRect = newSelection.normalized();
2100 const auto &columnMapping = syncView ? syncView->d_func()->horizontalLogicalIndices
2101 : horizontalLogicalIndices;
2102 const auto &rowMapping = syncView ? syncView->d_func()->verticalLogicalIndices
2103 : verticalLogicalIndices;
2104 const bool hasMapping = !columnMapping.empty() || !rowMapping.empty();
2106 QItemSelection select;
2107 QItemSelection deselect;
2109 const auto mergeInto =
2110 [
this, qaim, hasMapping](QItemSelection &selection,
2111 const QModelIndex &startIndex,
const QModelIndex &endIndex)
2114 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2115 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()),
2116 logicalColumnIndex(modelIndex.column()));
2117 selection.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2120 selection.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
2126 const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
2127 const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
2128 mergeInto(select, startIndex, endIndex);
2132 if (oldRect.x() < newRect.x()) {
2133 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2134 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
2135 mergeInto(deselect, startIndex, endIndex);
2136 }
else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
2137 const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
2138 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2139 mergeInto(deselect, startIndex, endIndex);
2142 if (oldRect.y() < newRect.y()) {
2143 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2144 const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
2145 mergeInto(deselect, startIndex, endIndex);
2146 }
else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
2147 const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
2148 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2149 mergeInto(deselect, startIndex, endIndex);
2152 if (selectionFlag == QItemSelectionModel::Select) {
2154 deselect.merge(existingSelection, QItemSelectionModel::Deselect);
2155 selectionModel->select(deselect, QItemSelectionModel::Deselect);
2156 selectionModel->select(select, QItemSelectionModel::Select);
2157 }
else if (selectionFlag == QItemSelectionModel::Deselect){
2158 QItemSelection oldSelection = existingSelection;
2159 oldSelection.merge(select, QItemSelectionModel::Deselect);
2160 selectionModel->select(oldSelection, QItemSelectionModel::Select);
2161 selectionModel->select(select, QItemSelectionModel::Deselect);
2167void QQuickTableViewPrivate::cancelSelectionTracking()
2170 selectionStartCell = QPoint(-1, -1);
2171 selectionEndCell = QPoint(-1, -1);
2172 existingSelection.clear();
2173 selectionFlag = QItemSelectionModel::NoUpdate;
2174 if (selectableCallbackFunction)
2175 selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
2178void QQuickTableViewPrivate::clearSelection()
2180 if (!selectionModel)
2182 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2183 selectionModel->clearSelection();
2186void QQuickTableViewPrivate::normalizeSelection()
2192 if (selectionEndCell.x() < selectionStartCell.x())
2193 std::swap(selectionStartCell.rx(), selectionEndCell.rx());
2194 if (selectionEndCell.y() < selectionStartCell.y())
2195 std::swap(selectionStartCell.ry(), selectionEndCell.ry());
2198QRectF QQuickTableViewPrivate::selectionRectangle()
const
2200 Q_Q(
const QQuickTableView);
2202 if (loadedColumns.isEmpty() || loadedRows.isEmpty())
2205 QPoint topLeftCell = selectionStartCell;
2206 QPoint bottomRightCell = selectionEndCell;
2207 if (bottomRightCell.x() < topLeftCell.x())
2208 std::swap(topLeftCell.rx(), bottomRightCell.rx());
2209 if (selectionEndCell.y() < topLeftCell.y())
2210 std::swap(topLeftCell.ry(), bottomRightCell.ry());
2212 const QPoint leftCell(topLeftCell.x(), topRow());
2213 const QPoint topCell(leftColumn(), topLeftCell.y());
2214 const QPoint rightCell(bottomRightCell.x(), topRow());
2215 const QPoint bottomCell(leftColumn(), bottomRightCell.y());
2228 if (loadedItems.contains(modelIndexAtCell(leftCell)))
2229 left = loadedTableItem(leftCell)->geometry().left();
2230 else if (leftCell.x() > rightColumn())
2231 left = q->contentWidth();
2233 if (loadedItems.contains(modelIndexAtCell(topCell)))
2234 top = loadedTableItem(topCell)->geometry().top();
2235 else if (topCell.y() > bottomRow())
2236 top = q->contentHeight();
2238 if (loadedItems.contains(modelIndexAtCell(rightCell)))
2239 right = loadedTableItem(rightCell)->geometry().right();
2240 else if (rightCell.x() > rightColumn())
2241 right = q->contentWidth();
2243 if (loadedItems.contains(modelIndexAtCell(bottomCell)))
2244 bottom = loadedTableItem(bottomCell)->geometry().bottom();
2245 else if (bottomCell.y() > bottomRow())
2246 bottom = q->contentHeight();
2248 return QRectF(left, top, right - left, bottom - top);
2251QRect QQuickTableViewPrivate::selection()
const
2253 const qreal w = selectionEndCell.x() - selectionStartCell.x();
2254 const qreal h = selectionEndCell.y() - selectionStartCell.y();
2255 return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
2258QSizeF QQuickTableViewPrivate::scrollTowardsPoint(
const QPointF &pos,
const QSizeF &step)
2260 Q_Q(QQuickTableView);
2262 if (loadedItems.isEmpty())
2272 const bool outsideLeft = pos.x() < viewportRect.x();
2273 const bool outsideRight = pos.x() >= viewportRect.right() - 1;
2274 const bool outsideTop = pos.y() < viewportRect.y();
2275 const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
2278 const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
2279 const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
2280 if (remainingDist > 0 || !firstColumnLoaded) {
2281 qreal stepX = step.width();
2282 if (firstColumnLoaded)
2283 stepX = qMin(stepX, remainingDist);
2284 q->setContentX(q->contentX() - stepX);
2285 dist.setWidth(pos.x() - viewportRect.left() - 1);
2287 }
else if (outsideRight) {
2288 const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
2289 const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
2290 if (remainingDist > 0 || !lastColumnLoaded) {
2291 qreal stepX = step.width();
2292 if (lastColumnLoaded)
2293 stepX = qMin(stepX, remainingDist);
2294 q->setContentX(q->contentX() + stepX);
2295 dist.setWidth(pos.x() - viewportRect.right() - 1);
2300 const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
2301 const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
2302 if (remainingDist > 0 || !firstRowLoaded) {
2303 qreal stepY = step.height();
2305 stepY = qMin(stepY, remainingDist);
2306 q->setContentY(q->contentY() - stepY);
2307 dist.setHeight(pos.y() - viewportRect.top() - 1);
2309 }
else if (outsideBottom) {
2310 const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
2311 const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
2312 if (remainingDist > 0 || !lastRowLoaded) {
2313 qreal stepY = step.height();
2315 stepY = qMin(stepY, remainingDist);
2316 q->setContentY(q->contentY() + stepY);
2317 dist.setHeight(pos.y() - viewportRect.bottom() - 1);
2324void QQuickTableViewPrivate::setCallback(std::function<
void (CallBackFlag)> func)
2326 selectableCallbackFunction = func;
2329QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(
const QObject *object)
const
2331 QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object,
false);
2332 return static_cast<QQuickTableViewAttached *>(attachedObject);
2335QQuickTableViewAttached::QQuickTableViewAttached(QObject *parent)
2338 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
2345 for (
int i = 0; i < 3; ++i) {
2346 parentItem = parentItem->parentItem();
2349 if (
auto tableView = qobject_cast<QQuickTableView *>(parentItem)) {
2356int QQuickTableViewPrivate::modelIndexAtCell(
const QPoint &cell)
const
2362 int availableColumns = tableSize.width();
2363 return (cell.y() * availableColumns) + cell.x();
2365 int availableRows = tableSize.height();
2366 return (cell.x() * availableRows) + cell.y();
2370QPoint QQuickTableViewPrivate::cellAtModelIndex(
int modelIndex)
const
2376 int availableColumns = tableSize.width();
2377 int row =
int(modelIndex / availableColumns);
2378 int column = modelIndex % availableColumns;
2379 return QPoint(column, row);
2381 int availableRows = tableSize.height();
2382 int column =
int(modelIndex / availableRows);
2383 int row = modelIndex % availableRows;
2384 return QPoint(column, row);
2388int QQuickTableViewPrivate::modelIndexToCellIndex(
const QModelIndex &modelIndex,
bool visualIndex)
const
2392 const QPoint cell = q_func()->cellAtIndex(modelIndex);
2393 if (!cellIsValid(cell))
2395 return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
2398int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
const
2400 return int(log2(
float(edge)));
2403void QQuickTableViewPrivate::clearEdgeSizeCache()
2405 cachedColumnWidth.startIndex = kEdgeIndexNotSet;
2406 cachedRowHeight.startIndex = kEdgeIndexNotSet;
2408 for (Qt::Edge edge : allTableEdges)
2409 cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
2412int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
const
2416 int startIndex = -1;
2418 case Qt::LeftEdge: startIndex = leftColumn() - 1;
break;
2419 case Qt::RightEdge: startIndex = rightColumn() + 1;
break;
2420 case Qt::TopEdge: startIndex = topRow() - 1;
break;
2421 case Qt::BottomEdge: startIndex = bottomRow() + 1;
break;
2424 return nextVisibleEdgeIndex(edge, startIndex);
2427int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge,
int startIndex)
const
2433 auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
2434 if (cachedResult.containsIndex(edge, startIndex))
2435 return cachedResult.endIndex;
2439 int foundIndex = kEdgeIndexNotSet;
2440 int testIndex = startIndex;
2443 case Qt::LeftEdge: {
2445 if (testIndex < 0) {
2446 foundIndex = kEdgeIndexAtEnd;
2450 if (!isColumnHidden(testIndex)) {
2451 foundIndex = testIndex;
2458 case Qt::RightEdge: {
2460 if (testIndex > tableSize.width() - 1) {
2461 foundIndex = kEdgeIndexAtEnd;
2465 if (!isColumnHidden(testIndex)) {
2466 foundIndex = testIndex;
2475 if (testIndex < 0) {
2476 foundIndex = kEdgeIndexAtEnd;
2480 if (!isRowHidden(testIndex)) {
2481 foundIndex = testIndex;
2488 case Qt::BottomEdge: {
2490 if (testIndex > tableSize.height() - 1) {
2491 foundIndex = kEdgeIndexAtEnd;
2495 if (!isRowHidden(testIndex)) {
2496 foundIndex = testIndex;
2505 cachedResult.startIndex = startIndex;
2506 cachedResult.endIndex = foundIndex;
2510void QQuickTableViewPrivate::updateContentWidth()
2521 Q_Q(QQuickTableView);
2523 if (syncHorizontally) {
2524 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2525 q->QQuickFlickable::setContentWidth(syncView->contentWidth());
2529 if (explicitContentWidth.isValid()) {
2535 if (loadedItems.isEmpty()) {
2536 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2537 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2538 q->QQuickFlickable::setContentWidth(kDefaultColumnWidth);
2540 q->QQuickFlickable::setContentWidth(0);
2544 const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2545 const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
2546 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2547 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2548 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2549 const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
2551 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2552 q->QQuickFlickable::setContentWidth(estimatedWidth);
2555void QQuickTableViewPrivate::updateContentHeight()
2557 Q_Q(QQuickTableView);
2559 if (syncVertically) {
2560 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2561 q->QQuickFlickable::setContentHeight(syncView->contentHeight());
2565 if (explicitContentHeight.isValid()) {
2571 if (loadedItems.isEmpty()) {
2572 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2573 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2574 q->QQuickFlickable::setContentHeight(kDefaultRowHeight);
2576 q->QQuickFlickable::setContentHeight(0);
2580 const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2581 const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
2582 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2583 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2584 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2585 const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
2587 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2588 q->QQuickFlickable::setContentHeight(estimatedHeight);
2591void QQuickTableViewPrivate::updateExtents()
2604 Q_Q(QQuickTableView);
2606 bool tableMovedHorizontally =
false;
2607 bool tableMovedVertically =
false;
2609 const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
2610 const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2611 const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
2612 const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2614 QPointF prevOrigin = origin;
2615 QSizeF prevEndExtent = endExtent;
2617 if (syncHorizontally) {
2618 const auto syncView_d = syncView->d_func();
2619 origin.rx() = syncView_d->origin.x();
2620 endExtent.rwidth() = syncView_d->endExtent.width();
2621 }
else if (nextLeftColumn == kEdgeIndexAtEnd) {
2624 if (loadedTableOuterRect.left() > viewportRect.left()) {
2629 if (loadedTableOuterRect.left() > origin.x()) {
2630 const qreal diff = loadedTableOuterRect.left() - origin.x();
2631 loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
2632 loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
2633 tableMovedHorizontally =
true;
2636 origin.rx() = loadedTableOuterRect.left();
2637 }
else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
2641 const int columnsRemaining = nextLeftColumn + 1;
2642 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2643 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2644 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2645 origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
2646 }
else if (nextRightColumn == kEdgeIndexAtEnd) {
2649 if (loadedTableOuterRect.right() < viewportRect.right()) {
2654 const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
2655 if (loadedTableOuterRect.right() < w) {
2656 const qreal diff = loadedTableOuterRect.right() - w;
2657 loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
2658 loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
2659 tableMovedHorizontally =
true;
2662 endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
2663 }
else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
2667 const int columnsRemaining = tableSize.width() - nextRightColumn;
2668 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2669 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2670 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2671 const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
2672 endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
2675 if (syncVertically) {
2676 const auto syncView_d = syncView->d_func();
2677 origin.ry() = syncView_d->origin.y();
2678 endExtent.rheight() = syncView_d->endExtent.height();
2679 }
else if (nextTopRow == kEdgeIndexAtEnd) {
2682 if (loadedTableOuterRect.top() > viewportRect.top()) {
2687 if (loadedTableOuterRect.top() > origin.y()) {
2688 const qreal diff = loadedTableOuterRect.top() - origin.y();
2689 loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
2690 loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
2691 tableMovedVertically =
true;
2694 origin.ry() = loadedTableOuterRect.top();
2695 }
else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
2699 const int rowsRemaining = nextTopRow + 1;
2700 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2701 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2702 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2703 origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
2704 }
else if (nextBottomRow == kEdgeIndexAtEnd) {
2707 if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
2712 const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
2713 if (loadedTableOuterRect.bottom() < h) {
2714 const qreal diff = loadedTableOuterRect.bottom() - h;
2715 loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
2716 loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
2717 tableMovedVertically =
true;
2720 endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
2721 }
else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
2725 const int rowsRemaining = tableSize.height() - nextBottomRow;
2726 const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
2727 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2728 const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
2729 const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
2730 endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
2733 if (tableMovedHorizontally || tableMovedVertically) {
2734 qCDebug(lcTableViewDelegateLifecycle) <<
"move table to" << loadedTableOuterRect;
2738 relayoutTableItems();
2741 for (
auto syncChild : std::as_const(syncChildren)) {
2742 auto syncChild_d = syncChild->d_func();
2743 syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
2744 if (tableMovedHorizontally)
2745 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
2746 if (tableMovedVertically)
2747 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
2751 if (prevOrigin != origin || prevEndExtent != endExtent) {
2752 if (prevOrigin != origin)
2753 qCDebug(lcTableViewDelegateLifecycle) <<
"move origin to:" << origin;
2754 if (prevEndExtent != endExtent)
2755 qCDebug(lcTableViewDelegateLifecycle) <<
"move endExtent to:" << endExtent;
2759 hData.markExtentsDirty();
2760 vData.markExtentsDirty();
2761 updateBeginningEnd();
2762 if (!q->isMoving()) {
2766 q->returnToBounds();
2771void QQuickTableViewPrivate::updateAverageColumnWidth()
2773 if (explicitContentWidth.isValid()) {
2774 const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
2775 averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
2777 const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
2778 averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
2782void QQuickTableViewPrivate::updateAverageRowHeight()
2784 if (explicitContentHeight.isValid()) {
2785 const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
2786 averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
2788 const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
2789 averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
2793void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
2795 const QPoint topLeft = QPoint(leftColumn(), topRow());
2796 const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
2797 QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
2798 QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
2799 loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
2800 loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
2803QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
2809 if (loadedItems.isEmpty()) {
2811 return RebuildOption::None;
2814 RebuildOptions rebuildOptions = RebuildOption::None;
2816 if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
2820 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2821 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2826 for (
int column = leftColumn(); column <= rightColumn(); ++column) {
2827 const bool wasVisibleFromBefore = loadedColumns.contains(column);
2828 const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
2829 if (wasVisibleFromBefore == isVisibleNow)
2834 qCDebug(lcTableViewDelegateLifecycle) <<
"Column" << column <<
"changed visibility to" << isVisibleNow;
2835 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2836 if (column == leftColumn()) {
2839 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2845 if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
2849 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2850 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2855 for (
int row = topRow(); row <= bottomRow(); ++row) {
2856 const bool wasVisibleFromBefore = loadedRows.contains(row);
2857 const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
2858 if (wasVisibleFromBefore == isVisibleNow)
2863 qCDebug(lcTableViewDelegateLifecycle) <<
"Row" << row <<
"changed visibility to" << isVisibleNow;
2864 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2865 if (row == topRow())
2866 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2871 return rebuildOptions;
2874void QQuickTableViewPrivate::forceLayout(
bool immediate)
2876 clearEdgeSizeCache();
2877 RebuildOptions rebuildOptions = RebuildOption::None;
2879 const QSize actualTableSize = calculateTableSize();
2880 if (tableSize != actualTableSize) {
2884 rebuildOptions |= RebuildOption::ViewportOnly;
2892 rebuildOptions |= RebuildOption::LayoutOnly
2893 | RebuildOption::CalculateNewContentWidth
2894 | RebuildOption::CalculateNewContentHeight
2895 | checkForVisibilityChanges();
2897 scheduleRebuildTable(rebuildOptions);
2900 auto rootView = rootSyncView();
2901 const bool updated = rootView->d_func()->updateTableRecursive();
2903 qWarning() <<
"TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
2909void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
2911 if (loadRequest.edge() == Qt::Edge(0)) {
2913 loadedColumns.insert(loadRequest.column());
2914 loadedRows.insert(loadRequest.row());
2918 switch (loadRequest.edge()) {
2921 loadedColumns.insert(loadRequest.column());
2924 case Qt::BottomEdge:
2925 loadedRows.insert(loadRequest.row());
2930FxTableItem *QQuickTableViewPrivate::loadedTableItem(
const QPoint &cell)
const
2932 const int modelIndex = modelIndexAtCell(cell);
2934 return loadedItems.value(modelIndex);
2937FxTableItem *QQuickTableViewPrivate::createFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2939 Q_Q(QQuickTableView);
2941 bool ownItem =
false;
2942 const int modelRow = isTransposed ? logicalColumnIndex(cell.y()) : logicalRowIndex(cell.y());
2943 const int modelColumn = isTransposed ? logicalRowIndex(cell.x()) : logicalColumnIndex(cell.x());
2944 const int modelIndex = modelIndexAtCell(QPoint(modelColumn, modelRow));
2946 QObject *object = model->object(modelIndex, incubationMode);
2949 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2955 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2956 object =
new QQuickItem();
2960 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2964 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2965 model->release(object);
2966 item =
new QQuickItem();
2969 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2970 if (anchors && anchors->activeDirections())
2971 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2972 <<
". Use implicitWidth and implicitHeight instead.";
2979 item->setImplicitWidth(kDefaultColumnWidth);
2980 item->setImplicitHeight(kDefaultRowHeight);
2981 item->setParentItem(q->contentItem());
2985 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
2986 fxTableItem->setVisible(
false);
2987 fxTableItem->cell = cell;
2988 fxTableItem->index = modelIndex;
2992FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2997 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
2999 incubationMode = QQmlIncubator::Asynchronous;
3004 QScopedValueRollback guard(blockItemCreatedCallback,
true);
3005 auto item = createFxTableItem(cell, incubationMode);
3006 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
3010void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
3013 auto const tmpList = loadedItems;
3014 loadedItems.clear();
3015 for (FxTableItem *item : tmpList)
3016 releaseItem(item, reusableFlag);
3019void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
3021 Q_Q(QQuickTableView);
3024 auto item = fxTableItem->item;
3026 if (fxTableItem->ownItem) {
3030 auto releaseFlag = model->release(item, reusableFlag);
3031 if (releaseFlag == QQmlInstanceModel::Pooled) {
3032 fxTableItem->setVisible(
false);
3036 if (QQuickWindow *window = item->window()) {
3037 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
3039 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
3041 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
3042 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
3052void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
3054 const int modelIndex = modelIndexAtCell(cell);
3056 releaseItem(loadedItems.take(modelIndex), reusableFlag);
3058 tableModel->commitReleasedItems();
3061bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
3063 switch (tableEdge) {
3065 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
3067 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
3069 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
3070 case Qt::BottomEdge:
3071 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
3077bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
3083 switch (tableEdge) {
3085 if (loadedColumns.count() <= 1)
3087 if (positionXAnimation.isRunning()) {
3088 const qreal to = positionXAnimation.to().toFloat();
3089 if (to < viewportRect.x())
3092 return loadedTableInnerRect.left() <= fillRect.left();
3094 if (loadedColumns.count() <= 1)
3096 if (positionXAnimation.isRunning()) {
3097 const qreal to = positionXAnimation.to().toFloat();
3098 if (to > viewportRect.x())
3101 return loadedTableInnerRect.right() >= fillRect.right();
3103 if (loadedRows.count() <= 1)
3105 if (positionYAnimation.isRunning()) {
3106 const qreal to = positionYAnimation.to().toFloat();
3107 if (to < viewportRect.y())
3110 return loadedTableInnerRect.top() <= fillRect.top();
3111 case Qt::BottomEdge:
3112 if (loadedRows.count() <= 1)
3114 if (positionYAnimation.isRunning()) {
3115 const qreal to = positionYAnimation.to().toFloat();
3116 if (to > viewportRect.y())
3119 return loadedTableInnerRect.bottom() >= fillRect.bottom();
3125Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
3127 for (Qt::Edge edge : allTableEdges) {
3128 if (!canLoadTableEdge(edge, rect))
3130 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3131 if (nextIndex == kEdgeIndexAtEnd)
3139Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3141 for (Qt::Edge edge : allTableEdges) {
3142 if (canUnloadTableEdge(edge, rect))
3148qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3152 auto const cellItem = loadedTableItem(cell)->item;
3153 return cellItem->implicitWidth();
3156qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3160 auto const cellItem = loadedTableItem(cell)->item;
3161 return cellItem->implicitHeight();
3164qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3167 qreal columnWidth = 0;
3168 for (
const int row : loadedRows)
3169 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3174qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3177 qreal rowHeight = 0;
3178 for (
const int column : loadedColumns)
3179 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3183QSize QQuickTableViewPrivate::calculateTableSize()
3187 size = QSize(tableModel->columns(), tableModel->rows());
3189 size = QSize(1, model->count());
3191 return isTransposed ? size.transposed() : size;
3194qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3201 const qreal explicitColumnWidth = getColumnWidth(column);
3202 if (explicitColumnWidth >= 0)
3203 return explicitColumnWidth;
3205 if (syncHorizontally) {
3206 if (syncView->d_func()->loadedColumns.contains(column))
3207 return syncView->d_func()->getColumnLayoutWidth(column);
3215 qreal columnWidth = sizeHintForColumn(column);
3217 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3218 if (!layoutWarningIssued) {
3219 layoutWarningIssued =
true;
3220 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3222 columnWidth = kDefaultColumnWidth;
3228qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3232 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3235qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3239 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3242qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3246 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3249qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3253 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3256qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3263 const qreal explicitRowHeight = getRowHeight(row);
3264 if (explicitRowHeight >= 0)
3265 return explicitRowHeight;
3267 if (syncVertically) {
3268 if (syncView->d_func()->loadedRows.contains(row))
3269 return syncView->d_func()->getRowLayoutHeight(row);
3277 qreal rowHeight = sizeHintForRow(row);
3279 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3280 if (!layoutWarningIssued) {
3281 layoutWarningIssued =
true;
3282 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3284 rowHeight = kDefaultRowHeight;
3290qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3296 Q_Q(
const QQuickTableView);
3298 const int noExplicitColumnWidth = -1;
3300 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3301 return cachedColumnWidth.size;
3303 if (syncHorizontally)
3304 return syncView->d_func()->getColumnWidth(column);
3306 if (columnWidthProvider.isUndefined()) {
3310 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3311 if (explicitColumnWidth >= 0)
3312 return explicitColumnWidth;
3313 return noExplicitColumnWidth;
3316 qreal columnWidth = noExplicitColumnWidth;
3318 if (columnWidthProvider.isCallable()) {
3319 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3320 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3321 if (qIsNaN(columnWidth) || columnWidth < 0)
3322 columnWidth = noExplicitColumnWidth;
3324 if (!layoutWarningIssued) {
3325 layoutWarningIssued =
true;
3326 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3328 columnWidth = noExplicitColumnWidth;
3331 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3332 cachedColumnWidth.size = columnWidth;
3336qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3342 Q_Q(
const QQuickTableView);
3344 const int noExplicitRowHeight = -1;
3346 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3347 return cachedRowHeight.size;
3350 return syncView->d_func()->getRowHeight(row);
3352 if (rowHeightProvider.isUndefined()) {
3356 qreal explicitRowHeight = q->explicitRowHeight(row);
3357 if (explicitRowHeight >= 0)
3358 return explicitRowHeight;
3359 return noExplicitRowHeight;
3362 qreal rowHeight = noExplicitRowHeight;
3364 if (rowHeightProvider.isCallable()) {
3365 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3366 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3367 if (qIsNaN(rowHeight) || rowHeight < 0)
3368 rowHeight = noExplicitRowHeight;
3370 if (!layoutWarningIssued) {
3371 layoutWarningIssued =
true;
3372 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3374 rowHeight = noExplicitRowHeight;
3377 cachedRowHeight.startIndex = logicalRowIndex(row);
3378 cachedRowHeight.size = rowHeight;
3382qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3384 Q_Q(QQuickTableView);
3387 const int columnX = getEffectiveColumnX(column);
3389 if (subRect.isValid()) {
3390 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3393 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3396 if (alignment & Qt::AlignLeft) {
3397 contentX = columnX + subRect.x() + offset;
3398 }
else if (alignment & Qt::AlignRight) {
3399 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3400 }
else if (alignment & Qt::AlignHCenter) {
3401 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3402 contentX = columnX + subRect.x() - centerDistance + offset;
3405 const int columnWidth = getEffectiveColumnWidth(column);
3406 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3407 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3409 if (alignment & Qt::AlignLeft) {
3410 contentX = columnX + offset;
3411 }
else if (alignment & Qt::AlignRight) {
3412 contentX = columnX + columnWidth - viewportRect.width() + offset;
3413 }
else if (alignment & Qt::AlignHCenter) {
3414 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3415 contentX = columnX - centerDistance + offset;
3420 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3425qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3427 Q_Q(QQuickTableView);
3430 const int rowY = getEffectiveRowY(row);
3432 if (subRect.isValid()) {
3433 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3436 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3439 if (alignment & Qt::AlignTop) {
3440 contentY = rowY + subRect.y() + offset;
3441 }
else if (alignment & Qt::AlignBottom) {
3442 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3443 }
else if (alignment & Qt::AlignVCenter) {
3444 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3445 contentY = rowY + subRect.y() - centerDistance + offset;
3448 const int rowHeight = getEffectiveRowHeight(row);
3449 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3450 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3452 if (alignment & Qt::AlignTop) {
3453 contentY = rowY + offset;
3454 }
else if (alignment & Qt::AlignBottom) {
3455 contentY = rowY + rowHeight - viewportRect.height() + offset;
3456 }
else if (alignment & Qt::AlignVCenter) {
3457 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3458 contentY = rowY - centerDistance + offset;
3463 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3468bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3472 return qFuzzyIsNull(getColumnWidth(column));
3475bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3479 return qFuzzyIsNull(getRowHeight(row));
3482void QQuickTableViewPrivate::relayoutTableItems()
3484 qCDebug(lcTableViewDelegateLifecycle);
3486 if (viewportRect.isEmpty()) {
3488 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3492 qreal nextColumnX = loadedTableOuterRect.x();
3493 qreal nextRowY = loadedTableOuterRect.y();
3495 for (
const int column : loadedColumns) {
3497 const qreal width = getColumnLayoutWidth(column);
3499 for (
const int row : loadedRows) {
3500 auto item = loadedTableItem(QPoint(column, row));
3501 QRectF geometry = item->geometry();
3502 geometry.moveLeft(nextColumnX);
3503 geometry.setWidth(width);
3504 item->setGeometry(geometry);
3508 nextColumnX += width + cellSpacing.width();
3511 for (
const int row : loadedRows) {
3513 const qreal height = getRowLayoutHeight(row);
3515 for (
const int column : loadedColumns) {
3516 auto item = loadedTableItem(QPoint(column, row));
3517 QRectF geometry = item->geometry();
3518 geometry.moveTop(nextRowY);
3519 geometry.setHeight(height);
3520 item->setGeometry(geometry);
3524 nextRowY += height + cellSpacing.height();
3527 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3528 for (
const int column : loadedColumns) {
3529 for (
const int row : loadedRows) {
3530 QPoint cell = QPoint(column, row);
3531 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3537void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3539 int columnThatNeedsLayout;
3540 int neighbourColumn;
3544 if (tableEdge == Qt::LeftEdge) {
3545 columnThatNeedsLayout = leftColumn();
3546 neighbourColumn = loadedColumns.values().at(1);
3547 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3548 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3549 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3551 columnThatNeedsLayout = rightColumn();
3552 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3553 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3554 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3555 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3558 for (
const int row : loadedRows) {
3559 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3560 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3561 const qreal rowY = neighbourItem->geometry().y();
3562 const qreal rowHeight = neighbourItem->geometry().height();
3564 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3565 fxTableItem->setVisible(
true);
3567 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3571void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3573 int rowThatNeedsLayout;
3576 if (tableEdge == Qt::TopEdge) {
3577 rowThatNeedsLayout = topRow();
3578 neighbourRow = loadedRows.values().at(1);
3580 rowThatNeedsLayout = bottomRow();
3581 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3586 for (
const int column : loadedColumns) {
3587 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3588 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3589 const qreal columnX = neighbourItem->geometry().x();
3590 const qreal columnWidth = neighbourItem->geometry().width();
3591 fxTableItem->item->setX(columnX);
3592 fxTableItem->item->setWidth(columnWidth);
3597 if (tableEdge == Qt::TopEdge) {
3598 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3599 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3600 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3602 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3603 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3604 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3607 for (
const int column : loadedColumns) {
3608 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3609 fxTableItem->item->setY(rowY);
3610 fxTableItem->item->setHeight(rowHeight);
3611 fxTableItem->setVisible(
true);
3613 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3617void QQuickTableViewPrivate::layoutTopLeftItem()
3619 const QPoint cell(loadRequest.column(), loadRequest.row());
3620 auto topLeftItem = loadedTableItem(cell);
3621 auto item = topLeftItem->item;
3623 item->setPosition(loadRequest.startPosition());
3624 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3625 topLeftItem->setVisible(
true);
3626 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3629void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3631 if (loadRequest.edge() == Qt::Edge(0)) {
3633 layoutTopLeftItem();
3637 switch (loadRequest.edge()) {
3640 layoutVerticalEdge(loadRequest.edge());
3643 case Qt::BottomEdge:
3644 layoutHorizontalEdge(loadRequest.edge());
3649void QQuickTableViewPrivate::processLoadRequest()
3651 Q_Q(QQuickTableView);
3654 while (loadRequest.hasCurrentCell()) {
3655 QPoint cell = loadRequest.currentCell();
3656 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3664 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3665 loadRequest.moveToNextCell();
3668 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3670 syncLoadedTableFromLoadRequest();
3671 layoutTableEdgeFromLoadRequest();
3672 syncLoadedTableRectFromLoadedTable();
3674 if (rebuildState == RebuildState::Done) {
3678 drainReusePoolAfterLoadRequest();
3680 switch (loadRequest.edge()) {
3682 emit q->leftColumnChanged();
3685 emit q->rightColumnChanged();
3688 emit q->topRowChanged();
3690 case Qt::BottomEdge:
3691 emit q->bottomRowChanged();
3695 if (editIndex.isValid())
3698 emit q->layoutChanged();
3701 loadRequest.markAsDone();
3703 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3704 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3705 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3708void QQuickTableViewPrivate::processRebuildTable()
3710 Q_Q(QQuickTableView);
3712 if (rebuildState == RebuildState::Begin) {
3713 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3714 tableSizeBeforeRebuild = tableSize;
3715 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins(-1,-1,-1,-1)
3716 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3719 moveToNextRebuildState();
3721 if (rebuildState == RebuildState::LoadInitalTable) {
3723 if (!moveToNextRebuildState())
3727 if (rebuildState == RebuildState::VerifyTable) {
3728 if (loadedItems.isEmpty()) {
3729 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3730 updateContentWidth();
3731 updateContentHeight();
3732 rebuildState = RebuildState::Done;
3733 }
else if (!moveToNextRebuildState()) {
3738 if (rebuildState == RebuildState::LayoutTable) {
3739 layoutAfterLoadingInitialTable();
3740 loadAndUnloadVisibleEdges();
3741 if (!moveToNextRebuildState())
3745 if (rebuildState == RebuildState::CancelOvershoot) {
3746 cancelOvershootAfterLayout();
3747 loadAndUnloadVisibleEdges();
3748 if (!moveToNextRebuildState())
3752 if (rebuildState == RebuildState::UpdateContentSize) {
3753 updateContentSize();
3754 if (!moveToNextRebuildState())
3758 const bool preload = (rebuildOptions & RebuildOption::All
3759 && reusableFlag == QQmlTableInstanceModel::Reusable);
3761 if (rebuildState == RebuildState::PreloadColumns) {
3762 if (preload && !atTableEnd(Qt::RightEdge))
3763 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3764 if (!moveToNextRebuildState())
3768 if (rebuildState == RebuildState::PreloadRows) {
3769 if (preload && !atTableEnd(Qt::BottomEdge))
3770 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3771 if (!moveToNextRebuildState())
3775 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3776 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3778 if (!moveToNextRebuildState())
3782 if (rebuildState == RebuildState::Done) {
3783 if (tableSizeBeforeRebuild.width() != tableSize.width())
3784 emit q->columnsChanged();
3785 if (tableSizeBeforeRebuild.height() != tableSize.height())
3786 emit q->rowsChanged();
3787 if (edgesBeforeRebuild.left() != q->leftColumn())
3788 emit q->leftColumnChanged();
3789 if (edgesBeforeRebuild.right() != q->rightColumn())
3790 emit q->rightColumnChanged();
3791 if (edgesBeforeRebuild.top() != q->topRow())
3792 emit q->topRowChanged();
3793 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3794 emit q->bottomRowChanged();
3796 if (editIndex.isValid())
3798 updateCurrentRowAndColumn();
3802 tableModel->commitReleasedItems();
3804 emit q->layoutChanged();
3806 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3807 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3808 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3809 qCDebug(lcTableViewDelegateLifecycle());
3815bool QQuickTableViewPrivate::moveToNextRebuildState()
3817 if (loadRequest.isActive()) {
3823 if (rebuildState == RebuildState::Begin
3824 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3825 rebuildState = RebuildState::LayoutTable;
3827 rebuildState = RebuildState(
int(rebuildState) + 1);
3829 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3833void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3835 if (tableSize.isEmpty()) {
3837 topLeftCell.rx() = kEdgeIndexAtEnd;
3838 topLeftCell.ry() = kEdgeIndexAtEnd;
3842 if (syncHorizontally || syncVertically) {
3843 const auto syncView_d = syncView->d_func();
3845 if (syncView_d->loadedItems.isEmpty()) {
3846 topLeftCell.rx() = 0;
3847 topLeftCell.ry() = 0;
3852 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3853 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3854 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3856 if (syncHorizontally) {
3857 topLeftCell.rx() = syncViewTopLeftCell.x();
3858 topLeftPos.rx() = syncViewTopLeftPos.x();
3860 if (topLeftCell.x() >= tableSize.width()) {
3862 topLeftCell.rx() = kEdgeIndexAtEnd;
3863 topLeftPos.rx() = kEdgeIndexAtEnd;
3867 if (syncVertically) {
3868 topLeftCell.ry() = syncViewTopLeftCell.y();
3869 topLeftPos.ry() = syncViewTopLeftPos.y();
3871 if (topLeftCell.y() >= tableSize.height()) {
3873 topLeftCell.ry() = kEdgeIndexAtEnd;
3874 topLeftPos.ry() = kEdgeIndexAtEnd;
3878 if (syncHorizontally && syncVertically) {
3889 if (!syncHorizontally) {
3890 if (rebuildOptions & RebuildOption::All) {
3892 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3893 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3897 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3899 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3900 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3901 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3902 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3903 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3904 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3907 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3911 topLeftPos.rx() = loadedTableOuterRect.x();
3915 if (!syncVertically) {
3916 if (rebuildOptions & RebuildOption::All) {
3918 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3919 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3923 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3925 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3926 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3927 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3928 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3929 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3930 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3932 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3933 topLeftPos.ry() = loadedTableOuterRect.y();
3938void QQuickTableViewPrivate::loadInitialTable()
3940 tableSize = calculateTableSize();
3942 if (positionXAnimation.isRunning()) {
3943 positionXAnimation.stop();
3944 setLocalViewportX(positionXAnimation.to().toReal());
3948 if (positionYAnimation.isRunning()) {
3949 positionYAnimation.stop();
3950 setLocalViewportY(positionYAnimation.to().toReal());
3956 calculateTopLeft(topLeft, topLeftPos);
3957 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3958 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3960 if (!loadedItems.isEmpty()) {
3961 if (rebuildOptions & RebuildOption::All)
3962 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3963 else if (rebuildOptions & RebuildOption::ViewportOnly)
3964 releaseLoadedItems(reusableFlag);
3967 if (rebuildOptions & RebuildOption::All) {
3968 origin = QPointF(0, 0);
3969 endExtent = QSizeF(0, 0);
3970 hData.markExtentsDirty();
3971 vData.markExtentsDirty();
3972 updateBeginningEnd();
3975 loadedColumns.clear();
3977 loadedTableOuterRect = QRect();
3978 loadedTableInnerRect = QRect();
3979 clearEdgeSizeCache();
3981 if (syncHorizontally)
3982 setLocalViewportX(syncView->contentX());
3985 setLocalViewportY(syncView->contentY());
3987 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
3988 setLocalViewportX(topLeftPos.x());
3990 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
3991 setLocalViewportY(topLeftPos.y());
3996 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
4000 if (model->count() == 0) {
4001 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
4005 if (tableModel && !tableModel->delegate()) {
4006 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
4010 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
4011 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
4015 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
4016 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
4020 if (viewportRect.isEmpty()) {
4021 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
4027 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
4028 processLoadRequest();
4029 loadAndUnloadVisibleEdges();
4032void QQuickTableViewPrivate::updateContentSize()
4034 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
4035 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
4036 updateAverageColumnWidth();
4037 updateContentWidth();
4040 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
4041 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
4042 updateAverageRowHeight();
4043 updateContentHeight();
4049void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
4051 clearEdgeSizeCache();
4052 relayoutTableItems();
4053 syncLoadedTableRectFromLoadedTable();
4055 updateContentSize();
4057 adjustViewportXAccordingToAlignment();
4058 adjustViewportYAccordingToAlignment();
4061void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
4064 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4067 if (positionViewAtColumnAfterRebuild != leftColumn())
4070 const qreal newContentX = getAlignmentContentX(
4071 positionViewAtColumnAfterRebuild,
4072 positionViewAtColumnAlignment,
4073 positionViewAtColumnOffset,
4074 positionViewAtColumnSubRect);
4076 setLocalViewportX(newContentX);
4080void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
4083 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4086 if (positionViewAtRowAfterRebuild != topRow())
4089 const qreal newContentY = getAlignmentContentY(
4090 positionViewAtRowAfterRebuild,
4091 positionViewAtRowAlignment,
4092 positionViewAtRowOffset,
4093 positionViewAtRowSubRect);
4095 setLocalViewportY(newContentY);
4099void QQuickTableViewPrivate::cancelOvershootAfterLayout()
4101 Q_Q(QQuickTableView);
4107 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
4108 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
4109 const bool cancelVertically = positionVertically && !syncVertically;
4110 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
4112 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
4113 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
4114 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
4118 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
4119 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
4120 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
4125void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
4127 Q_Q(QQuickTableView);
4128 qCDebug(lcTableViewDelegateLifecycle) << edge;
4131 case Qt::LeftEdge: {
4132 const int column = leftColumn();
4133 for (
int row : loadedRows)
4134 unloadItem(QPoint(column, row));
4135 loadedColumns.remove(column);
4136 syncLoadedTableRectFromLoadedTable();
4137 if (rebuildState == RebuildState::Done)
4138 emit q->leftColumnChanged();
4140 case Qt::RightEdge: {
4141 const int column = rightColumn();
4142 for (
int row : loadedRows)
4143 unloadItem(QPoint(column, row));
4144 loadedColumns.remove(column);
4145 syncLoadedTableRectFromLoadedTable();
4146 if (rebuildState == RebuildState::Done)
4147 emit q->rightColumnChanged();
4150 const int row = topRow();
4151 for (
int col : loadedColumns)
4152 unloadItem(QPoint(col, row));
4153 loadedRows.remove(row);
4154 syncLoadedTableRectFromLoadedTable();
4155 if (rebuildState == RebuildState::Done)
4156 emit q->topRowChanged();
4158 case Qt::BottomEdge: {
4159 const int row = bottomRow();
4160 for (
int col : loadedColumns)
4161 unloadItem(QPoint(col, row));
4162 loadedRows.remove(row);
4163 syncLoadedTableRectFromLoadedTable();
4164 if (rebuildState == RebuildState::Done)
4165 emit q->bottomRowChanged();
4169 if (rebuildState == RebuildState::Done)
4170 emit q->layoutChanged();
4172 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4175void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4177 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4178 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4180 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4181 ? loadedRows.values() : loadedColumns.values();
4182 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4183 processLoadRequest();
4186void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4198 if (loadRequest.isActive()) {
4204 if (loadedItems.isEmpty()) {
4214 tableModified =
false;
4216 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4217 tableModified =
true;
4221 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4222 tableModified =
true;
4223 loadEdge(edge, incubationMode);
4224 if (loadRequest.isActive())
4227 }
while (tableModified);
4231void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4233 Q_Q(QQuickTableView);
4235 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4238 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4268 const int w = loadedColumns.count();
4269 const int h = loadedRows.count();
4270 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4271 const int maxTime = minTime * 2;
4272 tableModel->drainReusableItemsPool(maxTime);
4275void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4276 if (!q_func()->isComponentComplete()) {
4281 scheduledRebuildOptions |= options;
4285QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4287 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4288 while (QQuickTableView *view = root->d_func()->syncView)
4293void QQuickTableViewPrivate::updatePolish()
4300 rootSyncView()->d_func()->updateTableRecursive();
4303bool QQuickTableViewPrivate::updateTableRecursive()
4313 const bool updateComplete = updateTable();
4314 if (!updateComplete)
4317 const auto children = syncChildren;
4318 for (
auto syncChild : children) {
4319 auto syncChild_d = syncChild->d_func();
4321 RebuildOption::PositionViewAtRow |
4322 RebuildOption::PositionViewAtColumn |
4323 RebuildOption::CalculateNewTopLeftRow |
4324 RebuildOption::CalculateNewTopLeftColumn;
4325 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4327 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4328 if (!descendantUpdateComplete)
4332 rebuildOptions = RebuildOption::None;
4337bool QQuickTableViewPrivate::updateTable()
4346 QScopedValueRollback polishGuard(polishing,
true);
4348 if (loadRequest.isActive()) {
4356 if (rebuildState != RebuildState::Done) {
4357 processRebuildTable();
4358 return rebuildState == RebuildState::Done;
4361 syncWithPendingChanges();
4363 if (rebuildState == RebuildState::Begin) {
4364 processRebuildTable();
4365 return rebuildState == RebuildState::Done;
4368 if (loadedItems.isEmpty())
4369 return !loadRequest.isActive();
4371 loadAndUnloadVisibleEdges();
4374 return !loadRequest.isActive();
4377void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4379 if (inUpdateContentSize) {
4391 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4394void QQuickTableViewPrivate::requestSort(
int logicalColumn,
bool clearable)
4396 if (!sortingEnabled || logicalColumn < 0)
4399 auto *sourceModel = qaim(modelImpl());
4401 qmlWarning(q_func()) <<
"Sorting is only supported for QAbstractItemModel based models.";
4405 if (logicalColumn >= sourceModel->columnCount())
4408 Qt::SortOrder defaultSortOrder = Qt::AscendingOrder;
4409 const QVariant value = sourceModel->headerData(logicalColumn, Qt::Horizontal, Qt::InitialSortOrderRole);
4410 if (value.canConvert<
int>())
4411 defaultSortOrder =
static_cast<Qt::SortOrder>(value.toInt());
4414
4415
4416
4417
4418 if (sortColumn == logicalColumn) {
4419 if (clearable && sortOrder != defaultSortOrder) {
4420 sortByColumn(-1, Qt::AscendingOrder);
4424 sortByColumn(logicalColumn, flipOrder(sortOrder));
4428 sortByColumn(logicalColumn, defaultSortOrder);
4431void QQuickTableViewPrivate::sortByColumn(
int column, Qt::SortOrder order)
4433 Q_Q(QQuickTableView);
4440 if (!componentFinalized) {
4441 updateSortState(column, order);
4445 auto *sourceModel = qaim(modelImpl());
4447 qmlWarning(q) <<
"Sorting is only supported for QAbstractItemModel based models.";
4451 updateSortState(column, order);
4455 sourceModel->sort(column, order);
4458void QQuickTableViewPrivate::updateSortState(
int column, Qt::SortOrder order)
4460 Q_Q(QQuickTableView);
4462 const bool columnChanged = sortColumn != column;
4463 const bool orderChanged = sortOrder != order;
4465 if (!columnChanged && !orderChanged)
4468 sortColumn = column;
4472 emit q->sortColumnChanged();
4475 emit q->sortOrderChanged();
4478QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4480 const auto data = QQmlData::get(q_func());
4481 if (!data || !data->propertyCache)
4482 return QTypeRevision::zero();
4484 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4485 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4488 return qmlTypeView.metaObjectRevision();
4491void QQuickTableViewPrivate::createWrapperModel()
4493 Q_Q(QQuickTableView);
4499 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4500 tableModel->useImportVersion(resolveImportVersion());
4504bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4506 if (!selectionModel)
4509 QAbstractItemModel *model = selectionModel->model();
4513 return selectionModel->isSelected(q_func()->modelIndex(cell));
4516bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4518 if (!selectionModel)
4521 QAbstractItemModel *model = selectionModel->model();
4525 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4528void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4530 if (!inSelectionModelUpdate) {
4534 cancelSelectionTracking();
4537 const auto &selectedIndexes = selected.indexes();
4538 const auto &deselectedIndexes = deselected.indexes();
4539 for (
int i = 0; i < selectedIndexes.size(); ++i)
4540 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4541 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4542 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4545void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4547 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4548 qmlWarning(q_func())
4549 <<
"Cannot select cells: TableView.selectionModel.model is not "
4550 <<
"compatible with the model displayed in the view";
4554 const int cellIndex = modelIndexToCellIndex(modelIndex);
4555 if (!loadedItems.contains(cellIndex))
4557 const QPoint cell = cellAtModelIndex(cellIndex);
4558 QQuickItem *item = loadedTableItem(cell)->item;
4559 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4562QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4577 return qaim(modelImpl());
4580QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4583 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4584 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4585 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4588void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4590 updateCurrentRowAndColumn();
4592 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4593 const int cellIndex = *it;
4594 const QPoint cell = cellAtModelIndex(cellIndex);
4595 const bool selected = selectedInSelectionModel(cell);
4596 const bool current = currentInSelectionModel(cell);
4597 QQuickItem *item = loadedTableItem(cell)->item;
4598 const bool editing = editIndex == q_func()->modelIndex(cell);
4599 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4600 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4601 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4605void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4607 if (current.isValid() && current.model() != selectionSourceModel()) {
4608 qmlWarning(q_func())
4609 <<
"Cannot change current index: TableView.selectionModel.model is not "
4610 <<
"compatible with the model displayed in the view";
4614 updateCurrentRowAndColumn();
4615 setCurrentOnDelegateItem(previous,
false);
4616 setCurrentOnDelegateItem(current,
true);
4619void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4621 Q_Q(QQuickTableView);
4623 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4624 const QPoint currentCell = q->cellAtIndex(currentIndex);
4625 if (currentCell.x() != currentColumn) {
4626 currentColumn = currentCell.x();
4627 emit q->currentColumnChanged();
4630 if (currentCell.y() != currentRow) {
4631 currentRow = currentCell.y();
4632 emit q->currentRowChanged();
4636void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4638 const int cellIndex = modelIndexToCellIndex(index);
4639 if (!loadedItems.contains(cellIndex))
4642 const QPoint cell = cellAtModelIndex(cellIndex);
4643 QQuickItem *item = loadedTableItem(cell)->item;
4644 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4647void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4649 if (blockItemCreatedCallback)
4652 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4653 << cellAtModelIndex(modelIndex);
4659 processLoadRequest();
4660 loadAndUnloadVisibleEdges();
4664void QQuickTableViewPrivate::updateItemProperties(
int flatIndex, QObject *object,
bool init)
4666 Q_Q(QQuickTableView);
4667 const QPoint cell = cellAtModelIndex(flatIndex);
4668 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4669 const bool current = currentInSelectionModel(visualCell);
4670 const bool selected = selectedInSelectionModel(visualCell);
4672 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), flatIndex, object, init);
4673 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), flatIndex, object, init);
4674 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), flatIndex, object, init);
4675 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), flatIndex, object, init);
4676 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), flatIndex, object, init);
4679void QQuickTableViewPrivate::initItemCallback(
int flatIndex, QObject *object)
4681 Q_Q(QQuickTableView);
4682 Q_UNUSED(flatIndex);
4684 auto item = qobject_cast<QQuickItem*>(object);
4688 item->setParentItem(q->contentItem());
4691 if (
auto attached = getAttachedObject(item))
4692 attached->setView(q);
4695void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4697 Q_UNUSED(modelIndex);
4699 if (
auto attached = getAttachedObject(object))
4700 emit attached->pooled();
4703void QQuickTableViewPrivate::itemReusedCallback(
int flatIndex, QObject *object)
4705 Q_UNUSED(flatIndex);
4707 if (
auto item = qobject_cast<QQuickItem*>(object))
4708 QQuickItemPrivate::get(item)->setCulled(
false);
4710 if (
auto attached = getAttachedObject(object))
4711 emit attached->reused();
4714void QQuickTableViewPrivate::syncWithPendingChanges()
4724 syncDelegateModelAccess();
4728 syncRebuildOptions();
4731void QQuickTableViewPrivate::syncRebuildOptions()
4733 if (!scheduledRebuildOptions)
4736 rebuildState = RebuildState::Begin;
4737 rebuildOptions = scheduledRebuildOptions;
4738 scheduledRebuildOptions = RebuildOption::None;
4740 if (loadedItems.isEmpty())
4741 rebuildOptions.setFlag(RebuildOption::All);
4744 if (rebuildOptions.testFlag(RebuildOption::All)) {
4745 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4746 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4747 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4748 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4749 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4750 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4753 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4754 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4756 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4757 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4760void QQuickTableViewPrivate::syncDelegate()
4769 if (assignedDelegate != tableModel->delegate())
4770 tableModel->setDelegate(assignedDelegate);
4773void QQuickTableViewPrivate::syncDelegateModelAccess()
4782 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4785QVariant QQuickTableViewPrivate::modelImpl()
const
4787 if (needsModelSynchronization)
4788 return assignedModel;
4790 return tableModel->model();
4791 return QVariant::fromValue(model);
4794void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4796 assignedModel = newModel;
4797 needsModelSynchronization =
true;
4799 if (componentFinalized)
4800 updateSortState(-1, Qt::AscendingOrder);
4802 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4803 emit q_func()->modelChanged();
4806void QQuickTableViewPrivate::syncModel()
4809 if (tableModel->model() == assignedModel)
4811 }
else if (QVariant::fromValue(model) == assignedModel) {
4816 disconnectFromModel();
4817 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4820 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4821 qvariant_cast<QObject *>(assignedModel));
4823 if (instanceModel) {
4826 tableModel =
nullptr;
4828 model = instanceModel;
4831 createWrapperModel();
4832 tableModel->setModel(assignedModel);
4835 needsModelSynchronization =
false;
4839void QQuickTableViewPrivate::syncSyncView()
4841 Q_Q(QQuickTableView);
4843 if (assignedSyncView != syncView) {
4845 syncView->d_func()->syncChildren.removeOne(q);
4847 if (assignedSyncView) {
4848 QQuickTableView *view = assignedSyncView;
4852 if (!layoutWarningIssued) {
4853 layoutWarningIssued =
true;
4854 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4859 view = view->d_func()->syncView;
4862 assignedSyncView->d_func()->syncChildren.append(q);
4863 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4866 syncView = assignedSyncView;
4869 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4870 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4872 if (syncHorizontally) {
4873 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4874 q->setColumnSpacing(syncView->columnSpacing());
4875 q->setLeftMargin(syncView->leftMargin());
4876 q->setRightMargin(syncView->rightMargin());
4877 updateContentWidth();
4879 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4880 if (syncView->leftColumn() != q->leftColumn()
4881 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4888 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4889 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4894 if (syncVertically) {
4895 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4896 q->setRowSpacing(syncView->rowSpacing());
4897 q->setTopMargin(syncView->topMargin());
4898 q->setBottomMargin(syncView->bottomMargin());
4899 updateContentHeight();
4901 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4902 if (syncView->topRow() != q->topRow()
4903 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4910 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4911 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4916 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4922 const auto syncView_d = syncView->d_func();
4923 if (!syncView_d->loadedItems.isEmpty()) {
4924 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4925 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4926 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4927 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4932void QQuickTableViewPrivate::syncPositionView()
4938 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4939 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4942void QQuickTableViewPrivate::connectToModel()
4944 Q_Q(QQuickTableView);
4947 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4948 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4949 QObjectPrivate::connect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4950 QObjectPrivate::connect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4951 QObjectPrivate::connect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
4954 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4956 if (
auto const aim = model->abstractItemModel()) {
4962 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4963 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4964 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4965 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4966 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4967 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4968 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4969 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4970 connect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4972 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4976 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
4977 q, &QQuickTableView::modelChanged);
4981void QQuickTableViewPrivate::disconnectFromModel()
4983 Q_Q(QQuickTableView);
4986 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4987 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4988 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4989 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4990 QObjectPrivate::disconnect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
4992 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4994 if (
auto const aim = model->abstractItemModel()) {
4995 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4996 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4997 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4998 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4999 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
5000 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
5001 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
5002 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
5003 disconnect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
5005 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
5009 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
5010 q, &QQuickTableView::modelChanged);
5014void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
5016 Q_UNUSED(changeSet);
5020 scheduleRebuildTable(RebuildOption::ViewportOnly
5021 | RebuildOption::CalculateNewContentWidth
5022 | RebuildOption::CalculateNewContentHeight);
5025void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
5027 if (parent != QModelIndex())
5030 scheduleRebuildTable(RebuildOption::ViewportOnly);
5033void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
5035 if (parent != QModelIndex())
5038 scheduleRebuildTable(RebuildOption::ViewportOnly);
5041void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
5043 if (parent != QModelIndex())
5046 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
5049void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
5051 Q_Q(QQuickTableView);
5053 if (parent != QModelIndex())
5057 if (!editIndex.isValid() && editItem)
5060 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
5063void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
5065 if (parent != QModelIndex())
5073 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
5076void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
5078 Q_Q(QQuickTableView);
5080 if (parent != QModelIndex())
5084 if (!editIndex.isValid() && editItem)
5087 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
5090void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
5095 scheduleRebuildTable(RebuildOption::ViewportOnly);
5098void QQuickTableViewPrivate::fetchMoreData()
5100 if (tableModel && tableModel->canFetchMore()) {
5101 tableModel->fetchMore();
5102 scheduleRebuildTable(RebuildOption::ViewportOnly);
5106void QQuickTableViewPrivate::modelResetCallback()
5108 Q_Q(QQuickTableView);
5110 scheduleRebuildTable(RebuildOption::All);
5113void QQuickTableViewPrivate::dataChangedCallback(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles)
5115 const auto *chooser = qobject_cast<
const QQmlDelegateChooser *>(assignedDelegate);
5119 if (loadedItems.isEmpty()
5120 || topLeft.column() > rightColumn() || bottomRight.column() < leftColumn()
5121 || topLeft.row() > bottomRow() || bottomRight.row() < topRow()) {
5125 if (!roles.empty()) {
5126 const int roleIndex = topLeft.model()->roleNames().key(chooser->role().toUtf8());
5127 if (!roles.contains(roleIndex))
5131 scheduleRebuildTable(RebuildOption::ViewportOnly);
5134void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5136 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
5139 if (syncVertically) {
5140 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
5142 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
5144 assignedPositionViewAtRowAfterRebuild = row;
5145 positionViewAtRowAlignment = verticalAlignment;
5146 positionViewAtRowOffset = offset;
5147 positionViewAtRowSubRect = subRect;
5148 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
5149 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
5154void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5156 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
5159 if (syncHorizontally) {
5160 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
5162 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
5164 assignedPositionViewAtColumnAfterRebuild = column;
5165 positionViewAtColumnAlignment = horizontalAlignment;
5166 positionViewAtColumnOffset = offset;
5167 positionViewAtColumnSubRect = subRect;
5168 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
5169 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
5174bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5176 Q_Q(QQuickTableView);
5183 if (row < topRow()) {
5184 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
5186 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
5187 }
else if (row > bottomRow()) {
5188 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
5190 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
5191 }
else if (row < topRow() || row > bottomRow()) {
5195 if (!loadedRows.contains(row))
5198 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
5199 if (qFuzzyCompare(newContentY, q->contentY()))
5203 const qreal diffY = qAbs(newContentY - q->contentY());
5204 const qreal duration = qBound(700., diffY * 5, 1500.);
5205 positionYAnimation.setTo(newContentY);
5206 positionYAnimation.setDuration(duration);
5207 positionYAnimation.restart();
5209 positionYAnimation.stop();
5210 q->setContentY(newContentY);
5216bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5218 Q_Q(QQuickTableView);
5225 if (column < leftColumn()) {
5226 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
5228 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
5229 }
else if (column > rightColumn()) {
5230 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
5232 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
5233 }
else if (column < leftColumn() || column > rightColumn()) {
5237 if (!loadedColumns.contains(column))
5240 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5241 if (qFuzzyCompare(newContentX, q->contentX()))
5245 const qreal diffX = qAbs(newContentX - q->contentX());
5246 const qreal duration = qBound(700., diffX * 5, 1500.);
5247 positionXAnimation.setTo(newContentX);
5248 positionXAnimation.setDuration(duration);
5249 positionXAnimation.restart();
5251 positionXAnimation.stop();
5252 q->setContentX(newContentX);
5258void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5260 Q_Q(QQuickTableView);
5270 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5271 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5272 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5276 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5277 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5278 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5282void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5287 Q_Q(QQuickTableView);
5288 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5290 if (qFuzzyCompare(contentX, q->contentX()))
5293 q->setContentX(contentX);
5296void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5301 Q_Q(QQuickTableView);
5302 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5304 if (qFuzzyCompare(contentY, q->contentY()))
5307 q->setContentY(contentY);
5310void QQuickTableViewPrivate::syncViewportRect()
5318 Q_Q(QQuickTableView);
5320 qreal w = q->width();
5321 qreal h = q->height();
5323 for (
auto syncChild : std::as_const(syncChildren)) {
5324 auto syncChild_d = syncChild->d_func();
5325 if (syncChild_d->syncHorizontally)
5326 w = qMax(w, syncChild->width());
5327 if (syncChild_d->syncVertically)
5328 h = qMax(h, syncChild->height());
5331 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5334void QQuickTableViewPrivate::init()
5336 Q_Q(QQuickTableView);
5338 q->setFlag(QQuickItem::ItemIsFocusScope);
5339 q->setActiveFocusOnTab(
true);
5341 positionXAnimation.setTargetObject(q);
5342 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5343 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5345 positionYAnimation.setTargetObject(q);
5346 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5347 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5349 auto tapHandler =
new QQuickTableViewTapHandler(q);
5351 hoverHandler =
new QQuickTableViewHoverHandler(q);
5352 resizeHandler =
new QQuickTableViewResizeHandler(q);
5354 hoverHandler->setEnabled(resizableRows || resizableColumns);
5355 resizeHandler->setEnabled(resizableRows || resizableColumns);
5363 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, q, [
this, q, tapHandler] {
5364 if (!tapHandler->isPressed())
5367 positionXAnimation.stop();
5368 positionYAnimation.stop();
5370 if (!q->isInteractive())
5371 handleTap(tapHandler->point());
5374 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, q, [
this, q, tapHandler] {
5375 if (q->isInteractive())
5376 handleTap(tapHandler->point());
5379 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, q, [
this, q, tapHandler] {
5380 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5381 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5383 if (resizeRow || resizeColumn) {
5385 q->setRowHeight(hoverHandler->m_row, -1);
5387 q->setColumnWidth(hoverHandler->m_column, -1);
5388 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5389 const QPointF pos = tapHandler->point().pressPosition();
5390 const QPoint cell = q->cellAtPosition(pos);
5391 const QModelIndex index = q->modelIndex(cell);
5392 if (canEdit(index,
false))
5398void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5400 Q_Q(QQuickTableView);
5402 if (keyNavigationEnabled)
5403 q->forceActiveFocus(Qt::MouseFocusReason);
5405 if (point.modifiers() != Qt::NoModifier)
5407 if (resizableRows && hoverHandler->m_row != -1)
5409 if (resizableColumns && hoverHandler->m_column != -1)
5411 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5417void QQuickTableViewPrivate::executeTap(
const QQuickHandlerPoint &point)
5419 Q_Q(QQuickTableView);
5421 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5422 bool tappedCellIsSelected =
false;
5425 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5427 if (canEdit(tappedIndex,
false)) {
5428 if (editTriggers & QQuickTableView::SingleTapped) {
5429 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5431 q->edit(tappedIndex);
5433 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5434 q->edit(tappedIndex);
5441 if (pointerNavigationEnabled) {
5442 closeEditorAndCommit();
5443 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5445 cancelSelectionTracking();
5447 setCurrentIndexFromTap(point.position());
5451bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5455 Q_Q(QQuickTableView);
5457 if (!tappedIndex.isValid()) {
5459 qmlWarning(q) <<
"cannot edit: index is not valid!";
5463 auto const sourceModel = qaim(modelImpl());
5466 qmlWarning(q) <<
"cannot edit: TableView.model does not inherit QAbstractItemModel!";
5470 const QModelIndex buddyIndex = sourceModel->buddy(tappedIndex);
5471 if (!(sourceModel->flags(buddyIndex) & Qt::ItemIsEditable)) {
5473 if (buddyIndex != tappedIndex)
5474 qmlWarning(q) <<
"cannot edit: the buddy index flags don't include Qt::ItemIsEditable.";
5476 qmlWarning(q) <<
"cannot edit: the index flags don't include Qt::ItemIsEditable";
5481 const QPoint cell = q->cellAtIndex(buddyIndex);
5482 const QQuickItem *cellItem = q->itemAtCell(cell);
5485 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5489 auto attached = getAttachedObject(cellItem);
5490 if (!attached || !attached->editDelegate()) {
5492 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5499void QQuickTableViewPrivate::syncViewportPosRecursive()
5501 Q_Q(QQuickTableView);
5502 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5505 auto syncView_d = syncView->d_func();
5506 if (!syncView_d->inSyncViewportPosRecursive) {
5507 if (syncHorizontally)
5508 syncView_d->setLocalViewportX(q->contentX());
5510 syncView_d->setLocalViewportY(q->contentY());
5511 syncView_d->syncViewportPosRecursive();
5515 for (
auto syncChild : std::as_const(syncChildren)) {
5516 auto syncChild_d = syncChild->d_func();
5517 if (!syncChild_d->inSyncViewportPosRecursive) {
5518 if (syncChild_d->syncHorizontally)
5519 syncChild_d->setLocalViewportX(q->contentX());
5520 if (syncChild_d->syncVertically)
5521 syncChild_d->setLocalViewportY(q->contentY());
5522 syncChild_d->syncViewportPosRecursive();
5527void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5529 Q_Q(QQuickTableView);
5531 const QPoint cell = q->cellAtPosition(pos);
5532 if (!cellIsValid(cell))
5535 setCurrentIndex(cell);
5538void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5540 if (!selectionModel)
5543 const auto index = q_func()->modelIndex(cell);
5544 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5547bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5549 Q_Q(QQuickTableView);
5551 if (!selectionModel || !selectionModel->model())
5554 const QModelIndex currentIndex = selectionModel->currentIndex();
5555 const QPoint currentCell = q->cellAtIndex(currentIndex);
5557 if (!q->activeFocusOnTab()) {
5560 case Qt::Key_Backtab:
5565 if (!cellIsValid(currentCell)) {
5571 case Qt::Key_PageUp:
5572 case Qt::Key_PageDown:
5576 case Qt::Key_Backtab:
5577 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5580 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5581 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5588 auto beginMoveCurrentIndex = [&](){
5589 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5590 const bool startNewSelection = selectionRectangle().isEmpty();
5591 if (!shouldSelect) {
5593 cancelSelectionTracking();
5594 }
else if (startNewSelection) {
5598 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5599 if (loadedItems.contains(serializedStartIndex)) {
5600 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5601 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5602 setSelectionStartPos(startGeometry.center());
5603 if (selectableCallbackFunction)
5604 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5610 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5611 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5613 if (polishScheduled)
5615 const int serializedEndIndex = modelIndexAtCell(cell);
5616 if (loadedItems.contains(serializedEndIndex)) {
5617 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5618 setSelectionEndPos(endGeometry.center());
5619 if (selectableCallbackFunction)
5620 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5623 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5628 beginMoveCurrentIndex();
5629 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5630 if (nextRow == kEdgeIndexAtEnd)
5632 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5633 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5634 endMoveCurrentIndex({currentCell.x(), nextRow});
5636 case Qt::Key_Down: {
5637 beginMoveCurrentIndex();
5638 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5639 if (nextRow == kEdgeIndexAtEnd)
5641 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5642 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5643 endMoveCurrentIndex({currentCell.x(), nextRow});
5645 case Qt::Key_Left: {
5646 beginMoveCurrentIndex();
5647 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5648 if (nextColumn == kEdgeIndexAtEnd)
5650 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5651 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5652 endMoveCurrentIndex({nextColumn, currentCell.y()});
5654 case Qt::Key_Right: {
5655 beginMoveCurrentIndex();
5656 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5657 if (nextColumn == kEdgeIndexAtEnd)
5659 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5660 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5661 endMoveCurrentIndex({nextColumn, currentCell.y()});
5663 case Qt::Key_PageDown: {
5664 int newBottomRow = -1;
5665 beginMoveCurrentIndex();
5666 if (currentCell.y() < bottomRow()) {
5668 newBottomRow = bottomRow();
5669 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5671 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5672 positionYAnimation.complete();
5673 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5674 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5675 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5676 positionYAnimation.complete();
5678 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5680 case Qt::Key_PageUp: {
5682 beginMoveCurrentIndex();
5683 if (currentCell.y() > topRow()) {
5685 newTopRow = topRow();
5686 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5688 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5689 positionYAnimation.complete();
5690 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5691 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5692 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5693 positionYAnimation.complete();
5695 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5697 case Qt::Key_Home: {
5698 beginMoveCurrentIndex();
5699 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5700 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5701 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5704 beginMoveCurrentIndex();
5705 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5706 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5707 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5710 beginMoveCurrentIndex();
5711 int nextRow = currentCell.y();
5712 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5713 if (nextColumn == kEdgeIndexAtEnd) {
5714 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5715 if (nextRow == kEdgeIndexAtEnd)
5716 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5717 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5718 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5719 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5723 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5724 marginX = q->leftMargin();
5725 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5726 marginX = -q->leftMargin();
5728 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5729 endMoveCurrentIndex({nextColumn, nextRow});
5731 case Qt::Key_Backtab: {
5732 beginMoveCurrentIndex();
5733 int nextRow = currentCell.y();
5734 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5735 if (nextColumn == kEdgeIndexAtEnd) {
5736 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5737 if (nextRow == kEdgeIndexAtEnd)
5738 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5739 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5740 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5741 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5745 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5746 marginX = q->leftMargin();
5747 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5748 marginX = -q->leftMargin();
5750 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5751 endMoveCurrentIndex({nextColumn, nextRow});
5760bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5762 Q_Q(QQuickTableView);
5764 if (editTriggers == QQuickTableView::NoEditTriggers)
5766 if (!selectionModel || !selectionModel->model())
5769 const QModelIndex index = selectionModel->currentIndex();
5770 const QPoint cell = q->cellAtIndex(index);
5771 const QQuickItem *cellItem = q->itemAtCell(cell);
5775 auto attached = getAttachedObject(cellItem);
5776 if (!attached || !attached->editDelegate())
5779 bool anyKeyPressed =
false;
5780 bool editKeyPressed =
false;
5783 case Qt::Key_Return:
5788 anyKeyPressed =
true;
5789 editKeyPressed =
true;
5793 case Qt::Key_Control:
5796 case Qt::Key_Backtab:
5799 anyKeyPressed =
true;
5802 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5803 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5805 if (!(editKeyAccepted || anyKeyAccepted))
5808 if (!canEdit(index,
false)) {
5817 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5820 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5826QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5832 Q_Q(QQuickTableView);
5833 if (QObject *focusObject = editItem->window()->focusObject()) {
5834 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5835 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5836 focusItem->installEventFilter(q);
5843void QQuickTableViewPrivate::closeEditorAndCommit()
5848 if (
auto attached = getAttachedObject(editItem))
5849 emit attached->commit();
5851 q_func()->closeEditor();
5854#if QT_CONFIG(cursor)
5855void QQuickTableViewPrivate::updateCursor()
5857 int row = resizableRows ? hoverHandler->m_row : -1;
5858 int column = resizableColumns ? hoverHandler->m_column : -1;
5860 const auto resizeState = resizeHandler->state();
5861 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5862 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5865 row = resizeHandler->m_row;
5866 column = resizeHandler->m_column;
5869 if (row != -1 || column != -1) {
5870 Qt::CursorShape shape;
5871 if (row != -1 && column != -1)
5872 shape = Qt::SizeFDiagCursor;
5874 shape = Qt::SplitVCursor;
5876 shape = Qt::SplitHCursor;
5879 qApp->changeOverrideCursor(shape);
5881 qApp->setOverrideCursor(shape);
5884 }
else if (m_cursorSet) {
5885 qApp->restoreOverrideCursor();
5886 m_cursorSet =
false;
5891void QQuickTableViewPrivate::updateEditItem()
5893 Q_Q(QQuickTableView);
5898 const QPoint cell = q->cellAtIndex(editIndex);
5899 auto cellItem = q->itemAtCell(cell);
5910 editItem->parentItem()->setX(-editItem->width() - 10000);
5914QQuickTableView::QQuickTableView(QQuickItem *parent)
5915 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5920QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5921 : QQuickFlickable(dd, parent)
5926QQuickTableView::~QQuickTableView()
5928 Q_D(QQuickTableView);
5932 auto syncView_d = d->syncView->d_func();
5933 syncView_d->syncChildren.removeOne(
this);
5934 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5938void QQuickTableView::componentFinalized()
5952 Q_D(QQuickTableView);
5953 qCDebug(lcTableViewDelegateLifecycle);
5955 d->componentFinalized =
true;
5957 if (d->sortColumn >= 0)
5958 d->sortByColumn(d->sortColumn, d->sortOrder);
5963qreal QQuickTableView::minXExtent()
const
5965 return QQuickFlickable::minXExtent() - d_func()->origin.x();
5968qreal QQuickTableView::maxXExtent()
const
5970 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
5973qreal QQuickTableView::minYExtent()
const
5975 return QQuickFlickable::minYExtent() - d_func()->origin.y();
5978qreal QQuickTableView::maxYExtent()
const
5980 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
5983int QQuickTableView::rows()
const
5985 return d_func()->tableSize.height();
5988int QQuickTableView::columns()
const
5990 return d_func()->tableSize.width();
5993qreal QQuickTableView::rowSpacing()
const
5995 return d_func()->cellSpacing.height();
5998void QQuickTableView::setRowSpacing(qreal spacing)
6000 Q_D(QQuickTableView);
6001 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
6003 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
6006 d->cellSpacing.setHeight(spacing);
6007 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
6008 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
6009 emit rowSpacingChanged();
6012qreal QQuickTableView::columnSpacing()
const
6014 return d_func()->cellSpacing.width();
6017void QQuickTableView::setColumnSpacing(qreal spacing)
6019 Q_D(QQuickTableView);
6020 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
6022 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
6025 d->cellSpacing.setWidth(spacing);
6026 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
6027 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
6028 emit columnSpacingChanged();
6031QJSValue QQuickTableView::rowHeightProvider()
const
6033 return d_func()->rowHeightProvider;
6036void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
6038 Q_D(QQuickTableView);
6039 if (provider.strictlyEquals(d->rowHeightProvider))
6042 d->rowHeightProvider = provider;
6043 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
6044 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
6045 emit rowHeightProviderChanged();
6048QJSValue QQuickTableView::columnWidthProvider()
const
6050 return d_func()->columnWidthProvider;
6053void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
6055 Q_D(QQuickTableView);
6056 if (provider.strictlyEquals(d->columnWidthProvider))
6059 d->columnWidthProvider = provider;
6060 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
6061 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
6062 emit columnWidthProviderChanged();
6065QVariant QQuickTableView::model()
const
6067 return d_func()->modelImpl();
6070void QQuickTableView::setModel(
const QVariant &newModel)
6072 Q_D(QQuickTableView);
6074 QVariant model = newModel;
6075 if (model.userType() == qMetaTypeId<QJSValue>())
6076 model = model.value<QJSValue>().toVariant();
6078 if (model == d->assignedModel)
6082 d->setModelImpl(model);
6083 if (d->selectionModel)
6084 d->selectionModel->setModel(d->selectionSourceModel());
6087QQmlComponent *QQuickTableView::delegate()
const
6089 return d_func()->assignedDelegate;
6092void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
6094 Q_D(QQuickTableView);
6095 if (newDelegate == d->assignedDelegate)
6098 d->assignedDelegate = newDelegate;
6099 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
6101 emit delegateChanged();
6104QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
6106 return d_func()->editTriggers;
6109void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
6111 Q_D(QQuickTableView);
6112 if (editTriggers == d->editTriggers)
6115 d->editTriggers = editTriggers;
6117 emit editTriggersChanged();
6121
6122
6123
6124
6125
6126QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
6128 Q_D(
const QQuickTableView);
6129 return d->assignedDelegateModelAccess;
6132void QQuickTableView::setDelegateModelAccess(
6133 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
6135 Q_D(QQuickTableView);
6136 if (delegateModelAccess == d->assignedDelegateModelAccess)
6139 d->assignedDelegateModelAccess = delegateModelAccess;
6140 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
6142 emit delegateModelAccessChanged();
6145bool QQuickTableView::sortingEnabled()
const
6147 Q_D(
const QQuickTableView);
6148 return d->sortingEnabled;
6151void QQuickTableView::setSortingEnabled(
bool enabled)
6153 Q_D(QQuickTableView);
6155 if (d->sortingEnabled == enabled)
6158 d->sortingEnabled = enabled;
6159 emit sortingEnabledChanged();
6161 if (enabled && d->sortColumn >= 0)
6162 d->sortByColumn(d->sortColumn, d->sortOrder);
6165int QQuickTableView::sortColumn()
const
6167 Q_D(
const QQuickTableView);
6168 return d->sortColumn;
6171void QQuickTableView::setSortColumn(
int column)
6173 Q_D(QQuickTableView);
6175 if (column < -1 || d->sortColumn == column)
6178 d->sortByColumn(column, d->sortOrder);
6181Qt::SortOrder QQuickTableView::sortOrder()
const
6183 Q_D(
const QQuickTableView);
6184 return d->sortOrder;
6187void QQuickTableView::setSortOrder(Qt::SortOrder order)
6189 Q_D(QQuickTableView);
6191 if (d->sortOrder == order)
6195 if (d->sortColumn < 0) {
6196 d->updateSortState(d->sortColumn, order);
6200 d->sortByColumn(d->sortColumn, order);
6203void QQuickTableView::sortByColumn(
int column, Qt::SortOrder order)
6205 Q_D(QQuickTableView);
6206 d->sortByColumn(column, order);
6209bool QQuickTableView::reuseItems()
const
6211 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
6214void QQuickTableView::setReuseItems(
bool reuse)
6216 Q_D(QQuickTableView);
6217 if (reuseItems() == reuse)
6220 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
6222 if (!reuse && d->tableModel) {
6225 d->tableModel->drainReusableItemsPool(0);
6228 emit reuseItemsChanged();
6231void QQuickTableView::setContentWidth(qreal width)
6233 Q_D(QQuickTableView);
6234 d->explicitContentWidth = width;
6235 QQuickFlickable::setContentWidth(width);
6238void QQuickTableView::setContentHeight(qreal height)
6240 Q_D(QQuickTableView);
6241 d->explicitContentHeight = height;
6242 QQuickFlickable::setContentHeight(height);
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262QQuickTableView *QQuickTableView::syncView()
const
6264 return d_func()->assignedSyncView;
6267void QQuickTableView::setSyncView(QQuickTableView *view)
6269 Q_D(QQuickTableView);
6270 if (d->assignedSyncView == view)
6275 d->clearIndexMapping();
6277 d->assignedSyncView = view;
6278 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6280 emit syncViewChanged();
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301Qt::Orientations QQuickTableView::syncDirection()
const
6303 return d_func()->assignedSyncDirection;
6306void QQuickTableView::setSyncDirection(Qt::Orientations direction)
6308 Q_D(QQuickTableView);
6309 if (d->assignedSyncDirection == direction)
6312 d->assignedSyncDirection = direction;
6313 if (d->assignedSyncView)
6314 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6316 emit syncDirectionChanged();
6319QItemSelectionModel *QQuickTableView::selectionModel()
const
6321 return d_func()->selectionModel;
6324void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6326 Q_D(QQuickTableView);
6327 if (d->selectionModel == selectionModel)
6334 if (d->selectionModel) {
6335 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6336 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6337 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6338 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6341 d->selectionModel = selectionModel;
6343 if (d->selectionModel) {
6344 d->selectionModel->setModel(d->selectionSourceModel());
6345 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6346 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6347 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6348 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6351 d->updateSelectedOnAllDelegateItems();
6353 emit selectionModelChanged();
6356bool QQuickTableView::animate()
const
6358 return d_func()->animate;
6361void QQuickTableView::setAnimate(
bool animate)
6363 Q_D(QQuickTableView);
6364 if (d->animate == animate)
6367 d->animate = animate;
6369 d->positionXAnimation.stop();
6370 d->positionYAnimation.stop();
6373 emit animateChanged();
6376bool QQuickTableView::keyNavigationEnabled()
const
6378 return d_func()->keyNavigationEnabled;
6381void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6383 Q_D(QQuickTableView);
6384 if (d->keyNavigationEnabled == enabled)
6387 d->keyNavigationEnabled = enabled;
6389 emit keyNavigationEnabledChanged();
6392bool QQuickTableView::pointerNavigationEnabled()
const
6394 return d_func()->pointerNavigationEnabled;
6397void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6399 Q_D(QQuickTableView);
6400 if (d->pointerNavigationEnabled == enabled)
6403 d->pointerNavigationEnabled = enabled;
6405 emit pointerNavigationEnabledChanged();
6408int QQuickTableView::leftColumn()
const
6410 Q_D(
const QQuickTableView);
6411 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6414int QQuickTableView::rightColumn()
const
6416 Q_D(
const QQuickTableView);
6417 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6420int QQuickTableView::topRow()
const
6422 Q_D(
const QQuickTableView);
6423 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6426int QQuickTableView::bottomRow()
const
6428 Q_D(
const QQuickTableView);
6429 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6432int QQuickTableView::currentRow()
const
6434 return d_func()->currentRow;
6437int QQuickTableView::currentColumn()
const
6439 return d_func()->currentColumn;
6442void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6444 Q_D(QQuickTableView);
6445 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6452 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6453 mode &= AlignTop | AlignBottom | AlignVCenter;
6454 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6455 }
else if (mode == Contain) {
6456 if (row < topRow()) {
6457 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6458 }
else if (row > bottomRow()) {
6459 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6460 }
else if (row == topRow()) {
6461 if (!subRect.isValid()) {
6462 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6464 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6465 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6466 if (subRectTop < d->viewportRect.y())
6467 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6468 else if (subRectBottom > d->viewportRect.bottom())
6469 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6471 }
else if (row == bottomRow()) {
6472 if (!subRect.isValid()) {
6473 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6477 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6478 if (subRectBottom > d->viewportRect.bottom())
6479 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6482 }
else if (mode == Visible) {
6483 if (row < topRow()) {
6484 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6485 }
else if (row > bottomRow()) {
6486 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6487 }
else if (subRect.isValid()) {
6488 if (row == topRow()) {
6489 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6490 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6491 if (subRectBottom < d->viewportRect.top())
6492 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6493 else if (subRectTop > d->viewportRect.bottom())
6494 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6495 }
else if (row == bottomRow()) {
6498 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6499 if (subRectTop > d->viewportRect.bottom())
6500 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6504 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6508void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6510 Q_D(QQuickTableView);
6511 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6518 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6519 mode &= AlignLeft | AlignRight | AlignHCenter;
6520 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6521 }
else if (mode == Contain) {
6522 if (column < leftColumn()) {
6523 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6524 }
else if (column > rightColumn()) {
6525 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6526 }
else if (column == leftColumn()) {
6527 if (!subRect.isValid()) {
6528 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6530 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6531 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6532 if (subRectLeft < d->viewportRect.left())
6533 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6534 else if (subRectRight > d->viewportRect.right())
6535 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6537 }
else if (column == rightColumn()) {
6538 if (!subRect.isValid()) {
6539 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6543 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6544 if (subRectRight > d->viewportRect.right())
6545 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6548 }
else if (mode == Visible) {
6549 if (column < leftColumn()) {
6550 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6551 }
else if (column > rightColumn()) {
6552 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6553 }
else if (subRect.isValid()) {
6554 if (column == leftColumn()) {
6555 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6556 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6557 if (subRectRight < d->viewportRect.left())
6558 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6559 else if (subRectLeft > d->viewportRect.right())
6560 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6561 }
else if (column == rightColumn()) {
6564 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6565 if (subRectLeft > d->viewportRect.right())
6566 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6570 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6574void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6576 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6577 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6578 if (!horizontalMode && !verticalMode) {
6579 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6584 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6586 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6589void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6591 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6592 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6593 if (!horizontalMode && !verticalMode) {
6594 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6599 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6601 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6604#if QT_DEPRECATED_SINCE(6
, 5
)
6605void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6607 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6608 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6609 if (!horizontalMode && !verticalMode) {
6610 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6615 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6617 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6621void QQuickTableView::moveColumn(
int source,
int destination)
6623 Q_D(QQuickTableView);
6624 d->moveSection(source, destination, Qt::Horizontal);
6627void QQuickTableView::moveRow(
int source,
int destination)
6629 Q_D(QQuickTableView);
6630 d->moveSection(source, destination, Qt::Vertical);
6633void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientation orientation)
6635 Q_Q(QQuickTableView);
6637 if (source < 0 || destination < 0 ||
6638 (orientation == Qt::Horizontal &&
6639 (source >= tableSize.width() || destination >= tableSize.width())) ||
6640 (orientation == Qt::Vertical &&
6641 (source >= tableSize.height() || destination >= tableSize.height())))
6644 if (source == destination)
6647 if (m_sectionState != SectionState::Moving) {
6648 m_sectionState = SectionState::Moving;
6650 syncView->d_func()->moveSection(source, destination, orientation);
6653 initializeIndexMapping();
6656 auto &visualIndices = visualIndicesForOrientation(orientation);
6657 auto &logicalIndices = logicalIndicesForOrientation(orientation);
6659 const int logical = logicalIndices.at(source).index;
6660 int visual = source;
6662 if (destination > source) {
6663 while (visual < destination) {
6664 SectionData &visualData = visualIndices[logicalIndices[visual + 1].index];
6665 SectionData &logicalData = logicalIndices[visual];
6666 visualData.prevIndex = visualData.index;
6667 visualData.index = visual;
6668 logicalData.prevIndex = logicalData.index;
6669 logicalData.index = logicalIndices[visual + 1].index;
6673 while (visual > destination) {
6674 SectionData &visualData = visualIndices[logicalIndices[visual - 1].index];
6675 SectionData &logicalData = logicalIndices[visual];
6676 visualData.prevIndex = visualData.index;
6677 visualData.index = visual;
6678 logicalData.prevIndex = logicalData.index;
6679 logicalData.index = logicalIndices[visual - 1].index;
6684 visualIndices[logical].prevIndex = visualIndices[logical].index;
6685 visualIndices[logical].index = destination;
6686 logicalIndices[destination].prevIndex = logicalIndices[destination].index;
6687 logicalIndices[destination].index = logical;
6691 for (
auto syncChild : std::as_const(syncChildren)) {
6692 auto syncChild_d = syncChild->d_func();
6693 if (syncChild_d->m_sectionState != SectionState::Moving &&
6694 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6695 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6696 syncChild_d->moveSection(source, destination, orientation);
6701 scheduleRebuildTable(RebuildOption::ViewportOnly);
6702 m_sectionState = SectionState::Idle;
6705 const int startIndex = (source > destination) ? destination : source;
6706 const int endIndex = (source > destination) ? source : destination;
6707 const auto &logicalDataIndices = syncView
6708 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6709 : logicalIndicesForOrientation(orientation);
6710 const auto &visualDataIndices = syncView
6711 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6712 : visualIndicesForOrientation(orientation);
6713 for (
int index = startIndex; index <= endIndex; index++) {
6714 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6715 if (orientation == Qt::Horizontal)
6716 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6718 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6723void QQuickTableView::clearColumnReordering()
6725 Q_D(QQuickTableView);
6726 d->clearSection(Qt::Horizontal);
6729void QQuickTableView::clearRowReordering()
6731 Q_D(QQuickTableView);
6732 d->clearSection(Qt::Vertical);
6735void QQuickTableViewPrivate::clearSection(Qt::Orientation orientation)
6737 Q_Q(QQuickTableView);
6739 const auto &oldLogicalIndices = syncView
6740 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6741 : logicalIndicesForOrientation(orientation);
6742 const auto &oldVisualIndices = syncView
6743 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6744 : visualIndicesForOrientation(orientation);
6747 syncView->d_func()->clearSection(orientation);
6750 logicalIndicesForOrientation(orientation).clear();
6751 visualIndicesForOrientation(orientation).clear();
6752 scheduleRebuildTable(RebuildOption::ViewportOnly);
6756 for (
int index = 0; index <
int(oldLogicalIndices.size()); index++) {
6757 const auto &logicalDataIndices = oldLogicalIndices;
6758 const auto &visualDataIndices = oldVisualIndices;
6759 if (logicalDataIndices[index].index != index) {
6760 const int currentIndex = logicalDataIndices[index].index;
6761 if (orientation == Qt::Horizontal)
6762 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6764 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6769void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6771 if (!modelIndex.isValid())
6774 const int cellIndex = modelIndexToCellIndex(modelIndex);
6775 if (!loadedItems.contains(cellIndex))
6777 const QPoint cell = cellAtModelIndex(cellIndex);
6778 QQuickItem *item = loadedTableItem(cell)->item;
6779 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6782QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6784 Q_D(
const QQuickTableView);
6785 const int modelIndex = d->modelIndexAtCell(cell);
6786 if (!d->loadedItems.contains(modelIndex))
6788 return d->loadedItems.value(modelIndex)->item;
6791#if QT_DEPRECATED_SINCE(6
, 5
)
6792QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6794 return itemAtCell(QPoint(column, row));
6798QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6800 Q_D(
const QQuickTableView);
6801 const int serializedIndex = d->modelIndexToCellIndex(index);
6802 if (!d->loadedItems.contains(serializedIndex))
6804 return d->loadedItems.value(serializedIndex)->item;
6807#if QT_DEPRECATED_SINCE(6
, 4
)
6808QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6810 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6813QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6815 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6819QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6821 return cellAtPosition(QPoint(x, y), includeSpacing);
6824QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6826 Q_D(
const QQuickTableView);
6828 if (!d->loadedTableOuterRect.contains(position))
6829 return QPoint(-1, -1);
6831 const qreal hSpace = d->cellSpacing.width();
6832 const qreal vSpace = d->cellSpacing.height();
6833 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6834 qreal currentRowEnd = d->loadedTableOuterRect.y();
6836 int foundColumn = -1;
6839 for (
const int column : d->loadedColumns) {
6840 currentColumnEnd += d->getEffectiveColumnWidth(column);
6841 if (position.x() < currentColumnEnd) {
6842 foundColumn = column;
6845 currentColumnEnd += hSpace;
6846 if (!includeSpacing && position.x() < currentColumnEnd) {
6848 return QPoint(-1, -1);
6849 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6850 foundColumn = column;
6855 for (
const int row : d->loadedRows) {
6856 currentRowEnd += d->getEffectiveRowHeight(row);
6857 if (position.y() < currentRowEnd) {
6861 currentRowEnd += vSpace;
6862 if (!includeSpacing && position.y() < currentRowEnd) {
6864 return QPoint(-1, -1);
6866 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6872 return QPoint(foundColumn, foundRow);
6875bool QQuickTableView::isColumnLoaded(
int column)
const
6877 Q_D(
const QQuickTableView);
6878 if (!d->loadedColumns.contains(column))
6881 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6884 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6891bool QQuickTableView::isRowLoaded(
int row)
const
6893 Q_D(
const QQuickTableView);
6894 if (!d->loadedRows.contains(row))
6897 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6900 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6907qreal QQuickTableView::columnWidth(
int column)
const
6909 Q_D(
const QQuickTableView);
6910 if (!isColumnLoaded(column))
6913 return d->getEffectiveColumnWidth(column);
6916qreal QQuickTableView::rowHeight(
int row)
const
6918 Q_D(
const QQuickTableView);
6919 if (!isRowLoaded(row))
6922 return d->getEffectiveRowHeight(row);
6925qreal QQuickTableView::implicitColumnWidth(
int column)
const
6927 Q_D(
const QQuickTableView);
6928 if (!isColumnLoaded(column))
6931 return d->sizeHintForColumn(column);
6934qreal QQuickTableView::implicitRowHeight(
int row)
const
6936 Q_D(
const QQuickTableView);
6937 if (!isRowLoaded(row))
6940 return d->sizeHintForRow(row);
6943void QQuickTableView::setColumnWidth(
int column, qreal size)
6945 Q_D(QQuickTableView);
6947 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6951 if (d->syncHorizontally) {
6952 d->syncView->setColumnWidth(column, size);
6956 if (qFuzzyCompare(explicitColumnWidth(column), size))
6960 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6962 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6964 if (d->loadedItems.isEmpty())
6967 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6968 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6969 d->forceLayout(
false);
6972void QQuickTableView::clearColumnWidths()
6974 Q_D(QQuickTableView);
6976 if (d->syncHorizontally) {
6977 d->syncView->clearColumnWidths();
6981 if (d->explicitColumnWidths.isEmpty())
6984 d->explicitColumnWidths.clear();
6985 d->forceLayout(
false);
6988qreal QQuickTableView::explicitColumnWidth(
int column)
const
6990 Q_D(
const QQuickTableView);
6992 if (d->syncHorizontally)
6993 return d->syncView->explicitColumnWidth(column);
6995 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6996 if (it != d->explicitColumnWidths.constEnd())
7001void QQuickTableView::setRowHeight(
int row, qreal size)
7003 Q_D(QQuickTableView);
7005 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
7009 if (d->syncVertically) {
7010 d->syncView->setRowHeight(row, size);
7014 if (qFuzzyCompare(explicitRowHeight(row), size))
7018 d->explicitRowHeights.remove(d->logicalRowIndex(row));
7020 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
7022 if (d->loadedItems.isEmpty())
7025 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
7026 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
7027 d->forceLayout(
false);
7030void QQuickTableView::clearRowHeights()
7032 Q_D(QQuickTableView);
7034 if (d->syncVertically) {
7035 d->syncView->clearRowHeights();
7039 if (d->explicitRowHeights.isEmpty())
7042 d->explicitRowHeights.clear();
7043 d->forceLayout(
false);
7046qreal QQuickTableView::explicitRowHeight(
int row)
const
7048 Q_D(
const QQuickTableView);
7050 if (d->syncVertically)
7051 return d->syncView->explicitRowHeight(row);
7053 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
7054 if (it != d->explicitRowHeights.constEnd())
7059QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
7061 Q_D(
const QQuickTableView);
7062 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
7065 auto const qaim = d->model->abstractItemModel();
7069 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
7072QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
7074 if (!index.isValid() || index.parent().isValid())
7076 Q_D(
const QQuickTableView);
7077 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
7080#if QT_DEPRECATED_SINCE(6
, 4
)
7081QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
7083 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
7089 return modelIndex({row, column});
7091 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
7092 "Use index(row, column) instead. For more information, see "
7093 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
7094 return modelIndex({column, row});
7099QModelIndex QQuickTableView::index(
int row,
int column)
const
7101 return modelIndex({column, row});
7104int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
7106 return cellAtIndex(index).y();
7109int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
7111 return cellAtIndex(index).x();
7114void QQuickTableView::forceLayout()
7116 d_func()->forceLayout(
true);
7119void QQuickTableView::edit(
const QModelIndex &requestedIndex)
7121 Q_D(QQuickTableView);
7124 if (!d->canEdit(requestedIndex,
true))
7127 const auto *aim = d->qaim(d->modelImpl());
7132 const QModelIndex index = aim->buddy(requestedIndex);
7134 if (d->editIndex == index)
7140 if (!d->editModel) {
7141 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
7142 d->editModel->useImportVersion(d->resolveImportVersion());
7143 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
this,
7144 [
this, d] (
int serializedModelIndex, QObject *object) {
7150 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
7151 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
7152 d->editItem = qmlobject_cast<QQuickItem*>(object);
7156 const bool init =
true;
7157 d->updateItemProperties(serializedModelIndex, object, init);
7158 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
7160 d->editItem->setParentItem(cellItem);
7167 if (d->selectionModel)
7168 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
7171 d->closeEditorAndCommit();
7173 const auto cellItem = itemAtCell(cellAtIndex(index));
7175 const auto attached = d->getAttachedObject(cellItem);
7178 d->editModel->setModel(d->tableModel->model());
7179 d->editModel->setDelegate(attached->editDelegate());
7181 const int cellIndex = d->getEditCellIndex(index);
7182 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
7184 d->editIndex = QModelIndex();
7185 d->editItem =
nullptr;
7186 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
7193 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
7194 d->editItem =
nullptr;
7195 d->editIndex = QModelIndex();
7196 d->editModel->release(object, QQmlInstanceModel::NotReusable);
7202 d->model->object(cellIndex, QQmlIncubator::Synchronous);
7205 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
7208 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
7209 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
7212void QQuickTableView::closeEditor()
7214 Q_D(QQuickTableView);
7219 QQuickItem *cellItem = d->editItem->parentItem();
7220 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
7221 d->editItem =
nullptr;
7224 const int cellIndex = d->getEditCellIndex(d->editIndex);
7225 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
7227 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
7229 if (d->editIndex.isValid()) {
7232 d->editIndex = QModelIndex();
7236QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
7238 return new QQuickTableViewAttached(obj);
7241void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
7243 Q_D(QQuickTableView);
7244 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
7246 if (d->tableModel) {
7249 d->tableModel->drainReusableItemsPool(0);
7252 d->forceLayout(
false);
7255void QQuickTableView::viewportMoved(Qt::Orientations orientation)
7257 Q_D(QQuickTableView);
7263 QQuickFlickable::viewportMoved(orientation);
7264 if (d->inSetLocalViewportPos)
7271 d->syncViewportPosRecursive();
7273 auto rootView = d->rootSyncView();
7274 auto rootView_d = rootView->d_func();
7276 rootView_d->scheduleRebuildIfFastFlick();
7278 if (!rootView_d->polishScheduled) {
7279 if (rootView_d->scheduledRebuildOptions) {
7286 const bool updated = rootView->d_func()->updateTableRecursive();
7296void QQuickTableView::keyPressEvent(QKeyEvent *e)
7298 Q_D(QQuickTableView);
7300 if (!d->keyNavigationEnabled) {
7301 QQuickFlickable::keyPressEvent(e);
7305 if (d->tableSize.isEmpty())
7308 if (d->editIndex.isValid()) {
7314 if (d->setCurrentIndexFromKeyEvent(e))
7317 if (d->editFromKeyEvent(e))
7320 QQuickFlickable::keyPressEvent(e);
7323bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
7325 Q_D(QQuickTableView);
7327 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
7330 return QQuickFlickable::eventFilter(obj, event);
7333 switch (event->type()) {
7334 case QEvent::KeyPress: {
7335 Q_ASSERT(d->editItem);
7336 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7337 switch (keyEvent->key()) {
7339 case Qt::Key_Return:
7340 d->closeEditorAndCommit();
7343 case Qt::Key_Backtab:
7344 if (activeFocusOnTab()) {
7345 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7346 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7347 if (d->canEdit(currentIndex,
false))
7353 case Qt::Key_Escape:
7358 case QEvent::FocusOut:
7361 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7362 d->closeEditorAndCommit();
7368 return QQuickFlickable::eventFilter(obj, event);
7371bool QQuickTableView::alternatingRows()
const
7373 return d_func()->alternatingRows;
7376void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7378 Q_D(QQuickTableView);
7379 if (d->alternatingRows == alternatingRows)
7382 d->alternatingRows = alternatingRows;
7383 emit alternatingRowsChanged();
7386QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7388 return d_func()->selectionBehavior;
7391void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7393 Q_D(QQuickTableView);
7394 if (d->selectionBehavior == selectionBehavior)
7397 d->selectionBehavior = selectionBehavior;
7398 emit selectionBehaviorChanged();
7401QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7403 return d_func()->selectionMode;
7406void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7408 Q_D(QQuickTableView);
7409 if (d->selectionMode == selectionMode)
7412 d->selectionMode = selectionMode;
7413 emit selectionModeChanged();
7416bool QQuickTableView::resizableColumns()
const
7418 return d_func()->resizableColumns;
7421void QQuickTableView::setResizableColumns(
bool enabled)
7423 Q_D(QQuickTableView);
7424 if (d->resizableColumns == enabled)
7427 d->resizableColumns = enabled;
7428 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7429 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7431 emit resizableColumnsChanged();
7434bool QQuickTableView::resizableRows()
const
7436 return d_func()->resizableRows;
7439void QQuickTableView::setResizableRows(
bool enabled)
7441 Q_D(QQuickTableView);
7442 if (d->resizableRows == enabled)
7445 d->resizableRows = enabled;
7446 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7447 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7449 emit resizableRowsChanged();
7454 : QQuickHoverHandler(view->contentItem())
7458 connect(
this, &QQuickHoverHandler::hoveredChanged,
this, [
this] {
7463#if QT_CONFIG(cursor)
7464 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7465 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7466 tableViewPrivate->updateCursor();
7473 QQuickHoverHandler::handleEventPoint(event, point);
7475 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7476#if QT_CONFIG(cursor)
7477 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7480 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7481 const auto item = tableView->itemAtCell(cell);
7485#if QT_CONFIG(cursor)
7486 tableViewPrivate->updateCursor();
7491 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7492 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7493 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7494 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7495 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7496#if QT_CONFIG(cursor)
7497 tableViewPrivate->updateCursor();
7508 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7513 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7517 if (event->type() == QEvent::Type::Wheel)
7522 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7523 return !tableView->isMoving();
7532 setObjectName(
"tableViewResizeHandler");
7536 , QPointingDevice::GrabTransition transition
7538 , QEventPoint &point)
7540 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7542 switch (transition) {
7543 case QPointingDevice::GrabPassive:
7544 case QPointingDevice::GrabExclusive:
7546 case QPointingDevice::UngrabPassive:
7547 case QPointingDevice::UngrabExclusive:
7548 case QPointingDevice::CancelGrabPassive:
7549 case QPointingDevice::CancelGrabExclusive:
7550 case QPointingDevice::OverrideGrabPassive:
7551 if (m_state == DraggingStarted || m_state == Dragging) {
7552 m_state = DraggingFinished;
7553 updateDrag(ev, point);
7561 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7562 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7563 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7570 updateDrag(event, point);
7575 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7576 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7578 if (m_state == DraggingFinished)
7579 m_state = Listening;
7581 if (point.state() == QEventPoint::Pressed) {
7582 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7583 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7584 if (m_row != -1 || m_column != -1)
7586 }
else if (point.state() == QEventPoint::Released) {
7587 if (m_state == DraggingStarted || m_state == Dragging)
7588 m_state = DraggingFinished;
7590 m_state = Listening;
7591 }
else if (point.state() == QEventPoint::Updated) {
7596 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7597 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7598 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7599 if (dragDist > qApp->styleHints()->startDragDistance())
7600 m_state = DraggingStarted;
7602 case DraggingStarted:
7607 case DraggingFinished:
7617 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7618#if QT_CONFIG(cursor)
7619 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7626 setPassiveGrab(event, point,
true);
7630 tableView->setFiltersChildMouseEvents(
false);
7631#if QT_CONFIG(cursor)
7632 tableViewPrivate->setActivePointerHandler(
this);
7635 case DraggingStarted:
7636 setExclusiveGrab(event, point,
true);
7637 m_columnStartX = point.position().x();
7638 m_columnStartWidth = tableView->columnWidth(m_column);
7639 m_rowStartY = point.position().y();
7640 m_rowStartHeight = tableView->rowHeight(m_row);
7641#if QT_CONFIG(cursor)
7642 tableViewPrivate->updateCursor();
7646 const qreal distX = point.position().x() - m_columnStartX;
7647 const qreal distY = point.position().y() - m_rowStartY;
7649 tableView->setColumnWidth(
m_column, qMax(0.001, m_columnStartWidth + distX));
7651 tableView->setRowHeight(
m_row, qMax(0.001, m_rowStartHeight + distY));
7653 case DraggingFinished: {
7654 tableView->setFiltersChildMouseEvents(
true);
7655#if QT_CONFIG(cursor)
7656 tableViewPrivate->setActivePointerHandler(
nullptr);
7657 tableViewPrivate->updateCursor();
7664#if QT_CONFIG(quick_draganddrop)
7666QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7667 : QQuickTableViewPointerHandler(view)
7669 setObjectName(
"tableViewDragHandler");
7672QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7677void QQuickTableViewSectionDragHandler::resetDragData()
7679 if (m_state != Listening) {
7680 m_state = Listening;
7681 resetSectionOverlay();
7684 if (m_grabResult.data())
7685 m_grabResult.data()->disconnect();
7686 if (!m_drag.isNull()) {
7687 m_drag->disconnect();
7690 if (!m_dropArea.isNull()) {
7691 m_dropArea->disconnect();
7694 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7695 tableView->setFiltersChildMouseEvents(
true);
7699void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7701 if (m_destination != -1) {
7702 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7703 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7704 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7705 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7706 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7711void QQuickTableViewSectionDragHandler::grabSection()
7714 QPixmap pixmap(m_grabResult->image().size());
7715 pixmap.fill(Qt::transparent);
7716 QPainter painter(&pixmap);
7717 painter.setOpacity(0.6);
7718 painter.drawImage(0, 0, m_grabResult->image());
7722 auto *mimeData =
new QMimeData();
7723 mimeData->setImageData(pixmap);
7724 m_drag->setMimeData(mimeData);
7725 m_drag->setPixmap(pixmap);
7728void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7732 if (m_state == Dragging) {
7733 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7734 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7735 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7736 m_state = DraggingFinished;
7737 resetSectionOverlay();
7738 if (m_scrollTimer.isActive())
7739 m_scrollTimer.stop();
7744void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7748 if (m_state == Dragging) {
7749 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7750 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7751 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7752 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7754 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7755 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7756 if (newDestination != m_destination) {
7758 resetSectionOverlay();
7760 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7761 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7762 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7763 m_destination = newDestination;
7767 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7768 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7769 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7770 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7771 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7772 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7773 if (useStartPos || useEndPos) {
7774 if (!m_scrollTimer.isActive()) {
7775 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7776 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7777 m_scrollTimer.start(1);
7780 if (m_scrollTimer.isActive())
7781 m_scrollTimer.stop();
7786void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7790 if (action == Qt::IgnoreAction) {
7791 resetSectionOverlay();
7792 if (m_scrollTimer.isActive())
7793 m_scrollTimer.stop();
7797void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7799 QQuickSinglePointHandler::handleEventPoint(event, point);
7801 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7802 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7803 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7804 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7807 if (m_state == DraggingFinished) {
7808 if (m_scrollTimer.isActive())
7809 m_scrollTimer.stop();
7813 if (point.state() == QEventPoint::Pressed) {
7817 setPassiveGrab(event, point,
true);
7821 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7822 tableView->setFiltersChildMouseEvents(
false);
7824 }
else if (point.state() == QEventPoint::Released) {
7826 if (m_scrollTimer.isActive())
7827 m_scrollTimer.stop();
7829 }
else if (point.state() == QEventPoint::Updated) {
7831 const qreal distX = point.position().x() - point.pressPosition().x();
7832 const qreal distY = point.position().y() - point.pressPosition().y();
7833 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7834 if (dragDist > qApp->styleHints()->startDragDistance()) {
7838 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7839 auto *item = tableView->itemAtCell(cell);
7842 if (m_drag.isNull()) {
7843 m_drag =
new QDrag(item);
7844 connect(m_drag.data(), &QDrag::actionChanged,
this,
7845 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7848 QObject::connect(&m_scrollTimer, &QTimer::timeout,
this, [&]{
7849 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7850 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7851 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7852 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7855 if (m_dropArea.isNull()) {
7856 m_dropArea =
new QQuickDropArea(tableView);
7857 m_dropArea->setSize(tableView->size());
7858 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7859 &QQuickTableViewSectionDragHandler::handleDrag);
7860 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7861 &QQuickTableViewSectionDragHandler::handleDrop);
7864 m_grabResult = item->grabToImage();
7865 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7866 &QQuickTableViewSectionDragHandler::grabSection);
7868 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7869 m_state = DraggingStarted;
7871 tableViewPrivate->setActivePointerHandler(
this);
7875 case DraggingStarted: {
7876 if (m_drag && m_drag->mimeData()) {
7877 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7879 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7881 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7885 if (m_state == Dragging)
7888 tableViewPrivate->setActivePointerHandler(
nullptr);
7902void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7904 if (!sectionDragHandler) {
7905 Q_Q(QQuickTableView);
7906 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7907 sectionDragHandler->setSectionOrientation(orientation);
7911void QQuickTableViewPrivate::destroySectionDragHandler()
7913 if (sectionDragHandler) {
7914 delete sectionDragHandler;
7915 sectionDragHandler =
nullptr;
7920void QQuickTableViewPrivate::initializeIndexMapping()
7922 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7923 visualIndex.resize(size);
7924 logicalIndex.resize(size);
7925 for (
int index = 0; index < size; ++index)
7926 visualIndex[index].index = logicalIndex[index].index = index;
7929 if (horizontalVisualIndices.size() != size_t(tableSize.width())
7930 || horizontalLogicalIndices.size() != size_t(tableSize.width()))
7931 initIndices(horizontalVisualIndices, horizontalLogicalIndices, tableSize.width());
7933 if (verticalVisualIndices.size() != size_t(tableSize.height())
7934 || verticalLogicalIndices.size() != size_t(tableSize.height()))
7935 initIndices(verticalVisualIndices, verticalLogicalIndices, tableSize.height());
7938void QQuickTableViewPrivate::clearIndexMapping()
7940 horizontalLogicalIndices.clear();
7941 horizontalVisualIndices.clear();
7943 verticalLogicalIndices.clear();
7944 verticalVisualIndices.clear();
7947int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7950 return syncView->d_func()->logicalRowIndex(visualIndex);
7951 if (verticalLogicalIndices.empty() || visualIndex < 0)
7953 return verticalLogicalIndices.at(visualIndex).index;
7956int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7959 return syncView->d_func()->logicalColumnIndex(visualIndex);
7960 if (horizontalLogicalIndices.empty() || visualIndex < 0)
7962 return horizontalLogicalIndices.at(visualIndex).index;
7965int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7968 return syncView->d_func()->visualRowIndex(logicalIndex);
7969 if (verticalVisualIndices.empty() || logicalIndex < 0)
7970 return logicalIndex;
7971 return verticalVisualIndices.at(logicalIndex).index;
7974int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7977 return syncView->d_func()->visualColumnIndex(logicalIndex);
7978 if (horizontalVisualIndices.empty() || logicalIndex < 0)
7979 return logicalIndex;
7980 return horizontalVisualIndices.at(logicalIndex).index;
7983int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7987 const bool hasProxyModel = (modelImpl() != assignedModel);
7988 return modelIndexToCellIndex(index, hasProxyModel);
7994 : QQuickTapHandler(view->contentItem())
7996 setObjectName(
"tableViewTapHandler");
8001 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
8002 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
8003 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
8008#include "moc_qquicktableview_p.cpp"
8009#include "moc_qquicktableview_p_p.cpp"
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override
bool isHoveringGrid() const
QQuickTableViewPointerHandler(QQuickTableView *view)
bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override
Returns true if the given point (as part of event) could be relevant at all to this handler,...
void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *ev, QEventPoint &point) override
Notification that the grab has changed in some way which is relevant to this handler.
void updateState(QEventPoint &point)
void updateDrag(QPointerEvent *event, QEventPoint &point)
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override
bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override
Returns true if the given point (as part of event) could be relevant at all to this handler,...
QDebug operator<<(QDebug debug, QDir::Filters filters)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
#define TV_REBUILDOPTION(OPTION)
static const Qt::Edge allTableEdges[]
#define Q_TABLEVIEW_ASSERT(cond, output)
#define Q_TABLEVIEW_UNREACHABLE(output)
#define TV_REBUILDSTATE(STATE)
static const char * kRequiredProperty_current
static const char * kRequiredProperty_tableView
static const char * kRequiredProperty_editing
static const char * kRequiredProperty_selected
static const char * kRequiredProperty_containsDrag
static const char * kRequiredProperties
static constexpr Qt::SortOrder flipOrder(Qt::SortOrder order)