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#if QT_CONFIG(accessibility)
24#include <QtGui/qaccessible.h>
27#include <QtCore/qtyperevision.h>
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
385
386
387
388
391
392
393
394
395
396
397
398
399
400
403
404
405
406
407
408
409
410
411
412
413
414
417
418
419
420
421
422
425
426
427
428
429
430
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
481
482
483
484
485
486
487
488
489
490
491
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
541
542
543
544
547
548
549
550
551
552
553
554
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
631
632
633
634
635
636
639
640
641
642
643
644
647
648
649
650
651
652
655
656
657
658
659
660
663
664
665
666
667
668
669
670
671
672
673
676
677
678
679
680
681
682
683
684
685
686
689
690
691
692
693
694
695
696
697
698
699
700
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
724
725
726
727
728
729
730
731
732
733
734
735
736
739
740
741
742
743
744
745
746
747
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
797
798
799
800
801
802
805
806
807
808
809
810
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
864
865
866
867
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
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
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1058
1059
1060
1061
1062
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1089
1090
1091
1092
1093
1094
1095
1096
1097
1100
1101
1102
1103
1104
1105
1106
1107
1110
1111
1112
1113
1114
1115
1116
1117
1118
1121
1122
1123
1124
1125
1126
1127
1128
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1162
1163
1164
1165
1166
1167
1168
1169
1170
1173
1174
1175
1176
1177
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1198
1199
1200
1201
1202
1205
1206
1207
1208
1209
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1231
1232
1233
1234
1237
1238
1239
1240
1241
1242
1243
1244
1247
1248
1249
1250
1251
1252
1253
1254
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
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
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1329
1330
1331
1332
1333
1334
1335
1336
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
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
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1401
1402
1403
1404
1405
1406
1407
1408
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1473
1474
1475
1476
1477
1478
1479
1482
1483
1484
1485
1486
1487
1488
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1527
1528
1529
1530
1531
1532
1533
1534
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1553
1554
1555
1556
1557
1558
1559
1562
1563
1564
1565
1566
1567
1568
1571
1572
1573
1574
1575
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
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
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1693QQuickSelectable::~QQuickSelectable() { }
1697#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
1698#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
1711 return (order == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder;
1716#define TV_REBUILDSTATE(STATE)
1717 case QQuickTableViewPrivate::RebuildState::STATE:
1718 dbg << QStringLiteral(#STATE); break;
1738#define TV_REBUILDOPTION(OPTION)
1739 if (options & QQuickTableViewPrivate::RebuildOption::OPTION)
1740 dbg << QStringLiteral(#OPTION)
1742 if (options == QQuickTableViewPrivate::RebuildOption::None) {
1743 dbg << QStringLiteral(
"None");
1759QQuickTableViewPrivate::EdgeRange::EdgeRange()
1760 : startIndex(kEdgeIndexNotSet)
1761 , endIndex(kEdgeIndexNotSet)
1765bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge,
int index)
1767 if (startIndex == kEdgeIndexNotSet)
1770 if (endIndex == kEdgeIndexAtEnd) {
1774 return index <= startIndex;
1776 case Qt::BottomEdge:
1777 return index >= startIndex;
1781 const int s = std::min(startIndex, endIndex);
1782 const int e = std::max(startIndex, endIndex);
1783 return index >= s && index <= e;
1786QQuickTableViewPrivate::QQuickTableViewPrivate()
1787 : QQuickFlickablePrivate()
1791QQuickTableViewPrivate::~QQuickTableViewPrivate()
1794 QQuickItem *cellItem = editItem->parentItem();
1796 editModel->dispose(editItem);
1797 tableModel->release(cellItem, QQmlInstanceModel::NotReusable);
1803 for (
auto *fxTableItem : loadedItems) {
1804 if (
auto item = fxTableItem->item) {
1805 if (fxTableItem->ownItem)
1807 else if (tableModel)
1808 tableModel->dispose(item);
1817QString QQuickTableViewPrivate::tableLayoutToString()
const
1819 if (loadedItems.isEmpty())
1820 return QLatin1String(
"table is empty!");
1821 return QString(QLatin1String(
"table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
1822 .arg(leftColumn()).arg(topRow())
1823 .arg(rightColumn()).arg(bottomRow())
1824 .arg(loadedItems.size())
1825 .arg(loadedTableOuterRect.x())
1826 .arg(loadedTableOuterRect.y())
1827 .arg(loadedTableOuterRect.width())
1828 .arg(loadedTableOuterRect.height());
1831void QQuickTableViewPrivate::dumpTable()
const
1833 auto listCopy = loadedItems.values();
1834 std::stable_sort(listCopy.begin(), listCopy.end(),
1835 [](
const FxTableItem *lhs,
const FxTableItem *rhs)
1836 {
return lhs->index < rhs->index; });
1838 qWarning() << QStringLiteral(
"******* TABLE DUMP *******");
1839 for (
int i = 0; i < listCopy.size(); ++i)
1840 qWarning() <<
static_cast<FxTableItem *>(listCopy.at(i))->cell;
1841 qWarning() << tableLayoutToString();
1843 const QString filename = QStringLiteral(
"QQuickTableView_dumptable_capture.png");
1844 const QString path = QDir::current().absoluteFilePath(filename);
1845 if (q_func()->window() && q_func()->window()->grabWindow().save(path))
1846 qWarning() <<
"Window capture saved to:" << path;
1849void QQuickTableViewPrivate::setRequiredProperty(
const char *property,
1850 const QVariant &value,
int serializedModelIndex, QObject *object,
bool init)
1852 Q_Q(QQuickTableView);
1854 QQmlTableInstanceModel *tableInstanceModel = qobject_cast<QQmlTableInstanceModel *>(model);
1855 if (!tableInstanceModel) {
1865 const QString propertyName = QString::fromUtf8(property);
1868 bool wasRequired =
false;
1869 if (object == editItem) {
1872 wasRequired = editModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1874 wasRequired = tableInstanceModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1877 QStringList propertyList = object->property(kRequiredProperties).toStringList();
1878 object->setProperty(kRequiredProperties, propertyList << propertyName);
1882 const QStringList propertyList = object->property(kRequiredProperties).toStringList();
1883 if (propertyList.contains(propertyName)) {
1884 const auto metaObject = object->metaObject();
1885 const int propertyIndex = metaObject->indexOfProperty(property);
1886 const auto metaProperty = metaObject->property(propertyIndex);
1887 metaProperty.write(object, value);
1897 const QModelIndex modelIndex = q->modelIndex(cellAtModelIndex(serializedModelIndex));
1898 if (modelIndex == editIndex) {
1899 const QStringList propertyList = editItem->property(kRequiredProperties).toStringList();
1900 if (propertyList.contains(propertyName)) {
1901 const auto metaObject = editItem->metaObject();
1902 const int propertyIndex = metaObject->indexOfProperty(property);
1903 const auto metaProperty = metaObject->property(propertyIndex);
1904 metaProperty.write(editItem, value);
1912QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget()
const
1914 return const_cast<QQuickTableView *>(q_func())->contentItem();
1917bool QQuickTableViewPrivate::hasSelection()
const
1919 return selectionModel && selectionModel->hasSelection();
1922bool QQuickTableViewPrivate::startSelection(
const QPointF &pos, Qt::KeyboardModifiers modifiers)
1924 Q_Q(QQuickTableView);
1925 if (!selectionModel) {
1926 if (warnNoSelectionModel)
1927 qmlWarning(q_func()) <<
"Cannot start selection: no SelectionModel assigned!";
1928 warnNoSelectionModel =
false;
1932 if (selectionBehavior == QQuickTableView::SelectionDisabled) {
1933 qmlWarning(q) <<
"Cannot start selection: TableView.selectionBehavior == TableView.SelectionDisabled";
1938 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
1944 if (selectionMode == QQuickTableView::SingleSelection
1945 || selectionMode == QQuickTableView::ContiguousSelection
1946 || modifiers == Qt::NoModifier)
1948 else if (selectionModel)
1949 existingSelection = selectionModel->selection();
1955 selectionFlag = QItemSelectionModel::Select;
1956 if (modifiers & Qt::ControlModifier) {
1957 QPoint startCell = clampedCellAtPos(pos);
1958 if (!cellIsValid(startCell))
1960 const QModelIndex startIndex = q->index(startCell.y(), startCell.x());
1961 if (selectionModel->isSelected(startIndex))
1962 selectionFlag = QItemSelectionModel::Deselect;
1965 selectionStartCell = QPoint(-1, -1);
1966 selectionEndCell = QPoint(-1, -1);
1967 closeEditorAndCommit();
1971void QQuickTableViewPrivate::setSelectionStartPos(
const QPointF &pos)
1973 Q_Q(QQuickTableView);
1974 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1975 if (loadedItems.isEmpty())
1977 if (!selectionModel) {
1978 if (warnNoSelectionModel)
1979 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1980 warnNoSelectionModel =
false;
1983 const QAbstractItemModel *qaim = selectionModel->model();
1987 if (selectionMode == QQuickTableView::SingleSelection
1988 && cellIsValid(selectionStartCell)) {
1992 const QRect prevSelection = selection();
1994 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1997 if (pos.x() == -1) {
1999 clampedCell = q->cellAtIndex(selectionModel->currentIndex());
2001 clampedCell = clampedCellAtPos(pos);
2002 if (cellIsValid(clampedCell))
2003 setCurrentIndex(clampedCell);
2006 if (!cellIsValid(clampedCell))
2009 switch (selectionBehavior) {
2010 case QQuickTableView::SelectCells:
2011 selectionStartCell = clampedCell;
2013 case QQuickTableView::SelectRows:
2014 selectionStartCell = QPoint(0, clampedCell.y());
2016 case QQuickTableView::SelectColumns:
2017 selectionStartCell = QPoint(clampedCell.x(), 0);
2019 case QQuickTableView::SelectionDisabled:
2023 if (!cellIsValid(selectionEndCell))
2027 updateSelection(prevSelection, selection());
2030void QQuickTableViewPrivate::setSelectionEndPos(
const QPointF &pos)
2032 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
2033 if (loadedItems.isEmpty())
2035 if (!selectionModel) {
2036 if (warnNoSelectionModel)
2037 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
2038 warnNoSelectionModel =
false;
2041 const QAbstractItemModel *qaim = selectionModel->model();
2045 const QRect prevSelection = selection();
2048 if (selectionMode == QQuickTableView::SingleSelection) {
2049 clampedCell = selectionStartCell;
2051 clampedCell = clampedCellAtPos(pos);
2052 if (!cellIsValid(clampedCell))
2056 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2058 setCurrentIndex(clampedCell);
2060 switch (selectionBehavior) {
2061 case QQuickTableView::SelectCells:
2062 selectionEndCell = clampedCell;
2064 case QQuickTableView::SelectRows:
2065 selectionEndCell = QPoint(tableSize.width() - 1, clampedCell.y());
2067 case QQuickTableView::SelectColumns:
2068 selectionEndCell = QPoint(clampedCell.x(), tableSize.height() - 1);
2070 case QQuickTableView::SelectionDisabled:
2074 if (!cellIsValid(selectionStartCell))
2078 updateSelection(prevSelection, selection());
2081QPoint QQuickTableViewPrivate::clampedCellAtPos(
const QPointF &pos)
const
2083 Q_Q(
const QQuickTableView);
2086 QPoint cell = q->cellAtPosition(pos,
true);
2087 if (cellIsValid(cell))
2090 if (loadedTableOuterRect.width() == 0 || loadedTableOuterRect.height() == 0)
2091 return QPoint(-1, -1);
2095 qBound(loadedTableOuterRect.x(), pos.x(), loadedTableOuterRect.right() - 1),
2096 qBound(loadedTableOuterRect.y(), pos.y(), loadedTableOuterRect.bottom() - 1));
2097 QPointF clampedPosInView = q->mapFromItem(selectionPointerHandlerTarget(), clampedPos);
2098 clampedPosInView.rx() = qBound(0., clampedPosInView.x(), viewportRect.width());
2099 clampedPosInView.ry() = qBound(0., clampedPosInView.y(), viewportRect.height());
2100 clampedPos = q->mapToItem(selectionPointerHandlerTarget(), clampedPosInView);
2102 return q->cellAtPosition(clampedPos,
true);
2105void QQuickTableViewPrivate::updateSelection(
const QRect &oldSelection,
const QRect &newSelection)
2107 if (oldSelection == newSelection)
2110 const QAbstractItemModel *qaim = selectionModel->model();
2111 const QRect oldRect = oldSelection.normalized();
2112 const QRect newRect = newSelection.normalized();
2114 const auto &columnMapping = syncView ? syncView->d_func()->horizontalLogicalIndices
2115 : horizontalLogicalIndices;
2116 const auto &rowMapping = syncView ? syncView->d_func()->verticalLogicalIndices
2117 : verticalLogicalIndices;
2118 const bool hasMapping = !columnMapping.empty() || !rowMapping.empty();
2120 QItemSelection select;
2121 QItemSelection deselect;
2123 const auto mergeInto =
2124 [
this, qaim, hasMapping](QItemSelection &selection,
2125 const QModelIndex &startIndex,
const QModelIndex &endIndex)
2128 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2129 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()),
2130 logicalColumnIndex(modelIndex.column()));
2131 selection.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2134 selection.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
2140 const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
2141 const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
2142 mergeInto(select, startIndex, endIndex);
2146 if (oldRect.x() < newRect.x()) {
2147 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2148 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
2149 mergeInto(deselect, startIndex, endIndex);
2150 }
else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
2151 const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
2152 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2153 mergeInto(deselect, startIndex, endIndex);
2156 if (oldRect.y() < newRect.y()) {
2157 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2158 const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
2159 mergeInto(deselect, startIndex, endIndex);
2160 }
else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
2161 const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
2162 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2163 mergeInto(deselect, startIndex, endIndex);
2166 if (selectionFlag == QItemSelectionModel::Select) {
2168 deselect.merge(existingSelection, QItemSelectionModel::Deselect);
2169 selectionModel->select(deselect, QItemSelectionModel::Deselect);
2170 selectionModel->select(select, QItemSelectionModel::Select);
2171 }
else if (selectionFlag == QItemSelectionModel::Deselect){
2172 QItemSelection oldSelection = existingSelection;
2173 oldSelection.merge(select, QItemSelectionModel::Deselect);
2174 selectionModel->select(oldSelection, QItemSelectionModel::Select);
2175 selectionModel->select(select, QItemSelectionModel::Deselect);
2181void QQuickTableViewPrivate::cancelSelectionTracking()
2184 selectionStartCell = QPoint(-1, -1);
2185 selectionEndCell = QPoint(-1, -1);
2186 existingSelection.clear();
2187 selectionFlag = QItemSelectionModel::NoUpdate;
2188 if (selectableCallbackFunction)
2189 selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
2192void QQuickTableViewPrivate::clearSelection()
2194 if (!selectionModel)
2196 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2197 selectionModel->clearSelection();
2200void QQuickTableViewPrivate::normalizeSelection()
2206 if (selectionEndCell.x() < selectionStartCell.x())
2207 std::swap(selectionStartCell.rx(), selectionEndCell.rx());
2208 if (selectionEndCell.y() < selectionStartCell.y())
2209 std::swap(selectionStartCell.ry(), selectionEndCell.ry());
2212QRectF QQuickTableViewPrivate::selectionRectangle()
const
2214 Q_Q(
const QQuickTableView);
2216 if (loadedColumns.isEmpty() || loadedRows.isEmpty())
2219 QPoint topLeftCell = selectionStartCell;
2220 QPoint bottomRightCell = selectionEndCell;
2221 if (bottomRightCell.x() < topLeftCell.x())
2222 std::swap(topLeftCell.rx(), bottomRightCell.rx());
2223 if (selectionEndCell.y() < topLeftCell.y())
2224 std::swap(topLeftCell.ry(), bottomRightCell.ry());
2226 const QPoint leftCell(topLeftCell.x(), topRow());
2227 const QPoint topCell(leftColumn(), topLeftCell.y());
2228 const QPoint rightCell(bottomRightCell.x(), topRow());
2229 const QPoint bottomCell(leftColumn(), bottomRightCell.y());
2242 if (loadedItems.contains(modelIndexAtCell(leftCell)))
2243 left = loadedTableItem(leftCell)->geometry().left();
2244 else if (leftCell.x() > rightColumn())
2245 left = q->contentWidth();
2247 if (loadedItems.contains(modelIndexAtCell(topCell)))
2248 top = loadedTableItem(topCell)->geometry().top();
2249 else if (topCell.y() > bottomRow())
2250 top = q->contentHeight();
2252 if (loadedItems.contains(modelIndexAtCell(rightCell)))
2253 right = loadedTableItem(rightCell)->geometry().right();
2254 else if (rightCell.x() > rightColumn())
2255 right = q->contentWidth();
2257 if (loadedItems.contains(modelIndexAtCell(bottomCell)))
2258 bottom = loadedTableItem(bottomCell)->geometry().bottom();
2259 else if (bottomCell.y() > bottomRow())
2260 bottom = q->contentHeight();
2262 return QRectF(left, top, right - left, bottom - top);
2265QRect QQuickTableViewPrivate::selection()
const
2267 const qreal w = selectionEndCell.x() - selectionStartCell.x();
2268 const qreal h = selectionEndCell.y() - selectionStartCell.y();
2269 return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
2272QSizeF QQuickTableViewPrivate::scrollTowardsPoint(
const QPointF &pos,
const QSizeF &step)
2274 Q_Q(QQuickTableView);
2276 if (loadedItems.isEmpty())
2286 const bool outsideLeft = pos.x() < viewportRect.x();
2287 const bool outsideRight = pos.x() >= viewportRect.right() - 1;
2288 const bool outsideTop = pos.y() < viewportRect.y();
2289 const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
2292 const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
2293 const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
2294 if (remainingDist > 0 || !firstColumnLoaded) {
2295 qreal stepX = step.width();
2296 if (firstColumnLoaded)
2297 stepX = qMin(stepX, remainingDist);
2298 q->setContentX(q->contentX() - stepX);
2299 dist.setWidth(pos.x() - viewportRect.left() - 1);
2301 }
else if (outsideRight) {
2302 const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
2303 const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
2304 if (remainingDist > 0 || !lastColumnLoaded) {
2305 qreal stepX = step.width();
2306 if (lastColumnLoaded)
2307 stepX = qMin(stepX, remainingDist);
2308 q->setContentX(q->contentX() + stepX);
2309 dist.setWidth(pos.x() - viewportRect.right() - 1);
2314 const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
2315 const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
2316 if (remainingDist > 0 || !firstRowLoaded) {
2317 qreal stepY = step.height();
2319 stepY = qMin(stepY, remainingDist);
2320 q->setContentY(q->contentY() - stepY);
2321 dist.setHeight(pos.y() - viewportRect.top() - 1);
2323 }
else if (outsideBottom) {
2324 const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
2325 const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
2326 if (remainingDist > 0 || !lastRowLoaded) {
2327 qreal stepY = step.height();
2329 stepY = qMin(stepY, remainingDist);
2330 q->setContentY(q->contentY() + stepY);
2331 dist.setHeight(pos.y() - viewportRect.bottom() - 1);
2338void QQuickTableViewPrivate::setCallback(std::function<
void (CallBackFlag)> func)
2340 selectableCallbackFunction = func;
2343QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(
const QObject *object)
const
2345 QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object,
false);
2346 return static_cast<QQuickTableViewAttached *>(attachedObject);
2349QQuickTableViewAttached::QQuickTableViewAttached(QObject *parent)
2352 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
2359 for (
int i = 0; i < 3; ++i) {
2360 parentItem = parentItem->parentItem();
2363 if (
auto tableView = qobject_cast<QQuickTableView *>(parentItem)) {
2370int QQuickTableViewPrivate::modelIndexAtCell(
const QPoint &cell)
const
2376 int availableColumns = tableSize.width();
2377 return (cell.y() * availableColumns) + cell.x();
2379 int availableRows = tableSize.height();
2380 return (cell.x() * availableRows) + cell.y();
2384QPoint QQuickTableViewPrivate::cellAtModelIndex(
int modelIndex)
const
2390 int availableColumns = tableSize.width();
2391 int row =
int(modelIndex / availableColumns);
2392 int column = modelIndex % availableColumns;
2393 return QPoint(column, row);
2395 int availableRows = tableSize.height();
2396 int column =
int(modelIndex / availableRows);
2397 int row = modelIndex % availableRows;
2398 return QPoint(column, row);
2402int QQuickTableViewPrivate::modelIndexToCellIndex(
const QModelIndex &modelIndex,
bool visualIndex)
const
2406 const QPoint cell = q_func()->cellAtIndex(modelIndex);
2407 if (!cellIsValid(cell))
2409 return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
2412int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
const
2414 return int(log2(
float(edge)));
2417void QQuickTableViewPrivate::clearEdgeSizeCache()
2419 cachedColumnWidth.startIndex = kEdgeIndexNotSet;
2420 cachedRowHeight.startIndex = kEdgeIndexNotSet;
2422 for (Qt::Edge edge : allTableEdges)
2423 cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
2426int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
const
2430 int startIndex = -1;
2432 case Qt::LeftEdge: startIndex = leftColumn() - 1;
break;
2433 case Qt::RightEdge: startIndex = rightColumn() + 1;
break;
2434 case Qt::TopEdge: startIndex = topRow() - 1;
break;
2435 case Qt::BottomEdge: startIndex = bottomRow() + 1;
break;
2438 return nextVisibleEdgeIndex(edge, startIndex);
2441int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge,
int startIndex)
const
2447 auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
2448 if (cachedResult.containsIndex(edge, startIndex))
2449 return cachedResult.endIndex;
2453 int foundIndex = kEdgeIndexNotSet;
2454 int testIndex = startIndex;
2457 case Qt::LeftEdge: {
2459 if (testIndex < 0) {
2460 foundIndex = kEdgeIndexAtEnd;
2464 if (!isColumnHidden(testIndex)) {
2465 foundIndex = testIndex;
2472 case Qt::RightEdge: {
2474 if (testIndex > tableSize.width() - 1) {
2475 foundIndex = kEdgeIndexAtEnd;
2479 if (!isColumnHidden(testIndex)) {
2480 foundIndex = testIndex;
2489 if (testIndex < 0) {
2490 foundIndex = kEdgeIndexAtEnd;
2494 if (!isRowHidden(testIndex)) {
2495 foundIndex = testIndex;
2502 case Qt::BottomEdge: {
2504 if (testIndex > tableSize.height() - 1) {
2505 foundIndex = kEdgeIndexAtEnd;
2509 if (!isRowHidden(testIndex)) {
2510 foundIndex = testIndex;
2519 cachedResult.startIndex = startIndex;
2520 cachedResult.endIndex = foundIndex;
2524void QQuickTableViewPrivate::updateContentWidth()
2535 Q_Q(QQuickTableView);
2537 if (syncHorizontally) {
2538 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2539 q->QQuickFlickable::setContentWidth(syncView->contentWidth());
2543 if (explicitContentWidth.isValid()) {
2549 if (loadedItems.isEmpty()) {
2550 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2551 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2552 q->QQuickFlickable::setContentWidth(kDefaultColumnWidth);
2554 q->QQuickFlickable::setContentWidth(0);
2558 const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2559 const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
2560 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2561 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2562 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2563 const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
2565 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2566 q->QQuickFlickable::setContentWidth(estimatedWidth);
2569void QQuickTableViewPrivate::updateContentHeight()
2571 Q_Q(QQuickTableView);
2573 if (syncVertically) {
2574 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2575 q->QQuickFlickable::setContentHeight(syncView->contentHeight());
2579 if (explicitContentHeight.isValid()) {
2585 if (loadedItems.isEmpty()) {
2586 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2587 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2588 q->QQuickFlickable::setContentHeight(kDefaultRowHeight);
2590 q->QQuickFlickable::setContentHeight(0);
2594 const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2595 const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
2596 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2597 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2598 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2599 const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
2601 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2602 q->QQuickFlickable::setContentHeight(estimatedHeight);
2605void QQuickTableViewPrivate::updateExtents()
2618 Q_Q(QQuickTableView);
2620 bool tableMovedHorizontally =
false;
2621 bool tableMovedVertically =
false;
2623 const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
2624 const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2625 const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
2626 const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2628 QPointF prevOrigin = origin;
2629 QSizeF prevEndExtent = endExtent;
2631 if (syncHorizontally) {
2632 const auto syncView_d = syncView->d_func();
2633 origin.rx() = syncView_d->origin.x();
2634 endExtent.rwidth() = syncView_d->endExtent.width();
2635 }
else if (nextLeftColumn == kEdgeIndexAtEnd) {
2638 if (loadedTableOuterRect.left() > viewportRect.left()) {
2643 if (loadedTableOuterRect.left() > origin.x()) {
2644 const qreal diff = loadedTableOuterRect.left() - origin.x();
2645 loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
2646 loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
2647 tableMovedHorizontally =
true;
2650 origin.rx() = loadedTableOuterRect.left();
2651 }
else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
2655 const int columnsRemaining = nextLeftColumn + 1;
2656 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2657 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2658 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2659 origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
2660 }
else if (nextRightColumn == kEdgeIndexAtEnd) {
2663 if (loadedTableOuterRect.right() < viewportRect.right()) {
2668 const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
2669 if (loadedTableOuterRect.right() < w) {
2670 const qreal diff = loadedTableOuterRect.right() - w;
2671 loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
2672 loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
2673 tableMovedHorizontally =
true;
2676 endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
2677 }
else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
2681 const int columnsRemaining = tableSize.width() - nextRightColumn;
2682 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2683 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2684 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2685 const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
2686 endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
2689 if (syncVertically) {
2690 const auto syncView_d = syncView->d_func();
2691 origin.ry() = syncView_d->origin.y();
2692 endExtent.rheight() = syncView_d->endExtent.height();
2693 }
else if (nextTopRow == kEdgeIndexAtEnd) {
2696 if (loadedTableOuterRect.top() > viewportRect.top()) {
2701 if (loadedTableOuterRect.top() > origin.y()) {
2702 const qreal diff = loadedTableOuterRect.top() - origin.y();
2703 loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
2704 loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
2705 tableMovedVertically =
true;
2708 origin.ry() = loadedTableOuterRect.top();
2709 }
else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
2713 const int rowsRemaining = nextTopRow + 1;
2714 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2715 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2716 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2717 origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
2718 }
else if (nextBottomRow == kEdgeIndexAtEnd) {
2721 if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
2726 const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
2727 if (loadedTableOuterRect.bottom() < h) {
2728 const qreal diff = loadedTableOuterRect.bottom() - h;
2729 loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
2730 loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
2731 tableMovedVertically =
true;
2734 endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
2735 }
else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
2739 const int rowsRemaining = tableSize.height() - nextBottomRow;
2740 const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
2741 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2742 const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
2743 const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
2744 endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
2747 if (tableMovedHorizontally || tableMovedVertically) {
2748 qCDebug(lcTableViewDelegateLifecycle) <<
"move table to" << loadedTableOuterRect;
2752 relayoutTableItems();
2755 for (
auto syncChild : std::as_const(syncChildren)) {
2756 auto syncChild_d = syncChild->d_func();
2757 syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
2758 if (tableMovedHorizontally)
2759 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
2760 if (tableMovedVertically)
2761 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
2765 if (prevOrigin != origin || prevEndExtent != endExtent) {
2766 if (prevOrigin != origin)
2767 qCDebug(lcTableViewDelegateLifecycle) <<
"move origin to:" << origin;
2768 if (prevEndExtent != endExtent)
2769 qCDebug(lcTableViewDelegateLifecycle) <<
"move endExtent to:" << endExtent;
2773 hData.markExtentsDirty();
2774 vData.markExtentsDirty();
2775 updateBeginningEnd();
2776 if (!q->isMoving()) {
2780 q->returnToBounds();
2785void QQuickTableViewPrivate::updateAverageColumnWidth()
2787 if (explicitContentWidth.isValid()) {
2788 const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
2789 averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
2791 const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
2792 averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
2796void QQuickTableViewPrivate::updateAverageRowHeight()
2798 if (explicitContentHeight.isValid()) {
2799 const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
2800 averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
2802 const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
2803 averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
2807void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
2809 const QPoint topLeft = QPoint(leftColumn(), topRow());
2810 const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
2811 QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
2812 QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
2813 loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
2814 loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
2817QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
2823 if (loadedItems.isEmpty()) {
2825 return RebuildOption::None;
2828 RebuildOptions rebuildOptions = RebuildOption::None;
2830 if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
2834 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2835 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2840 for (
int column = leftColumn(); column <= rightColumn(); ++column) {
2841 const bool wasVisibleFromBefore = loadedColumns.contains(column);
2842 const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
2843 if (wasVisibleFromBefore == isVisibleNow)
2848 qCDebug(lcTableViewDelegateLifecycle) <<
"Column" << column <<
"changed visibility to" << isVisibleNow;
2849 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2850 if (column == leftColumn()) {
2853 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2859 if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
2863 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2864 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2869 for (
int row = topRow(); row <= bottomRow(); ++row) {
2870 const bool wasVisibleFromBefore = loadedRows.contains(row);
2871 const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
2872 if (wasVisibleFromBefore == isVisibleNow)
2877 qCDebug(lcTableViewDelegateLifecycle) <<
"Row" << row <<
"changed visibility to" << isVisibleNow;
2878 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2879 if (row == topRow())
2880 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2885 return rebuildOptions;
2888void QQuickTableViewPrivate::forceLayout(
bool immediate)
2890 clearEdgeSizeCache();
2891 RebuildOptions rebuildOptions = RebuildOption::None;
2893 const QSize actualTableSize = calculateTableSize();
2894 if (tableSize != actualTableSize) {
2898 rebuildOptions |= RebuildOption::ViewportOnly;
2906 rebuildOptions |= RebuildOption::LayoutOnly
2907 | RebuildOption::CalculateNewContentWidth
2908 | RebuildOption::CalculateNewContentHeight
2909 | checkForVisibilityChanges();
2911 scheduleRebuildTable(rebuildOptions);
2914 auto rootView = rootSyncView();
2915 const bool updated = rootView->d_func()->updateTableRecursive();
2917 qWarning() <<
"TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
2923void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
2925 if (loadRequest.edge() == Qt::Edge(0)) {
2927 loadedColumns.insert(loadRequest.column());
2928 loadedRows.insert(loadRequest.row());
2932 switch (loadRequest.edge()) {
2935 loadedColumns.insert(loadRequest.column());
2938 case Qt::BottomEdge:
2939 loadedRows.insert(loadRequest.row());
2944FxTableItem *QQuickTableViewPrivate::loadedTableItem(
const QPoint &cell)
const
2946 const int modelIndex = modelIndexAtCell(cell);
2948 return loadedItems.value(modelIndex);
2951FxTableItem *QQuickTableViewPrivate::createFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2953 Q_Q(QQuickTableView);
2955 bool ownItem =
false;
2956 const int modelRow = isTransposed ? logicalColumnIndex(cell.y()) : logicalRowIndex(cell.y());
2957 const int modelColumn = isTransposed ? logicalRowIndex(cell.x()) : logicalColumnIndex(cell.x());
2958 const int modelIndex = modelIndexAtCell(QPoint(modelColumn, modelRow));
2960 QObject *object = model->object(modelIndex, incubationMode);
2963 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2969 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2970 object =
new QQuickItem();
2974 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2978 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2979 model->release(object);
2980 item =
new QQuickItem();
2983 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2984 if (anchors && anchors->activeDirections())
2985 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2986 <<
". Use implicitWidth and implicitHeight instead.";
2993 item->setImplicitWidth(kDefaultColumnWidth);
2994 item->setImplicitHeight(kDefaultRowHeight);
2995 item->setParentItem(q->contentItem());
2999 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
3000 fxTableItem->setVisible(
false);
3001 fxTableItem->cell = cell;
3002 fxTableItem->index = modelIndex;
3006FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
3011 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
3013 incubationMode = QQmlIncubator::Asynchronous;
3018 QScopedValueRollback guard(blockItemCreatedCallback,
true);
3019 auto item = createFxTableItem(cell, incubationMode);
3020 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
3024void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
3027 auto const tmpList = loadedItems;
3028 loadedItems.clear();
3029 for (FxTableItem *item : tmpList)
3030 releaseItem(item, reusableFlag);
3033void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
3035 Q_Q(QQuickTableView);
3038 auto item = fxTableItem->item;
3040#if QT_CONFIG(accessibility)
3042 if (item == accessibleFocusItem)
3043 accessibleFocusItem =
nullptr;
3046 if (fxTableItem->ownItem) {
3050 auto releaseFlag = model->release(item, reusableFlag);
3051 if (releaseFlag == QQmlInstanceModel::Pooled) {
3052 fxTableItem->setVisible(
false);
3056 if (QQuickWindow *window = item->window()) {
3057 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
3059 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
3061 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
3062 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
3072void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
3074 const int modelIndex = modelIndexAtCell(cell);
3076 releaseItem(loadedItems.take(modelIndex), reusableFlag);
3078 tableModel->commitReleasedItems();
3081bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
3083 switch (tableEdge) {
3085 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
3087 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
3089 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
3090 case Qt::BottomEdge:
3091 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
3097bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
3103 switch (tableEdge) {
3105 if (loadedColumns.count() <= 1)
3107 if (positionXAnimation.isRunning()) {
3108 const qreal to = positionXAnimation.to().toFloat();
3109 if (to < viewportRect.x())
3112 return loadedTableInnerRect.left() <= fillRect.left();
3114 if (loadedColumns.count() <= 1)
3116 if (positionXAnimation.isRunning()) {
3117 const qreal to = positionXAnimation.to().toFloat();
3118 if (to > viewportRect.x())
3121 return loadedTableInnerRect.right() >= fillRect.right();
3123 if (loadedRows.count() <= 1)
3125 if (positionYAnimation.isRunning()) {
3126 const qreal to = positionYAnimation.to().toFloat();
3127 if (to < viewportRect.y())
3130 return loadedTableInnerRect.top() <= fillRect.top();
3131 case Qt::BottomEdge:
3132 if (loadedRows.count() <= 1)
3134 if (positionYAnimation.isRunning()) {
3135 const qreal to = positionYAnimation.to().toFloat();
3136 if (to > viewportRect.y())
3139 return loadedTableInnerRect.bottom() >= fillRect.bottom();
3145Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
3147 for (Qt::Edge edge : allTableEdges) {
3148 if (!canLoadTableEdge(edge, rect))
3150 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3151 if (nextIndex == kEdgeIndexAtEnd)
3159Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3161 for (Qt::Edge edge : allTableEdges) {
3162 if (canUnloadTableEdge(edge, rect))
3168qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3172 auto const cellItem = loadedTableItem(cell)->item;
3173 return cellItem->implicitWidth();
3176qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3180 auto const cellItem = loadedTableItem(cell)->item;
3181 return cellItem->implicitHeight();
3184qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3187 qreal columnWidth = 0;
3188 for (
const int row : loadedRows)
3189 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3194qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3197 qreal rowHeight = 0;
3198 for (
const int column : loadedColumns)
3199 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3203QSize QQuickTableViewPrivate::calculateTableSize()
3207 size = QSize(tableModel->columns(), tableModel->rows());
3209 size = QSize(1, model->count());
3211 return isTransposed ? size.transposed() : size;
3214qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3221 const qreal explicitColumnWidth = getColumnWidth(column);
3222 if (explicitColumnWidth >= 0)
3223 return explicitColumnWidth;
3225 if (syncHorizontally) {
3226 if (syncView->d_func()->loadedColumns.contains(column))
3227 return syncView->d_func()->getColumnLayoutWidth(column);
3235 qreal columnWidth = sizeHintForColumn(column);
3237 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3238 if (!layoutWarningIssued) {
3239 layoutWarningIssued =
true;
3240 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3242 columnWidth = kDefaultColumnWidth;
3248qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3252 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3255qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3259 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3262qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3266 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3269qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3273 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3276qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3283 const qreal explicitRowHeight = getRowHeight(row);
3284 if (explicitRowHeight >= 0)
3285 return explicitRowHeight;
3287 if (syncVertically) {
3288 if (syncView->d_func()->loadedRows.contains(row))
3289 return syncView->d_func()->getRowLayoutHeight(row);
3297 qreal rowHeight = sizeHintForRow(row);
3299 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3300 if (!layoutWarningIssued) {
3301 layoutWarningIssued =
true;
3302 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3304 rowHeight = kDefaultRowHeight;
3310qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3316 Q_Q(
const QQuickTableView);
3318 const int noExplicitColumnWidth = -1;
3320 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3321 return cachedColumnWidth.size;
3323 if (syncHorizontally)
3324 return syncView->d_func()->getColumnWidth(column);
3326 if (columnWidthProvider.isUndefined()) {
3330 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3331 if (explicitColumnWidth >= 0)
3332 return explicitColumnWidth;
3333 return noExplicitColumnWidth;
3336 qreal columnWidth = noExplicitColumnWidth;
3338 if (columnWidthProvider.isCallable()) {
3339 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3340 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3341 if (qIsNaN(columnWidth) || columnWidth < 0)
3342 columnWidth = noExplicitColumnWidth;
3344 if (!layoutWarningIssued) {
3345 layoutWarningIssued =
true;
3346 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3348 columnWidth = noExplicitColumnWidth;
3351 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3352 cachedColumnWidth.size = columnWidth;
3356qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3362 Q_Q(
const QQuickTableView);
3364 const int noExplicitRowHeight = -1;
3366 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3367 return cachedRowHeight.size;
3370 return syncView->d_func()->getRowHeight(row);
3372 if (rowHeightProvider.isUndefined()) {
3376 qreal explicitRowHeight = q->explicitRowHeight(row);
3377 if (explicitRowHeight >= 0)
3378 return explicitRowHeight;
3379 return noExplicitRowHeight;
3382 qreal rowHeight = noExplicitRowHeight;
3384 if (rowHeightProvider.isCallable()) {
3385 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3386 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3387 if (qIsNaN(rowHeight) || rowHeight < 0)
3388 rowHeight = noExplicitRowHeight;
3390 if (!layoutWarningIssued) {
3391 layoutWarningIssued =
true;
3392 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3394 rowHeight = noExplicitRowHeight;
3397 cachedRowHeight.startIndex = logicalRowIndex(row);
3398 cachedRowHeight.size = rowHeight;
3402qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3404 Q_Q(QQuickTableView);
3407 const int columnX = getEffectiveColumnX(column);
3409 if (subRect.isValid()) {
3410 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3413 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3416 if (alignment & Qt::AlignLeft) {
3417 contentX = columnX + subRect.x() + offset;
3418 }
else if (alignment & Qt::AlignRight) {
3419 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3420 }
else if (alignment & Qt::AlignHCenter) {
3421 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3422 contentX = columnX + subRect.x() - centerDistance + offset;
3425 const int columnWidth = getEffectiveColumnWidth(column);
3426 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3427 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3429 if (alignment & Qt::AlignLeft) {
3430 contentX = columnX + offset;
3431 }
else if (alignment & Qt::AlignRight) {
3432 contentX = columnX + columnWidth - viewportRect.width() + offset;
3433 }
else if (alignment & Qt::AlignHCenter) {
3434 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3435 contentX = columnX - centerDistance + offset;
3440 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3445qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3447 Q_Q(QQuickTableView);
3450 const int rowY = getEffectiveRowY(row);
3452 if (subRect.isValid()) {
3453 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3456 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3459 if (alignment & Qt::AlignTop) {
3460 contentY = rowY + subRect.y() + offset;
3461 }
else if (alignment & Qt::AlignBottom) {
3462 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3463 }
else if (alignment & Qt::AlignVCenter) {
3464 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3465 contentY = rowY + subRect.y() - centerDistance + offset;
3468 const int rowHeight = getEffectiveRowHeight(row);
3469 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3470 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3472 if (alignment & Qt::AlignTop) {
3473 contentY = rowY + offset;
3474 }
else if (alignment & Qt::AlignBottom) {
3475 contentY = rowY + rowHeight - viewportRect.height() + offset;
3476 }
else if (alignment & Qt::AlignVCenter) {
3477 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3478 contentY = rowY - centerDistance + offset;
3483 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3488bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3492 return qFuzzyIsNull(getColumnWidth(column));
3495bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3499 return qFuzzyIsNull(getRowHeight(row));
3502void QQuickTableViewPrivate::relayoutTableItems()
3504 qCDebug(lcTableViewDelegateLifecycle);
3506 if (viewportRect.isEmpty()) {
3508 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3512 qreal nextColumnX = loadedTableOuterRect.x();
3513 qreal nextRowY = loadedTableOuterRect.y();
3515 for (
const int column : loadedColumns) {
3517 const qreal width = getColumnLayoutWidth(column);
3519 for (
const int row : loadedRows) {
3520 auto item = loadedTableItem(QPoint(column, row));
3521 QRectF geometry = item->geometry();
3522 geometry.moveLeft(nextColumnX);
3523 geometry.setWidth(width);
3524 item->setGeometry(geometry);
3528 nextColumnX += width + cellSpacing.width();
3531 for (
const int row : loadedRows) {
3533 const qreal height = getRowLayoutHeight(row);
3535 for (
const int column : loadedColumns) {
3536 auto item = loadedTableItem(QPoint(column, row));
3537 QRectF geometry = item->geometry();
3538 geometry.moveTop(nextRowY);
3539 geometry.setHeight(height);
3540 item->setGeometry(geometry);
3544 nextRowY += height + cellSpacing.height();
3547 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3548 for (
const int column : loadedColumns) {
3549 for (
const int row : loadedRows) {
3550 QPoint cell = QPoint(column, row);
3551 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3557void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3559 int columnThatNeedsLayout;
3560 int neighbourColumn;
3564 if (tableEdge == Qt::LeftEdge) {
3565 columnThatNeedsLayout = leftColumn();
3566 neighbourColumn = loadedColumns.values().at(1);
3567 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3568 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3569 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3571 columnThatNeedsLayout = rightColumn();
3572 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3573 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3574 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3575 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3578 for (
const int row : loadedRows) {
3579 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3580 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3581 const qreal rowY = neighbourItem->geometry().y();
3582 const qreal rowHeight = neighbourItem->geometry().height();
3584 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3585 fxTableItem->setVisible(
true);
3587 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3591void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3593 int rowThatNeedsLayout;
3596 if (tableEdge == Qt::TopEdge) {
3597 rowThatNeedsLayout = topRow();
3598 neighbourRow = loadedRows.values().at(1);
3600 rowThatNeedsLayout = bottomRow();
3601 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3606 for (
const int column : loadedColumns) {
3607 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3608 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3609 const qreal columnX = neighbourItem->geometry().x();
3610 const qreal columnWidth = neighbourItem->geometry().width();
3611 fxTableItem->item->setX(columnX);
3612 fxTableItem->item->setWidth(columnWidth);
3617 if (tableEdge == Qt::TopEdge) {
3618 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3619 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3620 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3622 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3623 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3624 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3627 for (
const int column : loadedColumns) {
3628 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3629 fxTableItem->item->setY(rowY);
3630 fxTableItem->item->setHeight(rowHeight);
3631 fxTableItem->setVisible(
true);
3633 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3637void QQuickTableViewPrivate::layoutTopLeftItem()
3639 const QPoint cell(loadRequest.column(), loadRequest.row());
3640 auto topLeftItem = loadedTableItem(cell);
3641 auto item = topLeftItem->item;
3643 item->setPosition(loadRequest.startPosition());
3644 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3645 topLeftItem->setVisible(
true);
3646 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3649void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3651 if (loadRequest.edge() == Qt::Edge(0)) {
3653 layoutTopLeftItem();
3657 switch (loadRequest.edge()) {
3660 layoutVerticalEdge(loadRequest.edge());
3663 case Qt::BottomEdge:
3664 layoutHorizontalEdge(loadRequest.edge());
3669void QQuickTableViewPrivate::processLoadRequest()
3671 Q_Q(QQuickTableView);
3674 while (loadRequest.hasCurrentCell()) {
3675 QPoint cell = loadRequest.currentCell();
3676 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3684 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3685 loadRequest.moveToNextCell();
3688 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3690 syncLoadedTableFromLoadRequest();
3691 layoutTableEdgeFromLoadRequest();
3692 syncLoadedTableRectFromLoadedTable();
3693#if QT_CONFIG(accessibility)
3694 updateAccessibleFocus();
3697 if (rebuildState == RebuildState::Done) {
3701 drainReusePoolAfterLoadRequest();
3703 switch (loadRequest.edge()) {
3705 emit q->leftColumnChanged();
3708 emit q->rightColumnChanged();
3711 emit q->topRowChanged();
3713 case Qt::BottomEdge:
3714 emit q->bottomRowChanged();
3718 if (editIndex.isValid())
3721 emit q->layoutChanged();
3724 loadRequest.markAsDone();
3726 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3727 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3728 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3731void QQuickTableViewPrivate::processRebuildTable()
3733 Q_Q(QQuickTableView);
3735 if (rebuildState == RebuildState::Begin) {
3736 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3737 tableSizeBeforeRebuild = tableSize;
3738 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins(-1,-1,-1,-1)
3739 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3742 moveToNextRebuildState();
3744 if (rebuildState == RebuildState::LoadInitalTable) {
3746 if (!moveToNextRebuildState())
3750 if (rebuildState == RebuildState::VerifyTable) {
3751 if (loadedItems.isEmpty()) {
3752 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3753 updateContentWidth();
3754 updateContentHeight();
3755 rebuildState = RebuildState::Done;
3756 }
else if (!moveToNextRebuildState()) {
3761 if (rebuildState == RebuildState::LayoutTable) {
3762 layoutAfterLoadingInitialTable();
3763 loadAndUnloadVisibleEdges();
3764 if (!moveToNextRebuildState())
3768 if (rebuildState == RebuildState::CancelOvershoot) {
3769 cancelOvershootAfterLayout();
3770 loadAndUnloadVisibleEdges();
3771 if (!moveToNextRebuildState())
3775 if (rebuildState == RebuildState::UpdateContentSize) {
3776 updateContentSize();
3777 if (!moveToNextRebuildState())
3781 const bool preload = (rebuildOptions & RebuildOption::All
3782 && reusableFlag == QQmlTableInstanceModel::Reusable);
3784 if (rebuildState == RebuildState::PreloadColumns) {
3785 if (preload && !atTableEnd(Qt::RightEdge))
3786 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3787 if (!moveToNextRebuildState())
3791 if (rebuildState == RebuildState::PreloadRows) {
3792 if (preload && !atTableEnd(Qt::BottomEdge))
3793 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3794 if (!moveToNextRebuildState())
3798 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3799 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3801 if (!moveToNextRebuildState())
3805 if (rebuildState == RebuildState::Done) {
3806 if (tableSizeBeforeRebuild.width() != tableSize.width())
3807 emit q->columnsChanged();
3808 if (tableSizeBeforeRebuild.height() != tableSize.height())
3809 emit q->rowsChanged();
3810 if (edgesBeforeRebuild.left() != q->leftColumn())
3811 emit q->leftColumnChanged();
3812 if (edgesBeforeRebuild.right() != q->rightColumn())
3813 emit q->rightColumnChanged();
3814 if (edgesBeforeRebuild.top() != q->topRow())
3815 emit q->topRowChanged();
3816 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3817 emit q->bottomRowChanged();
3819 if (editIndex.isValid())
3821 updateCurrentRowAndColumn();
3825 tableModel->commitReleasedItems();
3827 emit q->layoutChanged();
3829 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3830 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3831 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3832 qCDebug(lcTableViewDelegateLifecycle());
3838bool QQuickTableViewPrivate::moveToNextRebuildState()
3840 if (loadRequest.isActive()) {
3846 if (rebuildState == RebuildState::Begin
3847 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3848 rebuildState = RebuildState::LayoutTable;
3850 rebuildState = RebuildState(
int(rebuildState) + 1);
3852 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3856void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3858 if (tableSize.isEmpty()) {
3860 topLeftCell.rx() = kEdgeIndexAtEnd;
3861 topLeftCell.ry() = kEdgeIndexAtEnd;
3865 if (syncHorizontally || syncVertically) {
3866 const auto syncView_d = syncView->d_func();
3868 if (syncView_d->loadedItems.isEmpty()) {
3869 topLeftCell.rx() = 0;
3870 topLeftCell.ry() = 0;
3875 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3876 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3877 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3879 if (syncHorizontally) {
3880 topLeftCell.rx() = syncViewTopLeftCell.x();
3881 topLeftPos.rx() = syncViewTopLeftPos.x();
3883 if (topLeftCell.x() >= tableSize.width()) {
3885 topLeftCell.rx() = kEdgeIndexAtEnd;
3886 topLeftPos.rx() = kEdgeIndexAtEnd;
3890 if (syncVertically) {
3891 topLeftCell.ry() = syncViewTopLeftCell.y();
3892 topLeftPos.ry() = syncViewTopLeftPos.y();
3894 if (topLeftCell.y() >= tableSize.height()) {
3896 topLeftCell.ry() = kEdgeIndexAtEnd;
3897 topLeftPos.ry() = kEdgeIndexAtEnd;
3901 if (syncHorizontally && syncVertically) {
3912 if (!syncHorizontally) {
3913 if (rebuildOptions & RebuildOption::All) {
3915 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3916 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3920 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3922 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3923 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3924 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3925 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3926 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3927 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3930 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3934 topLeftPos.rx() = loadedTableOuterRect.x();
3938 if (!syncVertically) {
3939 if (rebuildOptions & RebuildOption::All) {
3941 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3942 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3946 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3948 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3949 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3950 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3951 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3952 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3953 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3955 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3956 topLeftPos.ry() = loadedTableOuterRect.y();
3961void QQuickTableViewPrivate::loadInitialTable()
3963 tableSize = calculateTableSize();
3965 if (positionXAnimation.isRunning()) {
3966 positionXAnimation.stop();
3967 setLocalViewportX(positionXAnimation.to().toReal());
3971 if (positionYAnimation.isRunning()) {
3972 positionYAnimation.stop();
3973 setLocalViewportY(positionYAnimation.to().toReal());
3979 calculateTopLeft(topLeft, topLeftPos);
3980 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3981 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3983 if (!loadedItems.isEmpty()) {
3984 if (rebuildOptions & RebuildOption::All)
3985 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3986 else if (rebuildOptions & RebuildOption::ViewportOnly)
3987 releaseLoadedItems(reusableFlag);
3990 if (rebuildOptions & RebuildOption::All) {
3991 origin = QPointF(0, 0);
3992 endExtent = QSizeF(0, 0);
3993 hData.markExtentsDirty();
3994 vData.markExtentsDirty();
3995 updateBeginningEnd();
3998 loadedColumns.clear();
4000 loadedTableOuterRect = QRect();
4001 loadedTableInnerRect = QRect();
4002 clearEdgeSizeCache();
4004 if (syncHorizontally)
4005 setLocalViewportX(syncView->contentX());
4008 setLocalViewportY(syncView->contentY());
4010 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
4011 setLocalViewportX(topLeftPos.x());
4013 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
4014 setLocalViewportY(topLeftPos.y());
4019 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
4023 if (model->count() == 0) {
4024 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
4028 if (tableModel && !tableModel->delegate()) {
4029 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
4033 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
4034 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
4038 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
4039 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
4043 if (viewportRect.isEmpty()) {
4044 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
4050 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
4051 processLoadRequest();
4052 loadAndUnloadVisibleEdges();
4055void QQuickTableViewPrivate::updateContentSize()
4057 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
4058 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
4059 updateAverageColumnWidth();
4060 updateContentWidth();
4063 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
4064 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
4065 updateAverageRowHeight();
4066 updateContentHeight();
4072void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
4074 clearEdgeSizeCache();
4075 relayoutTableItems();
4076 syncLoadedTableRectFromLoadedTable();
4078 updateContentSize();
4080 adjustViewportXAccordingToAlignment();
4081 adjustViewportYAccordingToAlignment();
4084void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
4087 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4090 if (positionViewAtColumnAfterRebuild != leftColumn())
4093 const qreal newContentX = getAlignmentContentX(
4094 positionViewAtColumnAfterRebuild,
4095 positionViewAtColumnAlignment,
4096 positionViewAtColumnOffset,
4097 positionViewAtColumnSubRect);
4099 setLocalViewportX(newContentX);
4103void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
4106 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4109 if (positionViewAtRowAfterRebuild != topRow())
4112 const qreal newContentY = getAlignmentContentY(
4113 positionViewAtRowAfterRebuild,
4114 positionViewAtRowAlignment,
4115 positionViewAtRowOffset,
4116 positionViewAtRowSubRect);
4118 setLocalViewportY(newContentY);
4122void QQuickTableViewPrivate::cancelOvershootAfterLayout()
4124 Q_Q(QQuickTableView);
4130 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
4131 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
4132 const bool cancelVertically = positionVertically && !syncVertically;
4133 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
4135 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
4136 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
4137 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
4141 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
4142 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
4143 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
4148void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
4150 Q_Q(QQuickTableView);
4151 qCDebug(lcTableViewDelegateLifecycle) << edge;
4154 case Qt::LeftEdge: {
4155 const int column = leftColumn();
4156 for (
int row : loadedRows)
4157 unloadItem(QPoint(column, row));
4158 loadedColumns.remove(column);
4159 syncLoadedTableRectFromLoadedTable();
4160 if (rebuildState == RebuildState::Done)
4161 emit q->leftColumnChanged();
4163 case Qt::RightEdge: {
4164 const int column = rightColumn();
4165 for (
int row : loadedRows)
4166 unloadItem(QPoint(column, row));
4167 loadedColumns.remove(column);
4168 syncLoadedTableRectFromLoadedTable();
4169 if (rebuildState == RebuildState::Done)
4170 emit q->rightColumnChanged();
4173 const int row = topRow();
4174 for (
int col : loadedColumns)
4175 unloadItem(QPoint(col, row));
4176 loadedRows.remove(row);
4177 syncLoadedTableRectFromLoadedTable();
4178 if (rebuildState == RebuildState::Done)
4179 emit q->topRowChanged();
4181 case Qt::BottomEdge: {
4182 const int row = bottomRow();
4183 for (
int col : loadedColumns)
4184 unloadItem(QPoint(col, row));
4185 loadedRows.remove(row);
4186 syncLoadedTableRectFromLoadedTable();
4187 if (rebuildState == RebuildState::Done)
4188 emit q->bottomRowChanged();
4192 if (rebuildState == RebuildState::Done)
4193 emit q->layoutChanged();
4195 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4198void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4200 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4201 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4203 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4204 ? loadedRows.values() : loadedColumns.values();
4205 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4206 processLoadRequest();
4209void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4221 if (loadRequest.isActive()) {
4227 if (loadedItems.isEmpty()) {
4237 tableModified =
false;
4239 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4240 tableModified =
true;
4244 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4245 tableModified =
true;
4246 loadEdge(edge, incubationMode);
4247 if (loadRequest.isActive())
4250 }
while (tableModified);
4254void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4256 Q_Q(QQuickTableView);
4258 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4261 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4291 const int w = loadedColumns.count();
4292 const int h = loadedRows.count();
4293 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4294 const int maxTime = minTime * 2;
4295 tableModel->drainReusableItemsPool(maxTime);
4298void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4299 if (!q_func()->isComponentComplete()) {
4304 scheduledRebuildOptions |= options;
4308QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4310 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4311 while (QQuickTableView *view = root->d_func()->syncView)
4316void QQuickTableViewPrivate::updatePolish()
4323 rootSyncView()->d_func()->updateTableRecursive();
4326bool QQuickTableViewPrivate::updateTableRecursive()
4336 const bool updateComplete = updateTable();
4337 if (!updateComplete)
4340 const auto children = syncChildren;
4341 for (
auto syncChild : children) {
4342 auto syncChild_d = syncChild->d_func();
4344 RebuildOption::PositionViewAtRow |
4345 RebuildOption::PositionViewAtColumn |
4346 RebuildOption::CalculateNewTopLeftRow |
4347 RebuildOption::CalculateNewTopLeftColumn;
4348 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4350 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4351 if (!descendantUpdateComplete)
4355 rebuildOptions = RebuildOption::None;
4360bool QQuickTableViewPrivate::updateTable()
4369 QScopedValueRollback polishGuard(polishing,
true);
4371 if (loadRequest.isActive()) {
4379 if (rebuildState != RebuildState::Done) {
4380 processRebuildTable();
4381 return rebuildState == RebuildState::Done;
4384 syncWithPendingChanges();
4386 if (rebuildState == RebuildState::Begin) {
4387 processRebuildTable();
4388 return rebuildState == RebuildState::Done;
4391 if (loadedItems.isEmpty())
4392 return !loadRequest.isActive();
4394 loadAndUnloadVisibleEdges();
4397 return !loadRequest.isActive();
4400void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4402 if (inUpdateContentSize) {
4414 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4417void QQuickTableViewPrivate::requestSort(
int logicalColumn,
bool clearable)
4419 if (!sortingEnabled || logicalColumn < 0)
4422 auto *sourceModel = qaim(modelImpl());
4424 qmlWarning(q_func()) <<
"Sorting is only supported for QAbstractItemModel based models.";
4428 if (logicalColumn >= sourceModel->columnCount())
4431 Qt::SortOrder defaultSortOrder = Qt::AscendingOrder;
4432 const QVariant value = sourceModel->headerData(logicalColumn, Qt::Horizontal, Qt::InitialSortOrderRole);
4433 if (value.canConvert<
int>())
4434 defaultSortOrder =
static_cast<Qt::SortOrder>(value.toInt());
4437
4438
4439
4440
4441 if (sortColumn == logicalColumn) {
4442 if (clearable && sortOrder != defaultSortOrder) {
4443 sortByColumn(-1, Qt::AscendingOrder);
4447 sortByColumn(logicalColumn, flipOrder(sortOrder));
4451 sortByColumn(logicalColumn, defaultSortOrder);
4454void QQuickTableViewPrivate::sortByColumn(
int column, Qt::SortOrder order)
4456 Q_Q(QQuickTableView);
4463 if (!componentFinalized) {
4464 updateSortState(column, order);
4468 auto *sourceModel = qaim(modelImpl());
4470 qmlWarning(q) <<
"Sorting is only supported for QAbstractItemModel based models.";
4474 updateSortState(column, order);
4478 sourceModel->sort(column, order);
4481void QQuickTableViewPrivate::updateSortState(
int column, Qt::SortOrder order)
4483 Q_Q(QQuickTableView);
4485 const bool columnChanged = sortColumn != column;
4486 const bool orderChanged = sortOrder != order;
4488 if (!columnChanged && !orderChanged)
4491 sortColumn = column;
4495 emit q->sortColumnChanged();
4498 emit q->sortOrderChanged();
4501QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4503 const auto data = QQmlData::get(q_func());
4504 if (!data || !data->propertyCache)
4505 return QTypeRevision::zero();
4507 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4508 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4511 return qmlTypeView.metaObjectRevision();
4514void QQuickTableViewPrivate::createWrapperModel()
4516 Q_Q(QQuickTableView);
4522 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4523 tableModel->useImportVersion(resolveImportVersion());
4527bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4529 if (!selectionModel)
4532 QAbstractItemModel *model = selectionModel->model();
4536 return selectionModel->isSelected(q_func()->modelIndex(cell));
4539bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4541 if (!selectionModel)
4544 QAbstractItemModel *model = selectionModel->model();
4548 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4551void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4553 if (!inSelectionModelUpdate) {
4557 cancelSelectionTracking();
4560 const auto &selectedIndexes = selected.indexes();
4561 const auto &deselectedIndexes = deselected.indexes();
4562 for (
int i = 0; i < selectedIndexes.size(); ++i)
4563 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4564 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4565 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4568void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4570 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4571 qmlWarning(q_func())
4572 <<
"Cannot select cells: TableView.selectionModel.model is not "
4573 <<
"compatible with the model displayed in the view";
4577 const int cellIndex = modelIndexToCellIndex(modelIndex);
4578 if (!loadedItems.contains(cellIndex))
4580 const QPoint cell = cellAtModelIndex(cellIndex);
4581 QQuickItem *item = loadedTableItem(cell)->item;
4582 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4585QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4600 return qaim(modelImpl());
4603QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4606 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4607 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4608 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4611void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4613 updateCurrentRowAndColumn();
4615 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4616 const int cellIndex = *it;
4617 const QPoint cell = cellAtModelIndex(cellIndex);
4618 const bool selected = selectedInSelectionModel(cell);
4619 const bool current = currentInSelectionModel(cell);
4620 QQuickItem *item = loadedTableItem(cell)->item;
4621 const bool editing = editIndex == q_func()->modelIndex(cell);
4622 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4623 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4624 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4628void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4630 if (current.isValid() && current.model() != selectionSourceModel()) {
4631 qmlWarning(q_func())
4632 <<
"Cannot change current index: TableView.selectionModel.model is not "
4633 <<
"compatible with the model displayed in the view";
4637 updateCurrentRowAndColumn();
4638 setCurrentOnDelegateItem(previous,
false);
4639 setCurrentOnDelegateItem(current,
true);
4640#if QT_CONFIG(accessibility)
4641 updateAccessibleFocus();
4645void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4647 Q_Q(QQuickTableView);
4649 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4650 const QPoint currentCell = q->cellAtIndex(currentIndex);
4651 if (currentCell.x() != currentColumn) {
4652 currentColumn = currentCell.x();
4653 emit q->currentColumnChanged();
4656 if (currentCell.y() != currentRow) {
4657 currentRow = currentCell.y();
4658 emit q->currentRowChanged();
4662void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4664 const int cellIndex = modelIndexToCellIndex(index);
4665 if (!loadedItems.contains(cellIndex))
4668 const QPoint cell = cellAtModelIndex(cellIndex);
4669 QQuickItem *item = loadedTableItem(cell)->item;
4670 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4673#if QT_CONFIG(accessibility)
4679void QQuickTableViewPrivate::updateAccessibleFocus()
4681 Q_Q(QQuickTableView);
4682 QQuickItem *item =
nullptr;
4683 if (QAccessible::isActive() && q->hasActiveFocus() && selectionModel) {
4684 const int cellIndex = modelIndexToCellIndex(selectionModel->currentIndex());
4685 if (loadedItems.contains(cellIndex))
4686 item = loadedTableItem(cellAtModelIndex(cellIndex))->item;
4688 if (item == accessibleFocusItem)
4690 accessibleFocusItem = item;
4691 if (item && QQuickItemPrivate::get(item)->isAccessible) {
4692 QAccessibleEvent event(item, QAccessible::Focus);
4693 QAccessible::updateAccessibility(&event);
4698void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4700 if (blockItemCreatedCallback)
4703 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4704 << cellAtModelIndex(modelIndex);
4710 processLoadRequest();
4711 loadAndUnloadVisibleEdges();
4715void QQuickTableViewPrivate::updateItemProperties(
int flatIndex, QObject *object,
bool init)
4717 Q_Q(QQuickTableView);
4718 const QPoint cell = cellAtModelIndex(flatIndex);
4719 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4720 const bool current = currentInSelectionModel(visualCell);
4721 const bool selected = selectedInSelectionModel(visualCell);
4723 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), flatIndex, object, init);
4724 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), flatIndex, object, init);
4725 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), flatIndex, object, init);
4726 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), flatIndex, object, init);
4727 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), flatIndex, object, init);
4730void QQuickTableViewPrivate::initItemCallback(
int flatIndex, QObject *object)
4732 Q_Q(QQuickTableView);
4733 Q_UNUSED(flatIndex);
4735 auto item = qobject_cast<QQuickItem*>(object);
4739 item->setParentItem(q->contentItem());
4742 if (
auto attached = getAttachedObject(item))
4743 attached->setView(q);
4746void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4748 Q_UNUSED(modelIndex);
4750 if (
auto attached = getAttachedObject(object))
4751 emit attached->pooled();
4754void QQuickTableViewPrivate::itemReusedCallback(
int flatIndex, QObject *object)
4756 Q_UNUSED(flatIndex);
4758 if (
auto item = qobject_cast<QQuickItem*>(object))
4759 QQuickItemPrivate::get(item)->setCulled(
false);
4761 if (
auto attached = getAttachedObject(object))
4762 emit attached->reused();
4765void QQuickTableViewPrivate::syncWithPendingChanges()
4775 syncDelegateModelAccess();
4779 syncRebuildOptions();
4782void QQuickTableViewPrivate::syncRebuildOptions()
4784 if (!scheduledRebuildOptions)
4787 rebuildState = RebuildState::Begin;
4788 rebuildOptions = scheduledRebuildOptions;
4789 scheduledRebuildOptions = RebuildOption::None;
4791 if (loadedItems.isEmpty())
4792 rebuildOptions.setFlag(RebuildOption::All);
4795 if (rebuildOptions.testFlag(RebuildOption::All)) {
4796 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4797 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4798 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4799 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4800 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4801 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4804 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4805 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4807 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4808 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4811void QQuickTableViewPrivate::syncDelegate()
4820 if (assignedDelegate != tableModel->delegate())
4821 tableModel->setDelegate(assignedDelegate);
4824void QQuickTableViewPrivate::syncDelegateModelAccess()
4833 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4836QVariant QQuickTableViewPrivate::modelImpl()
const
4838 if (needsModelSynchronization)
4839 return assignedModel;
4841 return tableModel->model();
4842 return QVariant::fromValue(model);
4845void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4847 assignedModel = newModel;
4848 needsModelSynchronization =
true;
4850 if (componentFinalized)
4851 updateSortState(-1, Qt::AscendingOrder);
4853 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4854 emit q_func()->modelChanged();
4857void QQuickTableViewPrivate::syncModel()
4860 if (tableModel->model() == assignedModel)
4862 }
else if (QVariant::fromValue(model) == assignedModel) {
4867 disconnectFromModel();
4868 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4871 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4872 qvariant_cast<QObject *>(assignedModel));
4874 if (instanceModel) {
4877 tableModel =
nullptr;
4879 model = instanceModel;
4882 createWrapperModel();
4883 tableModel->setModel(assignedModel);
4886 needsModelSynchronization =
false;
4890void QQuickTableViewPrivate::syncSyncView()
4892 Q_Q(QQuickTableView);
4894 if (assignedSyncView != syncView) {
4896 syncView->d_func()->syncChildren.removeOne(q);
4898 if (assignedSyncView) {
4899 QQuickTableView *view = assignedSyncView;
4903 if (!layoutWarningIssued) {
4904 layoutWarningIssued =
true;
4905 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4910 view = view->d_func()->syncView;
4913 assignedSyncView->d_func()->syncChildren.append(q);
4914 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4917 syncView = assignedSyncView;
4920 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4921 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4923 if (syncHorizontally) {
4924 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4925 q->setColumnSpacing(syncView->columnSpacing());
4926 q->setLeftMargin(syncView->leftMargin());
4927 q->setRightMargin(syncView->rightMargin());
4928 updateContentWidth();
4930 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4931 if (syncView->leftColumn() != q->leftColumn()
4932 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4939 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4940 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4945 if (syncVertically) {
4946 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4947 q->setRowSpacing(syncView->rowSpacing());
4948 q->setTopMargin(syncView->topMargin());
4949 q->setBottomMargin(syncView->bottomMargin());
4950 updateContentHeight();
4952 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4953 if (syncView->topRow() != q->topRow()
4954 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4961 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4962 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4967 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4973 const auto syncView_d = syncView->d_func();
4974 if (!syncView_d->loadedItems.isEmpty()) {
4975 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4976 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4977 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4978 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4983void QQuickTableViewPrivate::syncPositionView()
4989 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4990 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4993void QQuickTableViewPrivate::connectToModel()
4995 Q_Q(QQuickTableView);
4998 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4999 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
5000 QObjectPrivate::connect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
5001 QObjectPrivate::connect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
5002 QObjectPrivate::connect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
5005 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
5007 if (
auto const aim = model->abstractItemModel()) {
5013 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
5014 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
5015 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
5016 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
5017 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
5018 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
5019 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
5020 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
5021 connect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
5023 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
5027 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
5028 q, &QQuickTableView::modelChanged);
5032void QQuickTableViewPrivate::disconnectFromModel()
5034 Q_Q(QQuickTableView);
5037 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
5038 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
5039 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
5040 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
5041 QObjectPrivate::disconnect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
5043 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
5045 if (
auto const aim = model->abstractItemModel()) {
5046 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
5047 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
5048 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
5049 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
5050 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
5051 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
5052 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
5053 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
5054 disconnect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
5056 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
5060 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
5061 q, &QQuickTableView::modelChanged);
5065void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
5067 Q_UNUSED(changeSet);
5071 scheduleRebuildTable(RebuildOption::ViewportOnly
5072 | RebuildOption::CalculateNewContentWidth
5073 | RebuildOption::CalculateNewContentHeight);
5076void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
5078 if (parent != QModelIndex())
5081 scheduleRebuildTable(RebuildOption::ViewportOnly);
5084void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
5086 if (parent != QModelIndex())
5089 scheduleRebuildTable(RebuildOption::ViewportOnly);
5092void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
5094 if (parent != QModelIndex())
5097 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
5100void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
5102 Q_Q(QQuickTableView);
5104 if (parent != QModelIndex())
5108 if (!editIndex.isValid() && editItem)
5111 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
5114void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
5116 if (parent != QModelIndex())
5124 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
5127void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
5129 Q_Q(QQuickTableView);
5131 if (parent != QModelIndex())
5135 if (!editIndex.isValid() && editItem)
5138 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
5141void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
5146 scheduleRebuildTable(RebuildOption::ViewportOnly);
5149void QQuickTableViewPrivate::fetchMoreData()
5151 if (tableModel && tableModel->canFetchMore()) {
5152 tableModel->fetchMore();
5153 scheduleRebuildTable(RebuildOption::ViewportOnly);
5157void QQuickTableViewPrivate::modelResetCallback()
5159 Q_Q(QQuickTableView);
5161 scheduleRebuildTable(RebuildOption::All);
5164void QQuickTableViewPrivate::dataChangedCallback(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles)
5166 const auto *chooser = qobject_cast<
const QQmlDelegateChooser *>(assignedDelegate);
5170 if (loadedItems.isEmpty()
5171 || topLeft.column() > rightColumn() || bottomRight.column() < leftColumn()
5172 || topLeft.row() > bottomRow() || bottomRight.row() < topRow()) {
5176 if (!roles.empty()) {
5177 const int roleIndex = topLeft.model()->roleNames().key(chooser->role().toUtf8());
5178 if (!roles.contains(roleIndex))
5182 scheduleRebuildTable(RebuildOption::ViewportOnly);
5185void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5187 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
5190 if (syncVertically) {
5191 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
5193 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
5195 assignedPositionViewAtRowAfterRebuild = row;
5196 positionViewAtRowAlignment = verticalAlignment;
5197 positionViewAtRowOffset = offset;
5198 positionViewAtRowSubRect = subRect;
5199 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
5200 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
5205void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5207 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
5210 if (syncHorizontally) {
5211 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
5213 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
5215 assignedPositionViewAtColumnAfterRebuild = column;
5216 positionViewAtColumnAlignment = horizontalAlignment;
5217 positionViewAtColumnOffset = offset;
5218 positionViewAtColumnSubRect = subRect;
5219 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
5220 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
5225bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5227 Q_Q(QQuickTableView);
5234 if (row < topRow()) {
5235 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
5237 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
5238 }
else if (row > bottomRow()) {
5239 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
5241 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
5242 }
else if (row < topRow() || row > bottomRow()) {
5246 if (!loadedRows.contains(row))
5249 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
5250 if (qFuzzyCompare(newContentY, q->contentY()))
5254 const qreal diffY = qAbs(newContentY - q->contentY());
5255 const qreal duration = qBound(700., diffY * 5, 1500.);
5256 positionYAnimation.setTo(newContentY);
5257 positionYAnimation.setDuration(duration);
5258 positionYAnimation.restart();
5260 positionYAnimation.stop();
5261 q->setContentY(newContentY);
5267bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5269 Q_Q(QQuickTableView);
5276 if (column < leftColumn()) {
5277 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
5279 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
5280 }
else if (column > rightColumn()) {
5281 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
5283 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
5284 }
else if (column < leftColumn() || column > rightColumn()) {
5288 if (!loadedColumns.contains(column))
5291 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5292 if (qFuzzyCompare(newContentX, q->contentX()))
5296 const qreal diffX = qAbs(newContentX - q->contentX());
5297 const qreal duration = qBound(700., diffX * 5, 1500.);
5298 positionXAnimation.setTo(newContentX);
5299 positionXAnimation.setDuration(duration);
5300 positionXAnimation.restart();
5302 positionXAnimation.stop();
5303 q->setContentX(newContentX);
5309void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5311 Q_Q(QQuickTableView);
5321 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5322 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5323 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5327 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5328 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5329 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5333void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5338 Q_Q(QQuickTableView);
5339 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5341 if (qFuzzyCompare(contentX, q->contentX()))
5344 q->setContentX(contentX);
5347void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5352 Q_Q(QQuickTableView);
5353 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5355 if (qFuzzyCompare(contentY, q->contentY()))
5358 q->setContentY(contentY);
5361void QQuickTableViewPrivate::syncViewportRect()
5369 Q_Q(QQuickTableView);
5371 qreal w = q->width();
5372 qreal h = q->height();
5374 for (
auto syncChild : std::as_const(syncChildren)) {
5375 auto syncChild_d = syncChild->d_func();
5376 if (syncChild_d->syncHorizontally)
5377 w = qMax(w, syncChild->width());
5378 if (syncChild_d->syncVertically)
5379 h = qMax(h, syncChild->height());
5382 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5385void QQuickTableViewPrivate::init()
5387 Q_Q(QQuickTableView);
5389 q->setFlag(QQuickItem::ItemIsFocusScope);
5390 q->setActiveFocusOnTab(
true);
5391#if QT_CONFIG(accessibility)
5392 QObject::connect(q, &QQuickItem::activeFocusChanged, q, [
this] { updateAccessibleFocus(); });
5395 positionXAnimation.setTargetObject(q);
5396 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5397 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5399 positionYAnimation.setTargetObject(q);
5400 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5401 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5403 auto tapHandler =
new QQuickTableViewTapHandler(q);
5405 hoverHandler =
new QQuickTableViewHoverHandler(q);
5406 resizeHandler =
new QQuickTableViewResizeHandler(q);
5408 hoverHandler->setEnabled(resizableRows || resizableColumns);
5409 resizeHandler->setEnabled(resizableRows || resizableColumns);
5417 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, q, [
this, q, tapHandler] {
5418 if (!tapHandler->isPressed())
5421 positionXAnimation.stop();
5422 positionYAnimation.stop();
5424 if (!q->isInteractive())
5425 handleTap(tapHandler->point());
5428 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, q, [
this, q, tapHandler] {
5429 if (q->isInteractive())
5430 handleTap(tapHandler->point());
5433 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, q, [
this, q, tapHandler] {
5434 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5435 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5437 if (resizeRow || resizeColumn) {
5439 q->setRowHeight(hoverHandler->m_row, -1);
5441 q->setColumnWidth(hoverHandler->m_column, -1);
5442 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5443 const QPointF pos = tapHandler->point().pressPosition();
5444 const QPoint cell = q->cellAtPosition(pos);
5445 const QModelIndex index = q->modelIndex(cell);
5446 if (canEdit(index,
false))
5452void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5454 Q_Q(QQuickTableView);
5456 if (keyNavigationEnabled)
5457 q->forceActiveFocus(Qt::MouseFocusReason);
5459 if (point.modifiers() != Qt::NoModifier)
5461 if (resizableRows && hoverHandler->m_row != -1)
5463 if (resizableColumns && hoverHandler->m_column != -1)
5465 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5471void QQuickTableViewPrivate::executeTap(
const QQuickHandlerPoint &point)
5473 Q_Q(QQuickTableView);
5475 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5476 bool tappedCellIsSelected =
false;
5479 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5481 if (canEdit(tappedIndex,
false)) {
5482 if (editTriggers & QQuickTableView::SingleTapped) {
5483 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5485 q->edit(tappedIndex);
5487 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5488 q->edit(tappedIndex);
5495 if (pointerNavigationEnabled) {
5496 closeEditorAndCommit();
5497 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5499 cancelSelectionTracking();
5501 setCurrentIndexFromTap(point.position());
5505bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5509 Q_Q(QQuickTableView);
5511 if (!tappedIndex.isValid()) {
5513 qmlWarning(q) <<
"cannot edit: index is not valid!";
5517 auto const sourceModel = qaim(modelImpl());
5520 qmlWarning(q) <<
"cannot edit: TableView.model does not inherit QAbstractItemModel!";
5524 const QModelIndex buddyIndex = sourceModel->buddy(tappedIndex);
5525 if (!(sourceModel->flags(buddyIndex) & Qt::ItemIsEditable)) {
5527 if (buddyIndex != tappedIndex)
5528 qmlWarning(q) <<
"cannot edit: the buddy index flags don't include Qt::ItemIsEditable.";
5530 qmlWarning(q) <<
"cannot edit: the index flags don't include Qt::ItemIsEditable";
5535 const QPoint cell = q->cellAtIndex(buddyIndex);
5536 const QQuickItem *cellItem = q->itemAtCell(cell);
5539 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5543 auto attached = getAttachedObject(cellItem);
5544 if (!attached || !attached->editDelegate()) {
5546 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5553void QQuickTableViewPrivate::syncViewportPosRecursive()
5555 Q_Q(QQuickTableView);
5556 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5559 auto syncView_d = syncView->d_func();
5560 if (!syncView_d->inSyncViewportPosRecursive) {
5561 if (syncHorizontally)
5562 syncView_d->setLocalViewportX(q->contentX());
5564 syncView_d->setLocalViewportY(q->contentY());
5565 syncView_d->syncViewportPosRecursive();
5569 for (
auto syncChild : std::as_const(syncChildren)) {
5570 auto syncChild_d = syncChild->d_func();
5571 if (!syncChild_d->inSyncViewportPosRecursive) {
5572 if (syncChild_d->syncHorizontally)
5573 syncChild_d->setLocalViewportX(q->contentX());
5574 if (syncChild_d->syncVertically)
5575 syncChild_d->setLocalViewportY(q->contentY());
5576 syncChild_d->syncViewportPosRecursive();
5581void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5583 Q_Q(QQuickTableView);
5585 const QPoint cell = q->cellAtPosition(pos);
5586 if (!cellIsValid(cell))
5589 setCurrentIndex(cell);
5592void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5594 if (!selectionModel)
5597 const auto index = q_func()->modelIndex(cell);
5598 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5601bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5603 Q_Q(QQuickTableView);
5605 if (!selectionModel || !selectionModel->model())
5608 const QModelIndex currentIndex = selectionModel->currentIndex();
5609 const QPoint currentCell = q->cellAtIndex(currentIndex);
5611 if (!q->activeFocusOnTab()) {
5614 case Qt::Key_Backtab:
5619 if (!cellIsValid(currentCell)) {
5625 case Qt::Key_PageUp:
5626 case Qt::Key_PageDown:
5630 case Qt::Key_Backtab:
5631 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5634 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5635 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5642 auto beginMoveCurrentIndex = [&](){
5643 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5644 const bool startNewSelection = selectionRectangle().isEmpty();
5645 if (!shouldSelect) {
5647 cancelSelectionTracking();
5648 }
else if (startNewSelection) {
5652 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5653 if (loadedItems.contains(serializedStartIndex)) {
5654 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5655 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5656 setSelectionStartPos(startGeometry.center());
5657 if (selectableCallbackFunction)
5658 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5664 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5665 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5667 if (polishScheduled)
5669 const int serializedEndIndex = modelIndexAtCell(cell);
5670 if (loadedItems.contains(serializedEndIndex)) {
5671 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5672 setSelectionEndPos(endGeometry.center());
5673 if (selectableCallbackFunction)
5674 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5677 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5682 beginMoveCurrentIndex();
5683 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5684 if (nextRow == kEdgeIndexAtEnd)
5686 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5687 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5688 endMoveCurrentIndex({currentCell.x(), nextRow});
5690 case Qt::Key_Down: {
5691 beginMoveCurrentIndex();
5692 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5693 if (nextRow == kEdgeIndexAtEnd)
5695 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5696 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5697 endMoveCurrentIndex({currentCell.x(), nextRow});
5699 case Qt::Key_Left: {
5700 beginMoveCurrentIndex();
5701 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5702 if (nextColumn == kEdgeIndexAtEnd)
5704 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5705 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5706 endMoveCurrentIndex({nextColumn, currentCell.y()});
5708 case Qt::Key_Right: {
5709 beginMoveCurrentIndex();
5710 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5711 if (nextColumn == kEdgeIndexAtEnd)
5713 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5714 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5715 endMoveCurrentIndex({nextColumn, currentCell.y()});
5717 case Qt::Key_PageDown: {
5718 int newBottomRow = -1;
5719 beginMoveCurrentIndex();
5720 if (currentCell.y() < bottomRow()) {
5722 newBottomRow = bottomRow();
5723 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5725 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5726 positionYAnimation.complete();
5727 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5728 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5729 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5730 positionYAnimation.complete();
5732 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5734 case Qt::Key_PageUp: {
5736 beginMoveCurrentIndex();
5737 if (currentCell.y() > topRow()) {
5739 newTopRow = topRow();
5740 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5742 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5743 positionYAnimation.complete();
5744 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5745 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5746 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5747 positionYAnimation.complete();
5749 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5751 case Qt::Key_Home: {
5752 beginMoveCurrentIndex();
5753 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5754 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5755 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5758 beginMoveCurrentIndex();
5759 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5760 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5761 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5764 beginMoveCurrentIndex();
5765 int nextRow = currentCell.y();
5766 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5767 if (nextColumn == kEdgeIndexAtEnd) {
5768 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5769 if (nextRow == kEdgeIndexAtEnd)
5770 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5771 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5772 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5773 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5777 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5778 marginX = q->leftMargin();
5779 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5780 marginX = -q->leftMargin();
5782 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5783 endMoveCurrentIndex({nextColumn, nextRow});
5785 case Qt::Key_Backtab: {
5786 beginMoveCurrentIndex();
5787 int nextRow = currentCell.y();
5788 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5789 if (nextColumn == kEdgeIndexAtEnd) {
5790 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5791 if (nextRow == kEdgeIndexAtEnd)
5792 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5793 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5794 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5795 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5799 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5800 marginX = q->leftMargin();
5801 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5802 marginX = -q->leftMargin();
5804 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5805 endMoveCurrentIndex({nextColumn, nextRow});
5814bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5816 Q_Q(QQuickTableView);
5818 if (editTriggers == QQuickTableView::NoEditTriggers)
5820 if (!selectionModel || !selectionModel->model())
5823 const QModelIndex index = selectionModel->currentIndex();
5824 const QPoint cell = q->cellAtIndex(index);
5825 const QQuickItem *cellItem = q->itemAtCell(cell);
5829 auto attached = getAttachedObject(cellItem);
5830 if (!attached || !attached->editDelegate())
5833 bool anyKeyPressed =
false;
5834 bool editKeyPressed =
false;
5837 case Qt::Key_Return:
5842 anyKeyPressed =
true;
5843 editKeyPressed =
true;
5847 case Qt::Key_Control:
5850 case Qt::Key_Backtab:
5853 anyKeyPressed =
true;
5856 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5857 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5859 if (!(editKeyAccepted || anyKeyAccepted))
5862 if (!canEdit(index,
false)) {
5871 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5874 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5880QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5886 Q_Q(QQuickTableView);
5887 if (QObject *focusObject = editItem->window()->focusObject()) {
5888 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5889 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5890 focusItem->installEventFilter(q);
5897void QQuickTableViewPrivate::closeEditorAndCommit()
5902 if (
auto attached = getAttachedObject(editItem))
5903 emit attached->commit();
5905 q_func()->closeEditor();
5908#if QT_CONFIG(cursor)
5909void QQuickTableViewPrivate::updateCursor()
5911 int row = resizableRows ? hoverHandler->m_row : -1;
5912 int column = resizableColumns ? hoverHandler->m_column : -1;
5914 const auto resizeState = resizeHandler->state();
5915 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5916 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5919 row = resizeHandler->m_row;
5920 column = resizeHandler->m_column;
5923 if (row != -1 || column != -1) {
5924 Qt::CursorShape shape;
5925 if (row != -1 && column != -1)
5926 shape = Qt::SizeFDiagCursor;
5928 shape = Qt::SplitVCursor;
5930 shape = Qt::SplitHCursor;
5933 qApp->changeOverrideCursor(shape);
5935 qApp->setOverrideCursor(shape);
5938 }
else if (m_cursorSet) {
5939 qApp->restoreOverrideCursor();
5940 m_cursorSet =
false;
5945void QQuickTableViewPrivate::updateEditItem()
5947 Q_Q(QQuickTableView);
5952 const QPoint cell = q->cellAtIndex(editIndex);
5953 auto cellItem = q->itemAtCell(cell);
5964 editItem->parentItem()->setX(-editItem->width() - 10000);
5968QQuickTableView::QQuickTableView(QQuickItem *parent)
5969 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5974QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5975 : QQuickFlickable(dd, parent)
5980QQuickTableView::~QQuickTableView()
5982 Q_D(QQuickTableView);
5986 auto syncView_d = d->syncView->d_func();
5987 syncView_d->syncChildren.removeOne(
this);
5988 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5992void QQuickTableView::componentFinalized()
6006 Q_D(QQuickTableView);
6007 qCDebug(lcTableViewDelegateLifecycle);
6009 d->componentFinalized =
true;
6011 if (d->sortColumn >= 0)
6012 d->sortByColumn(d->sortColumn, d->sortOrder);
6017qreal QQuickTableView::minXExtent()
const
6019 return QQuickFlickable::minXExtent() - d_func()->origin.x();
6022qreal QQuickTableView::maxXExtent()
const
6024 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
6027qreal QQuickTableView::minYExtent()
const
6029 return QQuickFlickable::minYExtent() - d_func()->origin.y();
6032qreal QQuickTableView::maxYExtent()
const
6034 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
6037int QQuickTableView::rows()
const
6039 return d_func()->tableSize.height();
6042int QQuickTableView::columns()
const
6044 return d_func()->tableSize.width();
6047qreal QQuickTableView::rowSpacing()
const
6049 return d_func()->cellSpacing.height();
6052void QQuickTableView::setRowSpacing(qreal spacing)
6054 Q_D(QQuickTableView);
6055 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
6057 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
6060 d->cellSpacing.setHeight(spacing);
6061 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
6062 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
6063 emit rowSpacingChanged();
6066qreal QQuickTableView::columnSpacing()
const
6068 return d_func()->cellSpacing.width();
6071void QQuickTableView::setColumnSpacing(qreal spacing)
6073 Q_D(QQuickTableView);
6074 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
6076 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
6079 d->cellSpacing.setWidth(spacing);
6080 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
6081 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
6082 emit columnSpacingChanged();
6085QJSValue QQuickTableView::rowHeightProvider()
const
6087 return d_func()->rowHeightProvider;
6090void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
6092 Q_D(QQuickTableView);
6093 if (provider.strictlyEquals(d->rowHeightProvider))
6096 d->rowHeightProvider = provider;
6097 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
6098 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
6099 emit rowHeightProviderChanged();
6102QJSValue QQuickTableView::columnWidthProvider()
const
6104 return d_func()->columnWidthProvider;
6107void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
6109 Q_D(QQuickTableView);
6110 if (provider.strictlyEquals(d->columnWidthProvider))
6113 d->columnWidthProvider = provider;
6114 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
6115 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
6116 emit columnWidthProviderChanged();
6119QVariant QQuickTableView::model()
const
6121 return d_func()->modelImpl();
6124void QQuickTableView::setModel(
const QVariant &newModel)
6126 Q_D(QQuickTableView);
6128 QVariant model = newModel;
6129 if (model.userType() == qMetaTypeId<QJSValue>())
6130 model = model.value<QJSValue>().toVariant();
6132 if (model == d->assignedModel)
6136 d->setModelImpl(model);
6137 if (d->selectionModel)
6138 d->selectionModel->setModel(d->selectionSourceModel());
6141QQmlComponent *QQuickTableView::delegate()
const
6143 return d_func()->assignedDelegate;
6146void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
6148 Q_D(QQuickTableView);
6149 if (newDelegate == d->assignedDelegate)
6152 d->assignedDelegate = newDelegate;
6153 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
6155 emit delegateChanged();
6158QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
6160 return d_func()->editTriggers;
6163void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
6165 Q_D(QQuickTableView);
6166 if (editTriggers == d->editTriggers)
6169 d->editTriggers = editTriggers;
6171 emit editTriggersChanged();
6175
6176
6177
6178
6179
6180QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
6182 Q_D(
const QQuickTableView);
6183 return d->assignedDelegateModelAccess;
6186void QQuickTableView::setDelegateModelAccess(
6187 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
6189 Q_D(QQuickTableView);
6190 if (delegateModelAccess == d->assignedDelegateModelAccess)
6193 d->assignedDelegateModelAccess = delegateModelAccess;
6194 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
6196 emit delegateModelAccessChanged();
6199bool QQuickTableView::sortingEnabled()
const
6201 Q_D(
const QQuickTableView);
6202 return d->sortingEnabled;
6205void QQuickTableView::setSortingEnabled(
bool enabled)
6207 Q_D(QQuickTableView);
6209 if (d->sortingEnabled == enabled)
6212 d->sortingEnabled = enabled;
6213 emit sortingEnabledChanged();
6215 if (enabled && d->sortColumn >= 0)
6216 d->sortByColumn(d->sortColumn, d->sortOrder);
6219int QQuickTableView::sortColumn()
const
6221 Q_D(
const QQuickTableView);
6222 return d->sortColumn;
6225void QQuickTableView::setSortColumn(
int column)
6227 Q_D(QQuickTableView);
6229 if (column < -1 || d->sortColumn == column)
6232 d->sortByColumn(column, d->sortOrder);
6235Qt::SortOrder QQuickTableView::sortOrder()
const
6237 Q_D(
const QQuickTableView);
6238 return d->sortOrder;
6241void QQuickTableView::setSortOrder(Qt::SortOrder order)
6243 Q_D(QQuickTableView);
6245 if (d->sortOrder == order)
6249 if (d->sortColumn < 0) {
6250 d->updateSortState(d->sortColumn, order);
6254 d->sortByColumn(d->sortColumn, order);
6257void QQuickTableView::sortByColumn(
int column, Qt::SortOrder order)
6259 Q_D(QQuickTableView);
6260 d->sortByColumn(column, order);
6263bool QQuickTableView::reuseItems()
const
6265 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
6268void QQuickTableView::setReuseItems(
bool reuse)
6270 Q_D(QQuickTableView);
6271 if (reuseItems() == reuse)
6274 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
6276 if (!reuse && d->tableModel) {
6279 d->tableModel->drainReusableItemsPool(0);
6282 emit reuseItemsChanged();
6285void QQuickTableView::setContentWidth(qreal width)
6287 Q_D(QQuickTableView);
6288 d->explicitContentWidth = width;
6289 QQuickFlickable::setContentWidth(width);
6292void QQuickTableView::setContentHeight(qreal height)
6294 Q_D(QQuickTableView);
6295 d->explicitContentHeight = height;
6296 QQuickFlickable::setContentHeight(height);
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316QQuickTableView *QQuickTableView::syncView()
const
6318 return d_func()->assignedSyncView;
6321void QQuickTableView::setSyncView(QQuickTableView *view)
6323 Q_D(QQuickTableView);
6324 if (d->assignedSyncView == view)
6329 d->clearIndexMapping();
6331 d->assignedSyncView = view;
6332 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6334 emit syncViewChanged();
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355Qt::Orientations QQuickTableView::syncDirection()
const
6357 return d_func()->assignedSyncDirection;
6360void QQuickTableView::setSyncDirection(Qt::Orientations direction)
6362 Q_D(QQuickTableView);
6363 if (d->assignedSyncDirection == direction)
6366 d->assignedSyncDirection = direction;
6367 if (d->assignedSyncView)
6368 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6370 emit syncDirectionChanged();
6373QItemSelectionModel *QQuickTableView::selectionModel()
const
6375 return d_func()->selectionModel;
6378void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6380 Q_D(QQuickTableView);
6381 if (d->selectionModel == selectionModel)
6388 if (d->selectionModel) {
6389 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6390 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6391 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6392 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6395 d->selectionModel = selectionModel;
6397 if (d->selectionModel) {
6398 d->selectionModel->setModel(d->selectionSourceModel());
6399 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6400 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6401 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6402 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6405 d->updateSelectedOnAllDelegateItems();
6407 emit selectionModelChanged();
6410bool QQuickTableView::animate()
const
6412 return d_func()->animate;
6415void QQuickTableView::setAnimate(
bool animate)
6417 Q_D(QQuickTableView);
6418 if (d->animate == animate)
6421 d->animate = animate;
6423 d->positionXAnimation.stop();
6424 d->positionYAnimation.stop();
6427 emit animateChanged();
6430bool QQuickTableView::keyNavigationEnabled()
const
6432 return d_func()->keyNavigationEnabled;
6435void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6437 Q_D(QQuickTableView);
6438 if (d->keyNavigationEnabled == enabled)
6441 d->keyNavigationEnabled = enabled;
6443 emit keyNavigationEnabledChanged();
6446bool QQuickTableView::pointerNavigationEnabled()
const
6448 return d_func()->pointerNavigationEnabled;
6451void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6453 Q_D(QQuickTableView);
6454 if (d->pointerNavigationEnabled == enabled)
6457 d->pointerNavigationEnabled = enabled;
6459 emit pointerNavigationEnabledChanged();
6462int QQuickTableView::leftColumn()
const
6464 Q_D(
const QQuickTableView);
6465 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6468int QQuickTableView::rightColumn()
const
6470 Q_D(
const QQuickTableView);
6471 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6474int QQuickTableView::topRow()
const
6476 Q_D(
const QQuickTableView);
6477 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6480int QQuickTableView::bottomRow()
const
6482 Q_D(
const QQuickTableView);
6483 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6486int QQuickTableView::currentRow()
const
6488 return d_func()->currentRow;
6491int QQuickTableView::currentColumn()
const
6493 return d_func()->currentColumn;
6496void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6498 Q_D(QQuickTableView);
6499 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6506 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6507 mode &= AlignTop | AlignBottom | AlignVCenter;
6508 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6509 }
else if (mode == Contain) {
6510 if (row < topRow()) {
6511 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6512 }
else if (row > bottomRow()) {
6513 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6514 }
else if (row == topRow()) {
6515 if (!subRect.isValid()) {
6516 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6518 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6519 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6520 if (subRectTop < d->viewportRect.y())
6521 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6522 else if (subRectBottom > d->viewportRect.bottom())
6523 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6525 }
else if (row == bottomRow()) {
6526 if (!subRect.isValid()) {
6527 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6531 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6532 if (subRectBottom > d->viewportRect.bottom())
6533 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6536 }
else if (mode == Visible) {
6537 if (row < topRow()) {
6538 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6539 }
else if (row > bottomRow()) {
6540 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6541 }
else if (subRect.isValid()) {
6542 if (row == topRow()) {
6543 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6544 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6545 if (subRectBottom < d->viewportRect.top())
6546 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6547 else if (subRectTop > d->viewportRect.bottom())
6548 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6549 }
else if (row == bottomRow()) {
6552 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6553 if (subRectTop > d->viewportRect.bottom())
6554 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6558 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6562void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6564 Q_D(QQuickTableView);
6565 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6572 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6573 mode &= AlignLeft | AlignRight | AlignHCenter;
6574 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6575 }
else if (mode == Contain) {
6576 if (column < leftColumn()) {
6577 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6578 }
else if (column > rightColumn()) {
6579 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6580 }
else if (column == leftColumn()) {
6581 if (!subRect.isValid()) {
6582 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6584 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6585 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6586 if (subRectLeft < d->viewportRect.left())
6587 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6588 else if (subRectRight > d->viewportRect.right())
6589 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6591 }
else if (column == rightColumn()) {
6592 if (!subRect.isValid()) {
6593 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6597 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6598 if (subRectRight > d->viewportRect.right())
6599 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6602 }
else if (mode == Visible) {
6603 if (column < leftColumn()) {
6604 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6605 }
else if (column > rightColumn()) {
6606 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6607 }
else if (subRect.isValid()) {
6608 if (column == leftColumn()) {
6609 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6610 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6611 if (subRectRight < d->viewportRect.left())
6612 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6613 else if (subRectLeft > d->viewportRect.right())
6614 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6615 }
else if (column == rightColumn()) {
6618 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6619 if (subRectLeft > d->viewportRect.right())
6620 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6624 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6628void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6630 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6631 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6632 if (!horizontalMode && !verticalMode) {
6633 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6638 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6640 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6643void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6645 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6646 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6647 if (!horizontalMode && !verticalMode) {
6648 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6653 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6655 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6658#if QT_DEPRECATED_SINCE(6
, 5
)
6659void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6661 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6662 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6663 if (!horizontalMode && !verticalMode) {
6664 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6669 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6671 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6675void QQuickTableView::moveColumn(
int source,
int destination)
6677 Q_D(QQuickTableView);
6678 d->moveSection(source, destination, Qt::Horizontal);
6681void QQuickTableView::moveRow(
int source,
int destination)
6683 Q_D(QQuickTableView);
6684 d->moveSection(source, destination, Qt::Vertical);
6687void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientation orientation)
6689 Q_Q(QQuickTableView);
6691 if (source < 0 || destination < 0 ||
6692 (orientation == Qt::Horizontal &&
6693 (source >= tableSize.width() || destination >= tableSize.width())) ||
6694 (orientation == Qt::Vertical &&
6695 (source >= tableSize.height() || destination >= tableSize.height())))
6698 if (source == destination)
6701 if (m_sectionState != SectionState::Moving) {
6702 m_sectionState = SectionState::Moving;
6704 syncView->d_func()->moveSection(source, destination, orientation);
6707 initializeIndexMapping();
6710 auto &visualIndices = visualIndicesForOrientation(orientation);
6711 auto &logicalIndices = logicalIndicesForOrientation(orientation);
6713 const int logical = logicalIndices.at(source).index;
6714 int visual = source;
6716 if (destination > source) {
6717 while (visual < destination) {
6718 SectionData &visualData = visualIndices[logicalIndices[visual + 1].index];
6719 SectionData &logicalData = logicalIndices[visual];
6720 visualData.prevIndex = visualData.index;
6721 visualData.index = visual;
6722 logicalData.prevIndex = logicalData.index;
6723 logicalData.index = logicalIndices[visual + 1].index;
6727 while (visual > destination) {
6728 SectionData &visualData = visualIndices[logicalIndices[visual - 1].index];
6729 SectionData &logicalData = logicalIndices[visual];
6730 visualData.prevIndex = visualData.index;
6731 visualData.index = visual;
6732 logicalData.prevIndex = logicalData.index;
6733 logicalData.index = logicalIndices[visual - 1].index;
6738 visualIndices[logical].prevIndex = visualIndices[logical].index;
6739 visualIndices[logical].index = destination;
6740 logicalIndices[destination].prevIndex = logicalIndices[destination].index;
6741 logicalIndices[destination].index = logical;
6745 for (
auto syncChild : std::as_const(syncChildren)) {
6746 auto syncChild_d = syncChild->d_func();
6747 if (syncChild_d->m_sectionState != SectionState::Moving &&
6748 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6749 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6750 syncChild_d->moveSection(source, destination, orientation);
6755 scheduleRebuildTable(RebuildOption::ViewportOnly);
6756 m_sectionState = SectionState::Idle;
6759 const int startIndex = (source > destination) ? destination : source;
6760 const int endIndex = (source > destination) ? source : destination;
6761 const auto &logicalDataIndices = syncView
6762 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6763 : logicalIndicesForOrientation(orientation);
6764 const auto &visualDataIndices = syncView
6765 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6766 : visualIndicesForOrientation(orientation);
6767 for (
int index = startIndex; index <= endIndex; index++) {
6768 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6769 if (orientation == Qt::Horizontal)
6770 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6772 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6777void QQuickTableView::clearColumnReordering()
6779 Q_D(QQuickTableView);
6780 d->clearSection(Qt::Horizontal);
6783void QQuickTableView::clearRowReordering()
6785 Q_D(QQuickTableView);
6786 d->clearSection(Qt::Vertical);
6789void QQuickTableViewPrivate::clearSection(Qt::Orientation orientation)
6791 Q_Q(QQuickTableView);
6793 const auto &oldLogicalIndices = syncView
6794 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6795 : logicalIndicesForOrientation(orientation);
6796 const auto &oldVisualIndices = syncView
6797 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6798 : visualIndicesForOrientation(orientation);
6801 syncView->d_func()->clearSection(orientation);
6804 logicalIndicesForOrientation(orientation).clear();
6805 visualIndicesForOrientation(orientation).clear();
6806 scheduleRebuildTable(RebuildOption::ViewportOnly);
6810 for (
int index = 0; index <
int(oldLogicalIndices.size()); index++) {
6811 const auto &logicalDataIndices = oldLogicalIndices;
6812 const auto &visualDataIndices = oldVisualIndices;
6813 if (logicalDataIndices[index].index != index) {
6814 const int currentIndex = logicalDataIndices[index].index;
6815 if (orientation == Qt::Horizontal)
6816 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6818 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6823void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6825 if (!modelIndex.isValid())
6828 const int cellIndex = modelIndexToCellIndex(modelIndex);
6829 if (!loadedItems.contains(cellIndex))
6831 const QPoint cell = cellAtModelIndex(cellIndex);
6832 QQuickItem *item = loadedTableItem(cell)->item;
6833 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6836QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6838 Q_D(
const QQuickTableView);
6839 const int modelIndex = d->modelIndexAtCell(cell);
6840 if (!d->loadedItems.contains(modelIndex))
6842 return d->loadedItems.value(modelIndex)->item;
6845#if QT_DEPRECATED_SINCE(6
, 5
)
6846QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6848 return itemAtCell(QPoint(column, row));
6852QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6854 Q_D(
const QQuickTableView);
6855 const int serializedIndex = d->modelIndexToCellIndex(index);
6856 if (!d->loadedItems.contains(serializedIndex))
6858 return d->loadedItems.value(serializedIndex)->item;
6861#if QT_DEPRECATED_SINCE(6
, 4
)
6862QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6864 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6867QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6869 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6873QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6875 return cellAtPosition(QPoint(x, y), includeSpacing);
6878QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6880 Q_D(
const QQuickTableView);
6882 if (!d->loadedTableOuterRect.contains(position))
6883 return QPoint(-1, -1);
6885 const qreal hSpace = d->cellSpacing.width();
6886 const qreal vSpace = d->cellSpacing.height();
6887 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6888 qreal currentRowEnd = d->loadedTableOuterRect.y();
6890 int foundColumn = -1;
6893 for (
const int column : d->loadedColumns) {
6894 currentColumnEnd += d->getEffectiveColumnWidth(column);
6895 if (position.x() < currentColumnEnd) {
6896 foundColumn = column;
6899 currentColumnEnd += hSpace;
6900 if (!includeSpacing && position.x() < currentColumnEnd) {
6902 return QPoint(-1, -1);
6903 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6904 foundColumn = column;
6909 for (
const int row : d->loadedRows) {
6910 currentRowEnd += d->getEffectiveRowHeight(row);
6911 if (position.y() < currentRowEnd) {
6915 currentRowEnd += vSpace;
6916 if (!includeSpacing && position.y() < currentRowEnd) {
6918 return QPoint(-1, -1);
6920 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6926 return QPoint(foundColumn, foundRow);
6929bool QQuickTableView::isColumnLoaded(
int column)
const
6931 Q_D(
const QQuickTableView);
6932 if (!d->loadedColumns.contains(column))
6935 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6938 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6945bool QQuickTableView::isRowLoaded(
int row)
const
6947 Q_D(
const QQuickTableView);
6948 if (!d->loadedRows.contains(row))
6951 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6954 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6961qreal QQuickTableView::columnWidth(
int column)
const
6963 Q_D(
const QQuickTableView);
6964 if (!isColumnLoaded(column))
6967 return d->getEffectiveColumnWidth(column);
6970qreal QQuickTableView::rowHeight(
int row)
const
6972 Q_D(
const QQuickTableView);
6973 if (!isRowLoaded(row))
6976 return d->getEffectiveRowHeight(row);
6979qreal QQuickTableView::implicitColumnWidth(
int column)
const
6981 Q_D(
const QQuickTableView);
6982 if (!isColumnLoaded(column))
6985 return d->sizeHintForColumn(column);
6988qreal QQuickTableView::implicitRowHeight(
int row)
const
6990 Q_D(
const QQuickTableView);
6991 if (!isRowLoaded(row))
6994 return d->sizeHintForRow(row);
6997void QQuickTableView::setColumnWidth(
int column, qreal size)
6999 Q_D(QQuickTableView);
7001 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
7005 if (d->syncHorizontally) {
7006 d->syncView->setColumnWidth(column, size);
7010 if (qFuzzyCompare(explicitColumnWidth(column), size))
7014 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
7016 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
7018 if (d->loadedItems.isEmpty())
7021 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
7022 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
7023 d->forceLayout(
false);
7026void QQuickTableView::clearColumnWidths()
7028 Q_D(QQuickTableView);
7030 if (d->syncHorizontally) {
7031 d->syncView->clearColumnWidths();
7035 if (d->explicitColumnWidths.isEmpty())
7038 d->explicitColumnWidths.clear();
7039 d->forceLayout(
false);
7042qreal QQuickTableView::explicitColumnWidth(
int column)
const
7044 Q_D(
const QQuickTableView);
7046 if (d->syncHorizontally)
7047 return d->syncView->explicitColumnWidth(column);
7049 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
7050 if (it != d->explicitColumnWidths.constEnd())
7055void QQuickTableView::setRowHeight(
int row, qreal size)
7057 Q_D(QQuickTableView);
7059 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
7063 if (d->syncVertically) {
7064 d->syncView->setRowHeight(row, size);
7068 if (qFuzzyCompare(explicitRowHeight(row), size))
7072 d->explicitRowHeights.remove(d->logicalRowIndex(row));
7074 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
7076 if (d->loadedItems.isEmpty())
7079 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
7080 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
7081 d->forceLayout(
false);
7084void QQuickTableView::clearRowHeights()
7086 Q_D(QQuickTableView);
7088 if (d->syncVertically) {
7089 d->syncView->clearRowHeights();
7093 if (d->explicitRowHeights.isEmpty())
7096 d->explicitRowHeights.clear();
7097 d->forceLayout(
false);
7100qreal QQuickTableView::explicitRowHeight(
int row)
const
7102 Q_D(
const QQuickTableView);
7104 if (d->syncVertically)
7105 return d->syncView->explicitRowHeight(row);
7107 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
7108 if (it != d->explicitRowHeights.constEnd())
7113QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
7115 Q_D(
const QQuickTableView);
7116 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
7119 auto const qaim = d->model->abstractItemModel();
7123 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
7126QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
7128 if (!index.isValid() || index.parent().isValid())
7130 Q_D(
const QQuickTableView);
7131 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
7134#if QT_DEPRECATED_SINCE(6
, 4
)
7135QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
7137 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
7143 return modelIndex({row, column});
7145 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
7146 "Use index(row, column) instead. For more information, see "
7147 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
7148 return modelIndex({column, row});
7153QModelIndex QQuickTableView::index(
int row,
int column)
const
7155 return modelIndex({column, row});
7158int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
7160 return cellAtIndex(index).y();
7163int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
7165 return cellAtIndex(index).x();
7168void QQuickTableView::forceLayout()
7170 d_func()->forceLayout(
true);
7173void QQuickTableView::edit(
const QModelIndex &requestedIndex)
7175 Q_D(QQuickTableView);
7178 if (!d->canEdit(requestedIndex,
true))
7181 const auto *aim = d->qaim(d->modelImpl());
7186 const QModelIndex index = aim->buddy(requestedIndex);
7188 if (d->editIndex == index)
7194 if (!d->editModel) {
7195 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
7196 d->editModel->useImportVersion(d->resolveImportVersion());
7197 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
this,
7198 [
this, d] (
int serializedModelIndex, QObject *object) {
7204 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
7205 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
7206 d->editItem = qmlobject_cast<QQuickItem*>(object);
7210 const bool init =
true;
7211 d->updateItemProperties(serializedModelIndex, object, init);
7212 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
7214 d->editItem->setParentItem(cellItem);
7221 if (d->selectionModel)
7222 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
7225 d->closeEditorAndCommit();
7227 const auto cellItem = itemAtCell(cellAtIndex(index));
7229 const auto attached = d->getAttachedObject(cellItem);
7232 d->editModel->setModel(d->tableModel->model());
7233 d->editModel->setDelegate(attached->editDelegate());
7235 const int cellIndex = d->getEditCellIndex(index);
7236 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
7238 d->editIndex = QModelIndex();
7239 d->editItem =
nullptr;
7240 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
7247 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
7248 d->editItem =
nullptr;
7249 d->editIndex = QModelIndex();
7250 d->editModel->release(object, QQmlInstanceModel::NotReusable);
7256 d->model->object(cellIndex, QQmlIncubator::Synchronous);
7259 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
7262 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
7263 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
7266void QQuickTableView::closeEditor()
7268 Q_D(QQuickTableView);
7273 QQuickItem *cellItem = d->editItem->parentItem();
7274 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
7275 d->editItem =
nullptr;
7278 const int cellIndex = d->getEditCellIndex(d->editIndex);
7279 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
7281 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
7283 if (d->editIndex.isValid()) {
7286 d->editIndex = QModelIndex();
7288#if QT_CONFIG(accessibility)
7290 d->accessibleFocusItem =
nullptr;
7291 d->updateAccessibleFocus();
7295QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
7297 return new QQuickTableViewAttached(obj);
7300void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
7302 Q_D(QQuickTableView);
7303 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
7305 if (d->tableModel) {
7308 d->tableModel->drainReusableItemsPool(0);
7311 d->forceLayout(
false);
7314void QQuickTableView::viewportMoved(Qt::Orientations orientation)
7316 Q_D(QQuickTableView);
7322 QQuickFlickable::viewportMoved(orientation);
7323 if (d->inSetLocalViewportPos)
7330 d->syncViewportPosRecursive();
7332 auto rootView = d->rootSyncView();
7333 auto rootView_d = rootView->d_func();
7335 rootView_d->scheduleRebuildIfFastFlick();
7337 if (!rootView_d->polishScheduled) {
7338 if (rootView_d->scheduledRebuildOptions) {
7345 const bool updated = rootView->d_func()->updateTableRecursive();
7355void QQuickTableView::keyPressEvent(QKeyEvent *e)
7357 Q_D(QQuickTableView);
7359 if (!d->keyNavigationEnabled) {
7360 QQuickFlickable::keyPressEvent(e);
7364 if (d->tableSize.isEmpty())
7367 if (d->editIndex.isValid()) {
7373 if (d->setCurrentIndexFromKeyEvent(e))
7376 if (d->editFromKeyEvent(e))
7379 QQuickFlickable::keyPressEvent(e);
7382bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
7384 Q_D(QQuickTableView);
7386 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
7389 return QQuickFlickable::eventFilter(obj, event);
7392 switch (event->type()) {
7393 case QEvent::KeyPress: {
7394 Q_ASSERT(d->editItem);
7395 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7396 switch (keyEvent->key()) {
7398 case Qt::Key_Return:
7399 d->closeEditorAndCommit();
7402 case Qt::Key_Backtab:
7403 if (activeFocusOnTab()) {
7404 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7405 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7406 if (d->canEdit(currentIndex,
false))
7412 case Qt::Key_Escape:
7417 case QEvent::FocusOut:
7420 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7421 d->closeEditorAndCommit();
7427 return QQuickFlickable::eventFilter(obj, event);
7430bool QQuickTableView::alternatingRows()
const
7432 return d_func()->alternatingRows;
7435void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7437 Q_D(QQuickTableView);
7438 if (d->alternatingRows == alternatingRows)
7441 d->alternatingRows = alternatingRows;
7442 emit alternatingRowsChanged();
7445QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7447 return d_func()->selectionBehavior;
7450void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7452 Q_D(QQuickTableView);
7453 if (d->selectionBehavior == selectionBehavior)
7456 d->selectionBehavior = selectionBehavior;
7457 emit selectionBehaviorChanged();
7460QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7462 return d_func()->selectionMode;
7465void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7467 Q_D(QQuickTableView);
7468 if (d->selectionMode == selectionMode)
7471 d->selectionMode = selectionMode;
7472 emit selectionModeChanged();
7475bool QQuickTableView::resizableColumns()
const
7477 return d_func()->resizableColumns;
7480void QQuickTableView::setResizableColumns(
bool enabled)
7482 Q_D(QQuickTableView);
7483 if (d->resizableColumns == enabled)
7486 d->resizableColumns = enabled;
7487 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7488 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7490 emit resizableColumnsChanged();
7493bool QQuickTableView::resizableRows()
const
7495 return d_func()->resizableRows;
7498void QQuickTableView::setResizableRows(
bool enabled)
7500 Q_D(QQuickTableView);
7501 if (d->resizableRows == enabled)
7504 d->resizableRows = enabled;
7505 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7506 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7508 emit resizableRowsChanged();
7513 : QQuickHoverHandler(view->contentItem())
7517 connect(
this, &QQuickHoverHandler::hoveredChanged,
this, [
this] {
7522#if QT_CONFIG(cursor)
7523 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7524 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7525 tableViewPrivate->updateCursor();
7532 QQuickHoverHandler::handleEventPoint(event, point);
7534 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7535#if QT_CONFIG(cursor)
7536 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7539 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7540 const auto item = tableView->itemAtCell(cell);
7544#if QT_CONFIG(cursor)
7545 tableViewPrivate->updateCursor();
7550 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7551 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7552 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7553 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7554 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7555#if QT_CONFIG(cursor)
7556 tableViewPrivate->updateCursor();
7567 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7572 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7576 if (event->type() == QEvent::Type::Wheel)
7581 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7582 return !tableView->isMoving();
7591 setObjectName(
"tableViewResizeHandler");
7595 , QPointingDevice::GrabTransition transition
7597 , QEventPoint &point)
7599 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7601 switch (transition) {
7602 case QPointingDevice::GrabPassive:
7603 case QPointingDevice::GrabExclusive:
7605 case QPointingDevice::UngrabPassive:
7606 case QPointingDevice::UngrabExclusive:
7607 case QPointingDevice::CancelGrabPassive:
7608 case QPointingDevice::CancelGrabExclusive:
7609 case QPointingDevice::OverrideGrabPassive:
7610 if (m_state == DraggingStarted || m_state == Dragging) {
7611 m_state = DraggingFinished;
7612 updateDrag(ev, point);
7620 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7621 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7622 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7629 updateDrag(event, point);
7634 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7635 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7637 if (m_state == DraggingFinished)
7638 m_state = Listening;
7640 if (point.state() == QEventPoint::Pressed) {
7641 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7642 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7643 if (m_row != -1 || m_column != -1)
7645 }
else if (point.state() == QEventPoint::Released) {
7646 if (m_state == DraggingStarted || m_state == Dragging)
7647 m_state = DraggingFinished;
7649 m_state = Listening;
7650 }
else if (point.state() == QEventPoint::Updated) {
7655 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7656 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7657 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7658 if (dragDist > qApp->styleHints()->startDragDistance())
7659 m_state = DraggingStarted;
7661 case DraggingStarted:
7666 case DraggingFinished:
7676 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7677#if QT_CONFIG(cursor)
7678 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7685 setPassiveGrab(event, point,
true);
7689 tableView->setFiltersChildMouseEvents(
false);
7690#if QT_CONFIG(cursor)
7691 tableViewPrivate->setActivePointerHandler(
this);
7694 case DraggingStarted:
7695 setExclusiveGrab(event, point,
true);
7696 m_columnStartX = point.position().x();
7697 m_columnStartWidth = tableView->columnWidth(m_column);
7698 m_rowStartY = point.position().y();
7699 m_rowStartHeight = tableView->rowHeight(m_row);
7700#if QT_CONFIG(cursor)
7701 tableViewPrivate->updateCursor();
7705 const qreal distX = point.position().x() - m_columnStartX;
7706 const qreal distY = point.position().y() - m_rowStartY;
7708 tableView->setColumnWidth(
m_column, qMax(0.001, m_columnStartWidth + distX));
7710 tableView->setRowHeight(
m_row, qMax(0.001, m_rowStartHeight + distY));
7712 case DraggingFinished: {
7713 tableView->setFiltersChildMouseEvents(
true);
7714#if QT_CONFIG(cursor)
7715 tableViewPrivate->setActivePointerHandler(
nullptr);
7716 tableViewPrivate->updateCursor();
7723#if QT_CONFIG(quick_draganddrop)
7725QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7726 : QQuickTableViewPointerHandler(view)
7728 setObjectName(
"tableViewDragHandler");
7731QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7736void QQuickTableViewSectionDragHandler::resetDragData()
7738 if (m_state != Listening) {
7739 m_state = Listening;
7740 resetSectionOverlay();
7743 if (m_grabResult.data())
7744 m_grabResult.data()->disconnect();
7745 if (!m_drag.isNull()) {
7746 m_drag->disconnect();
7749 if (!m_dropArea.isNull()) {
7750 m_dropArea->disconnect();
7753 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7754 tableView->setFiltersChildMouseEvents(
true);
7758void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7760 if (m_destination != -1) {
7761 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7762 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7763 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7764 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7765 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7770void QQuickTableViewSectionDragHandler::grabSection()
7773 QPixmap pixmap(m_grabResult->image().size());
7774 pixmap.fill(Qt::transparent);
7775 QPainter painter(&pixmap);
7776 painter.setOpacity(0.6);
7777 painter.drawImage(0, 0, m_grabResult->image());
7781 auto *mimeData =
new QMimeData();
7782 mimeData->setImageData(pixmap);
7783 m_drag->setMimeData(mimeData);
7784 m_drag->setPixmap(pixmap);
7787void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7791 if (m_state == Dragging) {
7792 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7793 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7794 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7795 m_state = DraggingFinished;
7796 resetSectionOverlay();
7797 if (m_scrollTimer.isActive())
7798 m_scrollTimer.stop();
7803void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7807 if (m_state == Dragging) {
7808 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7809 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7810 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7811 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7813 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7814 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7815 if (newDestination != m_destination) {
7817 resetSectionOverlay();
7819 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7820 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7821 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7822 m_destination = newDestination;
7826 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7827 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7828 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7829 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7830 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7831 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7832 if (useStartPos || useEndPos) {
7833 if (!m_scrollTimer.isActive()) {
7834 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7835 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7836 m_scrollTimer.start(1);
7839 if (m_scrollTimer.isActive())
7840 m_scrollTimer.stop();
7845void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7849 if (action == Qt::IgnoreAction) {
7850 resetSectionOverlay();
7851 if (m_scrollTimer.isActive())
7852 m_scrollTimer.stop();
7856void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7858 QQuickSinglePointHandler::handleEventPoint(event, point);
7860 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7861 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7862 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7863 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7866 if (m_state == DraggingFinished) {
7867 if (m_scrollTimer.isActive())
7868 m_scrollTimer.stop();
7872 if (point.state() == QEventPoint::Pressed) {
7876 setPassiveGrab(event, point,
true);
7880 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7881 tableView->setFiltersChildMouseEvents(
false);
7883 }
else if (point.state() == QEventPoint::Released) {
7885 if (m_scrollTimer.isActive())
7886 m_scrollTimer.stop();
7888 }
else if (point.state() == QEventPoint::Updated) {
7890 const qreal distX = point.position().x() - point.pressPosition().x();
7891 const qreal distY = point.position().y() - point.pressPosition().y();
7892 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7893 if (dragDist > qApp->styleHints()->startDragDistance()) {
7897 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7898 auto *item = tableView->itemAtCell(cell);
7901 if (m_drag.isNull()) {
7902 m_drag =
new QDrag(item);
7903 connect(m_drag.data(), &QDrag::actionChanged,
this,
7904 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7907 QObject::connect(&m_scrollTimer, &QTimer::timeout,
this, [&]{
7908 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7909 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7910 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7911 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7914 if (m_dropArea.isNull()) {
7915 m_dropArea =
new QQuickDropArea(tableView);
7916 m_dropArea->setSize(tableView->size());
7917 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7918 &QQuickTableViewSectionDragHandler::handleDrag);
7919 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7920 &QQuickTableViewSectionDragHandler::handleDrop);
7923 m_grabResult = item->grabToImage();
7924 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7925 &QQuickTableViewSectionDragHandler::grabSection);
7927 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7928 m_state = DraggingStarted;
7930 tableViewPrivate->setActivePointerHandler(
this);
7934 case DraggingStarted: {
7935 if (m_drag && m_drag->mimeData()) {
7936 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7938 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7940 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7944 if (m_state == Dragging)
7947 tableViewPrivate->setActivePointerHandler(
nullptr);
7961void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7963 if (!sectionDragHandler) {
7964 Q_Q(QQuickTableView);
7965 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7966 sectionDragHandler->setSectionOrientation(orientation);
7970void QQuickTableViewPrivate::destroySectionDragHandler()
7972 if (sectionDragHandler) {
7973 delete sectionDragHandler;
7974 sectionDragHandler =
nullptr;
7979void QQuickTableViewPrivate::initializeIndexMapping()
7981 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7982 visualIndex.resize(size);
7983 logicalIndex.resize(size);
7984 for (
int index = 0; index < size; ++index)
7985 visualIndex[index].index = logicalIndex[index].index = index;
7988 if (horizontalVisualIndices.size() != size_t(tableSize.width())
7989 || horizontalLogicalIndices.size() != size_t(tableSize.width()))
7990 initIndices(horizontalVisualIndices, horizontalLogicalIndices, tableSize.width());
7992 if (verticalVisualIndices.size() != size_t(tableSize.height())
7993 || verticalLogicalIndices.size() != size_t(tableSize.height()))
7994 initIndices(verticalVisualIndices, verticalLogicalIndices, tableSize.height());
7997void QQuickTableViewPrivate::clearIndexMapping()
7999 horizontalLogicalIndices.clear();
8000 horizontalVisualIndices.clear();
8002 verticalLogicalIndices.clear();
8003 verticalVisualIndices.clear();
8006int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
8009 return syncView->d_func()->logicalRowIndex(visualIndex);
8010 if (verticalLogicalIndices.empty() || visualIndex < 0)
8012 return verticalLogicalIndices.at(visualIndex).index;
8015int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
8018 return syncView->d_func()->logicalColumnIndex(visualIndex);
8019 if (horizontalLogicalIndices.empty() || visualIndex < 0)
8021 return horizontalLogicalIndices.at(visualIndex).index;
8024int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
8027 return syncView->d_func()->visualRowIndex(logicalIndex);
8028 if (verticalVisualIndices.empty() || logicalIndex < 0)
8029 return logicalIndex;
8030 return verticalVisualIndices.at(logicalIndex).index;
8033int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
8036 return syncView->d_func()->visualColumnIndex(logicalIndex);
8037 if (horizontalVisualIndices.empty() || logicalIndex < 0)
8038 return logicalIndex;
8039 return horizontalVisualIndices.at(logicalIndex).index;
8042int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
8046 const bool hasProxyModel = (modelImpl() != assignedModel);
8047 return modelIndexToCellIndex(index, hasProxyModel);
8053 : QQuickTapHandler(view->contentItem())
8055 setObjectName(
"tableViewTapHandler");
8060 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
8061 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
8062 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
8067#include "moc_qquicktableview_p.cpp"
8068#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)