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>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
385
386
387
388
389
390
391
392
393
394
397
398
399
400
401
402
403
404
405
406
407
408
411
412
413
414
415
416
419
420
421
422
423
424
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
475
476
477
478
479
480
481
482
483
484
485
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
541
542
543
544
545
546
547
548
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
625
626
627
628
629
630
633
634
635
636
637
638
641
642
643
644
645
646
649
650
651
652
653
654
657
658
659
660
661
662
663
664
665
666
667
670
671
672
673
674
675
676
677
678
679
680
683
684
685
686
687
688
689
690
691
692
693
694
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
718
719
720
721
722
723
724
725
726
727
728
729
730
733
734
735
736
737
738
739
740
741
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
791
792
793
794
795
796
799
800
801
802
803
804
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
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
917
918
919
920
923
924
925
926
927
928
929
930
931
932
933
934
937
938
939
940
941
942
943
944
945
946
947
948
949
952
953
954
955
956
957
958
959
960
961
962
963
964
967
968
969
970
971
974
975
976
977
978
979
980
981
982
983
986
987
988
989
990
991
992
993
994
995
998
999
1000
1001
1002
1003
1004
1005
1006
1009
1010
1011
1012
1013
1014
1015
1016
1019
1020
1021
1022
1023
1024
1025
1026
1027
1030
1031
1032
1033
1034
1035
1036
1037
1040
1041
1042
1043
1044
1045
1046
1047
1048
1051
1052
1053
1054
1055
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1076
1077
1078
1079
1080
1083
1084
1085
1086
1087
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1109
1110
1111
1112
1115
1116
1117
1118
1119
1120
1121
1122
1125
1126
1127
1128
1129
1130
1131
1132
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1207
1208
1209
1210
1211
1212
1213
1214
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1279
1280
1281
1282
1283
1284
1285
1286
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1351
1352
1353
1354
1355
1356
1357
1360
1361
1362
1363
1364
1365
1366
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1405
1406
1407
1408
1409
1410
1411
1412
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1431
1432
1433
1434
1435
1436
1437
1440
1441
1442
1443
1444
1445
1446
1449
1450
1451
1452
1453
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1571QQuickSelectable::~QQuickSelectable() { }
1575#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
1576#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
1589#define TV_REBUILDSTATE(STATE)
1590 case QQuickTableViewPrivate::RebuildState::STATE:
1591 dbg << QStringLiteral(#STATE); break;
1611#define TV_REBUILDOPTION(OPTION)
1612 if (options & QQuickTableViewPrivate::RebuildOption::OPTION)
1613 dbg << QStringLiteral(#OPTION)
1615 if (options == QQuickTableViewPrivate::RebuildOption::None) {
1616 dbg << QStringLiteral(
"None");
1632QQuickTableViewPrivate::EdgeRange::EdgeRange()
1633 : startIndex(kEdgeIndexNotSet)
1634 , endIndex(kEdgeIndexNotSet)
1638bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge,
int index)
1640 if (startIndex == kEdgeIndexNotSet)
1643 if (endIndex == kEdgeIndexAtEnd) {
1647 return index <= startIndex;
1649 case Qt::BottomEdge:
1650 return index >= startIndex;
1654 const int s = std::min(startIndex, endIndex);
1655 const int e = std::max(startIndex, endIndex);
1656 return index >= s && index <= e;
1659QQuickTableViewPrivate::QQuickTableViewPrivate()
1660 : QQuickFlickablePrivate()
1664QQuickTableViewPrivate::~QQuickTableViewPrivate()
1667 QQuickItem *cellItem = editItem->parentItem();
1669 editModel->dispose(editItem);
1670 tableModel->release(cellItem, QQmlInstanceModel::NotReusable);
1676 for (
auto *fxTableItem : loadedItems) {
1677 if (
auto item = fxTableItem->item) {
1678 if (fxTableItem->ownItem)
1680 else if (tableModel)
1681 tableModel->dispose(item);
1690QString QQuickTableViewPrivate::tableLayoutToString()
const
1692 if (loadedItems.isEmpty())
1693 return QLatin1String(
"table is empty!");
1694 return QString(QLatin1String(
"table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
1695 .arg(leftColumn()).arg(topRow())
1696 .arg(rightColumn()).arg(bottomRow())
1697 .arg(loadedItems.size())
1698 .arg(loadedTableOuterRect.x())
1699 .arg(loadedTableOuterRect.y())
1700 .arg(loadedTableOuterRect.width())
1701 .arg(loadedTableOuterRect.height());
1704void QQuickTableViewPrivate::dumpTable()
const
1706 auto listCopy = loadedItems.values();
1707 std::stable_sort(listCopy.begin(), listCopy.end(),
1708 [](
const FxTableItem *lhs,
const FxTableItem *rhs)
1709 {
return lhs->index < rhs->index; });
1711 qWarning() << QStringLiteral(
"******* TABLE DUMP *******");
1712 for (
int i = 0; i < listCopy.size(); ++i)
1713 qWarning() <<
static_cast<FxTableItem *>(listCopy.at(i))->cell;
1714 qWarning() << tableLayoutToString();
1716 const QString filename = QStringLiteral(
"QQuickTableView_dumptable_capture.png");
1717 const QString path = QDir::current().absoluteFilePath(filename);
1718 if (q_func()->window() && q_func()->window()->grabWindow().save(path))
1719 qWarning() <<
"Window capture saved to:" << path;
1722void QQuickTableViewPrivate::setRequiredProperty(
const char *property,
1723 const QVariant &value,
int serializedModelIndex, QObject *object,
bool init)
1725 Q_Q(QQuickTableView);
1727 QQmlTableInstanceModel *tableInstanceModel = qobject_cast<QQmlTableInstanceModel *>(model);
1728 if (!tableInstanceModel) {
1738 const QString propertyName = QString::fromUtf8(property);
1741 bool wasRequired =
false;
1742 if (object == editItem) {
1745 wasRequired = editModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1747 wasRequired = tableInstanceModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1750 QStringList propertyList = object->property(kRequiredProperties).toStringList();
1751 object->setProperty(kRequiredProperties, propertyList << propertyName);
1755 const QStringList propertyList = object->property(kRequiredProperties).toStringList();
1756 if (propertyList.contains(propertyName)) {
1757 const auto metaObject = object->metaObject();
1758 const int propertyIndex = metaObject->indexOfProperty(property);
1759 const auto metaProperty = metaObject->property(propertyIndex);
1760 metaProperty.write(object, value);
1770 const QModelIndex modelIndex = q->modelIndex(cellAtModelIndex(serializedModelIndex));
1771 if (modelIndex == editIndex) {
1772 const QStringList propertyList = editItem->property(kRequiredProperties).toStringList();
1773 if (propertyList.contains(propertyName)) {
1774 const auto metaObject = editItem->metaObject();
1775 const int propertyIndex = metaObject->indexOfProperty(property);
1776 const auto metaProperty = metaObject->property(propertyIndex);
1777 metaProperty.write(editItem, value);
1785QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget()
const
1787 return const_cast<QQuickTableView *>(q_func())->contentItem();
1790bool QQuickTableViewPrivate::hasSelection()
const
1792 return selectionModel && selectionModel->hasSelection();
1795bool QQuickTableViewPrivate::startSelection(
const QPointF &pos, Qt::KeyboardModifiers modifiers)
1797 Q_Q(QQuickTableView);
1798 if (!selectionModel) {
1799 if (warnNoSelectionModel)
1800 qmlWarning(q_func()) <<
"Cannot start selection: no SelectionModel assigned!";
1801 warnNoSelectionModel =
false;
1805 if (selectionBehavior == QQuickTableView::SelectionDisabled) {
1806 qmlWarning(q) <<
"Cannot start selection: TableView.selectionBehavior == TableView.SelectionDisabled";
1811 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
1817 if (selectionMode == QQuickTableView::SingleSelection
1818 || selectionMode == QQuickTableView::ContiguousSelection
1819 || modifiers == Qt::NoModifier)
1821 else if (selectionModel)
1822 existingSelection = selectionModel->selection();
1828 selectionFlag = QItemSelectionModel::Select;
1829 if (modifiers & Qt::ControlModifier) {
1830 QPoint startCell = clampedCellAtPos(pos);
1831 if (!cellIsValid(startCell))
1833 const QModelIndex startIndex = q->index(startCell.y(), startCell.x());
1834 if (selectionModel->isSelected(startIndex))
1835 selectionFlag = QItemSelectionModel::Deselect;
1838 selectionStartCell = QPoint(-1, -1);
1839 selectionEndCell = QPoint(-1, -1);
1840 closeEditorAndCommit();
1844void QQuickTableViewPrivate::setSelectionStartPos(
const QPointF &pos)
1846 Q_Q(QQuickTableView);
1847 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1848 if (loadedItems.isEmpty())
1850 if (!selectionModel) {
1851 if (warnNoSelectionModel)
1852 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1853 warnNoSelectionModel =
false;
1856 const QAbstractItemModel *qaim = selectionModel->model();
1860 if (selectionMode == QQuickTableView::SingleSelection
1861 && cellIsValid(selectionStartCell)) {
1865 const QRect prevSelection = selection();
1868 if (pos.x() == -1) {
1870 clampedCell = q->cellAtIndex(selectionModel->currentIndex());
1872 clampedCell = clampedCellAtPos(pos);
1873 if (cellIsValid(clampedCell))
1874 setCurrentIndex(clampedCell);
1877 if (!cellIsValid(clampedCell))
1880 switch (selectionBehavior) {
1881 case QQuickTableView::SelectCells:
1882 selectionStartCell = clampedCell;
1884 case QQuickTableView::SelectRows:
1885 selectionStartCell = QPoint(0, clampedCell.y());
1887 case QQuickTableView::SelectColumns:
1888 selectionStartCell = QPoint(clampedCell.x(), 0);
1890 case QQuickTableView::SelectionDisabled:
1894 if (!cellIsValid(selectionEndCell))
1898 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1899 updateSelection(prevSelection, selection());
1902void QQuickTableViewPrivate::setSelectionEndPos(
const QPointF &pos)
1904 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1905 if (loadedItems.isEmpty())
1907 if (!selectionModel) {
1908 if (warnNoSelectionModel)
1909 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1910 warnNoSelectionModel =
false;
1913 const QAbstractItemModel *qaim = selectionModel->model();
1917 const QRect prevSelection = selection();
1920 if (selectionMode == QQuickTableView::SingleSelection) {
1921 clampedCell = selectionStartCell;
1923 clampedCell = clampedCellAtPos(pos);
1924 if (!cellIsValid(clampedCell))
1928 setCurrentIndex(clampedCell);
1930 switch (selectionBehavior) {
1931 case QQuickTableView::SelectCells:
1932 selectionEndCell = clampedCell;
1934 case QQuickTableView::SelectRows:
1935 selectionEndCell = QPoint(tableSize.width() - 1, clampedCell.y());
1937 case QQuickTableView::SelectColumns:
1938 selectionEndCell = QPoint(clampedCell.x(), tableSize.height() - 1);
1940 case QQuickTableView::SelectionDisabled:
1944 if (!cellIsValid(selectionStartCell))
1948 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1949 updateSelection(prevSelection, selection());
1952QPoint QQuickTableViewPrivate::clampedCellAtPos(
const QPointF &pos)
const
1954 Q_Q(
const QQuickTableView);
1957 QPoint cell = q->cellAtPosition(pos,
true);
1958 if (cellIsValid(cell))
1961 if (loadedTableOuterRect.width() == 0 || loadedTableOuterRect.height() == 0)
1962 return QPoint(-1, -1);
1966 qBound(loadedTableOuterRect.x(), pos.x(), loadedTableOuterRect.right() - 1),
1967 qBound(loadedTableOuterRect.y(), pos.y(), loadedTableOuterRect.bottom() - 1));
1968 QPointF clampedPosInView = q->mapFromItem(selectionPointerHandlerTarget(), clampedPos);
1969 clampedPosInView.rx() = qBound(0., clampedPosInView.x(), viewportRect.width());
1970 clampedPosInView.ry() = qBound(0., clampedPosInView.y(), viewportRect.height());
1971 clampedPos = q->mapToItem(selectionPointerHandlerTarget(), clampedPosInView);
1973 return q->cellAtPosition(clampedPos,
true);
1976void QQuickTableViewPrivate::updateSelection(
const QRect &oldSelection,
const QRect &newSelection)
1978 const QAbstractItemModel *qaim = selectionModel->model();
1979 const QRect oldRect = oldSelection.normalized();
1980 const QRect newRect = newSelection.normalized();
1982 QItemSelection select;
1983 QItemSelection deselect;
1987 const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
1988 const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
1989 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
1990 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
1991 select.append(QItemSelection(logicalModelIndex, logicalModelIndex));
1996 if (oldRect.x() < newRect.x()) {
1997 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
1998 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
1999 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2000 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2001 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2003 }
else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
2004 const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
2005 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2006 for (
auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2007 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2008 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2012 if (oldRect.y() < newRect.y()) {
2013 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2014 const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
2015 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2016 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2017 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2019 }
else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
2020 const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
2021 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2022 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2023 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2024 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2028 if (selectionFlag == QItemSelectionModel::Select) {
2030 deselect.merge(existingSelection, QItemSelectionModel::Deselect);
2031 selectionModel->select(deselect, QItemSelectionModel::Deselect);
2032 selectionModel->select(select, QItemSelectionModel::Select);
2033 }
else if (selectionFlag == QItemSelectionModel::Deselect){
2034 QItemSelection oldSelection = existingSelection;
2035 oldSelection.merge(select, QItemSelectionModel::Deselect);
2036 selectionModel->select(oldSelection, QItemSelectionModel::Select);
2037 selectionModel->select(select, QItemSelectionModel::Deselect);
2043void QQuickTableViewPrivate::cancelSelectionTracking()
2046 selectionStartCell = QPoint(-1, -1);
2047 selectionEndCell = QPoint(-1, -1);
2048 existingSelection.clear();
2049 selectionFlag = QItemSelectionModel::NoUpdate;
2050 if (selectableCallbackFunction)
2051 selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
2054void QQuickTableViewPrivate::clearSelection()
2056 if (!selectionModel)
2058 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2059 selectionModel->clearSelection();
2062void QQuickTableViewPrivate::normalizeSelection()
2068 if (selectionEndCell.x() < selectionStartCell.x())
2069 std::swap(selectionStartCell.rx(), selectionEndCell.rx());
2070 if (selectionEndCell.y() < selectionStartCell.y())
2071 std::swap(selectionStartCell.ry(), selectionEndCell.ry());
2074QRectF QQuickTableViewPrivate::selectionRectangle()
const
2076 Q_Q(
const QQuickTableView);
2078 if (loadedColumns.isEmpty() || loadedRows.isEmpty())
2081 QPoint topLeftCell = selectionStartCell;
2082 QPoint bottomRightCell = selectionEndCell;
2083 if (bottomRightCell.x() < topLeftCell.x())
2084 std::swap(topLeftCell.rx(), bottomRightCell.rx());
2085 if (selectionEndCell.y() < topLeftCell.y())
2086 std::swap(topLeftCell.ry(), bottomRightCell.ry());
2088 const QPoint leftCell(topLeftCell.x(), topRow());
2089 const QPoint topCell(leftColumn(), topLeftCell.y());
2090 const QPoint rightCell(bottomRightCell.x(), topRow());
2091 const QPoint bottomCell(leftColumn(), bottomRightCell.y());
2104 if (loadedItems.contains(modelIndexAtCell(leftCell)))
2105 left = loadedTableItem(leftCell)->geometry().left();
2106 else if (leftCell.x() > rightColumn())
2107 left = q->contentWidth();
2109 if (loadedItems.contains(modelIndexAtCell(topCell)))
2110 top = loadedTableItem(topCell)->geometry().top();
2111 else if (topCell.y() > bottomRow())
2112 top = q->contentHeight();
2114 if (loadedItems.contains(modelIndexAtCell(rightCell)))
2115 right = loadedTableItem(rightCell)->geometry().right();
2116 else if (rightCell.x() > rightColumn())
2117 right = q->contentWidth();
2119 if (loadedItems.contains(modelIndexAtCell(bottomCell)))
2120 bottom = loadedTableItem(bottomCell)->geometry().bottom();
2121 else if (bottomCell.y() > bottomRow())
2122 bottom = q->contentHeight();
2124 return QRectF(left, top, right - left, bottom - top);
2127QRect QQuickTableViewPrivate::selection()
const
2129 const qreal w = selectionEndCell.x() - selectionStartCell.x();
2130 const qreal h = selectionEndCell.y() - selectionStartCell.y();
2131 return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
2134QSizeF QQuickTableViewPrivate::scrollTowardsPoint(
const QPointF &pos,
const QSizeF &step)
2136 Q_Q(QQuickTableView);
2138 if (loadedItems.isEmpty())
2148 const bool outsideLeft = pos.x() < viewportRect.x();
2149 const bool outsideRight = pos.x() >= viewportRect.right() - 1;
2150 const bool outsideTop = pos.y() < viewportRect.y();
2151 const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
2154 const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
2155 const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
2156 if (remainingDist > 0 || !firstColumnLoaded) {
2157 qreal stepX = step.width();
2158 if (firstColumnLoaded)
2159 stepX = qMin(stepX, remainingDist);
2160 q->setContentX(q->contentX() - stepX);
2161 dist.setWidth(pos.x() - viewportRect.left() - 1);
2163 }
else if (outsideRight) {
2164 const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
2165 const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
2166 if (remainingDist > 0 || !lastColumnLoaded) {
2167 qreal stepX = step.width();
2168 if (lastColumnLoaded)
2169 stepX = qMin(stepX, remainingDist);
2170 q->setContentX(q->contentX() + stepX);
2171 dist.setWidth(pos.x() - viewportRect.right() - 1);
2176 const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
2177 const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
2178 if (remainingDist > 0 || !firstRowLoaded) {
2179 qreal stepY = step.height();
2181 stepY = qMin(stepY, remainingDist);
2182 q->setContentY(q->contentY() - stepY);
2183 dist.setHeight(pos.y() - viewportRect.top() - 1);
2185 }
else if (outsideBottom) {
2186 const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
2187 const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
2188 if (remainingDist > 0 || !lastRowLoaded) {
2189 qreal stepY = step.height();
2191 stepY = qMin(stepY, remainingDist);
2192 q->setContentY(q->contentY() + stepY);
2193 dist.setHeight(pos.y() - viewportRect.bottom() - 1);
2200void QQuickTableViewPrivate::setCallback(std::function<
void (CallBackFlag)> func)
2202 selectableCallbackFunction = func;
2205QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(
const QObject *object)
const
2207 QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object,
false);
2208 return static_cast<QQuickTableViewAttached *>(attachedObject);
2211QQuickTableViewAttached::QQuickTableViewAttached(QObject *parent)
2214 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
2221 for (
int i = 0; i < 3; ++i) {
2222 parentItem = parentItem->parentItem();
2225 if (
auto tableView = qobject_cast<QQuickTableView *>(parentItem)) {
2232int QQuickTableViewPrivate::modelIndexAtCell(
const QPoint &cell)
const
2238 int availableColumns = tableSize.width();
2239 return (cell.y() * availableColumns) + cell.x();
2241 int availableRows = tableSize.height();
2242 return (cell.x() * availableRows) + cell.y();
2246QPoint QQuickTableViewPrivate::cellAtModelIndex(
int modelIndex)
const
2252 int availableColumns = tableSize.width();
2253 int row =
int(modelIndex / availableColumns);
2254 int column = modelIndex % availableColumns;
2255 return QPoint(column, row);
2257 int availableRows = tableSize.height();
2258 int column =
int(modelIndex / availableRows);
2259 int row = modelIndex % availableRows;
2260 return QPoint(column, row);
2264int QQuickTableViewPrivate::modelIndexToCellIndex(
const QModelIndex &modelIndex,
bool visualIndex)
const
2268 const QPoint cell = q_func()->cellAtIndex(modelIndex);
2269 if (!cellIsValid(cell))
2271 return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
2274int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
const
2276 return int(log2(
float(edge)));
2279void QQuickTableViewPrivate::clearEdgeSizeCache()
2281 cachedColumnWidth.startIndex = kEdgeIndexNotSet;
2282 cachedRowHeight.startIndex = kEdgeIndexNotSet;
2284 for (Qt::Edge edge : allTableEdges)
2285 cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
2288int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
const
2292 int startIndex = -1;
2294 case Qt::LeftEdge: startIndex = leftColumn() - 1;
break;
2295 case Qt::RightEdge: startIndex = rightColumn() + 1;
break;
2296 case Qt::TopEdge: startIndex = topRow() - 1;
break;
2297 case Qt::BottomEdge: startIndex = bottomRow() + 1;
break;
2300 return nextVisibleEdgeIndex(edge, startIndex);
2303int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge,
int startIndex)
const
2309 auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
2310 if (cachedResult.containsIndex(edge, startIndex))
2311 return cachedResult.endIndex;
2315 int foundIndex = kEdgeIndexNotSet;
2316 int testIndex = startIndex;
2319 case Qt::LeftEdge: {
2321 if (testIndex < 0) {
2322 foundIndex = kEdgeIndexAtEnd;
2326 if (!isColumnHidden(testIndex)) {
2327 foundIndex = testIndex;
2334 case Qt::RightEdge: {
2336 if (testIndex > tableSize.width() - 1) {
2337 foundIndex = kEdgeIndexAtEnd;
2341 if (!isColumnHidden(testIndex)) {
2342 foundIndex = testIndex;
2351 if (testIndex < 0) {
2352 foundIndex = kEdgeIndexAtEnd;
2356 if (!isRowHidden(testIndex)) {
2357 foundIndex = testIndex;
2364 case Qt::BottomEdge: {
2366 if (testIndex > tableSize.height() - 1) {
2367 foundIndex = kEdgeIndexAtEnd;
2371 if (!isRowHidden(testIndex)) {
2372 foundIndex = testIndex;
2381 cachedResult.startIndex = startIndex;
2382 cachedResult.endIndex = foundIndex;
2386void QQuickTableViewPrivate::updateContentWidth()
2397 Q_Q(QQuickTableView);
2399 if (syncHorizontally) {
2400 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2401 q->QQuickFlickable::setContentWidth(syncView->contentWidth());
2405 if (explicitContentWidth.isValid()) {
2411 if (loadedItems.isEmpty()) {
2412 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2413 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2414 q->QQuickFlickable::setContentWidth(kDefaultColumnWidth);
2416 q->QQuickFlickable::setContentWidth(0);
2420 const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2421 const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
2422 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2423 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2424 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2425 const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
2427 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2428 q->QQuickFlickable::setContentWidth(estimatedWidth);
2431void QQuickTableViewPrivate::updateContentHeight()
2433 Q_Q(QQuickTableView);
2435 if (syncVertically) {
2436 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2437 q->QQuickFlickable::setContentHeight(syncView->contentHeight());
2441 if (explicitContentHeight.isValid()) {
2447 if (loadedItems.isEmpty()) {
2448 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2449 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2450 q->QQuickFlickable::setContentHeight(kDefaultRowHeight);
2452 q->QQuickFlickable::setContentHeight(0);
2456 const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2457 const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
2458 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2459 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2460 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2461 const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
2463 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2464 q->QQuickFlickable::setContentHeight(estimatedHeight);
2467void QQuickTableViewPrivate::updateExtents()
2480 Q_Q(QQuickTableView);
2482 bool tableMovedHorizontally =
false;
2483 bool tableMovedVertically =
false;
2485 const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
2486 const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2487 const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
2488 const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2490 QPointF prevOrigin = origin;
2491 QSizeF prevEndExtent = endExtent;
2493 if (syncHorizontally) {
2494 const auto syncView_d = syncView->d_func();
2495 origin.rx() = syncView_d->origin.x();
2496 endExtent.rwidth() = syncView_d->endExtent.width();
2497 }
else if (nextLeftColumn == kEdgeIndexAtEnd) {
2500 if (loadedTableOuterRect.left() > viewportRect.left()) {
2505 if (loadedTableOuterRect.left() > origin.x()) {
2506 const qreal diff = loadedTableOuterRect.left() - origin.x();
2507 loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
2508 loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
2509 tableMovedHorizontally =
true;
2512 origin.rx() = loadedTableOuterRect.left();
2513 }
else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
2517 const int columnsRemaining = nextLeftColumn + 1;
2518 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2519 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2520 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2521 origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
2522 }
else if (nextRightColumn == kEdgeIndexAtEnd) {
2525 if (loadedTableOuterRect.right() < viewportRect.right()) {
2530 const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
2531 if (loadedTableOuterRect.right() < w) {
2532 const qreal diff = loadedTableOuterRect.right() - w;
2533 loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
2534 loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
2535 tableMovedHorizontally =
true;
2538 endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
2539 }
else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
2543 const int columnsRemaining = tableSize.width() - nextRightColumn;
2544 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2545 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2546 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2547 const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
2548 endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
2551 if (syncVertically) {
2552 const auto syncView_d = syncView->d_func();
2553 origin.ry() = syncView_d->origin.y();
2554 endExtent.rheight() = syncView_d->endExtent.height();
2555 }
else if (nextTopRow == kEdgeIndexAtEnd) {
2558 if (loadedTableOuterRect.top() > viewportRect.top()) {
2563 if (loadedTableOuterRect.top() > origin.y()) {
2564 const qreal diff = loadedTableOuterRect.top() - origin.y();
2565 loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
2566 loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
2567 tableMovedVertically =
true;
2570 origin.ry() = loadedTableOuterRect.top();
2571 }
else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
2575 const int rowsRemaining = nextTopRow + 1;
2576 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2577 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2578 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2579 origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
2580 }
else if (nextBottomRow == kEdgeIndexAtEnd) {
2583 if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
2588 const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
2589 if (loadedTableOuterRect.bottom() < h) {
2590 const qreal diff = loadedTableOuterRect.bottom() - h;
2591 loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
2592 loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
2593 tableMovedVertically =
true;
2596 endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
2597 }
else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
2601 const int rowsRemaining = tableSize.height() - nextBottomRow;
2602 const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
2603 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2604 const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
2605 const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
2606 endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
2609 if (tableMovedHorizontally || tableMovedVertically) {
2610 qCDebug(lcTableViewDelegateLifecycle) <<
"move table to" << loadedTableOuterRect;
2614 relayoutTableItems();
2617 for (
auto syncChild : std::as_const(syncChildren)) {
2618 auto syncChild_d = syncChild->d_func();
2619 syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
2620 if (tableMovedHorizontally)
2621 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
2622 if (tableMovedVertically)
2623 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
2627 if (prevOrigin != origin || prevEndExtent != endExtent) {
2628 if (prevOrigin != origin)
2629 qCDebug(lcTableViewDelegateLifecycle) <<
"move origin to:" << origin;
2630 if (prevEndExtent != endExtent)
2631 qCDebug(lcTableViewDelegateLifecycle) <<
"move endExtent to:" << endExtent;
2635 hData.markExtentsDirty();
2636 vData.markExtentsDirty();
2637 updateBeginningEnd();
2638 if (!q->isMoving()) {
2642 q->returnToBounds();
2647void QQuickTableViewPrivate::updateAverageColumnWidth()
2649 if (explicitContentWidth.isValid()) {
2650 const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
2651 averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
2653 const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
2654 averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
2658void QQuickTableViewPrivate::updateAverageRowHeight()
2660 if (explicitContentHeight.isValid()) {
2661 const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
2662 averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
2664 const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
2665 averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
2669void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
2671 const QPoint topLeft = QPoint(leftColumn(), topRow());
2672 const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
2673 QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
2674 QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
2675 loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
2676 loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
2679QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
2685 if (loadedItems.isEmpty()) {
2687 return RebuildOption::None;
2690 RebuildOptions rebuildOptions = RebuildOption::None;
2692 if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
2696 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2697 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2702 for (
int column = leftColumn(); column <= rightColumn(); ++column) {
2703 const bool wasVisibleFromBefore = loadedColumns.contains(column);
2704 const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
2705 if (wasVisibleFromBefore == isVisibleNow)
2710 qCDebug(lcTableViewDelegateLifecycle) <<
"Column" << column <<
"changed visibility to" << isVisibleNow;
2711 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2712 if (column == leftColumn()) {
2715 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2721 if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
2725 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2726 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2731 for (
int row = topRow(); row <= bottomRow(); ++row) {
2732 const bool wasVisibleFromBefore = loadedRows.contains(row);
2733 const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
2734 if (wasVisibleFromBefore == isVisibleNow)
2739 qCDebug(lcTableViewDelegateLifecycle) <<
"Row" << row <<
"changed visibility to" << isVisibleNow;
2740 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2741 if (row == topRow())
2742 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2747 return rebuildOptions;
2750void QQuickTableViewPrivate::forceLayout(
bool immediate)
2752 clearEdgeSizeCache();
2753 RebuildOptions rebuildOptions = RebuildOption::None;
2755 const QSize actualTableSize = calculateTableSize();
2756 if (tableSize != actualTableSize) {
2760 rebuildOptions |= RebuildOption::ViewportOnly;
2768 rebuildOptions |= RebuildOption::LayoutOnly
2769 | RebuildOption::CalculateNewContentWidth
2770 | RebuildOption::CalculateNewContentHeight
2771 | checkForVisibilityChanges();
2773 scheduleRebuildTable(rebuildOptions);
2776 auto rootView = rootSyncView();
2777 const bool updated = rootView->d_func()->updateTableRecursive();
2779 qWarning() <<
"TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
2785void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
2787 if (loadRequest.edge() == Qt::Edge(0)) {
2789 loadedColumns.insert(loadRequest.column());
2790 loadedRows.insert(loadRequest.row());
2794 switch (loadRequest.edge()) {
2797 loadedColumns.insert(loadRequest.column());
2800 case Qt::BottomEdge:
2801 loadedRows.insert(loadRequest.row());
2806FxTableItem *QQuickTableViewPrivate::loadedTableItem(
const QPoint &cell)
const
2808 const int modelIndex = modelIndexAtCell(cell);
2810 return loadedItems.value(modelIndex);
2813FxTableItem *QQuickTableViewPrivate::createFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2815 Q_Q(QQuickTableView);
2817 bool ownItem =
false;
2819 int modelIndex = modelIndexAtCell(isTransposed ? QPoint(logicalRowIndex(cell.x()), logicalColumnIndex(cell.y())) :
2820 QPoint(logicalColumnIndex(cell.x()), logicalRowIndex(cell.y())));
2822 QObject* object = model->object(modelIndex, incubationMode);
2824 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2830 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2831 object =
new QQuickItem();
2835 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2839 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2840 model->release(object);
2841 item =
new QQuickItem();
2844 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2845 if (anchors && anchors->activeDirections())
2846 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2847 <<
". Use implicitWidth and implicitHeight instead.";
2854 item->setImplicitWidth(kDefaultColumnWidth);
2855 item->setImplicitHeight(kDefaultRowHeight);
2856 item->setParentItem(q->contentItem());
2860 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
2861 fxTableItem->setVisible(
false);
2862 fxTableItem->cell = cell;
2863 fxTableItem->index = modelIndex;
2867FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2872 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
2874 incubationMode = QQmlIncubator::Asynchronous;
2879 QScopedValueRollback guard(blockItemCreatedCallback,
true);
2880 auto item = createFxTableItem(cell, incubationMode);
2881 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
2885void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
2888 auto const tmpList = loadedItems;
2889 loadedItems.clear();
2890 for (FxTableItem *item : tmpList)
2891 releaseItem(item, reusableFlag);
2894void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
2896 Q_Q(QQuickTableView);
2899 auto item = fxTableItem->item;
2901 if (fxTableItem->ownItem) {
2905 auto releaseFlag = model->release(item, reusableFlag);
2906 if (releaseFlag == QQmlInstanceModel::Pooled) {
2907 fxTableItem->setVisible(
false);
2911 if (QQuickWindow *window = item->window()) {
2912 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
2914 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
2916 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
2917 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
2927void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
2929 const int modelIndex = modelIndexAtCell(cell);
2931 releaseItem(loadedItems.take(modelIndex), reusableFlag);
2934bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2936 switch (tableEdge) {
2938 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
2940 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
2942 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
2943 case Qt::BottomEdge:
2944 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
2950bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2956 switch (tableEdge) {
2958 if (loadedColumns.count() <= 1)
2960 if (positionXAnimation.isRunning()) {
2961 const qreal to = positionXAnimation.to().toFloat();
2962 if (to < viewportRect.x())
2965 return loadedTableInnerRect.left() <= fillRect.left();
2967 if (loadedColumns.count() <= 1)
2969 if (positionXAnimation.isRunning()) {
2970 const qreal to = positionXAnimation.to().toFloat();
2971 if (to > viewportRect.x())
2974 return loadedTableInnerRect.right() >= fillRect.right();
2976 if (loadedRows.count() <= 1)
2978 if (positionYAnimation.isRunning()) {
2979 const qreal to = positionYAnimation.to().toFloat();
2980 if (to < viewportRect.y())
2983 return loadedTableInnerRect.top() <= fillRect.top();
2984 case Qt::BottomEdge:
2985 if (loadedRows.count() <= 1)
2987 if (positionYAnimation.isRunning()) {
2988 const qreal to = positionYAnimation.to().toFloat();
2989 if (to > viewportRect.y())
2992 return loadedTableInnerRect.bottom() >= fillRect.bottom();
2998Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
3000 for (Qt::Edge edge : allTableEdges) {
3001 if (!canLoadTableEdge(edge, rect))
3003 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3004 if (nextIndex == kEdgeIndexAtEnd)
3012Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3014 for (Qt::Edge edge : allTableEdges) {
3015 if (canUnloadTableEdge(edge, rect))
3021qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3025 auto const cellItem = loadedTableItem(cell)->item;
3026 return cellItem->implicitWidth();
3029qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3033 auto const cellItem = loadedTableItem(cell)->item;
3034 return cellItem->implicitHeight();
3037qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3040 qreal columnWidth = 0;
3041 for (
const int row : loadedRows)
3042 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3047qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3050 qreal rowHeight = 0;
3051 for (
const int column : loadedColumns)
3052 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3056QSize QQuickTableViewPrivate::calculateTableSize()
3060 size = QSize(tableModel->columns(), tableModel->rows());
3062 size = QSize(1, model->count());
3064 return isTransposed ? size.transposed() : size;
3067qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3074 const qreal explicitColumnWidth = getColumnWidth(column);
3075 if (explicitColumnWidth >= 0)
3076 return explicitColumnWidth;
3078 if (syncHorizontally) {
3079 if (syncView->d_func()->loadedColumns.contains(column))
3080 return syncView->d_func()->getColumnLayoutWidth(column);
3088 qreal columnWidth = sizeHintForColumn(column);
3090 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3091 if (!layoutWarningIssued) {
3092 layoutWarningIssued =
true;
3093 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3095 columnWidth = kDefaultColumnWidth;
3101qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3105 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3108qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3112 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3115qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3119 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3122qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3126 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3129qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3136 const qreal explicitRowHeight = getRowHeight(row);
3137 if (explicitRowHeight >= 0)
3138 return explicitRowHeight;
3140 if (syncVertically) {
3141 if (syncView->d_func()->loadedRows.contains(row))
3142 return syncView->d_func()->getRowLayoutHeight(row);
3150 qreal rowHeight = sizeHintForRow(row);
3152 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3153 if (!layoutWarningIssued) {
3154 layoutWarningIssued =
true;
3155 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3157 rowHeight = kDefaultRowHeight;
3163qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3169 Q_Q(
const QQuickTableView);
3171 const int noExplicitColumnWidth = -1;
3173 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3174 return cachedColumnWidth.size;
3176 if (syncHorizontally)
3177 return syncView->d_func()->getColumnWidth(column);
3179 if (columnWidthProvider.isUndefined()) {
3183 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3184 if (explicitColumnWidth >= 0)
3185 return explicitColumnWidth;
3186 return noExplicitColumnWidth;
3189 qreal columnWidth = noExplicitColumnWidth;
3191 if (columnWidthProvider.isCallable()) {
3192 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3193 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3194 if (qIsNaN(columnWidth) || columnWidth < 0)
3195 columnWidth = noExplicitColumnWidth;
3197 if (!layoutWarningIssued) {
3198 layoutWarningIssued =
true;
3199 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3201 columnWidth = noExplicitColumnWidth;
3204 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3205 cachedColumnWidth.size = columnWidth;
3209qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3215 Q_Q(
const QQuickTableView);
3217 const int noExplicitRowHeight = -1;
3219 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3220 return cachedRowHeight.size;
3223 return syncView->d_func()->getRowHeight(row);
3225 if (rowHeightProvider.isUndefined()) {
3229 qreal explicitRowHeight = q->explicitRowHeight(row);
3230 if (explicitRowHeight >= 0)
3231 return explicitRowHeight;
3232 return noExplicitRowHeight;
3235 qreal rowHeight = noExplicitRowHeight;
3237 if (rowHeightProvider.isCallable()) {
3238 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3239 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3240 if (qIsNaN(rowHeight) || rowHeight < 0)
3241 rowHeight = noExplicitRowHeight;
3243 if (!layoutWarningIssued) {
3244 layoutWarningIssued =
true;
3245 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3247 rowHeight = noExplicitRowHeight;
3250 cachedRowHeight.startIndex = logicalRowIndex(row);
3251 cachedRowHeight.size = rowHeight;
3255qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3257 Q_Q(QQuickTableView);
3260 const int columnX = getEffectiveColumnX(column);
3262 if (subRect.isValid()) {
3263 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3266 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3269 if (alignment & Qt::AlignLeft) {
3270 contentX = columnX + subRect.x() + offset;
3271 }
else if (alignment & Qt::AlignRight) {
3272 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3273 }
else if (alignment & Qt::AlignHCenter) {
3274 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3275 contentX = columnX + subRect.x() - centerDistance + offset;
3278 const int columnWidth = getEffectiveColumnWidth(column);
3279 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3280 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3282 if (alignment & Qt::AlignLeft) {
3283 contentX = columnX + offset;
3284 }
else if (alignment & Qt::AlignRight) {
3285 contentX = columnX + columnWidth - viewportRect.width() + offset;
3286 }
else if (alignment & Qt::AlignHCenter) {
3287 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3288 contentX = columnX - centerDistance + offset;
3293 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3298qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3300 Q_Q(QQuickTableView);
3303 const int rowY = getEffectiveRowY(row);
3305 if (subRect.isValid()) {
3306 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3309 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3312 if (alignment & Qt::AlignTop) {
3313 contentY = rowY + subRect.y() + offset;
3314 }
else if (alignment & Qt::AlignBottom) {
3315 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3316 }
else if (alignment & Qt::AlignVCenter) {
3317 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3318 contentY = rowY + subRect.y() - centerDistance + offset;
3321 const int rowHeight = getEffectiveRowHeight(row);
3322 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3323 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3325 if (alignment & Qt::AlignTop) {
3326 contentY = rowY + offset;
3327 }
else if (alignment & Qt::AlignBottom) {
3328 contentY = rowY + rowHeight - viewportRect.height() + offset;
3329 }
else if (alignment & Qt::AlignVCenter) {
3330 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3331 contentY = rowY - centerDistance + offset;
3336 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3341bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3345 return qFuzzyIsNull(getColumnWidth(column));
3348bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3352 return qFuzzyIsNull(getRowHeight(row));
3355void QQuickTableViewPrivate::relayoutTableItems()
3357 qCDebug(lcTableViewDelegateLifecycle);
3359 if (viewportRect.isEmpty()) {
3361 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3365 qreal nextColumnX = loadedTableOuterRect.x();
3366 qreal nextRowY = loadedTableOuterRect.y();
3368 for (
const int column : loadedColumns) {
3370 const qreal width = getColumnLayoutWidth(column);
3372 for (
const int row : loadedRows) {
3373 auto item = loadedTableItem(QPoint(column, row));
3374 QRectF geometry = item->geometry();
3375 geometry.moveLeft(nextColumnX);
3376 geometry.setWidth(width);
3377 item->setGeometry(geometry);
3381 nextColumnX += width + cellSpacing.width();
3384 for (
const int row : loadedRows) {
3386 const qreal height = getRowLayoutHeight(row);
3388 for (
const int column : loadedColumns) {
3389 auto item = loadedTableItem(QPoint(column, row));
3390 QRectF geometry = item->geometry();
3391 geometry.moveTop(nextRowY);
3392 geometry.setHeight(height);
3393 item->setGeometry(geometry);
3397 nextRowY += height + cellSpacing.height();
3400 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3401 for (
const int column : loadedColumns) {
3402 for (
const int row : loadedRows) {
3403 QPoint cell = QPoint(column, row);
3404 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3410void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3412 int columnThatNeedsLayout;
3413 int neighbourColumn;
3417 if (tableEdge == Qt::LeftEdge) {
3418 columnThatNeedsLayout = leftColumn();
3419 neighbourColumn = loadedColumns.values().at(1);
3420 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3421 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3422 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3424 columnThatNeedsLayout = rightColumn();
3425 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3426 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3427 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3428 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3431 for (
const int row : loadedRows) {
3432 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3433 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3434 const qreal rowY = neighbourItem->geometry().y();
3435 const qreal rowHeight = neighbourItem->geometry().height();
3437 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3438 fxTableItem->setVisible(
true);
3440 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3444void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3446 int rowThatNeedsLayout;
3449 if (tableEdge == Qt::TopEdge) {
3450 rowThatNeedsLayout = topRow();
3451 neighbourRow = loadedRows.values().at(1);
3453 rowThatNeedsLayout = bottomRow();
3454 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3459 for (
const int column : loadedColumns) {
3460 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3461 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3462 const qreal columnX = neighbourItem->geometry().x();
3463 const qreal columnWidth = neighbourItem->geometry().width();
3464 fxTableItem->item->setX(columnX);
3465 fxTableItem->item->setWidth(columnWidth);
3470 if (tableEdge == Qt::TopEdge) {
3471 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3472 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3473 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3475 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3476 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3477 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3480 for (
const int column : loadedColumns) {
3481 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3482 fxTableItem->item->setY(rowY);
3483 fxTableItem->item->setHeight(rowHeight);
3484 fxTableItem->setVisible(
true);
3486 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3490void QQuickTableViewPrivate::layoutTopLeftItem()
3492 const QPoint cell(loadRequest.column(), loadRequest.row());
3493 auto topLeftItem = loadedTableItem(cell);
3494 auto item = topLeftItem->item;
3496 item->setPosition(loadRequest.startPosition());
3497 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3498 topLeftItem->setVisible(
true);
3499 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3502void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3504 if (loadRequest.edge() == Qt::Edge(0)) {
3506 layoutTopLeftItem();
3510 switch (loadRequest.edge()) {
3513 layoutVerticalEdge(loadRequest.edge());
3516 case Qt::BottomEdge:
3517 layoutHorizontalEdge(loadRequest.edge());
3522void QQuickTableViewPrivate::processLoadRequest()
3524 Q_Q(QQuickTableView);
3527 while (loadRequest.hasCurrentCell()) {
3528 QPoint cell = loadRequest.currentCell();
3529 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3537 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3538 loadRequest.moveToNextCell();
3541 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3543 syncLoadedTableFromLoadRequest();
3544 layoutTableEdgeFromLoadRequest();
3545 syncLoadedTableRectFromLoadedTable();
3547 if (rebuildState == RebuildState::Done) {
3551 drainReusePoolAfterLoadRequest();
3553 switch (loadRequest.edge()) {
3555 emit q->leftColumnChanged();
3558 emit q->rightColumnChanged();
3561 emit q->topRowChanged();
3563 case Qt::BottomEdge:
3564 emit q->bottomRowChanged();
3568 if (editIndex.isValid())
3571 emit q->layoutChanged();
3574 loadRequest.markAsDone();
3576 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3577 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3578 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3581void QQuickTableViewPrivate::processRebuildTable()
3583 Q_Q(QQuickTableView);
3585 if (rebuildState == RebuildState::Begin) {
3586 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3587 tableSizeBeforeRebuild = tableSize;
3588 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins(-1,-1,-1,-1)
3589 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3592 moveToNextRebuildState();
3594 if (rebuildState == RebuildState::LoadInitalTable) {
3596 if (!moveToNextRebuildState())
3600 if (rebuildState == RebuildState::VerifyTable) {
3601 if (loadedItems.isEmpty()) {
3602 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3603 updateContentWidth();
3604 updateContentHeight();
3605 rebuildState = RebuildState::Done;
3606 }
else if (!moveToNextRebuildState()) {
3611 if (rebuildState == RebuildState::LayoutTable) {
3612 layoutAfterLoadingInitialTable();
3613 loadAndUnloadVisibleEdges();
3614 if (!moveToNextRebuildState())
3618 if (rebuildState == RebuildState::CancelOvershoot) {
3619 cancelOvershootAfterLayout();
3620 loadAndUnloadVisibleEdges();
3621 if (!moveToNextRebuildState())
3625 if (rebuildState == RebuildState::UpdateContentSize) {
3626 updateContentSize();
3627 if (!moveToNextRebuildState())
3631 const bool preload = (rebuildOptions & RebuildOption::All
3632 && reusableFlag == QQmlTableInstanceModel::Reusable);
3634 if (rebuildState == RebuildState::PreloadColumns) {
3635 if (preload && !atTableEnd(Qt::RightEdge))
3636 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3637 if (!moveToNextRebuildState())
3641 if (rebuildState == RebuildState::PreloadRows) {
3642 if (preload && !atTableEnd(Qt::BottomEdge))
3643 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3644 if (!moveToNextRebuildState())
3648 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3649 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3651 if (!moveToNextRebuildState())
3655 if (rebuildState == RebuildState::Done) {
3656 if (tableSizeBeforeRebuild.width() != tableSize.width())
3657 emit q->columnsChanged();
3658 if (tableSizeBeforeRebuild.height() != tableSize.height())
3659 emit q->rowsChanged();
3660 if (edgesBeforeRebuild.left() != q->leftColumn())
3661 emit q->leftColumnChanged();
3662 if (edgesBeforeRebuild.right() != q->rightColumn())
3663 emit q->rightColumnChanged();
3664 if (edgesBeforeRebuild.top() != q->topRow())
3665 emit q->topRowChanged();
3666 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3667 emit q->bottomRowChanged();
3669 if (editIndex.isValid())
3671 updateCurrentRowAndColumn();
3673 emit q->layoutChanged();
3675 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3676 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3677 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3678 qCDebug(lcTableViewDelegateLifecycle());
3684bool QQuickTableViewPrivate::moveToNextRebuildState()
3686 if (loadRequest.isActive()) {
3692 if (rebuildState == RebuildState::Begin
3693 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3694 rebuildState = RebuildState::LayoutTable;
3696 rebuildState = RebuildState(
int(rebuildState) + 1);
3698 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3702void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3704 if (tableSize.isEmpty()) {
3706 topLeftCell.rx() = kEdgeIndexAtEnd;
3707 topLeftCell.ry() = kEdgeIndexAtEnd;
3711 if (syncHorizontally || syncVertically) {
3712 const auto syncView_d = syncView->d_func();
3714 if (syncView_d->loadedItems.isEmpty()) {
3715 topLeftCell.rx() = 0;
3716 topLeftCell.ry() = 0;
3721 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3722 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3723 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3725 if (syncHorizontally) {
3726 topLeftCell.rx() = syncViewTopLeftCell.x();
3727 topLeftPos.rx() = syncViewTopLeftPos.x();
3729 if (topLeftCell.x() >= tableSize.width()) {
3731 topLeftCell.rx() = kEdgeIndexAtEnd;
3732 topLeftPos.rx() = kEdgeIndexAtEnd;
3736 if (syncVertically) {
3737 topLeftCell.ry() = syncViewTopLeftCell.y();
3738 topLeftPos.ry() = syncViewTopLeftPos.y();
3740 if (topLeftCell.y() >= tableSize.height()) {
3742 topLeftCell.ry() = kEdgeIndexAtEnd;
3743 topLeftPos.ry() = kEdgeIndexAtEnd;
3747 if (syncHorizontally && syncVertically) {
3758 if (!syncHorizontally) {
3759 if (rebuildOptions & RebuildOption::All) {
3761 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3762 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3766 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3768 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3769 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3770 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3771 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3772 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3773 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3776 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3780 topLeftPos.rx() = loadedTableOuterRect.x();
3784 if (!syncVertically) {
3785 if (rebuildOptions & RebuildOption::All) {
3787 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3788 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3792 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3794 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3795 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3796 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3797 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3798 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3799 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3801 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3802 topLeftPos.ry() = loadedTableOuterRect.y();
3807void QQuickTableViewPrivate::loadInitialTable()
3809 tableSize = calculateTableSize();
3811 if (positionXAnimation.isRunning()) {
3812 positionXAnimation.stop();
3813 setLocalViewportX(positionXAnimation.to().toReal());
3817 if (positionYAnimation.isRunning()) {
3818 positionYAnimation.stop();
3819 setLocalViewportY(positionYAnimation.to().toReal());
3825 calculateTopLeft(topLeft, topLeftPos);
3826 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3827 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3829 if (!loadedItems.isEmpty()) {
3830 if (rebuildOptions & RebuildOption::All)
3831 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3832 else if (rebuildOptions & RebuildOption::ViewportOnly)
3833 releaseLoadedItems(reusableFlag);
3836 if (rebuildOptions & RebuildOption::All) {
3837 origin = QPointF(0, 0);
3838 endExtent = QSizeF(0, 0);
3839 hData.markExtentsDirty();
3840 vData.markExtentsDirty();
3841 updateBeginningEnd();
3844 loadedColumns.clear();
3846 loadedTableOuterRect = QRect();
3847 loadedTableInnerRect = QRect();
3848 clearEdgeSizeCache();
3850 if (syncHorizontally)
3851 setLocalViewportX(syncView->contentX());
3854 setLocalViewportY(syncView->contentY());
3856 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
3857 setLocalViewportX(topLeftPos.x());
3859 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
3860 setLocalViewportY(topLeftPos.y());
3865 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
3869 if (model->count() == 0) {
3870 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
3874 if (tableModel && !tableModel->delegate()) {
3875 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
3879 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
3880 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
3884 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
3885 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
3889 if (viewportRect.isEmpty()) {
3890 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
3896 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
3897 processLoadRequest();
3898 loadAndUnloadVisibleEdges();
3901void QQuickTableViewPrivate::updateContentSize()
3903 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
3904 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
3905 updateAverageColumnWidth();
3906 updateContentWidth();
3909 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
3910 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
3911 updateAverageRowHeight();
3912 updateContentHeight();
3918void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
3920 clearEdgeSizeCache();
3921 relayoutTableItems();
3922 syncLoadedTableRectFromLoadedTable();
3924 updateContentSize();
3926 adjustViewportXAccordingToAlignment();
3927 adjustViewportYAccordingToAlignment();
3930void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
3933 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
3936 if (positionViewAtColumnAfterRebuild != leftColumn())
3939 const qreal newContentX = getAlignmentContentX(
3940 positionViewAtColumnAfterRebuild,
3941 positionViewAtColumnAlignment,
3942 positionViewAtColumnOffset,
3943 positionViewAtColumnSubRect);
3945 setLocalViewportX(newContentX);
3949void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
3952 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
3955 if (positionViewAtRowAfterRebuild != topRow())
3958 const qreal newContentY = getAlignmentContentY(
3959 positionViewAtRowAfterRebuild,
3960 positionViewAtRowAlignment,
3961 positionViewAtRowOffset,
3962 positionViewAtRowSubRect);
3964 setLocalViewportY(newContentY);
3968void QQuickTableViewPrivate::cancelOvershootAfterLayout()
3970 Q_Q(QQuickTableView);
3976 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
3977 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
3978 const bool cancelVertically = positionVertically && !syncVertically;
3979 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
3981 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
3982 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
3983 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
3987 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
3988 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
3989 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
3994void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
3996 Q_Q(QQuickTableView);
3997 qCDebug(lcTableViewDelegateLifecycle) << edge;
4000 case Qt::LeftEdge: {
4001 const int column = leftColumn();
4002 for (
int row : loadedRows)
4003 unloadItem(QPoint(column, row));
4004 loadedColumns.remove(column);
4005 syncLoadedTableRectFromLoadedTable();
4006 if (rebuildState == RebuildState::Done)
4007 emit q->leftColumnChanged();
4009 case Qt::RightEdge: {
4010 const int column = rightColumn();
4011 for (
int row : loadedRows)
4012 unloadItem(QPoint(column, row));
4013 loadedColumns.remove(column);
4014 syncLoadedTableRectFromLoadedTable();
4015 if (rebuildState == RebuildState::Done)
4016 emit q->rightColumnChanged();
4019 const int row = topRow();
4020 for (
int col : loadedColumns)
4021 unloadItem(QPoint(col, row));
4022 loadedRows.remove(row);
4023 syncLoadedTableRectFromLoadedTable();
4024 if (rebuildState == RebuildState::Done)
4025 emit q->topRowChanged();
4027 case Qt::BottomEdge: {
4028 const int row = bottomRow();
4029 for (
int col : loadedColumns)
4030 unloadItem(QPoint(col, row));
4031 loadedRows.remove(row);
4032 syncLoadedTableRectFromLoadedTable();
4033 if (rebuildState == RebuildState::Done)
4034 emit q->bottomRowChanged();
4038 if (rebuildState == RebuildState::Done)
4039 emit q->layoutChanged();
4041 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4044void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4046 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4047 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4049 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4050 ? loadedRows.values() : loadedColumns.values();
4051 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4052 processLoadRequest();
4055void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4067 if (loadRequest.isActive()) {
4073 if (loadedItems.isEmpty()) {
4083 tableModified =
false;
4085 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4086 tableModified =
true;
4090 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4091 tableModified =
true;
4092 loadEdge(edge, incubationMode);
4093 if (loadRequest.isActive())
4096 }
while (tableModified);
4100void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4102 Q_Q(QQuickTableView);
4104 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4107 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4137 const int w = loadedColumns.count();
4138 const int h = loadedRows.count();
4139 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4140 const int maxTime = minTime * 2;
4141 tableModel->drainReusableItemsPool(maxTime);
4144void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4145 if (!q_func()->isComponentComplete()) {
4150 scheduledRebuildOptions |= options;
4154QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4156 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4157 while (QQuickTableView *view = root->d_func()->syncView)
4162void QQuickTableViewPrivate::updatePolish()
4169 rootSyncView()->d_func()->updateTableRecursive();
4172bool QQuickTableViewPrivate::updateTableRecursive()
4182 const bool updateComplete = updateTable();
4183 if (!updateComplete)
4186 const auto children = syncChildren;
4187 for (
auto syncChild : children) {
4188 auto syncChild_d = syncChild->d_func();
4190 RebuildOption::PositionViewAtRow |
4191 RebuildOption::PositionViewAtColumn |
4192 RebuildOption::CalculateNewTopLeftRow |
4193 RebuildOption::CalculateNewTopLeftColumn;
4194 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4196 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4197 if (!descendantUpdateComplete)
4201 rebuildOptions = RebuildOption::None;
4206bool QQuickTableViewPrivate::updateTable()
4215 QScopedValueRollback polishGuard(polishing,
true);
4217 if (loadRequest.isActive()) {
4225 if (rebuildState != RebuildState::Done) {
4226 processRebuildTable();
4227 return rebuildState == RebuildState::Done;
4230 syncWithPendingChanges();
4232 if (rebuildState == RebuildState::Begin) {
4233 processRebuildTable();
4234 return rebuildState == RebuildState::Done;
4237 if (loadedItems.isEmpty())
4238 return !loadRequest.isActive();
4240 loadAndUnloadVisibleEdges();
4243 return !loadRequest.isActive();
4246void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4248 if (inUpdateContentSize) {
4260 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4263QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4265 const auto data = QQmlData::get(q_func());
4266 if (!data || !data->propertyCache)
4267 return QTypeRevision::zero();
4269 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4270 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4273 return qmlTypeView.metaObjectRevision();
4276void QQuickTableViewPrivate::createWrapperModel()
4278 Q_Q(QQuickTableView);
4284 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4285 tableModel->useImportVersion(resolveImportVersion());
4289bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4291 if (!selectionModel)
4294 QAbstractItemModel *model = selectionModel->model();
4298 return selectionModel->isSelected(q_func()->modelIndex(cell));
4301bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4303 if (!selectionModel)
4306 QAbstractItemModel *model = selectionModel->model();
4310 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4313void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4315 if (!inSelectionModelUpdate) {
4319 cancelSelectionTracking();
4322 const auto &selectedIndexes = selected.indexes();
4323 const auto &deselectedIndexes = deselected.indexes();
4324 for (
int i = 0; i < selectedIndexes.size(); ++i)
4325 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4326 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4327 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4330void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4332 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4333 qmlWarning(q_func())
4334 <<
"Cannot select cells: TableView.selectionModel.model is not "
4335 <<
"compatible with the model displayed in the view";
4339 const int cellIndex = modelIndexToCellIndex(modelIndex);
4340 if (!loadedItems.contains(cellIndex))
4342 const QPoint cell = cellAtModelIndex(cellIndex);
4343 QQuickItem *item = loadedTableItem(cell)->item;
4344 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4347QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4362 return qaim(modelImpl());
4365QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4368 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4369 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4370 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4373void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4375 updateCurrentRowAndColumn();
4377 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4378 const int cellIndex = *it;
4379 const QPoint cell = cellAtModelIndex(cellIndex);
4380 const bool selected = selectedInSelectionModel(cell);
4381 const bool current = currentInSelectionModel(cell);
4382 QQuickItem *item = loadedTableItem(cell)->item;
4383 const bool editing = editIndex == q_func()->modelIndex(cell);
4384 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4385 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4386 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4390void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4392 if (current.isValid() && current.model() != selectionSourceModel()) {
4393 qmlWarning(q_func())
4394 <<
"Cannot change current index: TableView.selectionModel.model is not "
4395 <<
"compatible with the model displayed in the view";
4399 updateCurrentRowAndColumn();
4400 setCurrentOnDelegateItem(previous,
false);
4401 setCurrentOnDelegateItem(current,
true);
4404void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4406 Q_Q(QQuickTableView);
4408 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4409 const QPoint currentCell = q->cellAtIndex(currentIndex);
4410 if (currentCell.x() != currentColumn) {
4411 currentColumn = currentCell.x();
4412 emit q->currentColumnChanged();
4415 if (currentCell.y() != currentRow) {
4416 currentRow = currentCell.y();
4417 emit q->currentRowChanged();
4421void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4423 const int cellIndex = modelIndexToCellIndex(index);
4424 if (!loadedItems.contains(cellIndex))
4427 const QPoint cell = cellAtModelIndex(cellIndex);
4428 QQuickItem *item = loadedTableItem(cell)->item;
4429 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4432void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4434 if (blockItemCreatedCallback)
4437 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4438 << cellAtModelIndex(modelIndex);
4444 processLoadRequest();
4445 loadAndUnloadVisibleEdges();
4449void QQuickTableViewPrivate::initItemCallback(
int modelIndex, QObject *object)
4451 Q_Q(QQuickTableView);
4453 auto item = qobject_cast<QQuickItem*>(object);
4457 item->setParentItem(q->contentItem());
4460 if (
auto attached = getAttachedObject(item))
4461 attached->setView(q);
4463 const QPoint cell = cellAtModelIndex(modelIndex);
4464 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4465 const bool current = currentInSelectionModel(visualCell);
4466 const bool selected = selectedInSelectionModel(visualCell);
4468 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), modelIndex, item,
true);
4469 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object,
true);
4470 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object,
true);
4471 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), modelIndex, item,
true);
4472 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), modelIndex, item,
true);
4475void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4477 Q_UNUSED(modelIndex);
4479 if (
auto attached = getAttachedObject(object))
4480 emit attached->pooled();
4483void QQuickTableViewPrivate::itemReusedCallback(
int modelIndex, QObject *object)
4485 Q_Q(QQuickTableView);
4487 const QPoint cell = cellAtModelIndex(modelIndex);
4488 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4489 const bool current = currentInSelectionModel(visualCell);
4490 const bool selected = selectedInSelectionModel(visualCell);
4492 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), modelIndex, object,
false);
4493 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object,
false);
4494 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object,
false);
4496 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), modelIndex, object,
false);
4498 if (
auto item = qobject_cast<QQuickItem*>(object))
4499 QQuickItemPrivate::get(item)->setCulled(
false);
4501 if (
auto attached = getAttachedObject(object))
4502 emit attached->reused();
4505void QQuickTableViewPrivate::syncWithPendingChanges()
4515 syncDelegateModelAccess();
4519 syncRebuildOptions();
4522void QQuickTableViewPrivate::syncRebuildOptions()
4524 if (!scheduledRebuildOptions)
4527 rebuildState = RebuildState::Begin;
4528 rebuildOptions = scheduledRebuildOptions;
4529 scheduledRebuildOptions = RebuildOption::None;
4531 if (loadedItems.isEmpty())
4532 rebuildOptions.setFlag(RebuildOption::All);
4535 if (rebuildOptions.testFlag(RebuildOption::All)) {
4536 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4537 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4538 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4539 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4540 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4541 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4544 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4545 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4547 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4548 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4551void QQuickTableViewPrivate::syncDelegate()
4560 if (assignedDelegate != tableModel->delegate())
4561 tableModel->setDelegate(assignedDelegate);
4564void QQuickTableViewPrivate::syncDelegateModelAccess()
4573 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4576QVariant QQuickTableViewPrivate::modelImpl()
const
4578 if (needsModelSynchronization)
4579 return assignedModel;
4581 return tableModel->model();
4582 return QVariant::fromValue(model);
4585void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4587 assignedModel = newModel;
4588 needsModelSynchronization =
true;
4589 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4590 emit q_func()->modelChanged();
4593void QQuickTableViewPrivate::syncModel()
4596 if (tableModel->model() == assignedModel)
4598 }
else if (QVariant::fromValue(model) == assignedModel) {
4603 disconnectFromModel();
4604 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4607 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4608 qvariant_cast<QObject *>(assignedModel));
4610 if (instanceModel) {
4613 tableModel =
nullptr;
4615 model = instanceModel;
4618 createWrapperModel();
4619 tableModel->setModel(assignedModel);
4622 needsModelSynchronization =
false;
4626void QQuickTableViewPrivate::syncSyncView()
4628 Q_Q(QQuickTableView);
4630 if (assignedSyncView != syncView) {
4632 syncView->d_func()->syncChildren.removeOne(q);
4634 if (assignedSyncView) {
4635 QQuickTableView *view = assignedSyncView;
4639 if (!layoutWarningIssued) {
4640 layoutWarningIssued =
true;
4641 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4646 view = view->d_func()->syncView;
4649 assignedSyncView->d_func()->syncChildren.append(q);
4650 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4653 syncView = assignedSyncView;
4656 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4657 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4659 if (syncHorizontally) {
4660 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4661 q->setColumnSpacing(syncView->columnSpacing());
4662 q->setLeftMargin(syncView->leftMargin());
4663 q->setRightMargin(syncView->rightMargin());
4664 updateContentWidth();
4666 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4667 if (syncView->leftColumn() != q->leftColumn()
4668 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4675 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4676 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4681 if (syncVertically) {
4682 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4683 q->setRowSpacing(syncView->rowSpacing());
4684 q->setTopMargin(syncView->topMargin());
4685 q->setBottomMargin(syncView->bottomMargin());
4686 updateContentHeight();
4688 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4689 if (syncView->topRow() != q->topRow()
4690 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4697 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4698 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4703 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4709 const auto syncView_d = syncView->d_func();
4710 if (!syncView_d->loadedItems.isEmpty()) {
4711 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4712 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4713 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4714 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4719void QQuickTableViewPrivate::syncPositionView()
4725 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4726 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4729void QQuickTableViewPrivate::connectToModel()
4731 Q_Q(QQuickTableView);
4734 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4735 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4736 QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4737 QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4740 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4742 if (
auto const aim = model->abstractItemModel()) {
4748 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4749 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4750 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4751 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4752 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4753 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4754 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4755 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4756 connect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4758 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4762 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
4763 q, &QQuickTableView::modelChanged);
4767void QQuickTableViewPrivate::disconnectFromModel()
4769 Q_Q(QQuickTableView);
4772 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4773 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4774 QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4775 QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4777 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4779 if (
auto const aim = model->abstractItemModel()) {
4780 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4781 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4782 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4783 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4784 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4785 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4786 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4787 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4788 disconnect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4790 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4794 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
4795 q, &QQuickTableView::modelChanged);
4799void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
4801 Q_UNUSED(changeSet);
4805 scheduleRebuildTable(RebuildOption::ViewportOnly
4806 | RebuildOption::CalculateNewContentWidth
4807 | RebuildOption::CalculateNewContentHeight);
4810void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
4812 if (parent != QModelIndex())
4815 scheduleRebuildTable(RebuildOption::ViewportOnly);
4818void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
4820 if (parent != QModelIndex())
4823 scheduleRebuildTable(RebuildOption::ViewportOnly);
4826void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
4828 if (parent != QModelIndex())
4831 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4834void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
4836 Q_Q(QQuickTableView);
4838 if (parent != QModelIndex())
4842 if (!editIndex.isValid() && editItem)
4845 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4848void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
4850 if (parent != QModelIndex())
4858 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4861void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
4863 Q_Q(QQuickTableView);
4865 if (parent != QModelIndex())
4869 if (!editIndex.isValid() && editItem)
4872 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4875void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
4880 scheduleRebuildTable(RebuildOption::ViewportOnly);
4883void QQuickTableViewPrivate::fetchMoreData()
4885 if (tableModel && tableModel->canFetchMore()) {
4886 tableModel->fetchMore();
4887 scheduleRebuildTable(RebuildOption::ViewportOnly);
4891void QQuickTableViewPrivate::modelResetCallback()
4893 Q_Q(QQuickTableView);
4895 scheduleRebuildTable(RebuildOption::All);
4898void QQuickTableViewPrivate::dataChangedCallback(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles)
4900 const auto *chooser = qobject_cast<
const QQmlDelegateChooser *>(assignedDelegate);
4904 if (topLeft.column() > rightColumn() || bottomRight.column() < leftColumn() || topLeft.row() > bottomRow()
4905 || bottomRight.row() < topRow()) {
4909 if (!roles.empty()) {
4910 const int roleIndex = topLeft.model()->roleNames().key(chooser->role().toUtf8());
4911 if (!roles.contains(roleIndex))
4915 scheduleRebuildTable(RebuildOption::ViewportOnly);
4918void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4920 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
4923 if (syncVertically) {
4924 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
4926 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
4928 assignedPositionViewAtRowAfterRebuild = row;
4929 positionViewAtRowAlignment = verticalAlignment;
4930 positionViewAtRowOffset = offset;
4931 positionViewAtRowSubRect = subRect;
4932 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4933 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
4938void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4940 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
4943 if (syncHorizontally) {
4944 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
4946 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
4948 assignedPositionViewAtColumnAfterRebuild = column;
4949 positionViewAtColumnAlignment = horizontalAlignment;
4950 positionViewAtColumnOffset = offset;
4951 positionViewAtColumnSubRect = subRect;
4952 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4953 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
4958bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4960 Q_Q(QQuickTableView);
4967 if (row < topRow()) {
4968 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
4970 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
4971 }
else if (row > bottomRow()) {
4972 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
4974 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
4975 }
else if (row < topRow() || row > bottomRow()) {
4979 if (!loadedRows.contains(row))
4982 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
4983 if (qFuzzyCompare(newContentY, q->contentY()))
4987 const qreal diffY = qAbs(newContentY - q->contentY());
4988 const qreal duration = qBound(700., diffY * 5, 1500.);
4989 positionYAnimation.setTo(newContentY);
4990 positionYAnimation.setDuration(duration);
4991 positionYAnimation.restart();
4993 positionYAnimation.stop();
4994 q->setContentY(newContentY);
5000bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5002 Q_Q(QQuickTableView);
5009 if (column < leftColumn()) {
5010 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
5012 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
5013 }
else if (column > rightColumn()) {
5014 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
5016 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
5017 }
else if (column < leftColumn() || column > rightColumn()) {
5021 if (!loadedColumns.contains(column))
5024 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5025 if (qFuzzyCompare(newContentX, q->contentX()))
5029 const qreal diffX = qAbs(newContentX - q->contentX());
5030 const qreal duration = qBound(700., diffX * 5, 1500.);
5031 positionXAnimation.setTo(newContentX);
5032 positionXAnimation.setDuration(duration);
5033 positionXAnimation.restart();
5035 positionXAnimation.stop();
5036 q->setContentX(newContentX);
5042void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5044 Q_Q(QQuickTableView);
5054 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5055 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5056 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5060 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5061 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5062 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5066void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5071 Q_Q(QQuickTableView);
5072 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5074 if (qFuzzyCompare(contentX, q->contentX()))
5077 q->setContentX(contentX);
5080void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5085 Q_Q(QQuickTableView);
5086 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5088 if (qFuzzyCompare(contentY, q->contentY()))
5091 q->setContentY(contentY);
5094void QQuickTableViewPrivate::syncViewportRect()
5102 Q_Q(QQuickTableView);
5104 qreal w = q->width();
5105 qreal h = q->height();
5107 for (
auto syncChild : std::as_const(syncChildren)) {
5108 auto syncChild_d = syncChild->d_func();
5109 if (syncChild_d->syncHorizontally)
5110 w = qMax(w, syncChild->width());
5111 if (syncChild_d->syncVertically)
5112 h = qMax(h, syncChild->height());
5115 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5118void QQuickTableViewPrivate::init()
5120 Q_Q(QQuickTableView);
5122 q->setFlag(QQuickItem::ItemIsFocusScope);
5123 q->setActiveFocusOnTab(
true);
5125 positionXAnimation.setTargetObject(q);
5126 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5127 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5129 positionYAnimation.setTargetObject(q);
5130 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5131 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5133 auto tapHandler =
new QQuickTableViewTapHandler(q);
5135 hoverHandler =
new QQuickTableViewHoverHandler(q);
5136 resizeHandler =
new QQuickTableViewResizeHandler(q);
5138 hoverHandler->setEnabled(resizableRows || resizableColumns);
5139 resizeHandler->setEnabled(resizableRows || resizableColumns);
5147 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, q, [
this, q, tapHandler] {
5148 if (!tapHandler->isPressed())
5151 positionXAnimation.stop();
5152 positionYAnimation.stop();
5154 if (!q->isInteractive())
5155 handleTap(tapHandler->point());
5158 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, q, [
this, q, tapHandler] {
5159 if (q->isInteractive())
5160 handleTap(tapHandler->point());
5163 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, q, [
this, q, tapHandler] {
5164 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5165 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5167 if (resizeRow || resizeColumn) {
5169 q->setRowHeight(hoverHandler->m_row, -1);
5171 q->setColumnWidth(hoverHandler->m_column, -1);
5172 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5173 const QPointF pos = tapHandler->point().pressPosition();
5174 const QPoint cell = q->cellAtPosition(pos);
5175 const QModelIndex index = q->modelIndex(cell);
5176 if (canEdit(index,
false))
5182void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5184 Q_Q(QQuickTableView);
5186 if (keyNavigationEnabled)
5187 q->forceActiveFocus(Qt::MouseFocusReason);
5189 if (point.modifiers() != Qt::NoModifier)
5191 if (resizableRows && hoverHandler->m_row != -1)
5193 if (resizableColumns && hoverHandler->m_column != -1)
5195 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5198 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5199 bool tappedCellIsSelected =
false;
5202 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5204 if (canEdit(tappedIndex,
false)) {
5205 if (editTriggers & QQuickTableView::SingleTapped) {
5206 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5208 q->edit(tappedIndex);
5210 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5211 q->edit(tappedIndex);
5218 if (pointerNavigationEnabled) {
5219 closeEditorAndCommit();
5220 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5222 cancelSelectionTracking();
5224 setCurrentIndexFromTap(point.position());
5228bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5232 Q_Q(QQuickTableView);
5234 if (!tappedIndex.isValid()) {
5236 qmlWarning(q) <<
"cannot edit: index is not valid!";
5240 if (
auto const sourceModel = qaim(modelImpl())) {
5241 if (!(sourceModel->flags(tappedIndex) & Qt::ItemIsEditable)) {
5243 qmlWarning(q) <<
"cannot edit: QAbstractItemModel::flags(index) doesn't contain Qt::ItemIsEditable";
5248 const QPoint cell = q->cellAtIndex(tappedIndex);
5249 const QQuickItem *cellItem = q->itemAtCell(cell);
5252 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5256 auto attached = getAttachedObject(cellItem);
5257 if (!attached || !attached->editDelegate()) {
5259 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5266void QQuickTableViewPrivate::syncViewportPosRecursive()
5268 Q_Q(QQuickTableView);
5269 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5272 auto syncView_d = syncView->d_func();
5273 if (!syncView_d->inSyncViewportPosRecursive) {
5274 if (syncHorizontally)
5275 syncView_d->setLocalViewportX(q->contentX());
5277 syncView_d->setLocalViewportY(q->contentY());
5278 syncView_d->syncViewportPosRecursive();
5282 for (
auto syncChild : std::as_const(syncChildren)) {
5283 auto syncChild_d = syncChild->d_func();
5284 if (!syncChild_d->inSyncViewportPosRecursive) {
5285 if (syncChild_d->syncHorizontally)
5286 syncChild_d->setLocalViewportX(q->contentX());
5287 if (syncChild_d->syncVertically)
5288 syncChild_d->setLocalViewportY(q->contentY());
5289 syncChild_d->syncViewportPosRecursive();
5294void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5296 Q_Q(QQuickTableView);
5298 const QPoint cell = q->cellAtPosition(pos);
5299 if (!cellIsValid(cell))
5302 setCurrentIndex(cell);
5305void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5307 if (!selectionModel)
5310 const auto index = q_func()->modelIndex(cell);
5311 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5314bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5316 Q_Q(QQuickTableView);
5318 if (!selectionModel || !selectionModel->model())
5321 const QModelIndex currentIndex = selectionModel->currentIndex();
5322 const QPoint currentCell = q->cellAtIndex(currentIndex);
5324 if (!q->activeFocusOnTab()) {
5327 case Qt::Key_Backtab:
5332 if (!cellIsValid(currentCell)) {
5338 case Qt::Key_PageUp:
5339 case Qt::Key_PageDown:
5343 case Qt::Key_Backtab:
5344 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5347 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5348 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5355 auto beginMoveCurrentIndex = [&](){
5356 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5357 const bool startNewSelection = selectionRectangle().isEmpty();
5358 if (!shouldSelect) {
5360 cancelSelectionTracking();
5361 }
else if (startNewSelection) {
5365 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5366 if (loadedItems.contains(serializedStartIndex)) {
5367 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5368 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5369 setSelectionStartPos(startGeometry.center());
5370 if (selectableCallbackFunction)
5371 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5377 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5378 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5380 if (polishScheduled)
5382 const int serializedEndIndex = modelIndexAtCell(cell);
5383 if (loadedItems.contains(serializedEndIndex)) {
5384 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5385 setSelectionEndPos(endGeometry.center());
5386 if (selectableCallbackFunction)
5387 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5390 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5395 beginMoveCurrentIndex();
5396 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5397 if (nextRow == kEdgeIndexAtEnd)
5399 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5400 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5401 endMoveCurrentIndex({currentCell.x(), nextRow});
5403 case Qt::Key_Down: {
5404 beginMoveCurrentIndex();
5405 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5406 if (nextRow == kEdgeIndexAtEnd)
5408 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5409 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5410 endMoveCurrentIndex({currentCell.x(), nextRow});
5412 case Qt::Key_Left: {
5413 beginMoveCurrentIndex();
5414 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5415 if (nextColumn == kEdgeIndexAtEnd)
5417 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5418 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5419 endMoveCurrentIndex({nextColumn, currentCell.y()});
5421 case Qt::Key_Right: {
5422 beginMoveCurrentIndex();
5423 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5424 if (nextColumn == kEdgeIndexAtEnd)
5426 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5427 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5428 endMoveCurrentIndex({nextColumn, currentCell.y()});
5430 case Qt::Key_PageDown: {
5431 int newBottomRow = -1;
5432 beginMoveCurrentIndex();
5433 if (currentCell.y() < bottomRow()) {
5435 newBottomRow = bottomRow();
5436 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5438 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5439 positionYAnimation.complete();
5440 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5441 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5442 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5443 positionYAnimation.complete();
5445 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5447 case Qt::Key_PageUp: {
5449 beginMoveCurrentIndex();
5450 if (currentCell.y() > topRow()) {
5452 newTopRow = topRow();
5453 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5455 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5456 positionYAnimation.complete();
5457 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5458 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5459 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5460 positionYAnimation.complete();
5462 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5464 case Qt::Key_Home: {
5465 beginMoveCurrentIndex();
5466 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5467 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5468 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5471 beginMoveCurrentIndex();
5472 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5473 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5474 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5477 beginMoveCurrentIndex();
5478 int nextRow = currentCell.y();
5479 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5480 if (nextColumn == kEdgeIndexAtEnd) {
5481 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5482 if (nextRow == kEdgeIndexAtEnd)
5483 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5484 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5485 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5486 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5490 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5491 marginX = q->leftMargin();
5492 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5493 marginX = -q->leftMargin();
5495 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5496 endMoveCurrentIndex({nextColumn, nextRow});
5498 case Qt::Key_Backtab: {
5499 beginMoveCurrentIndex();
5500 int nextRow = currentCell.y();
5501 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5502 if (nextColumn == kEdgeIndexAtEnd) {
5503 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5504 if (nextRow == kEdgeIndexAtEnd)
5505 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5506 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5507 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5508 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5512 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5513 marginX = q->leftMargin();
5514 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5515 marginX = -q->leftMargin();
5517 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5518 endMoveCurrentIndex({nextColumn, nextRow});
5527bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5529 Q_Q(QQuickTableView);
5531 if (editTriggers == QQuickTableView::NoEditTriggers)
5533 if (!selectionModel || !selectionModel->model())
5536 const QModelIndex index = selectionModel->currentIndex();
5537 const QPoint cell = q->cellAtIndex(index);
5538 const QQuickItem *cellItem = q->itemAtCell(cell);
5542 auto attached = getAttachedObject(cellItem);
5543 if (!attached || !attached->editDelegate())
5546 bool anyKeyPressed =
false;
5547 bool editKeyPressed =
false;
5550 case Qt::Key_Return:
5555 anyKeyPressed =
true;
5556 editKeyPressed =
true;
5560 case Qt::Key_Control:
5563 case Qt::Key_Backtab:
5566 anyKeyPressed =
true;
5569 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5570 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5572 if (!(editKeyAccepted || anyKeyAccepted))
5575 if (!canEdit(index,
false)) {
5584 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5587 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5593QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5599 Q_Q(QQuickTableView);
5600 if (QObject *focusObject = editItem->window()->focusObject()) {
5601 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5602 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5603 focusItem->installEventFilter(q);
5610void QQuickTableViewPrivate::closeEditorAndCommit()
5615 if (
auto attached = getAttachedObject(editItem))
5616 emit attached->commit();
5618 q_func()->closeEditor();
5621#if QT_CONFIG(cursor)
5622void QQuickTableViewPrivate::updateCursor()
5624 int row = resizableRows ? hoverHandler->m_row : -1;
5625 int column = resizableColumns ? hoverHandler->m_column : -1;
5627 const auto resizeState = resizeHandler->state();
5628 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5629 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5632 row = resizeHandler->m_row;
5633 column = resizeHandler->m_column;
5636 if (row != -1 || column != -1) {
5637 Qt::CursorShape shape;
5638 if (row != -1 && column != -1)
5639 shape = Qt::SizeFDiagCursor;
5641 shape = Qt::SplitVCursor;
5643 shape = Qt::SplitHCursor;
5646 qApp->changeOverrideCursor(shape);
5648 qApp->setOverrideCursor(shape);
5651 }
else if (m_cursorSet) {
5652 qApp->restoreOverrideCursor();
5653 m_cursorSet =
false;
5658void QQuickTableViewPrivate::updateEditItem()
5660 Q_Q(QQuickTableView);
5665 const QPoint cell = q->cellAtIndex(editIndex);
5666 auto cellItem = q->itemAtCell(cell);
5677 editItem->parentItem()->setX(-editItem->width() - 10000);
5681QQuickTableView::QQuickTableView(QQuickItem *parent)
5682 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5687QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5688 : QQuickFlickable(dd, parent)
5693QQuickTableView::~QQuickTableView()
5695 Q_D(QQuickTableView);
5699 auto syncView_d = d->syncView->d_func();
5700 syncView_d->syncChildren.removeOne(
this);
5701 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5705void QQuickTableView::componentFinalized()
5719 Q_D(QQuickTableView);
5720 qCDebug(lcTableViewDelegateLifecycle);
5724qreal QQuickTableView::minXExtent()
const
5726 return QQuickFlickable::minXExtent() - d_func()->origin.x();
5729qreal QQuickTableView::maxXExtent()
const
5731 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
5734qreal QQuickTableView::minYExtent()
const
5736 return QQuickFlickable::minYExtent() - d_func()->origin.y();
5739qreal QQuickTableView::maxYExtent()
const
5741 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
5744int QQuickTableView::rows()
const
5746 return d_func()->tableSize.height();
5749int QQuickTableView::columns()
const
5751 return d_func()->tableSize.width();
5754qreal QQuickTableView::rowSpacing()
const
5756 return d_func()->cellSpacing.height();
5759void QQuickTableView::setRowSpacing(qreal spacing)
5761 Q_D(QQuickTableView);
5762 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5764 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
5767 d->cellSpacing.setHeight(spacing);
5768 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5769 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5770 emit rowSpacingChanged();
5773qreal QQuickTableView::columnSpacing()
const
5775 return d_func()->cellSpacing.width();
5778void QQuickTableView::setColumnSpacing(qreal spacing)
5780 Q_D(QQuickTableView);
5781 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5783 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
5786 d->cellSpacing.setWidth(spacing);
5787 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5788 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5789 emit columnSpacingChanged();
5792QJSValue QQuickTableView::rowHeightProvider()
const
5794 return d_func()->rowHeightProvider;
5797void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
5799 Q_D(QQuickTableView);
5800 if (provider.strictlyEquals(d->rowHeightProvider))
5803 d->rowHeightProvider = provider;
5804 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5805 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5806 emit rowHeightProviderChanged();
5809QJSValue QQuickTableView::columnWidthProvider()
const
5811 return d_func()->columnWidthProvider;
5814void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
5816 Q_D(QQuickTableView);
5817 if (provider.strictlyEquals(d->columnWidthProvider))
5820 d->columnWidthProvider = provider;
5821 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5822 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5823 emit columnWidthProviderChanged();
5826QVariant QQuickTableView::model()
const
5828 return d_func()->modelImpl();
5831void QQuickTableView::setModel(
const QVariant &newModel)
5833 Q_D(QQuickTableView);
5835 QVariant model = newModel;
5836 if (model.userType() == qMetaTypeId<QJSValue>())
5837 model = model.value<QJSValue>().toVariant();
5839 if (model == d->assignedModel)
5843 d->setModelImpl(model);
5844 if (d->selectionModel)
5845 d->selectionModel->setModel(d->selectionSourceModel());
5848QQmlComponent *QQuickTableView::delegate()
const
5850 return d_func()->assignedDelegate;
5853void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
5855 Q_D(QQuickTableView);
5856 if (newDelegate == d->assignedDelegate)
5859 d->assignedDelegate = newDelegate;
5860 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5862 emit delegateChanged();
5865QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
5867 return d_func()->editTriggers;
5870void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
5872 Q_D(QQuickTableView);
5873 if (editTriggers == d->editTriggers)
5876 d->editTriggers = editTriggers;
5878 emit editTriggersChanged();
5882
5883
5884
5885
5886
5887QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
5889 Q_D(
const QQuickTableView);
5890 return d->assignedDelegateModelAccess;
5893void QQuickTableView::setDelegateModelAccess(
5894 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
5896 Q_D(QQuickTableView);
5897 if (delegateModelAccess == d->assignedDelegateModelAccess)
5900 d->assignedDelegateModelAccess = delegateModelAccess;
5901 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5903 emit delegateModelAccessChanged();
5906bool QQuickTableView::reuseItems()
const
5908 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
5911void QQuickTableView::setReuseItems(
bool reuse)
5913 Q_D(QQuickTableView);
5914 if (reuseItems() == reuse)
5917 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
5919 if (!reuse && d->tableModel) {
5922 d->tableModel->drainReusableItemsPool(0);
5925 emit reuseItemsChanged();
5928void QQuickTableView::setContentWidth(qreal width)
5930 Q_D(QQuickTableView);
5931 d->explicitContentWidth = width;
5932 QQuickFlickable::setContentWidth(width);
5935void QQuickTableView::setContentHeight(qreal height)
5937 Q_D(QQuickTableView);
5938 d->explicitContentHeight = height;
5939 QQuickFlickable::setContentHeight(height);
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959QQuickTableView *QQuickTableView::syncView()
const
5961 return d_func()->assignedSyncView;
5964void QQuickTableView::setSyncView(QQuickTableView *view)
5966 Q_D(QQuickTableView);
5967 if (d->assignedSyncView == view)
5972 d->clearIndexMapping();
5974 d->assignedSyncView = view;
5975 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5977 emit syncViewChanged();
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998Qt::Orientations QQuickTableView::syncDirection()
const
6000 return d_func()->assignedSyncDirection;
6003void QQuickTableView::setSyncDirection(Qt::Orientations direction)
6005 Q_D(QQuickTableView);
6006 if (d->assignedSyncDirection == direction)
6009 d->assignedSyncDirection = direction;
6010 if (d->assignedSyncView)
6011 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6013 emit syncDirectionChanged();
6016QItemSelectionModel *QQuickTableView::selectionModel()
const
6018 return d_func()->selectionModel;
6021void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6023 Q_D(QQuickTableView);
6024 if (d->selectionModel == selectionModel)
6031 if (d->selectionModel) {
6032 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6033 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6034 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6035 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6038 d->selectionModel = selectionModel;
6040 if (d->selectionModel) {
6041 d->selectionModel->setModel(d->selectionSourceModel());
6042 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6043 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6044 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6045 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6048 d->updateSelectedOnAllDelegateItems();
6050 emit selectionModelChanged();
6053bool QQuickTableView::animate()
const
6055 return d_func()->animate;
6058void QQuickTableView::setAnimate(
bool animate)
6060 Q_D(QQuickTableView);
6061 if (d->animate == animate)
6064 d->animate = animate;
6066 d->positionXAnimation.stop();
6067 d->positionYAnimation.stop();
6070 emit animateChanged();
6073bool QQuickTableView::keyNavigationEnabled()
const
6075 return d_func()->keyNavigationEnabled;
6078void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6080 Q_D(QQuickTableView);
6081 if (d->keyNavigationEnabled == enabled)
6084 d->keyNavigationEnabled = enabled;
6086 emit keyNavigationEnabledChanged();
6089bool QQuickTableView::pointerNavigationEnabled()
const
6091 return d_func()->pointerNavigationEnabled;
6094void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6096 Q_D(QQuickTableView);
6097 if (d->pointerNavigationEnabled == enabled)
6100 d->pointerNavigationEnabled = enabled;
6102 emit pointerNavigationEnabledChanged();
6105int QQuickTableView::leftColumn()
const
6107 Q_D(
const QQuickTableView);
6108 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6111int QQuickTableView::rightColumn()
const
6113 Q_D(
const QQuickTableView);
6114 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6117int QQuickTableView::topRow()
const
6119 Q_D(
const QQuickTableView);
6120 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6123int QQuickTableView::bottomRow()
const
6125 Q_D(
const QQuickTableView);
6126 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6129int QQuickTableView::currentRow()
const
6131 return d_func()->currentRow;
6134int QQuickTableView::currentColumn()
const
6136 return d_func()->currentColumn;
6139void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6141 Q_D(QQuickTableView);
6142 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6149 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6150 mode &= AlignTop | AlignBottom | AlignVCenter;
6151 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6152 }
else if (mode == Contain) {
6153 if (row < topRow()) {
6154 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6155 }
else if (row > bottomRow()) {
6156 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6157 }
else if (row == topRow()) {
6158 if (!subRect.isValid()) {
6159 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6161 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6162 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6163 if (subRectTop < d->viewportRect.y())
6164 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6165 else if (subRectBottom > d->viewportRect.bottom())
6166 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6168 }
else if (row == bottomRow()) {
6169 if (!subRect.isValid()) {
6170 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6174 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6175 if (subRectBottom > d->viewportRect.bottom())
6176 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6179 }
else if (mode == Visible) {
6180 if (row < topRow()) {
6181 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6182 }
else if (row > bottomRow()) {
6183 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6184 }
else if (subRect.isValid()) {
6185 if (row == topRow()) {
6186 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6187 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6188 if (subRectBottom < d->viewportRect.top())
6189 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6190 else if (subRectTop > d->viewportRect.bottom())
6191 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6192 }
else if (row == bottomRow()) {
6195 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6196 if (subRectTop > d->viewportRect.bottom())
6197 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6201 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6205void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6207 Q_D(QQuickTableView);
6208 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6215 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6216 mode &= AlignLeft | AlignRight | AlignHCenter;
6217 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6218 }
else if (mode == Contain) {
6219 if (column < leftColumn()) {
6220 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6221 }
else if (column > rightColumn()) {
6222 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6223 }
else if (column == leftColumn()) {
6224 if (!subRect.isValid()) {
6225 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6227 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6228 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6229 if (subRectLeft < d->viewportRect.left())
6230 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6231 else if (subRectRight > d->viewportRect.right())
6232 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6234 }
else if (column == rightColumn()) {
6235 if (!subRect.isValid()) {
6236 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6240 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6241 if (subRectRight > d->viewportRect.right())
6242 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6245 }
else if (mode == Visible) {
6246 if (column < leftColumn()) {
6247 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6248 }
else if (column > rightColumn()) {
6249 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6250 }
else if (subRect.isValid()) {
6251 if (column == leftColumn()) {
6252 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6253 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6254 if (subRectRight < d->viewportRect.left())
6255 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6256 else if (subRectLeft > d->viewportRect.right())
6257 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6258 }
else if (column == rightColumn()) {
6261 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6262 if (subRectLeft > d->viewportRect.right())
6263 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6267 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6271void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6273 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6274 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6275 if (!horizontalMode && !verticalMode) {
6276 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6281 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6283 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6286void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6288 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6289 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6290 if (!horizontalMode && !verticalMode) {
6291 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6296 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6298 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6301#if QT_DEPRECATED_SINCE(6
, 5
)
6302void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6304 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6305 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6306 if (!horizontalMode && !verticalMode) {
6307 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6312 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6314 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6318void QQuickTableView::moveColumn(
int source,
int destination)
6320 Q_D(QQuickTableView);
6321 d->moveSection(source, destination, Qt::Horizontal);
6324void QQuickTableView::moveRow(
int source,
int destination)
6326 Q_D(QQuickTableView);
6327 d->moveSection(source, destination, Qt::Vertical);
6330void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientations orientation)
6332 Q_Q(QQuickTableView);
6334 if (source < 0 || destination < 0 ||
6335 (orientation == Qt::Horizontal &&
6336 (source >= tableSize.width() || destination >= tableSize.width())) ||
6337 (orientation == Qt::Vertical &&
6338 (source >= tableSize.height() || destination >= tableSize.height())))
6341 if (source == destination)
6344 if (m_sectionState != SectionState::Moving) {
6345 m_sectionState = SectionState::Moving;
6347 syncView->d_func()->moveSection(source, destination, orientation);
6350 initializeIndexMapping();
6353 SectionData *visualIndex =
nullptr;
6354 SectionData *logicalIndex =
nullptr;
6356 if (orientation == Qt::Horizontal) {
6357 visualIndex = visualIndices[0].data();
6358 logicalIndex = logicalIndices[0].data();
6359 }
else if (orientation == Qt::Vertical) {
6360 visualIndex = visualIndices[1].data();
6361 logicalIndex = logicalIndices[1].data();
6364 const int logical = logicalIndex[source].index;
6365 int visual = source;
6367 if (destination > source) {
6368 while (visual < destination) {
6369 SectionData &visualData = visualIndex[logicalIndex[visual + 1].index];
6370 SectionData &logicalData = logicalIndex[visual];
6371 visualData.prevIndex = visualData.index;
6372 visualData.index = visual;
6373 logicalData.prevIndex = logicalData.index;
6374 logicalData.index = logicalIndex[visual + 1].index;
6378 while (visual > destination) {
6379 SectionData &visualData = visualIndex[logicalIndex[visual - 1].index];
6380 SectionData &logicalData = logicalIndex[visual];
6381 visualData.prevIndex = visualData.index;
6382 visualData.index = visual;
6383 logicalData.prevIndex = logicalData.index;
6384 logicalData.index = logicalIndex[visual - 1].index;
6389 visualIndex[logical].prevIndex = visualIndex[logical].index;
6390 visualIndex[logical].index = destination;
6391 logicalIndex[destination].prevIndex = logicalIndex[destination].index;
6392 logicalIndex[destination].index = logical;
6396 for (
auto syncChild : std::as_const(syncChildren)) {
6397 auto syncChild_d = syncChild->d_func();
6398 if (syncChild_d->m_sectionState != SectionState::Moving &&
6399 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6400 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6401 syncChild_d->moveSection(source, destination, orientation);
6406 scheduleRebuildTable(RebuildOption::ViewportOnly);
6407 m_sectionState = SectionState::Idle;
6410 const int startIndex = (source > destination) ? destination : source;
6411 const int endIndex = (source > destination) ? source : destination;
6412 const int mapIndex =
static_cast<
int>(orientation) - 1;
6413 for (
int index = startIndex; index <= endIndex; index++) {
6414 const SectionData *logicalDataIndices = (syncView ? syncView->d_func()->logicalIndices[mapIndex].constData() : logicalIndices[mapIndex].constData());
6415 const SectionData *visualDataIndices = syncView ? syncView->d_func()->visualIndices[mapIndex].constData() : visualIndices[mapIndex].constData();
6416 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6417 if (orientation == Qt::Horizontal)
6418 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6420 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6425void QQuickTableView::clearColumnReordering()
6427 Q_D(QQuickTableView);
6428 d->clearSection(Qt::Horizontal);
6431void QQuickTableView::clearRowReordering()
6433 Q_D(QQuickTableView);
6434 d->clearSection(Qt::Vertical);
6437void QQuickTableViewPrivate::clearSection(Qt::Orientations orientation)
6439 Q_Q(QQuickTableView);
6441 const int mapIndex =
static_cast<
int>(orientation) - 1;
6442 const QList<SectionData> oldLogicalIndices = syncView ? syncView->d_func()->logicalIndices[mapIndex] : logicalIndices[mapIndex];
6443 const QList<SectionData> oldVisualIndices = syncView ? syncView->d_func()->visualIndices[mapIndex] : visualIndices[mapIndex];;
6446 syncView->d_func()->clearSection(orientation);
6449 logicalIndices[mapIndex].clear();
6450 visualIndices[mapIndex].clear();
6451 scheduleRebuildTable(RebuildOption::ViewportOnly);
6455 for (
int index = 0; index < oldLogicalIndices.size(); index++) {
6456 const SectionData *logicalDataIndices = oldLogicalIndices.constData();
6457 const SectionData *visualDataIndices = oldVisualIndices.constData();
6458 if (logicalDataIndices[index].index != index) {
6459 const int currentIndex = logicalDataIndices[index].index;
6460 if (orientation == Qt::Horizontal)
6461 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6463 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6468void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6470 if (!modelIndex.isValid())
6473 const int cellIndex = modelIndexToCellIndex(modelIndex);
6474 if (!loadedItems.contains(cellIndex))
6476 const QPoint cell = cellAtModelIndex(cellIndex);
6477 QQuickItem *item = loadedTableItem(cell)->item;
6478 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6481QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6483 Q_D(
const QQuickTableView);
6484 const int modelIndex = d->modelIndexAtCell(cell);
6485 if (!d->loadedItems.contains(modelIndex))
6487 return d->loadedItems.value(modelIndex)->item;
6490#if QT_DEPRECATED_SINCE(6
, 5
)
6491QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6493 return itemAtCell(QPoint(column, row));
6497QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6499 Q_D(
const QQuickTableView);
6500 const int serializedIndex = d->modelIndexToCellIndex(index);
6501 if (!d->loadedItems.contains(serializedIndex))
6503 return d->loadedItems.value(serializedIndex)->item;
6506#if QT_DEPRECATED_SINCE(6
, 4
)
6507QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6509 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6512QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6514 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6518QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6520 return cellAtPosition(QPoint(x, y), includeSpacing);
6523QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6525 Q_D(
const QQuickTableView);
6527 if (!d->loadedTableOuterRect.contains(position))
6528 return QPoint(-1, -1);
6530 const qreal hSpace = d->cellSpacing.width();
6531 const qreal vSpace = d->cellSpacing.height();
6532 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6533 qreal currentRowEnd = d->loadedTableOuterRect.y();
6535 int foundColumn = -1;
6538 for (
const int column : d->loadedColumns) {
6539 currentColumnEnd += d->getEffectiveColumnWidth(column);
6540 if (position.x() < currentColumnEnd) {
6541 foundColumn = column;
6544 currentColumnEnd += hSpace;
6545 if (!includeSpacing && position.x() < currentColumnEnd) {
6547 return QPoint(-1, -1);
6548 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6549 foundColumn = column;
6554 for (
const int row : d->loadedRows) {
6555 currentRowEnd += d->getEffectiveRowHeight(row);
6556 if (position.y() < currentRowEnd) {
6560 currentRowEnd += vSpace;
6561 if (!includeSpacing && position.y() < currentRowEnd) {
6563 return QPoint(-1, -1);
6565 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6571 return QPoint(foundColumn, foundRow);
6574bool QQuickTableView::isColumnLoaded(
int column)
const
6576 Q_D(
const QQuickTableView);
6577 if (!d->loadedColumns.contains(column))
6580 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6583 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6590bool QQuickTableView::isRowLoaded(
int row)
const
6592 Q_D(
const QQuickTableView);
6593 if (!d->loadedRows.contains(row))
6596 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6599 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6606qreal QQuickTableView::columnWidth(
int column)
const
6608 Q_D(
const QQuickTableView);
6609 if (!isColumnLoaded(column))
6612 return d->getEffectiveColumnWidth(column);
6615qreal QQuickTableView::rowHeight(
int row)
const
6617 Q_D(
const QQuickTableView);
6618 if (!isRowLoaded(row))
6621 return d->getEffectiveRowHeight(row);
6624qreal QQuickTableView::implicitColumnWidth(
int column)
const
6626 Q_D(
const QQuickTableView);
6627 if (!isColumnLoaded(column))
6630 return d->sizeHintForColumn(column);
6633qreal QQuickTableView::implicitRowHeight(
int row)
const
6635 Q_D(
const QQuickTableView);
6636 if (!isRowLoaded(row))
6639 return d->sizeHintForRow(row);
6642void QQuickTableView::setColumnWidth(
int column, qreal size)
6644 Q_D(QQuickTableView);
6646 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6650 if (d->syncHorizontally) {
6651 d->syncView->setColumnWidth(column, size);
6655 if (qFuzzyCompare(explicitColumnWidth(column), size))
6659 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6661 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6663 if (d->loadedItems.isEmpty())
6666 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6667 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6668 d->forceLayout(
false);
6671void QQuickTableView::clearColumnWidths()
6673 Q_D(QQuickTableView);
6675 if (d->syncHorizontally) {
6676 d->syncView->clearColumnWidths();
6680 if (d->explicitColumnWidths.isEmpty())
6683 d->explicitColumnWidths.clear();
6684 d->forceLayout(
false);
6687qreal QQuickTableView::explicitColumnWidth(
int column)
const
6689 Q_D(
const QQuickTableView);
6691 if (d->syncHorizontally)
6692 return d->syncView->explicitColumnWidth(column);
6694 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6695 if (it != d->explicitColumnWidths.constEnd())
6700void QQuickTableView::setRowHeight(
int row, qreal size)
6702 Q_D(QQuickTableView);
6704 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
6708 if (d->syncVertically) {
6709 d->syncView->setRowHeight(row, size);
6713 if (qFuzzyCompare(explicitRowHeight(row), size))
6717 d->explicitRowHeights.remove(d->logicalRowIndex(row));
6719 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
6721 if (d->loadedItems.isEmpty())
6724 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
6725 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
6726 d->forceLayout(
false);
6729void QQuickTableView::clearRowHeights()
6731 Q_D(QQuickTableView);
6733 if (d->syncVertically) {
6734 d->syncView->clearRowHeights();
6738 if (d->explicitRowHeights.isEmpty())
6741 d->explicitRowHeights.clear();
6742 d->forceLayout(
false);
6745qreal QQuickTableView::explicitRowHeight(
int row)
const
6747 Q_D(
const QQuickTableView);
6749 if (d->syncVertically)
6750 return d->syncView->explicitRowHeight(row);
6752 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
6753 if (it != d->explicitRowHeights.constEnd())
6758QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
6760 Q_D(
const QQuickTableView);
6761 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
6764 auto const qaim = d->model->abstractItemModel();
6768 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
6771QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
6773 if (!index.isValid() || index.parent().isValid())
6775 Q_D(
const QQuickTableView);
6776 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
6779#if QT_DEPRECATED_SINCE(6
, 4
)
6780QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
6782 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
6788 return modelIndex({row, column});
6790 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
6791 "Use index(row, column) instead. For more information, see "
6792 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
6793 return modelIndex({column, row});
6798QModelIndex QQuickTableView::index(
int row,
int column)
const
6800 return modelIndex({column, row});
6803int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
6805 return cellAtIndex(index).y();
6808int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
6810 return cellAtIndex(index).x();
6813void QQuickTableView::forceLayout()
6815 d_func()->forceLayout(
true);
6818void QQuickTableView::edit(
const QModelIndex &index)
6820 Q_D(QQuickTableView);
6822 if (!d->canEdit(index,
true))
6825 if (d->editIndex == index)
6831 if (!d->editModel) {
6832 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
6833 d->editModel->useImportVersion(d->resolveImportVersion());
6834 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
this,
6835 [
this, d] (
int serializedModelIndex, QObject *object) {
6841 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
6842 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
6843 d->editItem = qmlobject_cast<QQuickItem*>(object);
6847 d->initItemCallback(serializedModelIndex, object);
6848 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
6850 d->editItem->setParentItem(cellItem);
6857 if (d->selectionModel)
6858 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
6861 d->closeEditorAndCommit();
6863 const auto cellItem = itemAtCell(cellAtIndex(index));
6865 const auto attached = d->getAttachedObject(cellItem);
6868 d->editModel->setModel(d->tableModel->model());
6869 d->editModel->setDelegate(attached->editDelegate());
6871 const int cellIndex = d->getEditCellIndex(index);
6872 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
6874 d->editIndex = QModelIndex();
6875 d->editItem =
nullptr;
6876 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
6883 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
6884 d->editItem =
nullptr;
6885 d->editIndex = QModelIndex();
6886 d->editModel->release(object, QQmlInstanceModel::NotReusable);
6892 d->model->object(cellIndex, QQmlIncubator::Synchronous);
6895 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
6898 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
6899 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
6902void QQuickTableView::closeEditor()
6904 Q_D(QQuickTableView);
6909 QQuickItem *cellItem = d->editItem->parentItem();
6910 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
6911 d->editItem =
nullptr;
6914 const int cellIndex = d->getEditCellIndex(d->editIndex);
6915 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
6917 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
6919 if (d->editIndex.isValid()) {
6922 d->editIndex = QModelIndex();
6926QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
6928 return new QQuickTableViewAttached(obj);
6931void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
6933 Q_D(QQuickTableView);
6934 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
6936 if (d->tableModel) {
6939 d->tableModel->drainReusableItemsPool(0);
6942 d->forceLayout(
false);
6945void QQuickTableView::viewportMoved(Qt::Orientations orientation)
6947 Q_D(QQuickTableView);
6953 QQuickFlickable::viewportMoved(orientation);
6954 if (d->inSetLocalViewportPos)
6961 d->syncViewportPosRecursive();
6963 auto rootView = d->rootSyncView();
6964 auto rootView_d = rootView->d_func();
6966 rootView_d->scheduleRebuildIfFastFlick();
6968 if (!rootView_d->polishScheduled) {
6969 if (rootView_d->scheduledRebuildOptions) {
6976 const bool updated = rootView->d_func()->updateTableRecursive();
6986void QQuickTableView::keyPressEvent(QKeyEvent *e)
6988 Q_D(QQuickTableView);
6990 if (!d->keyNavigationEnabled) {
6991 QQuickFlickable::keyPressEvent(e);
6995 if (d->tableSize.isEmpty())
6998 if (d->editIndex.isValid()) {
7004 if (d->setCurrentIndexFromKeyEvent(e))
7007 if (d->editFromKeyEvent(e))
7010 QQuickFlickable::keyPressEvent(e);
7013bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
7015 Q_D(QQuickTableView);
7017 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
7020 return QQuickFlickable::eventFilter(obj, event);
7023 switch (event->type()) {
7024 case QEvent::KeyPress: {
7025 Q_ASSERT(d->editItem);
7026 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7027 switch (keyEvent->key()) {
7029 case Qt::Key_Return:
7030 d->closeEditorAndCommit();
7033 case Qt::Key_Backtab:
7034 if (activeFocusOnTab()) {
7035 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7036 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7037 if (d->canEdit(currentIndex,
false))
7043 case Qt::Key_Escape:
7048 case QEvent::FocusOut:
7051 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7052 d->closeEditorAndCommit();
7058 return QQuickFlickable::eventFilter(obj, event);
7061bool QQuickTableView::alternatingRows()
const
7063 return d_func()->alternatingRows;
7066void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7068 Q_D(QQuickTableView);
7069 if (d->alternatingRows == alternatingRows)
7072 d->alternatingRows = alternatingRows;
7073 emit alternatingRowsChanged();
7076QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7078 return d_func()->selectionBehavior;
7081void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7083 Q_D(QQuickTableView);
7084 if (d->selectionBehavior == selectionBehavior)
7087 d->selectionBehavior = selectionBehavior;
7088 emit selectionBehaviorChanged();
7091QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7093 return d_func()->selectionMode;
7096void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7098 Q_D(QQuickTableView);
7099 if (d->selectionMode == selectionMode)
7102 d->selectionMode = selectionMode;
7103 emit selectionModeChanged();
7106bool QQuickTableView::resizableColumns()
const
7108 return d_func()->resizableColumns;
7111void QQuickTableView::setResizableColumns(
bool enabled)
7113 Q_D(QQuickTableView);
7114 if (d->resizableColumns == enabled)
7117 d->resizableColumns = enabled;
7118 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7119 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7121 emit resizableColumnsChanged();
7124bool QQuickTableView::resizableRows()
const
7126 return d_func()->resizableRows;
7129void QQuickTableView::setResizableRows(
bool enabled)
7131 Q_D(QQuickTableView);
7132 if (d->resizableRows == enabled)
7135 d->resizableRows = enabled;
7136 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7137 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7139 emit resizableRowsChanged();
7144 : QQuickHoverHandler(view->contentItem())
7148 connect(
this, &QQuickHoverHandler::hoveredChanged,
this, [
this] {
7153#if QT_CONFIG(cursor)
7154 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7155 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7156 tableViewPrivate->updateCursor();
7163 QQuickHoverHandler::handleEventPoint(event, point);
7165 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7166#if QT_CONFIG(cursor)
7167 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7170 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7171 const auto item = tableView->itemAtCell(cell);
7175#if QT_CONFIG(cursor)
7176 tableViewPrivate->updateCursor();
7181 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7182 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7183 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7184 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7185 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7186#if QT_CONFIG(cursor)
7187 tableViewPrivate->updateCursor();
7198 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7203 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7207 if (event->type() == QEvent::Type::Wheel)
7212 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7213 return !tableView->isMoving();
7222 setObjectName(
"tableViewResizeHandler");
7226 , QPointingDevice::GrabTransition transition
7228 , QEventPoint &point)
7230 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7232 switch (transition) {
7233 case QPointingDevice::GrabPassive:
7234 case QPointingDevice::GrabExclusive:
7236 case QPointingDevice::UngrabPassive:
7237 case QPointingDevice::UngrabExclusive:
7238 case QPointingDevice::CancelGrabPassive:
7239 case QPointingDevice::CancelGrabExclusive:
7240 case QPointingDevice::OverrideGrabPassive:
7241 if (m_state == DraggingStarted || m_state == Dragging) {
7242 m_state = DraggingFinished;
7243 updateDrag(ev, point);
7251 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7252 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7253 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7260 updateDrag(event, point);
7265 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7266 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7268 if (m_state == DraggingFinished)
7269 m_state = Listening;
7271 if (point.state() == QEventPoint::Pressed) {
7272 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7273 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7274 if (m_row != -1 || m_column != -1)
7276 }
else if (point.state() == QEventPoint::Released) {
7277 if (m_state == DraggingStarted || m_state == Dragging)
7278 m_state = DraggingFinished;
7280 m_state = Listening;
7281 }
else if (point.state() == QEventPoint::Updated) {
7286 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7287 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7288 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7289 if (dragDist > qApp->styleHints()->startDragDistance())
7290 m_state = DraggingStarted;
7292 case DraggingStarted:
7297 case DraggingFinished:
7307 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7308#if QT_CONFIG(cursor)
7309 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7316 setPassiveGrab(event, point,
true);
7320 tableView->setFiltersChildMouseEvents(
false);
7321#if QT_CONFIG(cursor)
7322 tableViewPrivate->setActivePointerHandler(
this);
7325 case DraggingStarted:
7326 setExclusiveGrab(event, point,
true);
7327 m_columnStartX = point.position().x();
7328 m_columnStartWidth = tableView->columnWidth(m_column);
7329 m_rowStartY = point.position().y();
7330 m_rowStartHeight = tableView->rowHeight(m_row);
7331#if QT_CONFIG(cursor)
7332 tableViewPrivate->updateCursor();
7336 const qreal distX = point.position().x() - m_columnStartX;
7337 const qreal distY = point.position().y() - m_rowStartY;
7339 tableView->setColumnWidth(
m_column, qMax(0.001, m_columnStartWidth + distX));
7341 tableView->setRowHeight(
m_row, qMax(0.001, m_rowStartHeight + distY));
7343 case DraggingFinished: {
7344 tableView->setFiltersChildMouseEvents(
true);
7345#if QT_CONFIG(cursor)
7346 tableViewPrivate->setActivePointerHandler(
nullptr);
7347 tableViewPrivate->updateCursor();
7354#if QT_CONFIG(quick_draganddrop)
7356QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7357 : QQuickTableViewPointerHandler(view)
7359 setObjectName(
"tableViewDragHandler");
7362QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7367void QQuickTableViewSectionDragHandler::resetDragData()
7369 if (m_state != Listening) {
7370 m_state = Listening;
7371 resetSectionOverlay();
7374 if (m_grabResult.data())
7375 m_grabResult.data()->disconnect();
7376 if (!m_drag.isNull()) {
7377 m_drag->disconnect();
7380 if (!m_dropArea.isNull()) {
7381 m_dropArea->disconnect();
7384 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7385 tableView->setFiltersChildMouseEvents(
true);
7389void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7391 if (m_destination != -1) {
7392 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7393 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7394 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7395 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7396 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7401void QQuickTableViewSectionDragHandler::grabSection()
7404 QPixmap pixmap(m_grabResult->image().size());
7405 pixmap.fill(Qt::transparent);
7406 QPainter painter(&pixmap);
7407 painter.setOpacity(0.6);
7408 painter.drawImage(0, 0, m_grabResult->image());
7412 auto *mimeData =
new QMimeData();
7413 mimeData->setImageData(pixmap);
7414 m_drag->setMimeData(mimeData);
7415 m_drag->setPixmap(pixmap);
7418void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7422 if (m_state == Dragging) {
7423 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7424 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7425 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7426 m_state = DraggingFinished;
7427 resetSectionOverlay();
7428 if (m_scrollTimer.isActive())
7429 m_scrollTimer.stop();
7434void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7438 if (m_state == Dragging) {
7439 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7440 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7441 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7442 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7444 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7445 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7446 if (newDestination != m_destination) {
7448 resetSectionOverlay();
7450 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7451 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7452 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7453 m_destination = newDestination;
7457 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7458 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7459 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7460 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7461 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7462 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7463 if (useStartPos || useEndPos) {
7464 if (!m_scrollTimer.isActive()) {
7465 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7466 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7467 m_scrollTimer.start(1);
7470 if (m_scrollTimer.isActive())
7471 m_scrollTimer.stop();
7476void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7480 if (action == Qt::IgnoreAction) {
7481 resetSectionOverlay();
7482 if (m_scrollTimer.isActive())
7483 m_scrollTimer.stop();
7487void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7489 QQuickSinglePointHandler::handleEventPoint(event, point);
7491 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7492 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7493 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7494 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7497 if (m_state == DraggingFinished) {
7498 if (m_scrollTimer.isActive())
7499 m_scrollTimer.stop();
7503 if (point.state() == QEventPoint::Pressed) {
7507 setPassiveGrab(event, point,
true);
7511 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7512 tableView->setFiltersChildMouseEvents(
false);
7514 }
else if (point.state() == QEventPoint::Released) {
7516 if (m_scrollTimer.isActive())
7517 m_scrollTimer.stop();
7519 }
else if (point.state() == QEventPoint::Updated) {
7521 const qreal distX = point.position().x() - point.pressPosition().x();
7522 const qreal distY = point.position().y() - point.pressPosition().y();
7523 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7524 if (dragDist > qApp->styleHints()->startDragDistance()) {
7528 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7529 auto *item = tableView->itemAtCell(cell);
7532 if (m_drag.isNull()) {
7533 m_drag =
new QDrag(item);
7534 connect(m_drag.data(), &QDrag::actionChanged,
this,
7535 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7538 QObject::connect(&m_scrollTimer, &QTimer::timeout,
this, [&]{
7539 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7540 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7541 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7542 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7545 if (m_dropArea.isNull()) {
7546 m_dropArea =
new QQuickDropArea(tableView);
7547 m_dropArea->setSize(tableView->size());
7548 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7549 &QQuickTableViewSectionDragHandler::handleDrag);
7550 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7551 &QQuickTableViewSectionDragHandler::handleDrop);
7554 m_grabResult = item->grabToImage();
7555 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7556 &QQuickTableViewSectionDragHandler::grabSection);
7558 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7559 m_state = DraggingStarted;
7561 tableViewPrivate->setActivePointerHandler(
this);
7565 case DraggingStarted: {
7566 if (m_drag && m_drag->mimeData()) {
7567 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7569 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7571 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7575 if (m_state == Dragging)
7578 tableViewPrivate->setActivePointerHandler(
nullptr);
7592void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7594 if (!sectionDragHandler) {
7595 Q_Q(QQuickTableView);
7596 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7597 sectionDragHandler->setSectionOrientation(orientation);
7601void QQuickTableViewPrivate::destroySectionDragHandler()
7603 if (sectionDragHandler) {
7604 delete sectionDragHandler;
7605 sectionDragHandler =
nullptr;
7610void QQuickTableViewPrivate::initializeIndexMapping()
7612 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7613 visualIndex.resize(size);
7614 logicalIndex.resize(size);
7615 for (
int index = 0; index < size; ++index)
7616 visualIndex[index].index = logicalIndex[index].index = index;
7619 if (visualIndices[0].size() != tableSize.width()
7620 || logicalIndices[0].size() != tableSize.width())
7621 initIndices(visualIndices[0], logicalIndices[0], tableSize.width());
7623 if (visualIndices[1].size() != tableSize.height()
7624 || logicalIndices[1].size() != tableSize.height())
7625 initIndices(visualIndices[1], logicalIndices[1], tableSize.height());
7628void QQuickTableViewPrivate::clearIndexMapping()
7630 logicalIndices[0].clear();
7631 visualIndices[0].clear();
7633 logicalIndices[1].clear();
7634 visualIndices[1].clear();
7637int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7640 return syncView->d_func()->logicalRowIndex(visualIndex);
7641 if (logicalIndices[1].isEmpty() || visualIndex < 0)
7643 return logicalIndices[1].constData()[visualIndex].index;
7646int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7649 return syncView->d_func()->logicalColumnIndex(visualIndex);
7650 if (logicalIndices[0].isEmpty() || visualIndex < 0)
7652 return logicalIndices[0].constData()[visualIndex].index;
7655int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7658 return syncView->d_func()->visualRowIndex(logicalIndex);
7659 if (visualIndices[1].isEmpty() || logicalIndex < 0)
7660 return logicalIndex;
7661 return visualIndices[1].constData()[logicalIndex].index;
7664int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7667 return syncView->d_func()->visualColumnIndex(logicalIndex);
7668 if (visualIndices[0].isEmpty() || logicalIndex < 0)
7669 return logicalIndex;
7670 return visualIndices[0].constData()[logicalIndex].index;
7673int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7677 const bool hasProxyModel = (modelImpl() != assignedModel);
7678 return modelIndexToCellIndex(index, hasProxyModel);
7684 : QQuickTapHandler(view->contentItem())
7686 setObjectName(
"tableViewTapHandler");
7691 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7692 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7693 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
7698#include "moc_qquicktableview_p.cpp"
7699#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