8#include <QtCore/qtimer.h>
9#include <QtCore/qdir.h>
10#include <QtCore/qmimedata.h>
11#include <QtQmlModels/private/qqmldelegatemodel_p.h>
12#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
13#include <QtQml/private/qqmlincubator_p.h>
14#include <QtQmlModels/private/qqmlchangeset_p.h>
15#include <QtQml/qqmlinfo.h>
16#include <QtQuick/qquickitemgrabresult.h>
18#include <QtQuick/private/qquickflickable_p_p.h>
19#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
20#include <QtQuick/private/qquicktaphandler_p.h>
23
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
384
385
386
387
388
389
390
391
392
393
396
397
398
399
400
401
402
403
404
405
406
407
410
411
412
413
414
415
418
419
420
421
422
423
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
474
475
476
477
478
479
480
481
482
483
484
487
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
540
541
542
543
544
545
546
547
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
624
625
626
627
628
629
632
633
634
635
636
637
640
641
642
643
644
645
648
649
650
651
652
653
656
657
658
659
660
661
662
663
664
665
666
669
670
671
672
673
674
675
676
677
678
679
682
683
684
685
686
687
688
689
690
691
692
693
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
717
718
719
720
721
722
723
724
725
726
727
728
729
732
733
734
735
736
737
738
739
740
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
761
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
790
791
792
793
794
795
798
799
800
801
802
803
806
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
863
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
922
923
924
925
926
927
928
929
930
931
932
933
936
937
938
939
940
941
942
943
944
945
946
947
948
951
952
953
954
955
956
957
958
959
960
961
962
963
966
967
968
969
970
973
974
975
976
977
978
979
980
981
982
985
986
987
988
989
990
991
992
993
994
997
998
999
1000
1001
1002
1003
1004
1005
1008
1009
1010
1011
1012
1013
1014
1015
1018
1019
1020
1021
1022
1023
1024
1025
1026
1029
1030
1031
1032
1033
1034
1035
1036
1039
1040
1041
1042
1043
1044
1045
1046
1047
1050
1051
1052
1053
1054
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1075
1076
1077
1078
1079
1082
1083
1084
1085
1086
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1108
1109
1110
1111
1114
1115
1116
1117
1118
1119
1120
1121
1124
1125
1126
1127
1128
1129
1130
1131
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1160
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
1206
1207
1208
1209
1210
1211
1212
1213
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1232
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
1278
1279
1280
1281
1282
1283
1284
1285
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1350
1351
1352
1353
1354
1355
1356
1359
1360
1361
1362
1363
1364
1365
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1404
1405
1406
1407
1408
1409
1410
1411
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1430
1431
1432
1433
1434
1435
1436
1439
1440
1441
1442
1443
1444
1445
1448
1449
1450
1451
1452
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
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
1570QQuickSelectable::~QQuickSelectable() { }
1574#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
1575#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
1588#define TV_REBUILDSTATE(STATE)
1589 case QQuickTableViewPrivate::RebuildState::STATE:
1590 dbg << QStringLiteral(#STATE); break;
1610#define TV_REBUILDOPTION(OPTION)
1611 if (options & QQuickTableViewPrivate::RebuildOption::OPTION)
1612 dbg << QStringLiteral(#OPTION)
1614 if (options == QQuickTableViewPrivate::RebuildOption::None) {
1615 dbg << QStringLiteral(
"None");
1631QQuickTableViewPrivate::EdgeRange::EdgeRange()
1632 : startIndex(kEdgeIndexNotSet)
1633 , endIndex(kEdgeIndexNotSet)
1637bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge,
int index)
1639 if (startIndex == kEdgeIndexNotSet)
1642 if (endIndex == kEdgeIndexAtEnd) {
1646 return index <= startIndex;
1648 case Qt::BottomEdge:
1649 return index >= startIndex;
1653 const int s = std::min(startIndex, endIndex);
1654 const int e = std::max(startIndex, endIndex);
1655 return index >= s && index <= e;
1658QQuickTableViewPrivate::QQuickTableViewPrivate()
1659 : QQuickFlickablePrivate()
1663QQuickTableViewPrivate::~QQuickTableViewPrivate()
1666 QQuickItem *cellItem = editItem->parentItem();
1668 editModel->dispose(editItem);
1669 tableModel->release(cellItem, QQmlInstanceModel::NotReusable);
1675 for (
auto *fxTableItem : loadedItems) {
1676 if (
auto item = fxTableItem->item) {
1677 if (fxTableItem->ownItem)
1679 else if (tableModel)
1680 tableModel->dispose(item);
1689QString QQuickTableViewPrivate::tableLayoutToString()
const
1691 if (loadedItems.isEmpty())
1692 return QLatin1String(
"table is empty!");
1693 return QString(QLatin1String(
"table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
1694 .arg(leftColumn()).arg(topRow())
1695 .arg(rightColumn()).arg(bottomRow())
1696 .arg(loadedItems.size())
1697 .arg(loadedTableOuterRect.x())
1698 .arg(loadedTableOuterRect.y())
1699 .arg(loadedTableOuterRect.width())
1700 .arg(loadedTableOuterRect.height());
1703void QQuickTableViewPrivate::dumpTable()
const
1705 auto listCopy = loadedItems.values();
1706 std::stable_sort(listCopy.begin(), listCopy.end(),
1707 [](
const FxTableItem *lhs,
const FxTableItem *rhs)
1708 {
return lhs->index < rhs->index; });
1710 qWarning() << QStringLiteral(
"******* TABLE DUMP *******");
1711 for (
int i = 0; i < listCopy.size(); ++i)
1712 qWarning() <<
static_cast<FxTableItem *>(listCopy.at(i))->cell;
1713 qWarning() << tableLayoutToString();
1715 const QString filename = QStringLiteral(
"QQuickTableView_dumptable_capture.png");
1716 const QString path = QDir::current().absoluteFilePath(filename);
1717 if (q_func()->window() && q_func()->window()->grabWindow().save(path))
1718 qWarning() <<
"Window capture saved to:" << path;
1721void QQuickTableViewPrivate::setRequiredProperty(
const char *property,
1722 const QVariant &value,
int serializedModelIndex, QObject *object,
bool init)
1724 Q_Q(QQuickTableView);
1726 QQmlTableInstanceModel *tableInstanceModel = qobject_cast<QQmlTableInstanceModel *>(model);
1727 if (!tableInstanceModel) {
1737 const QString propertyName = QString::fromUtf8(property);
1740 bool wasRequired =
false;
1741 if (object == editItem) {
1744 wasRequired = editModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1746 wasRequired = tableInstanceModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1749 QStringList propertyList = object->property(kRequiredProperties).toStringList();
1750 object->setProperty(kRequiredProperties, propertyList << propertyName);
1754 const QStringList propertyList = object->property(kRequiredProperties).toStringList();
1755 if (propertyList.contains(propertyName)) {
1756 const auto metaObject = object->metaObject();
1757 const int propertyIndex = metaObject->indexOfProperty(property);
1758 const auto metaProperty = metaObject->property(propertyIndex);
1759 metaProperty.write(object, value);
1769 const QModelIndex modelIndex = q->modelIndex(cellAtModelIndex(serializedModelIndex));
1770 if (modelIndex == editIndex) {
1771 const QStringList propertyList = editItem->property(kRequiredProperties).toStringList();
1772 if (propertyList.contains(propertyName)) {
1773 const auto metaObject = editItem->metaObject();
1774 const int propertyIndex = metaObject->indexOfProperty(property);
1775 const auto metaProperty = metaObject->property(propertyIndex);
1776 metaProperty.write(editItem, value);
1784QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget()
const
1786 return const_cast<QQuickTableView *>(q_func())->contentItem();
1789bool QQuickTableViewPrivate::hasSelection()
const
1791 return selectionModel && selectionModel->hasSelection();
1794bool QQuickTableViewPrivate::startSelection(
const QPointF &pos, Qt::KeyboardModifiers modifiers)
1796 Q_Q(QQuickTableView);
1797 if (!selectionModel) {
1798 if (warnNoSelectionModel)
1799 qmlWarning(q_func()) <<
"Cannot start selection: no SelectionModel assigned!";
1800 warnNoSelectionModel =
false;
1804 if (selectionBehavior == QQuickTableView::SelectionDisabled) {
1805 qmlWarning(q) <<
"Cannot start selection: TableView.selectionBehavior == TableView.SelectionDisabled";
1810 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
1816 if (selectionMode == QQuickTableView::SingleSelection
1817 || selectionMode == QQuickTableView::ContiguousSelection
1818 || modifiers == Qt::NoModifier)
1820 else if (selectionModel)
1821 existingSelection = selectionModel->selection();
1827 selectionFlag = QItemSelectionModel::Select;
1828 if (modifiers & Qt::ControlModifier) {
1829 QPoint startCell = clampedCellAtPos(pos);
1830 if (!cellIsValid(startCell))
1832 const QModelIndex startIndex = q->index(startCell.y(), startCell.x());
1833 if (selectionModel->isSelected(startIndex))
1834 selectionFlag = QItemSelectionModel::Deselect;
1837 selectionStartCell = QPoint(-1, -1);
1838 selectionEndCell = QPoint(-1, -1);
1839 closeEditorAndCommit();
1843void QQuickTableViewPrivate::setSelectionStartPos(
const QPointF &pos)
1845 Q_Q(QQuickTableView);
1846 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1847 if (loadedItems.isEmpty())
1849 if (!selectionModel) {
1850 if (warnNoSelectionModel)
1851 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1852 warnNoSelectionModel =
false;
1855 const QAbstractItemModel *qaim = selectionModel->model();
1859 if (selectionMode == QQuickTableView::SingleSelection
1860 && cellIsValid(selectionStartCell)) {
1864 const QRect prevSelection = selection();
1867 if (pos.x() == -1) {
1869 clampedCell = q->cellAtIndex(selectionModel->currentIndex());
1871 clampedCell = clampedCellAtPos(pos);
1872 if (cellIsValid(clampedCell))
1873 setCurrentIndex(clampedCell);
1876 if (!cellIsValid(clampedCell))
1879 switch (selectionBehavior) {
1880 case QQuickTableView::SelectCells:
1881 selectionStartCell = clampedCell;
1883 case QQuickTableView::SelectRows:
1884 selectionStartCell = QPoint(0, clampedCell.y());
1886 case QQuickTableView::SelectColumns:
1887 selectionStartCell = QPoint(clampedCell.x(), 0);
1889 case QQuickTableView::SelectionDisabled:
1893 if (!cellIsValid(selectionEndCell))
1897 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1898 updateSelection(prevSelection, selection());
1901void QQuickTableViewPrivate::setSelectionEndPos(
const QPointF &pos)
1903 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1904 if (loadedItems.isEmpty())
1906 if (!selectionModel) {
1907 if (warnNoSelectionModel)
1908 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1909 warnNoSelectionModel =
false;
1912 const QAbstractItemModel *qaim = selectionModel->model();
1916 const QRect prevSelection = selection();
1919 if (selectionMode == QQuickTableView::SingleSelection) {
1920 clampedCell = selectionStartCell;
1922 clampedCell = clampedCellAtPos(pos);
1923 if (!cellIsValid(clampedCell))
1927 setCurrentIndex(clampedCell);
1929 switch (selectionBehavior) {
1930 case QQuickTableView::SelectCells:
1931 selectionEndCell = clampedCell;
1933 case QQuickTableView::SelectRows:
1934 selectionEndCell = QPoint(tableSize.width() - 1, clampedCell.y());
1936 case QQuickTableView::SelectColumns:
1937 selectionEndCell = QPoint(clampedCell.x(), tableSize.height() - 1);
1939 case QQuickTableView::SelectionDisabled:
1943 if (!cellIsValid(selectionStartCell))
1947 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1948 updateSelection(prevSelection, selection());
1951QPoint QQuickTableViewPrivate::clampedCellAtPos(
const QPointF &pos)
const
1953 Q_Q(
const QQuickTableView);
1956 QPoint cell = q->cellAtPosition(pos,
true);
1957 if (cellIsValid(cell))
1960 if (loadedTableOuterRect.width() == 0 || loadedTableOuterRect.height() == 0)
1961 return QPoint(-1, -1);
1965 qBound(loadedTableOuterRect.x(), pos.x(), loadedTableOuterRect.right() - 1),
1966 qBound(loadedTableOuterRect.y(), pos.y(), loadedTableOuterRect.bottom() - 1));
1967 QPointF clampedPosInView = q->mapFromItem(selectionPointerHandlerTarget(), clampedPos);
1968 clampedPosInView.rx() = qBound(0., clampedPosInView.x(), viewportRect.width());
1969 clampedPosInView.ry() = qBound(0., clampedPosInView.y(), viewportRect.height());
1970 clampedPos = q->mapToItem(selectionPointerHandlerTarget(), clampedPosInView);
1972 return q->cellAtPosition(clampedPos,
true);
1975void QQuickTableViewPrivate::updateSelection(
const QRect &oldSelection,
const QRect &newSelection)
1977 const QAbstractItemModel *qaim = selectionModel->model();
1978 const QRect oldRect = oldSelection.normalized();
1979 const QRect newRect = newSelection.normalized();
1981 QItemSelection select;
1982 QItemSelection deselect;
1986 const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
1987 const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
1988 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
1989 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
1990 select.append(QItemSelection(logicalModelIndex, logicalModelIndex));
1995 if (oldRect.x() < newRect.x()) {
1996 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
1997 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
1998 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
1999 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2000 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2002 }
else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
2003 const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
2004 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2005 for (
auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2006 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2007 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2011 if (oldRect.y() < newRect.y()) {
2012 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2013 const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
2014 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2015 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2016 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2018 }
else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
2019 const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
2020 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2021 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2022 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
2023 deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2027 if (selectionFlag == QItemSelectionModel::Select) {
2029 deselect.merge(existingSelection, QItemSelectionModel::Deselect);
2030 selectionModel->select(deselect, QItemSelectionModel::Deselect);
2031 selectionModel->select(select, QItemSelectionModel::Select);
2032 }
else if (selectionFlag == QItemSelectionModel::Deselect){
2033 QItemSelection oldSelection = existingSelection;
2034 oldSelection.merge(select, QItemSelectionModel::Deselect);
2035 selectionModel->select(oldSelection, QItemSelectionModel::Select);
2036 selectionModel->select(select, QItemSelectionModel::Deselect);
2042void QQuickTableViewPrivate::cancelSelectionTracking()
2045 selectionStartCell = QPoint(-1, -1);
2046 selectionEndCell = QPoint(-1, -1);
2047 existingSelection.clear();
2048 selectionFlag = QItemSelectionModel::NoUpdate;
2049 if (selectableCallbackFunction)
2050 selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
2053void QQuickTableViewPrivate::clearSelection()
2055 if (!selectionModel)
2057 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2058 selectionModel->clearSelection();
2061void QQuickTableViewPrivate::normalizeSelection()
2067 if (selectionEndCell.x() < selectionStartCell.x())
2068 std::swap(selectionStartCell.rx(), selectionEndCell.rx());
2069 if (selectionEndCell.y() < selectionStartCell.y())
2070 std::swap(selectionStartCell.ry(), selectionEndCell.ry());
2073QRectF QQuickTableViewPrivate::selectionRectangle()
const
2075 Q_Q(
const QQuickTableView);
2077 if (loadedColumns.isEmpty() || loadedRows.isEmpty())
2080 QPoint topLeftCell = selectionStartCell;
2081 QPoint bottomRightCell = selectionEndCell;
2082 if (bottomRightCell.x() < topLeftCell.x())
2083 std::swap(topLeftCell.rx(), bottomRightCell.rx());
2084 if (selectionEndCell.y() < topLeftCell.y())
2085 std::swap(topLeftCell.ry(), bottomRightCell.ry());
2087 const QPoint leftCell(topLeftCell.x(), topRow());
2088 const QPoint topCell(leftColumn(), topLeftCell.y());
2089 const QPoint rightCell(bottomRightCell.x(), topRow());
2090 const QPoint bottomCell(leftColumn(), bottomRightCell.y());
2103 if (loadedItems.contains(modelIndexAtCell(leftCell)))
2104 left = loadedTableItem(leftCell)->geometry().left();
2105 else if (leftCell.x() > rightColumn())
2106 left = q->contentWidth();
2108 if (loadedItems.contains(modelIndexAtCell(topCell)))
2109 top = loadedTableItem(topCell)->geometry().top();
2110 else if (topCell.y() > bottomRow())
2111 top = q->contentHeight();
2113 if (loadedItems.contains(modelIndexAtCell(rightCell)))
2114 right = loadedTableItem(rightCell)->geometry().right();
2115 else if (rightCell.x() > rightColumn())
2116 right = q->contentWidth();
2118 if (loadedItems.contains(modelIndexAtCell(bottomCell)))
2119 bottom = loadedTableItem(bottomCell)->geometry().bottom();
2120 else if (bottomCell.y() > bottomRow())
2121 bottom = q->contentHeight();
2123 return QRectF(left, top, right - left, bottom - top);
2126QRect QQuickTableViewPrivate::selection()
const
2128 const qreal w = selectionEndCell.x() - selectionStartCell.x();
2129 const qreal h = selectionEndCell.y() - selectionStartCell.y();
2130 return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
2133QSizeF QQuickTableViewPrivate::scrollTowardsPoint(
const QPointF &pos,
const QSizeF &step)
2135 Q_Q(QQuickTableView);
2137 if (loadedItems.isEmpty())
2147 const bool outsideLeft = pos.x() < viewportRect.x();
2148 const bool outsideRight = pos.x() >= viewportRect.right() - 1;
2149 const bool outsideTop = pos.y() < viewportRect.y();
2150 const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
2153 const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
2154 const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
2155 if (remainingDist > 0 || !firstColumnLoaded) {
2156 qreal stepX = step.width();
2157 if (firstColumnLoaded)
2158 stepX = qMin(stepX, remainingDist);
2159 q->setContentX(q->contentX() - stepX);
2160 dist.setWidth(pos.x() - viewportRect.left() - 1);
2162 }
else if (outsideRight) {
2163 const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
2164 const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
2165 if (remainingDist > 0 || !lastColumnLoaded) {
2166 qreal stepX = step.width();
2167 if (lastColumnLoaded)
2168 stepX = qMin(stepX, remainingDist);
2169 q->setContentX(q->contentX() + stepX);
2170 dist.setWidth(pos.x() - viewportRect.right() - 1);
2175 const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
2176 const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
2177 if (remainingDist > 0 || !firstRowLoaded) {
2178 qreal stepY = step.height();
2180 stepY = qMin(stepY, remainingDist);
2181 q->setContentY(q->contentY() - stepY);
2182 dist.setHeight(pos.y() - viewportRect.top() - 1);
2184 }
else if (outsideBottom) {
2185 const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
2186 const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
2187 if (remainingDist > 0 || !lastRowLoaded) {
2188 qreal stepY = step.height();
2190 stepY = qMin(stepY, remainingDist);
2191 q->setContentY(q->contentY() + stepY);
2192 dist.setHeight(pos.y() - viewportRect.bottom() - 1);
2199void QQuickTableViewPrivate::setCallback(std::function<
void (CallBackFlag)> func)
2201 selectableCallbackFunction = func;
2204QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(
const QObject *object)
const
2206 QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object,
false);
2207 return static_cast<QQuickTableViewAttached *>(attachedObject);
2210QQuickTableViewAttached::QQuickTableViewAttached(QObject *parent)
2213 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
2220 for (
int i = 0; i < 3; ++i) {
2221 parentItem = parentItem->parentItem();
2224 if (
auto tableView = qobject_cast<QQuickTableView *>(parentItem)) {
2231int QQuickTableViewPrivate::modelIndexAtCell(
const QPoint &cell)
const
2237 int availableColumns = tableSize.width();
2238 return (cell.y() * availableColumns) + cell.x();
2240 int availableRows = tableSize.height();
2241 return (cell.x() * availableRows) + cell.y();
2245QPoint QQuickTableViewPrivate::cellAtModelIndex(
int modelIndex)
const
2251 int availableColumns = tableSize.width();
2252 int row =
int(modelIndex / availableColumns);
2253 int column = modelIndex % availableColumns;
2254 return QPoint(column, row);
2256 int availableRows = tableSize.height();
2257 int column =
int(modelIndex / availableRows);
2258 int row = modelIndex % availableRows;
2259 return QPoint(column, row);
2263int QQuickTableViewPrivate::modelIndexToCellIndex(
const QModelIndex &modelIndex,
bool visualIndex)
const
2267 const QPoint cell = q_func()->cellAtIndex(modelIndex);
2268 if (!cellIsValid(cell))
2270 return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
2273int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
const
2275 return int(log2(
float(edge)));
2278void QQuickTableViewPrivate::clearEdgeSizeCache()
2280 cachedColumnWidth.startIndex = kEdgeIndexNotSet;
2281 cachedRowHeight.startIndex = kEdgeIndexNotSet;
2283 for (Qt::Edge edge : allTableEdges)
2284 cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
2287int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
const
2291 int startIndex = -1;
2293 case Qt::LeftEdge: startIndex = leftColumn() - 1;
break;
2294 case Qt::RightEdge: startIndex = rightColumn() + 1;
break;
2295 case Qt::TopEdge: startIndex = topRow() - 1;
break;
2296 case Qt::BottomEdge: startIndex = bottomRow() + 1;
break;
2299 return nextVisibleEdgeIndex(edge, startIndex);
2302int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge,
int startIndex)
const
2308 auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
2309 if (cachedResult.containsIndex(edge, startIndex))
2310 return cachedResult.endIndex;
2314 int foundIndex = kEdgeIndexNotSet;
2315 int testIndex = startIndex;
2318 case Qt::LeftEdge: {
2320 if (testIndex < 0) {
2321 foundIndex = kEdgeIndexAtEnd;
2325 if (!isColumnHidden(testIndex)) {
2326 foundIndex = testIndex;
2333 case Qt::RightEdge: {
2335 if (testIndex > tableSize.width() - 1) {
2336 foundIndex = kEdgeIndexAtEnd;
2340 if (!isColumnHidden(testIndex)) {
2341 foundIndex = testIndex;
2350 if (testIndex < 0) {
2351 foundIndex = kEdgeIndexAtEnd;
2355 if (!isRowHidden(testIndex)) {
2356 foundIndex = testIndex;
2363 case Qt::BottomEdge: {
2365 if (testIndex > tableSize.height() - 1) {
2366 foundIndex = kEdgeIndexAtEnd;
2370 if (!isRowHidden(testIndex)) {
2371 foundIndex = testIndex;
2380 cachedResult.startIndex = startIndex;
2381 cachedResult.endIndex = foundIndex;
2385void QQuickTableViewPrivate::updateContentWidth()
2396 Q_Q(QQuickTableView);
2398 if (syncHorizontally) {
2399 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2400 q->QQuickFlickable::setContentWidth(syncView->contentWidth());
2404 if (explicitContentWidth.isValid()) {
2410 if (loadedItems.isEmpty()) {
2411 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2412 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2413 q->QQuickFlickable::setContentWidth(kDefaultColumnWidth);
2415 q->QQuickFlickable::setContentWidth(0);
2419 const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2420 const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
2421 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2422 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2423 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2424 const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
2426 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2427 q->QQuickFlickable::setContentWidth(estimatedWidth);
2430void QQuickTableViewPrivate::updateContentHeight()
2432 Q_Q(QQuickTableView);
2434 if (syncVertically) {
2435 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2436 q->QQuickFlickable::setContentHeight(syncView->contentHeight());
2440 if (explicitContentHeight.isValid()) {
2446 if (loadedItems.isEmpty()) {
2447 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2448 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2449 q->QQuickFlickable::setContentHeight(kDefaultRowHeight);
2451 q->QQuickFlickable::setContentHeight(0);
2455 const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2456 const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
2457 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2458 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2459 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2460 const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
2462 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2463 q->QQuickFlickable::setContentHeight(estimatedHeight);
2466void QQuickTableViewPrivate::updateExtents()
2479 Q_Q(QQuickTableView);
2481 bool tableMovedHorizontally =
false;
2482 bool tableMovedVertically =
false;
2484 const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
2485 const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2486 const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
2487 const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2489 QPointF prevOrigin = origin;
2490 QSizeF prevEndExtent = endExtent;
2492 if (syncHorizontally) {
2493 const auto syncView_d = syncView->d_func();
2494 origin.rx() = syncView_d->origin.x();
2495 endExtent.rwidth() = syncView_d->endExtent.width();
2496 }
else if (nextLeftColumn == kEdgeIndexAtEnd) {
2499 if (loadedTableOuterRect.left() > viewportRect.left()) {
2504 if (loadedTableOuterRect.left() > origin.x()) {
2505 const qreal diff = loadedTableOuterRect.left() - origin.x();
2506 loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
2507 loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
2508 tableMovedHorizontally =
true;
2511 origin.rx() = loadedTableOuterRect.left();
2512 }
else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
2516 const int columnsRemaining = nextLeftColumn + 1;
2517 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2518 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2519 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2520 origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
2521 }
else if (nextRightColumn == kEdgeIndexAtEnd) {
2524 if (loadedTableOuterRect.right() < viewportRect.right()) {
2529 const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
2530 if (loadedTableOuterRect.right() < w) {
2531 const qreal diff = loadedTableOuterRect.right() - w;
2532 loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
2533 loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
2534 tableMovedHorizontally =
true;
2537 endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
2538 }
else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
2542 const int columnsRemaining = tableSize.width() - nextRightColumn;
2543 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2544 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2545 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2546 const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
2547 endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
2550 if (syncVertically) {
2551 const auto syncView_d = syncView->d_func();
2552 origin.ry() = syncView_d->origin.y();
2553 endExtent.rheight() = syncView_d->endExtent.height();
2554 }
else if (nextTopRow == kEdgeIndexAtEnd) {
2557 if (loadedTableOuterRect.top() > viewportRect.top()) {
2562 if (loadedTableOuterRect.top() > origin.y()) {
2563 const qreal diff = loadedTableOuterRect.top() - origin.y();
2564 loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
2565 loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
2566 tableMovedVertically =
true;
2569 origin.ry() = loadedTableOuterRect.top();
2570 }
else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
2574 const int rowsRemaining = nextTopRow + 1;
2575 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2576 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2577 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2578 origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
2579 }
else if (nextBottomRow == kEdgeIndexAtEnd) {
2582 if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
2587 const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
2588 if (loadedTableOuterRect.bottom() < h) {
2589 const qreal diff = loadedTableOuterRect.bottom() - h;
2590 loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
2591 loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
2592 tableMovedVertically =
true;
2595 endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
2596 }
else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
2600 const int rowsRemaining = tableSize.height() - nextBottomRow;
2601 const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
2602 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2603 const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
2604 const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
2605 endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
2608 if (tableMovedHorizontally || tableMovedVertically) {
2609 qCDebug(lcTableViewDelegateLifecycle) <<
"move table to" << loadedTableOuterRect;
2613 relayoutTableItems();
2616 for (
auto syncChild : std::as_const(syncChildren)) {
2617 auto syncChild_d = syncChild->d_func();
2618 syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
2619 if (tableMovedHorizontally)
2620 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
2621 if (tableMovedVertically)
2622 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
2626 if (prevOrigin != origin || prevEndExtent != endExtent) {
2627 if (prevOrigin != origin)
2628 qCDebug(lcTableViewDelegateLifecycle) <<
"move origin to:" << origin;
2629 if (prevEndExtent != endExtent)
2630 qCDebug(lcTableViewDelegateLifecycle) <<
"move endExtent to:" << endExtent;
2634 hData.markExtentsDirty();
2635 vData.markExtentsDirty();
2636 updateBeginningEnd();
2637 if (!q->isMoving()) {
2641 q->returnToBounds();
2646void QQuickTableViewPrivate::updateAverageColumnWidth()
2648 if (explicitContentWidth.isValid()) {
2649 const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
2650 averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
2652 const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
2653 averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
2657void QQuickTableViewPrivate::updateAverageRowHeight()
2659 if (explicitContentHeight.isValid()) {
2660 const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
2661 averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
2663 const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
2664 averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
2668void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
2670 const QPoint topLeft = QPoint(leftColumn(), topRow());
2671 const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
2672 QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
2673 QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
2674 loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
2675 loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
2678QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
2684 if (loadedItems.isEmpty()) {
2686 return RebuildOption::None;
2689 RebuildOptions rebuildOptions = RebuildOption::None;
2691 if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
2695 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2696 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2701 for (
int column = leftColumn(); column <= rightColumn(); ++column) {
2702 const bool wasVisibleFromBefore = loadedColumns.contains(column);
2703 const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
2704 if (wasVisibleFromBefore == isVisibleNow)
2709 qCDebug(lcTableViewDelegateLifecycle) <<
"Column" << column <<
"changed visibility to" << isVisibleNow;
2710 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2711 if (column == leftColumn()) {
2714 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2720 if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
2724 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2725 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2730 for (
int row = topRow(); row <= bottomRow(); ++row) {
2731 const bool wasVisibleFromBefore = loadedRows.contains(row);
2732 const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
2733 if (wasVisibleFromBefore == isVisibleNow)
2738 qCDebug(lcTableViewDelegateLifecycle) <<
"Row" << row <<
"changed visibility to" << isVisibleNow;
2739 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2740 if (row == topRow())
2741 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2746 return rebuildOptions;
2749void QQuickTableViewPrivate::forceLayout(
bool immediate)
2751 clearEdgeSizeCache();
2752 RebuildOptions rebuildOptions = RebuildOption::None;
2754 const QSize actualTableSize = calculateTableSize();
2755 if (tableSize != actualTableSize) {
2759 rebuildOptions |= RebuildOption::ViewportOnly;
2767 rebuildOptions |= RebuildOption::LayoutOnly
2768 | RebuildOption::CalculateNewContentWidth
2769 | RebuildOption::CalculateNewContentHeight
2770 | checkForVisibilityChanges();
2772 scheduleRebuildTable(rebuildOptions);
2775 auto rootView = rootSyncView();
2776 const bool updated = rootView->d_func()->updateTableRecursive();
2778 qWarning() <<
"TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
2784void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
2786 if (loadRequest.edge() == Qt::Edge(0)) {
2788 loadedColumns.insert(loadRequest.column());
2789 loadedRows.insert(loadRequest.row());
2793 switch (loadRequest.edge()) {
2796 loadedColumns.insert(loadRequest.column());
2799 case Qt::BottomEdge:
2800 loadedRows.insert(loadRequest.row());
2805FxTableItem *QQuickTableViewPrivate::loadedTableItem(
const QPoint &cell)
const
2807 const int modelIndex = modelIndexAtCell(cell);
2809 return loadedItems.value(modelIndex);
2812FxTableItem *QQuickTableViewPrivate::createFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2814 Q_Q(QQuickTableView);
2816 bool ownItem =
false;
2818 int modelIndex = modelIndexAtCell(isTransposed ? QPoint(logicalRowIndex(cell.x()), logicalColumnIndex(cell.y())) :
2819 QPoint(logicalColumnIndex(cell.x()), logicalRowIndex(cell.y())));
2821 QObject* object = model->object(modelIndex, incubationMode);
2823 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2829 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2830 object =
new QQuickItem();
2834 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2838 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2839 model->release(object);
2840 item =
new QQuickItem();
2843 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2844 if (anchors && anchors->activeDirections())
2845 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2846 <<
". Use implicitWidth and implicitHeight instead.";
2853 item->setImplicitWidth(kDefaultColumnWidth);
2854 item->setImplicitHeight(kDefaultRowHeight);
2855 item->setParentItem(q->contentItem());
2859 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
2860 fxTableItem->setVisible(
false);
2861 fxTableItem->cell = cell;
2862 fxTableItem->index = modelIndex;
2866FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2871 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
2873 incubationMode = QQmlIncubator::Asynchronous;
2878 QScopedValueRollback guard(blockItemCreatedCallback,
true);
2879 auto item = createFxTableItem(cell, incubationMode);
2880 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
2884void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
2887 auto const tmpList = loadedItems;
2888 loadedItems.clear();
2889 for (FxTableItem *item : tmpList)
2890 releaseItem(item, reusableFlag);
2893void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
2895 Q_Q(QQuickTableView);
2898 auto item = fxTableItem->item;
2900 if (fxTableItem->ownItem) {
2904 auto releaseFlag = model->release(item, reusableFlag);
2905 if (releaseFlag == QQmlInstanceModel::Pooled) {
2906 fxTableItem->setVisible(
false);
2910 if (QQuickWindow *window = item->window()) {
2911 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
2913 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
2915 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
2916 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
2926void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
2928 const int modelIndex = modelIndexAtCell(cell);
2930 releaseItem(loadedItems.take(modelIndex), reusableFlag);
2933bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2935 switch (tableEdge) {
2937 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
2939 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
2941 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
2942 case Qt::BottomEdge:
2943 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
2949bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2955 switch (tableEdge) {
2957 if (loadedColumns.count() <= 1)
2959 if (positionXAnimation.isRunning()) {
2960 const qreal to = positionXAnimation.to().toFloat();
2961 if (to < viewportRect.x())
2964 return loadedTableInnerRect.left() <= fillRect.left();
2966 if (loadedColumns.count() <= 1)
2968 if (positionXAnimation.isRunning()) {
2969 const qreal to = positionXAnimation.to().toFloat();
2970 if (to > viewportRect.x())
2973 return loadedTableInnerRect.right() >= fillRect.right();
2975 if (loadedRows.count() <= 1)
2977 if (positionYAnimation.isRunning()) {
2978 const qreal to = positionYAnimation.to().toFloat();
2979 if (to < viewportRect.y())
2982 return loadedTableInnerRect.top() <= fillRect.top();
2983 case Qt::BottomEdge:
2984 if (loadedRows.count() <= 1)
2986 if (positionYAnimation.isRunning()) {
2987 const qreal to = positionYAnimation.to().toFloat();
2988 if (to > viewportRect.y())
2991 return loadedTableInnerRect.bottom() >= fillRect.bottom();
2997Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
2999 for (Qt::Edge edge : allTableEdges) {
3000 if (!canLoadTableEdge(edge, rect))
3002 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3003 if (nextIndex == kEdgeIndexAtEnd)
3011Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3013 for (Qt::Edge edge : allTableEdges) {
3014 if (canUnloadTableEdge(edge, rect))
3020qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3024 auto const cellItem = loadedTableItem(cell)->item;
3025 return cellItem->implicitWidth();
3028qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3032 auto const cellItem = loadedTableItem(cell)->item;
3033 return cellItem->implicitHeight();
3036qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3039 qreal columnWidth = 0;
3040 for (
const int row : loadedRows)
3041 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3046qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3049 qreal rowHeight = 0;
3050 for (
const int column : loadedColumns)
3051 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3055QSize QQuickTableViewPrivate::calculateTableSize()
3059 size = QSize(tableModel->columns(), tableModel->rows());
3061 size = QSize(1, model->count());
3063 return isTransposed ? size.transposed() : size;
3066qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3073 const qreal explicitColumnWidth = getColumnWidth(column);
3074 if (explicitColumnWidth >= 0)
3075 return explicitColumnWidth;
3077 if (syncHorizontally) {
3078 if (syncView->d_func()->loadedColumns.contains(column))
3079 return syncView->d_func()->getColumnLayoutWidth(column);
3087 qreal columnWidth = sizeHintForColumn(column);
3089 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3090 if (!layoutWarningIssued) {
3091 layoutWarningIssued =
true;
3092 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3094 columnWidth = kDefaultColumnWidth;
3100qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3104 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3107qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3111 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3114qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3118 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3121qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3125 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3128qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3135 const qreal explicitRowHeight = getRowHeight(row);
3136 if (explicitRowHeight >= 0)
3137 return explicitRowHeight;
3139 if (syncVertically) {
3140 if (syncView->d_func()->loadedRows.contains(row))
3141 return syncView->d_func()->getRowLayoutHeight(row);
3149 qreal rowHeight = sizeHintForRow(row);
3151 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3152 if (!layoutWarningIssued) {
3153 layoutWarningIssued =
true;
3154 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3156 rowHeight = kDefaultRowHeight;
3162qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3168 Q_Q(
const QQuickTableView);
3170 const int noExplicitColumnWidth = -1;
3172 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3173 return cachedColumnWidth.size;
3175 if (syncHorizontally)
3176 return syncView->d_func()->getColumnWidth(column);
3178 if (columnWidthProvider.isUndefined()) {
3182 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3183 if (explicitColumnWidth >= 0)
3184 return explicitColumnWidth;
3185 return noExplicitColumnWidth;
3188 qreal columnWidth = noExplicitColumnWidth;
3190 if (columnWidthProvider.isCallable()) {
3191 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3192 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3193 if (qIsNaN(columnWidth) || columnWidth < 0)
3194 columnWidth = noExplicitColumnWidth;
3196 if (!layoutWarningIssued) {
3197 layoutWarningIssued =
true;
3198 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3200 columnWidth = noExplicitColumnWidth;
3203 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3204 cachedColumnWidth.size = columnWidth;
3208qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3214 Q_Q(
const QQuickTableView);
3216 const int noExplicitRowHeight = -1;
3218 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3219 return cachedRowHeight.size;
3222 return syncView->d_func()->getRowHeight(row);
3224 if (rowHeightProvider.isUndefined()) {
3228 qreal explicitRowHeight = q->explicitRowHeight(row);
3229 if (explicitRowHeight >= 0)
3230 return explicitRowHeight;
3231 return noExplicitRowHeight;
3234 qreal rowHeight = noExplicitRowHeight;
3236 if (rowHeightProvider.isCallable()) {
3237 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3238 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3239 if (qIsNaN(rowHeight) || rowHeight < 0)
3240 rowHeight = noExplicitRowHeight;
3242 if (!layoutWarningIssued) {
3243 layoutWarningIssued =
true;
3244 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3246 rowHeight = noExplicitRowHeight;
3249 cachedRowHeight.startIndex = logicalRowIndex(row);
3250 cachedRowHeight.size = rowHeight;
3254qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3256 Q_Q(QQuickTableView);
3259 const int columnX = getEffectiveColumnX(column);
3261 if (subRect.isValid()) {
3262 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3265 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3268 if (alignment & Qt::AlignLeft) {
3269 contentX = columnX + subRect.x() + offset;
3270 }
else if (alignment & Qt::AlignRight) {
3271 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3272 }
else if (alignment & Qt::AlignHCenter) {
3273 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3274 contentX = columnX + subRect.x() - centerDistance + offset;
3277 const int columnWidth = getEffectiveColumnWidth(column);
3278 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3279 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3281 if (alignment & Qt::AlignLeft) {
3282 contentX = columnX + offset;
3283 }
else if (alignment & Qt::AlignRight) {
3284 contentX = columnX + columnWidth - viewportRect.width() + offset;
3285 }
else if (alignment & Qt::AlignHCenter) {
3286 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3287 contentX = columnX - centerDistance + offset;
3292 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3297qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3299 Q_Q(QQuickTableView);
3302 const int rowY = getEffectiveRowY(row);
3304 if (subRect.isValid()) {
3305 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3308 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3311 if (alignment & Qt::AlignTop) {
3312 contentY = rowY + subRect.y() + offset;
3313 }
else if (alignment & Qt::AlignBottom) {
3314 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3315 }
else if (alignment & Qt::AlignVCenter) {
3316 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3317 contentY = rowY + subRect.y() - centerDistance + offset;
3320 const int rowHeight = getEffectiveRowHeight(row);
3321 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3322 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3324 if (alignment & Qt::AlignTop) {
3325 contentY = rowY + offset;
3326 }
else if (alignment & Qt::AlignBottom) {
3327 contentY = rowY + rowHeight - viewportRect.height() + offset;
3328 }
else if (alignment & Qt::AlignVCenter) {
3329 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3330 contentY = rowY - centerDistance + offset;
3335 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3340bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3344 return qFuzzyIsNull(getColumnWidth(column));
3347bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3351 return qFuzzyIsNull(getRowHeight(row));
3354void QQuickTableViewPrivate::relayoutTableItems()
3356 qCDebug(lcTableViewDelegateLifecycle);
3358 if (viewportRect.isEmpty()) {
3360 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3364 qreal nextColumnX = loadedTableOuterRect.x();
3365 qreal nextRowY = loadedTableOuterRect.y();
3367 for (
const int column : loadedColumns) {
3369 const qreal width = getColumnLayoutWidth(column);
3371 for (
const int row : loadedRows) {
3372 auto item = loadedTableItem(QPoint(column, row));
3373 QRectF geometry = item->geometry();
3374 geometry.moveLeft(nextColumnX);
3375 geometry.setWidth(width);
3376 item->setGeometry(geometry);
3380 nextColumnX += width + cellSpacing.width();
3383 for (
const int row : loadedRows) {
3385 const qreal height = getRowLayoutHeight(row);
3387 for (
const int column : loadedColumns) {
3388 auto item = loadedTableItem(QPoint(column, row));
3389 QRectF geometry = item->geometry();
3390 geometry.moveTop(nextRowY);
3391 geometry.setHeight(height);
3392 item->setGeometry(geometry);
3396 nextRowY += height + cellSpacing.height();
3399 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3400 for (
const int column : loadedColumns) {
3401 for (
const int row : loadedRows) {
3402 QPoint cell = QPoint(column, row);
3403 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3409void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3411 int columnThatNeedsLayout;
3412 int neighbourColumn;
3416 if (tableEdge == Qt::LeftEdge) {
3417 columnThatNeedsLayout = leftColumn();
3418 neighbourColumn = loadedColumns.values().at(1);
3419 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3420 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3421 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3423 columnThatNeedsLayout = rightColumn();
3424 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3425 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3426 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3427 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3430 for (
const int row : loadedRows) {
3431 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3432 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3433 const qreal rowY = neighbourItem->geometry().y();
3434 const qreal rowHeight = neighbourItem->geometry().height();
3436 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3437 fxTableItem->setVisible(
true);
3439 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3443void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3445 int rowThatNeedsLayout;
3448 if (tableEdge == Qt::TopEdge) {
3449 rowThatNeedsLayout = topRow();
3450 neighbourRow = loadedRows.values().at(1);
3452 rowThatNeedsLayout = bottomRow();
3453 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3458 for (
const int column : loadedColumns) {
3459 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3460 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3461 const qreal columnX = neighbourItem->geometry().x();
3462 const qreal columnWidth = neighbourItem->geometry().width();
3463 fxTableItem->item->setX(columnX);
3464 fxTableItem->item->setWidth(columnWidth);
3469 if (tableEdge == Qt::TopEdge) {
3470 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3471 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3472 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3474 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3475 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3476 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3479 for (
const int column : loadedColumns) {
3480 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3481 fxTableItem->item->setY(rowY);
3482 fxTableItem->item->setHeight(rowHeight);
3483 fxTableItem->setVisible(
true);
3485 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3489void QQuickTableViewPrivate::layoutTopLeftItem()
3491 const QPoint cell(loadRequest.column(), loadRequest.row());
3492 auto topLeftItem = loadedTableItem(cell);
3493 auto item = topLeftItem->item;
3495 item->setPosition(loadRequest.startPosition());
3496 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3497 topLeftItem->setVisible(
true);
3498 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3501void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3503 if (loadRequest.edge() == Qt::Edge(0)) {
3505 layoutTopLeftItem();
3509 switch (loadRequest.edge()) {
3512 layoutVerticalEdge(loadRequest.edge());
3515 case Qt::BottomEdge:
3516 layoutHorizontalEdge(loadRequest.edge());
3521void QQuickTableViewPrivate::processLoadRequest()
3523 Q_Q(QQuickTableView);
3526 while (loadRequest.hasCurrentCell()) {
3527 QPoint cell = loadRequest.currentCell();
3528 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3536 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3537 loadRequest.moveToNextCell();
3540 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3542 syncLoadedTableFromLoadRequest();
3543 layoutTableEdgeFromLoadRequest();
3544 syncLoadedTableRectFromLoadedTable();
3546 if (rebuildState == RebuildState::Done) {
3550 drainReusePoolAfterLoadRequest();
3552 switch (loadRequest.edge()) {
3554 emit q->leftColumnChanged();
3557 emit q->rightColumnChanged();
3560 emit q->topRowChanged();
3562 case Qt::BottomEdge:
3563 emit q->bottomRowChanged();
3567 if (editIndex.isValid())
3570 emit q->layoutChanged();
3573 loadRequest.markAsDone();
3575 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3576 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3577 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3580void QQuickTableViewPrivate::processRebuildTable()
3582 Q_Q(QQuickTableView);
3584 if (rebuildState == RebuildState::Begin) {
3585 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3586 tableSizeBeforeRebuild = tableSize;
3587 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins()
3588 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3591 moveToNextRebuildState();
3593 if (rebuildState == RebuildState::LoadInitalTable) {
3595 if (!moveToNextRebuildState())
3599 if (rebuildState == RebuildState::VerifyTable) {
3600 if (loadedItems.isEmpty()) {
3601 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3602 updateContentWidth();
3603 updateContentHeight();
3604 rebuildState = RebuildState::Done;
3605 }
else if (!moveToNextRebuildState()) {
3610 if (rebuildState == RebuildState::LayoutTable) {
3611 layoutAfterLoadingInitialTable();
3612 loadAndUnloadVisibleEdges();
3613 if (!moveToNextRebuildState())
3617 if (rebuildState == RebuildState::CancelOvershoot) {
3618 cancelOvershootAfterLayout();
3619 loadAndUnloadVisibleEdges();
3620 if (!moveToNextRebuildState())
3624 if (rebuildState == RebuildState::UpdateContentSize) {
3625 updateContentSize();
3626 if (!moveToNextRebuildState())
3630 const bool preload = (rebuildOptions & RebuildOption::All
3631 && reusableFlag == QQmlTableInstanceModel::Reusable);
3633 if (rebuildState == RebuildState::PreloadColumns) {
3634 if (preload && !atTableEnd(Qt::RightEdge))
3635 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3636 if (!moveToNextRebuildState())
3640 if (rebuildState == RebuildState::PreloadRows) {
3641 if (preload && !atTableEnd(Qt::BottomEdge))
3642 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3643 if (!moveToNextRebuildState())
3647 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3648 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3650 if (!moveToNextRebuildState())
3654 if (rebuildState == RebuildState::Done) {
3655 if (tableSizeBeforeRebuild.width() != tableSize.width())
3656 emit q->columnsChanged();
3657 if (tableSizeBeforeRebuild.height() != tableSize.height())
3658 emit q->rowsChanged();
3659 if (edgesBeforeRebuild.left() != q->leftColumn())
3660 emit q->leftColumnChanged();
3661 if (edgesBeforeRebuild.right() != q->rightColumn())
3662 emit q->rightColumnChanged();
3663 if (edgesBeforeRebuild.top() != q->topRow())
3664 emit q->topRowChanged();
3665 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3666 emit q->bottomRowChanged();
3668 if (editIndex.isValid())
3670 updateCurrentRowAndColumn();
3672 emit q->layoutChanged();
3674 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3675 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3676 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3677 qCDebug(lcTableViewDelegateLifecycle());
3683bool QQuickTableViewPrivate::moveToNextRebuildState()
3685 if (loadRequest.isActive()) {
3691 if (rebuildState == RebuildState::Begin
3692 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3693 rebuildState = RebuildState::LayoutTable;
3695 rebuildState = RebuildState(
int(rebuildState) + 1);
3697 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3701void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3703 if (tableSize.isEmpty()) {
3705 topLeftCell.rx() = kEdgeIndexAtEnd;
3706 topLeftCell.ry() = kEdgeIndexAtEnd;
3710 if (syncHorizontally || syncVertically) {
3711 const auto syncView_d = syncView->d_func();
3713 if (syncView_d->loadedItems.isEmpty()) {
3714 topLeftCell.rx() = 0;
3715 topLeftCell.ry() = 0;
3720 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3721 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3722 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3724 if (syncHorizontally) {
3725 topLeftCell.rx() = syncViewTopLeftCell.x();
3726 topLeftPos.rx() = syncViewTopLeftPos.x();
3728 if (topLeftCell.x() >= tableSize.width()) {
3730 topLeftCell.rx() = kEdgeIndexAtEnd;
3731 topLeftPos.rx() = kEdgeIndexAtEnd;
3735 if (syncVertically) {
3736 topLeftCell.ry() = syncViewTopLeftCell.y();
3737 topLeftPos.ry() = syncViewTopLeftPos.y();
3739 if (topLeftCell.y() >= tableSize.height()) {
3741 topLeftCell.ry() = kEdgeIndexAtEnd;
3742 topLeftPos.ry() = kEdgeIndexAtEnd;
3746 if (syncHorizontally && syncVertically) {
3757 if (!syncHorizontally) {
3758 if (rebuildOptions & RebuildOption::All) {
3760 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3761 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3765 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3767 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3768 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3769 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3770 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3771 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3772 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3775 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3779 topLeftPos.rx() = loadedTableOuterRect.x();
3783 if (!syncVertically) {
3784 if (rebuildOptions & RebuildOption::All) {
3786 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3787 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3791 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3793 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3794 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3795 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3796 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3797 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3798 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3800 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3801 topLeftPos.ry() = loadedTableOuterRect.y();
3806void QQuickTableViewPrivate::loadInitialTable()
3808 tableSize = calculateTableSize();
3810 if (positionXAnimation.isRunning()) {
3811 positionXAnimation.stop();
3812 setLocalViewportX(positionXAnimation.to().toReal());
3816 if (positionYAnimation.isRunning()) {
3817 positionYAnimation.stop();
3818 setLocalViewportY(positionYAnimation.to().toReal());
3824 calculateTopLeft(topLeft, topLeftPos);
3825 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3826 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3828 if (!loadedItems.isEmpty()) {
3829 if (rebuildOptions & RebuildOption::All)
3830 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3831 else if (rebuildOptions & RebuildOption::ViewportOnly)
3832 releaseLoadedItems(reusableFlag);
3835 if (rebuildOptions & RebuildOption::All) {
3836 origin = QPointF(0, 0);
3837 endExtent = QSizeF(0, 0);
3838 hData.markExtentsDirty();
3839 vData.markExtentsDirty();
3840 updateBeginningEnd();
3843 loadedColumns.clear();
3845 loadedTableOuterRect = QRect();
3846 loadedTableInnerRect = QRect();
3847 clearEdgeSizeCache();
3849 if (syncHorizontally)
3850 setLocalViewportX(syncView->contentX());
3853 setLocalViewportY(syncView->contentY());
3855 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
3856 setLocalViewportX(topLeftPos.x());
3858 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
3859 setLocalViewportY(topLeftPos.y());
3864 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
3868 if (model->count() == 0) {
3869 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
3873 if (tableModel && !tableModel->delegate()) {
3874 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
3878 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
3879 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
3883 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
3884 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
3888 if (viewportRect.isEmpty()) {
3889 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
3895 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
3896 processLoadRequest();
3897 loadAndUnloadVisibleEdges();
3900void QQuickTableViewPrivate::updateContentSize()
3902 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
3903 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
3904 updateAverageColumnWidth();
3905 updateContentWidth();
3908 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
3909 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
3910 updateAverageRowHeight();
3911 updateContentHeight();
3917void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
3919 clearEdgeSizeCache();
3920 relayoutTableItems();
3921 syncLoadedTableRectFromLoadedTable();
3923 updateContentSize();
3925 adjustViewportXAccordingToAlignment();
3926 adjustViewportYAccordingToAlignment();
3929void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
3932 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
3935 if (positionViewAtColumnAfterRebuild != leftColumn())
3938 const qreal newContentX = getAlignmentContentX(
3939 positionViewAtColumnAfterRebuild,
3940 positionViewAtColumnAlignment,
3941 positionViewAtColumnOffset,
3942 positionViewAtColumnSubRect);
3944 setLocalViewportX(newContentX);
3948void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
3951 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
3954 if (positionViewAtRowAfterRebuild != topRow())
3957 const qreal newContentY = getAlignmentContentY(
3958 positionViewAtRowAfterRebuild,
3959 positionViewAtRowAlignment,
3960 positionViewAtRowOffset,
3961 positionViewAtRowSubRect);
3963 setLocalViewportY(newContentY);
3967void QQuickTableViewPrivate::cancelOvershootAfterLayout()
3969 Q_Q(QQuickTableView);
3975 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
3976 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
3977 const bool cancelVertically = positionVertically && !syncVertically;
3978 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
3980 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
3981 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
3982 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
3986 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
3987 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
3988 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
3993void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
3995 Q_Q(QQuickTableView);
3996 qCDebug(lcTableViewDelegateLifecycle) << edge;
3999 case Qt::LeftEdge: {
4000 const int column = leftColumn();
4001 for (
int row : loadedRows)
4002 unloadItem(QPoint(column, row));
4003 loadedColumns.remove(column);
4004 syncLoadedTableRectFromLoadedTable();
4005 if (rebuildState == RebuildState::Done)
4006 emit q->leftColumnChanged();
4008 case Qt::RightEdge: {
4009 const int column = rightColumn();
4010 for (
int row : loadedRows)
4011 unloadItem(QPoint(column, row));
4012 loadedColumns.remove(column);
4013 syncLoadedTableRectFromLoadedTable();
4014 if (rebuildState == RebuildState::Done)
4015 emit q->rightColumnChanged();
4018 const int row = topRow();
4019 for (
int col : loadedColumns)
4020 unloadItem(QPoint(col, row));
4021 loadedRows.remove(row);
4022 syncLoadedTableRectFromLoadedTable();
4023 if (rebuildState == RebuildState::Done)
4024 emit q->topRowChanged();
4026 case Qt::BottomEdge: {
4027 const int row = bottomRow();
4028 for (
int col : loadedColumns)
4029 unloadItem(QPoint(col, row));
4030 loadedRows.remove(row);
4031 syncLoadedTableRectFromLoadedTable();
4032 if (rebuildState == RebuildState::Done)
4033 emit q->bottomRowChanged();
4037 if (rebuildState == RebuildState::Done)
4038 emit q->layoutChanged();
4040 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4043void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4045 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4046 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4048 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4049 ? loadedRows.values() : loadedColumns.values();
4050 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4051 processLoadRequest();
4054void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4066 if (loadRequest.isActive()) {
4072 if (loadedItems.isEmpty()) {
4082 tableModified =
false;
4084 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4085 tableModified =
true;
4089 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4090 tableModified =
true;
4091 loadEdge(edge, incubationMode);
4092 if (loadRequest.isActive())
4095 }
while (tableModified);
4099void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4101 Q_Q(QQuickTableView);
4103 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4106 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4136 const int w = loadedColumns.count();
4137 const int h = loadedRows.count();
4138 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4139 const int maxTime = minTime * 2;
4140 tableModel->drainReusableItemsPool(maxTime);
4143void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4144 if (!q_func()->isComponentComplete()) {
4149 scheduledRebuildOptions |= options;
4153QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4155 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4156 while (QQuickTableView *view = root->d_func()->syncView)
4161void QQuickTableViewPrivate::updatePolish()
4168 rootSyncView()->d_func()->updateTableRecursive();
4171bool QQuickTableViewPrivate::updateTableRecursive()
4181 const bool updateComplete = updateTable();
4182 if (!updateComplete)
4185 const auto children = syncChildren;
4186 for (
auto syncChild : children) {
4187 auto syncChild_d = syncChild->d_func();
4189 RebuildOption::PositionViewAtRow |
4190 RebuildOption::PositionViewAtColumn |
4191 RebuildOption::CalculateNewTopLeftRow |
4192 RebuildOption::CalculateNewTopLeftColumn;
4193 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4195 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4196 if (!descendantUpdateComplete)
4200 rebuildOptions = RebuildOption::None;
4205bool QQuickTableViewPrivate::updateTable()
4214 QScopedValueRollback polishGuard(polishing,
true);
4216 if (loadRequest.isActive()) {
4224 if (rebuildState != RebuildState::Done) {
4225 processRebuildTable();
4226 return rebuildState == RebuildState::Done;
4229 syncWithPendingChanges();
4231 if (rebuildState == RebuildState::Begin) {
4232 processRebuildTable();
4233 return rebuildState == RebuildState::Done;
4236 if (loadedItems.isEmpty())
4237 return !loadRequest.isActive();
4239 loadAndUnloadVisibleEdges();
4242 return !loadRequest.isActive();
4245void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4247 if (inUpdateContentSize) {
4259 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4262QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4264 const auto data = QQmlData::get(q_func());
4265 if (!data || !data->propertyCache)
4266 return QTypeRevision::zero();
4268 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4269 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4272 return qmlTypeView.metaObjectRevision();
4275void QQuickTableViewPrivate::createWrapperModel()
4277 Q_Q(QQuickTableView);
4283 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4284 tableModel->useImportVersion(resolveImportVersion());
4288bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4290 if (!selectionModel)
4293 QAbstractItemModel *model = selectionModel->model();
4297 return selectionModel->isSelected(q_func()->modelIndex(cell));
4300bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4302 if (!selectionModel)
4305 QAbstractItemModel *model = selectionModel->model();
4309 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4312void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4314 if (!inSelectionModelUpdate) {
4318 cancelSelectionTracking();
4321 const auto &selectedIndexes = selected.indexes();
4322 const auto &deselectedIndexes = deselected.indexes();
4323 for (
int i = 0; i < selectedIndexes.size(); ++i)
4324 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4325 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4326 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4329void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4331 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4332 qmlWarning(q_func())
4333 <<
"Cannot select cells: TableView.selectionModel.model is not "
4334 <<
"compatible with the model displayed in the view";
4338 const int cellIndex = modelIndexToCellIndex(modelIndex);
4339 if (!loadedItems.contains(cellIndex))
4341 const QPoint cell = cellAtModelIndex(cellIndex);
4342 QQuickItem *item = loadedTableItem(cell)->item;
4343 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4346QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4361 return qaim(modelImpl());
4364QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4367 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4368 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4369 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4372void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4374 updateCurrentRowAndColumn();
4376 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4377 const int cellIndex = *it;
4378 const QPoint cell = cellAtModelIndex(cellIndex);
4379 const bool selected = selectedInSelectionModel(cell);
4380 const bool current = currentInSelectionModel(cell);
4381 QQuickItem *item = loadedTableItem(cell)->item;
4382 const bool editing = editIndex == q_func()->modelIndex(cell);
4383 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4384 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4385 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4389void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4391 if (current.isValid() && current.model() != selectionSourceModel()) {
4392 qmlWarning(q_func())
4393 <<
"Cannot change current index: TableView.selectionModel.model is not "
4394 <<
"compatible with the model displayed in the view";
4398 updateCurrentRowAndColumn();
4399 setCurrentOnDelegateItem(previous,
false);
4400 setCurrentOnDelegateItem(current,
true);
4403void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4405 Q_Q(QQuickTableView);
4407 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4408 const QPoint currentCell = q->cellAtIndex(currentIndex);
4409 if (currentCell.x() != currentColumn) {
4410 currentColumn = currentCell.x();
4411 emit q->currentColumnChanged();
4414 if (currentCell.y() != currentRow) {
4415 currentRow = currentCell.y();
4416 emit q->currentRowChanged();
4420void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4422 const int cellIndex = modelIndexToCellIndex(index);
4423 if (!loadedItems.contains(cellIndex))
4426 const QPoint cell = cellAtModelIndex(cellIndex);
4427 QQuickItem *item = loadedTableItem(cell)->item;
4428 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4431void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4433 if (blockItemCreatedCallback)
4436 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4437 << cellAtModelIndex(modelIndex);
4443 processLoadRequest();
4444 loadAndUnloadVisibleEdges();
4448void QQuickTableViewPrivate::initItemCallback(
int modelIndex, QObject *object)
4450 Q_Q(QQuickTableView);
4452 auto item = qobject_cast<QQuickItem*>(object);
4456 item->setParentItem(q->contentItem());
4459 if (
auto attached = getAttachedObject(item))
4460 attached->setView(q);
4462 const QPoint cell = cellAtModelIndex(modelIndex);
4463 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4464 const bool current = currentInSelectionModel(visualCell);
4465 const bool selected = selectedInSelectionModel(visualCell);
4467 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), modelIndex, item,
true);
4468 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object,
true);
4469 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object,
true);
4470 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), modelIndex, item,
true);
4471 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), modelIndex, item,
true);
4474void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4476 Q_UNUSED(modelIndex);
4478 if (
auto attached = getAttachedObject(object))
4479 emit attached->pooled();
4482void QQuickTableViewPrivate::itemReusedCallback(
int modelIndex, QObject *object)
4484 Q_Q(QQuickTableView);
4486 const QPoint cell = cellAtModelIndex(modelIndex);
4487 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4488 const bool current = currentInSelectionModel(visualCell);
4489 const bool selected = selectedInSelectionModel(visualCell);
4491 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), modelIndex, object,
false);
4492 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object,
false);
4493 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object,
false);
4495 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), modelIndex, object,
false);
4497 if (
auto item = qobject_cast<QQuickItem*>(object))
4498 QQuickItemPrivate::get(item)->setCulled(
false);
4500 if (
auto attached = getAttachedObject(object))
4501 emit attached->reused();
4504void QQuickTableViewPrivate::syncWithPendingChanges()
4514 syncDelegateModelAccess();
4518 syncRebuildOptions();
4521void QQuickTableViewPrivate::syncRebuildOptions()
4523 if (!scheduledRebuildOptions)
4526 rebuildState = RebuildState::Begin;
4527 rebuildOptions = scheduledRebuildOptions;
4528 scheduledRebuildOptions = RebuildOption::None;
4530 if (loadedItems.isEmpty())
4531 rebuildOptions.setFlag(RebuildOption::All);
4534 if (rebuildOptions.testFlag(RebuildOption::All)) {
4535 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4536 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4537 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4538 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4539 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4540 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4543 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4544 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4546 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4547 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4550void QQuickTableViewPrivate::syncDelegate()
4559 if (assignedDelegate != tableModel->delegate())
4560 tableModel->setDelegate(assignedDelegate);
4563void QQuickTableViewPrivate::syncDelegateModelAccess()
4572 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4575QVariant QQuickTableViewPrivate::modelImpl()
const
4577 if (needsModelSynchronization)
4578 return assignedModel;
4580 return tableModel->model();
4581 return QVariant::fromValue(model);
4584void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4586 assignedModel = newModel;
4587 needsModelSynchronization =
true;
4588 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4589 emit q_func()->modelChanged();
4592void QQuickTableViewPrivate::syncModel()
4595 if (tableModel->model() == assignedModel)
4597 }
else if (QVariant::fromValue(model) == assignedModel) {
4602 disconnectFromModel();
4603 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4606 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4607 qvariant_cast<QObject *>(assignedModel));
4609 if (instanceModel) {
4612 tableModel =
nullptr;
4614 model = instanceModel;
4617 createWrapperModel();
4618 tableModel->setModel(assignedModel);
4621 needsModelSynchronization =
false;
4625void QQuickTableViewPrivate::syncSyncView()
4627 Q_Q(QQuickTableView);
4629 if (assignedSyncView != syncView) {
4631 syncView->d_func()->syncChildren.removeOne(q);
4633 if (assignedSyncView) {
4634 QQuickTableView *view = assignedSyncView;
4638 if (!layoutWarningIssued) {
4639 layoutWarningIssued =
true;
4640 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4645 view = view->d_func()->syncView;
4648 assignedSyncView->d_func()->syncChildren.append(q);
4649 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4652 syncView = assignedSyncView;
4655 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4656 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4658 if (syncHorizontally) {
4659 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4660 q->setColumnSpacing(syncView->columnSpacing());
4661 q->setLeftMargin(syncView->leftMargin());
4662 q->setRightMargin(syncView->rightMargin());
4663 updateContentWidth();
4665 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4666 if (syncView->leftColumn() != q->leftColumn()
4667 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4674 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4675 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4680 if (syncVertically) {
4681 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4682 q->setRowSpacing(syncView->rowSpacing());
4683 q->setTopMargin(syncView->topMargin());
4684 q->setBottomMargin(syncView->bottomMargin());
4685 updateContentHeight();
4687 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4688 if (syncView->topRow() != q->topRow()
4689 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4696 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4697 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4702 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4708 const auto syncView_d = syncView->d_func();
4709 if (!syncView_d->loadedItems.isEmpty()) {
4710 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4711 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4712 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4713 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4718void QQuickTableViewPrivate::syncPositionView()
4724 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4725 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4728void QQuickTableViewPrivate::connectToModel()
4730 Q_Q(QQuickTableView);
4733 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4734 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4735 QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4736 QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4739 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4741 if (
auto const aim = model->abstractItemModel()) {
4747 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4748 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4749 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4750 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4751 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4752 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4753 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4754 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4756 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4760 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
4761 q, &QQuickTableView::modelChanged);
4765void QQuickTableViewPrivate::disconnectFromModel()
4767 Q_Q(QQuickTableView);
4770 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4771 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4772 QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4773 QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4775 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4777 if (
auto const aim = model->abstractItemModel()) {
4778 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4779 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4780 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4781 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4782 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4783 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4784 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4785 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4787 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4791 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
4792 q, &QQuickTableView::modelChanged);
4796void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
4798 Q_UNUSED(changeSet);
4802 scheduleRebuildTable(RebuildOption::ViewportOnly
4803 | RebuildOption::CalculateNewContentWidth
4804 | RebuildOption::CalculateNewContentHeight);
4807void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
4809 if (parent != QModelIndex())
4812 scheduleRebuildTable(RebuildOption::ViewportOnly);
4815void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
4817 if (parent != QModelIndex())
4820 scheduleRebuildTable(RebuildOption::ViewportOnly);
4823void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
4825 if (parent != QModelIndex())
4828 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4831void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
4833 Q_Q(QQuickTableView);
4835 if (parent != QModelIndex())
4839 if (!editIndex.isValid() && editItem)
4842 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4845void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
4847 if (parent != QModelIndex())
4855 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4858void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
4860 Q_Q(QQuickTableView);
4862 if (parent != QModelIndex())
4866 if (!editIndex.isValid() && editItem)
4869 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4872void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
4877 scheduleRebuildTable(RebuildOption::ViewportOnly);
4880void QQuickTableViewPrivate::fetchMoreData()
4882 if (tableModel && tableModel->canFetchMore()) {
4883 tableModel->fetchMore();
4884 scheduleRebuildTable(RebuildOption::ViewportOnly);
4888void QQuickTableViewPrivate::modelResetCallback()
4890 Q_Q(QQuickTableView);
4892 scheduleRebuildTable(RebuildOption::All);
4895void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4897 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
4900 if (syncVertically) {
4901 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
4903 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
4905 assignedPositionViewAtRowAfterRebuild = row;
4906 positionViewAtRowAlignment = verticalAlignment;
4907 positionViewAtRowOffset = offset;
4908 positionViewAtRowSubRect = subRect;
4909 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4910 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
4915void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4917 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
4920 if (syncHorizontally) {
4921 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
4923 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
4925 assignedPositionViewAtColumnAfterRebuild = column;
4926 positionViewAtColumnAlignment = horizontalAlignment;
4927 positionViewAtColumnOffset = offset;
4928 positionViewAtColumnSubRect = subRect;
4929 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4930 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
4935bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4937 Q_Q(QQuickTableView);
4944 if (row < topRow()) {
4945 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
4947 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
4948 }
else if (row > bottomRow()) {
4949 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
4951 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
4952 }
else if (row < topRow() || row > bottomRow()) {
4956 if (!loadedRows.contains(row))
4959 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
4960 if (qFuzzyCompare(newContentY, q->contentY()))
4964 const qreal diffY = qAbs(newContentY - q->contentY());
4965 const qreal duration = qBound(700., diffY * 5, 1500.);
4966 positionYAnimation.setTo(newContentY);
4967 positionYAnimation.setDuration(duration);
4968 positionYAnimation.restart();
4970 positionYAnimation.stop();
4971 q->setContentY(newContentY);
4977bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4979 Q_Q(QQuickTableView);
4986 if (column < leftColumn()) {
4987 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
4989 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
4990 }
else if (column > rightColumn()) {
4991 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
4993 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
4994 }
else if (column < leftColumn() || column > rightColumn()) {
4998 if (!loadedColumns.contains(column))
5001 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5002 if (qFuzzyCompare(newContentX, q->contentX()))
5006 const qreal diffX = qAbs(newContentX - q->contentX());
5007 const qreal duration = qBound(700., diffX * 5, 1500.);
5008 positionXAnimation.setTo(newContentX);
5009 positionXAnimation.setDuration(duration);
5010 positionXAnimation.restart();
5012 positionXAnimation.stop();
5013 q->setContentX(newContentX);
5019void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5021 Q_Q(QQuickTableView);
5031 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5032 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5033 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5037 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5038 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5039 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5043void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5048 Q_Q(QQuickTableView);
5049 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5051 if (qFuzzyCompare(contentX, q->contentX()))
5054 q->setContentX(contentX);
5057void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5062 Q_Q(QQuickTableView);
5063 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5065 if (qFuzzyCompare(contentY, q->contentY()))
5068 q->setContentY(contentY);
5071void QQuickTableViewPrivate::syncViewportRect()
5079 Q_Q(QQuickTableView);
5081 qreal w = q->width();
5082 qreal h = q->height();
5084 for (
auto syncChild : std::as_const(syncChildren)) {
5085 auto syncChild_d = syncChild->d_func();
5086 if (syncChild_d->syncHorizontally)
5087 w = qMax(w, syncChild->width());
5088 if (syncChild_d->syncVertically)
5089 h = qMax(h, syncChild->height());
5092 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5095void QQuickTableViewPrivate::init()
5097 Q_Q(QQuickTableView);
5099 q->setFlag(QQuickItem::ItemIsFocusScope);
5100 q->setActiveFocusOnTab(
true);
5102 positionXAnimation.setTargetObject(q);
5103 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5104 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5106 positionYAnimation.setTargetObject(q);
5107 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5108 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5110 auto tapHandler =
new QQuickTableViewTapHandler(q);
5112 hoverHandler =
new QQuickTableViewHoverHandler(q);
5113 resizeHandler =
new QQuickTableViewResizeHandler(q);
5115 hoverHandler->setEnabled(resizableRows || resizableColumns);
5116 resizeHandler->setEnabled(resizableRows || resizableColumns);
5124 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, [
this, q, tapHandler] {
5125 if (!tapHandler->isPressed())
5128 positionXAnimation.stop();
5129 positionYAnimation.stop();
5131 if (!q->isInteractive())
5132 handleTap(tapHandler->point());
5135 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, [
this, q, tapHandler] {
5136 if (q->isInteractive())
5137 handleTap(tapHandler->point());
5140 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, [
this, q, tapHandler] {
5141 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5142 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5144 if (resizeRow || resizeColumn) {
5146 q->setRowHeight(hoverHandler->m_row, -1);
5148 q->setColumnWidth(hoverHandler->m_column, -1);
5149 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5150 const QPointF pos = tapHandler->point().pressPosition();
5151 const QPoint cell = q->cellAtPosition(pos);
5152 const QModelIndex index = q->modelIndex(cell);
5153 if (canEdit(index,
false))
5159void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5161 Q_Q(QQuickTableView);
5163 if (keyNavigationEnabled)
5164 q->forceActiveFocus(Qt::MouseFocusReason);
5166 if (point.modifiers() != Qt::NoModifier)
5168 if (resizableRows && hoverHandler->m_row != -1)
5170 if (resizableColumns && hoverHandler->m_column != -1)
5172 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5175 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5176 bool tappedCellIsSelected =
false;
5179 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5181 if (canEdit(tappedIndex,
false)) {
5182 if (editTriggers & QQuickTableView::SingleTapped) {
5183 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5185 q->edit(tappedIndex);
5187 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5188 q->edit(tappedIndex);
5195 if (pointerNavigationEnabled) {
5196 closeEditorAndCommit();
5197 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5199 cancelSelectionTracking();
5201 setCurrentIndexFromTap(point.position());
5205bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5209 Q_Q(QQuickTableView);
5211 if (!tappedIndex.isValid()) {
5213 qmlWarning(q) <<
"cannot edit: index is not valid!";
5217 if (
auto const sourceModel = qaim(modelImpl())) {
5218 if (!(sourceModel->flags(tappedIndex) & Qt::ItemIsEditable)) {
5220 qmlWarning(q) <<
"cannot edit: QAbstractItemModel::flags(index) doesn't contain Qt::ItemIsEditable";
5225 const QPoint cell = q->cellAtIndex(tappedIndex);
5226 const QQuickItem *cellItem = q->itemAtCell(cell);
5229 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5233 auto attached = getAttachedObject(cellItem);
5234 if (!attached || !attached->editDelegate()) {
5236 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5243void QQuickTableViewPrivate::syncViewportPosRecursive()
5245 Q_Q(QQuickTableView);
5246 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5249 auto syncView_d = syncView->d_func();
5250 if (!syncView_d->inSyncViewportPosRecursive) {
5251 if (syncHorizontally)
5252 syncView_d->setLocalViewportX(q->contentX());
5254 syncView_d->setLocalViewportY(q->contentY());
5255 syncView_d->syncViewportPosRecursive();
5259 for (
auto syncChild : std::as_const(syncChildren)) {
5260 auto syncChild_d = syncChild->d_func();
5261 if (!syncChild_d->inSyncViewportPosRecursive) {
5262 if (syncChild_d->syncHorizontally)
5263 syncChild_d->setLocalViewportX(q->contentX());
5264 if (syncChild_d->syncVertically)
5265 syncChild_d->setLocalViewportY(q->contentY());
5266 syncChild_d->syncViewportPosRecursive();
5271void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5273 Q_Q(QQuickTableView);
5275 const QPoint cell = q->cellAtPosition(pos);
5276 if (!cellIsValid(cell))
5279 setCurrentIndex(cell);
5282void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5284 if (!selectionModel)
5287 const auto index = q_func()->modelIndex(cell);
5288 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5291bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5293 Q_Q(QQuickTableView);
5295 if (!selectionModel || !selectionModel->model())
5298 const QModelIndex currentIndex = selectionModel->currentIndex();
5299 const QPoint currentCell = q->cellAtIndex(currentIndex);
5301 if (!q->activeFocusOnTab()) {
5304 case Qt::Key_Backtab:
5309 if (!cellIsValid(currentCell)) {
5315 case Qt::Key_PageUp:
5316 case Qt::Key_PageDown:
5320 case Qt::Key_Backtab:
5321 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5324 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5325 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5332 auto beginMoveCurrentIndex = [&](){
5333 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5334 const bool startNewSelection = selectionRectangle().isEmpty();
5335 if (!shouldSelect) {
5337 cancelSelectionTracking();
5338 }
else if (startNewSelection) {
5342 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5343 if (loadedItems.contains(serializedStartIndex)) {
5344 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5345 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5346 setSelectionStartPos(startGeometry.center());
5347 if (selectableCallbackFunction)
5348 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5354 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5355 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5357 if (polishScheduled)
5359 const int serializedEndIndex = modelIndexAtCell(cell);
5360 if (loadedItems.contains(serializedEndIndex)) {
5361 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5362 setSelectionEndPos(endGeometry.center());
5363 if (selectableCallbackFunction)
5364 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5367 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5372 beginMoveCurrentIndex();
5373 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5374 if (nextRow == kEdgeIndexAtEnd)
5376 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5377 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5378 endMoveCurrentIndex({currentCell.x(), nextRow});
5380 case Qt::Key_Down: {
5381 beginMoveCurrentIndex();
5382 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5383 if (nextRow == kEdgeIndexAtEnd)
5385 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5386 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5387 endMoveCurrentIndex({currentCell.x(), nextRow});
5389 case Qt::Key_Left: {
5390 beginMoveCurrentIndex();
5391 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5392 if (nextColumn == kEdgeIndexAtEnd)
5394 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5395 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5396 endMoveCurrentIndex({nextColumn, currentCell.y()});
5398 case Qt::Key_Right: {
5399 beginMoveCurrentIndex();
5400 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5401 if (nextColumn == kEdgeIndexAtEnd)
5403 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5404 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5405 endMoveCurrentIndex({nextColumn, currentCell.y()});
5407 case Qt::Key_PageDown: {
5408 int newBottomRow = -1;
5409 beginMoveCurrentIndex();
5410 if (currentCell.y() < bottomRow()) {
5412 newBottomRow = bottomRow();
5413 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5415 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5416 positionYAnimation.complete();
5417 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5418 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5419 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5420 positionYAnimation.complete();
5422 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5424 case Qt::Key_PageUp: {
5426 beginMoveCurrentIndex();
5427 if (currentCell.y() > topRow()) {
5429 newTopRow = topRow();
5430 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5432 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5433 positionYAnimation.complete();
5434 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5435 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5436 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5437 positionYAnimation.complete();
5439 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5441 case Qt::Key_Home: {
5442 beginMoveCurrentIndex();
5443 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5444 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5445 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5448 beginMoveCurrentIndex();
5449 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5450 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5451 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5454 beginMoveCurrentIndex();
5455 int nextRow = currentCell.y();
5456 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5457 if (nextColumn == kEdgeIndexAtEnd) {
5458 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5459 if (nextRow == kEdgeIndexAtEnd)
5460 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5461 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5462 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5463 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5467 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5468 marginX = q->leftMargin();
5469 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5470 marginX = -q->leftMargin();
5472 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5473 endMoveCurrentIndex({nextColumn, nextRow});
5475 case Qt::Key_Backtab: {
5476 beginMoveCurrentIndex();
5477 int nextRow = currentCell.y();
5478 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5479 if (nextColumn == kEdgeIndexAtEnd) {
5480 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5481 if (nextRow == kEdgeIndexAtEnd)
5482 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5483 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5484 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5485 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5489 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5490 marginX = q->leftMargin();
5491 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5492 marginX = -q->leftMargin();
5494 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5495 endMoveCurrentIndex({nextColumn, nextRow});
5504bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5506 Q_Q(QQuickTableView);
5508 if (editTriggers == QQuickTableView::NoEditTriggers)
5510 if (!selectionModel || !selectionModel->model())
5513 const QModelIndex index = selectionModel->currentIndex();
5514 const QPoint cell = q->cellAtIndex(index);
5515 const QQuickItem *cellItem = q->itemAtCell(cell);
5519 auto attached = getAttachedObject(cellItem);
5520 if (!attached || !attached->editDelegate())
5523 bool anyKeyPressed =
false;
5524 bool editKeyPressed =
false;
5527 case Qt::Key_Return:
5532 anyKeyPressed =
true;
5533 editKeyPressed =
true;
5537 case Qt::Key_Control:
5540 case Qt::Key_Backtab:
5543 anyKeyPressed =
true;
5546 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5547 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5549 if (!(editKeyAccepted || anyKeyAccepted))
5552 if (!canEdit(index,
false)) {
5561 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5564 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5570QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5576 Q_Q(QQuickTableView);
5577 if (QObject *focusObject = editItem->window()->focusObject()) {
5578 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5579 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5580 focusItem->installEventFilter(q);
5587void QQuickTableViewPrivate::closeEditorAndCommit()
5592 if (
auto attached = getAttachedObject(editItem))
5593 emit attached->commit();
5595 q_func()->closeEditor();
5598#if QT_CONFIG(cursor)
5599void QQuickTableViewPrivate::updateCursor()
5601 int row = resizableRows ? hoverHandler->m_row : -1;
5602 int column = resizableColumns ? hoverHandler->m_column : -1;
5604 const auto resizeState = resizeHandler->state();
5605 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5606 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5609 row = resizeHandler->m_row;
5610 column = resizeHandler->m_column;
5613 if (row != -1 || column != -1) {
5614 Qt::CursorShape shape;
5615 if (row != -1 && column != -1)
5616 shape = Qt::SizeFDiagCursor;
5618 shape = Qt::SplitVCursor;
5620 shape = Qt::SplitHCursor;
5623 qApp->changeOverrideCursor(shape);
5625 qApp->setOverrideCursor(shape);
5628 }
else if (m_cursorSet) {
5629 qApp->restoreOverrideCursor();
5630 m_cursorSet =
false;
5635void QQuickTableViewPrivate::updateEditItem()
5637 Q_Q(QQuickTableView);
5642 const QPoint cell = q->cellAtIndex(editIndex);
5643 auto cellItem = q->itemAtCell(cell);
5654 editItem->parentItem()->setX(-editItem->width() - 10000);
5658QQuickTableView::QQuickTableView(QQuickItem *parent)
5659 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5664QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5665 : QQuickFlickable(dd, parent)
5670QQuickTableView::~QQuickTableView()
5672 Q_D(QQuickTableView);
5676 auto syncView_d = d->syncView->d_func();
5677 syncView_d->syncChildren.removeOne(
this);
5678 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5682void QQuickTableView::componentFinalized()
5696 Q_D(QQuickTableView);
5697 qCDebug(lcTableViewDelegateLifecycle);
5701qreal QQuickTableView::minXExtent()
const
5703 return QQuickFlickable::minXExtent() - d_func()->origin.x();
5706qreal QQuickTableView::maxXExtent()
const
5708 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
5711qreal QQuickTableView::minYExtent()
const
5713 return QQuickFlickable::minYExtent() - d_func()->origin.y();
5716qreal QQuickTableView::maxYExtent()
const
5718 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
5721int QQuickTableView::rows()
const
5723 return d_func()->tableSize.height();
5726int QQuickTableView::columns()
const
5728 return d_func()->tableSize.width();
5731qreal QQuickTableView::rowSpacing()
const
5733 return d_func()->cellSpacing.height();
5736void QQuickTableView::setRowSpacing(qreal spacing)
5738 Q_D(QQuickTableView);
5739 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5741 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
5744 d->cellSpacing.setHeight(spacing);
5745 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5746 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5747 emit rowSpacingChanged();
5750qreal QQuickTableView::columnSpacing()
const
5752 return d_func()->cellSpacing.width();
5755void QQuickTableView::setColumnSpacing(qreal spacing)
5757 Q_D(QQuickTableView);
5758 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5760 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
5763 d->cellSpacing.setWidth(spacing);
5764 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5765 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5766 emit columnSpacingChanged();
5769QJSValue QQuickTableView::rowHeightProvider()
const
5771 return d_func()->rowHeightProvider;
5774void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
5776 Q_D(QQuickTableView);
5777 if (provider.strictlyEquals(d->rowHeightProvider))
5780 d->rowHeightProvider = provider;
5781 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5782 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5783 emit rowHeightProviderChanged();
5786QJSValue QQuickTableView::columnWidthProvider()
const
5788 return d_func()->columnWidthProvider;
5791void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
5793 Q_D(QQuickTableView);
5794 if (provider.strictlyEquals(d->columnWidthProvider))
5797 d->columnWidthProvider = provider;
5798 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5799 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5800 emit columnWidthProviderChanged();
5803QVariant QQuickTableView::model()
const
5805 return d_func()->modelImpl();
5808void QQuickTableView::setModel(
const QVariant &newModel)
5810 Q_D(QQuickTableView);
5812 QVariant model = newModel;
5813 if (model.userType() == qMetaTypeId<QJSValue>())
5814 model = model.value<QJSValue>().toVariant();
5816 if (model == d->assignedModel)
5820 d->setModelImpl(model);
5821 if (d->selectionModel)
5822 d->selectionModel->setModel(d->selectionSourceModel());
5825QQmlComponent *QQuickTableView::delegate()
const
5827 return d_func()->assignedDelegate;
5830void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
5832 Q_D(QQuickTableView);
5833 if (newDelegate == d->assignedDelegate)
5836 d->assignedDelegate = newDelegate;
5837 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5839 emit delegateChanged();
5842QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
5844 return d_func()->editTriggers;
5847void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
5849 Q_D(QQuickTableView);
5850 if (editTriggers == d->editTriggers)
5853 d->editTriggers = editTriggers;
5855 emit editTriggersChanged();
5859
5860
5861
5862
5863QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
5865 Q_D(
const QQuickTableView);
5866 return d->assignedDelegateModelAccess;
5869void QQuickTableView::setDelegateModelAccess(
5870 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
5872 Q_D(QQuickTableView);
5873 if (delegateModelAccess == d->assignedDelegateModelAccess)
5876 d->assignedDelegateModelAccess = delegateModelAccess;
5877 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5879 emit delegateModelAccessChanged();
5882bool QQuickTableView::reuseItems()
const
5884 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
5887void QQuickTableView::setReuseItems(
bool reuse)
5889 Q_D(QQuickTableView);
5890 if (reuseItems() == reuse)
5893 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
5895 if (!reuse && d->tableModel) {
5898 d->tableModel->drainReusableItemsPool(0);
5901 emit reuseItemsChanged();
5904void QQuickTableView::setContentWidth(qreal width)
5906 Q_D(QQuickTableView);
5907 d->explicitContentWidth = width;
5908 QQuickFlickable::setContentWidth(width);
5911void QQuickTableView::setContentHeight(qreal height)
5913 Q_D(QQuickTableView);
5914 d->explicitContentHeight = height;
5915 QQuickFlickable::setContentHeight(height);
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935QQuickTableView *QQuickTableView::syncView()
const
5937 return d_func()->assignedSyncView;
5940void QQuickTableView::setSyncView(QQuickTableView *view)
5942 Q_D(QQuickTableView);
5943 if (d->assignedSyncView == view)
5948 d->clearIndexMapping();
5950 d->assignedSyncView = view;
5951 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5953 emit syncViewChanged();
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974Qt::Orientations QQuickTableView::syncDirection()
const
5976 return d_func()->assignedSyncDirection;
5979void QQuickTableView::setSyncDirection(Qt::Orientations direction)
5981 Q_D(QQuickTableView);
5982 if (d->assignedSyncDirection == direction)
5985 d->assignedSyncDirection = direction;
5986 if (d->assignedSyncView)
5987 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5989 emit syncDirectionChanged();
5992QItemSelectionModel *QQuickTableView::selectionModel()
const
5994 return d_func()->selectionModel;
5997void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
5999 Q_D(QQuickTableView);
6000 if (d->selectionModel == selectionModel)
6007 if (d->selectionModel) {
6008 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6009 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6010 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6011 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6014 d->selectionModel = selectionModel;
6016 if (d->selectionModel) {
6017 d->selectionModel->setModel(d->selectionSourceModel());
6018 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6019 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6020 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6021 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6024 d->updateSelectedOnAllDelegateItems();
6026 emit selectionModelChanged();
6029bool QQuickTableView::animate()
const
6031 return d_func()->animate;
6034void QQuickTableView::setAnimate(
bool animate)
6036 Q_D(QQuickTableView);
6037 if (d->animate == animate)
6040 d->animate = animate;
6042 d->positionXAnimation.stop();
6043 d->positionYAnimation.stop();
6046 emit animateChanged();
6049bool QQuickTableView::keyNavigationEnabled()
const
6051 return d_func()->keyNavigationEnabled;
6054void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6056 Q_D(QQuickTableView);
6057 if (d->keyNavigationEnabled == enabled)
6060 d->keyNavigationEnabled = enabled;
6062 emit keyNavigationEnabledChanged();
6065bool QQuickTableView::pointerNavigationEnabled()
const
6067 return d_func()->pointerNavigationEnabled;
6070void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6072 Q_D(QQuickTableView);
6073 if (d->pointerNavigationEnabled == enabled)
6076 d->pointerNavigationEnabled = enabled;
6078 emit pointerNavigationEnabledChanged();
6081int QQuickTableView::leftColumn()
const
6083 Q_D(
const QQuickTableView);
6084 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6087int QQuickTableView::rightColumn()
const
6089 Q_D(
const QQuickTableView);
6090 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6093int QQuickTableView::topRow()
const
6095 Q_D(
const QQuickTableView);
6096 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6099int QQuickTableView::bottomRow()
const
6101 Q_D(
const QQuickTableView);
6102 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6105int QQuickTableView::currentRow()
const
6107 return d_func()->currentRow;
6110int QQuickTableView::currentColumn()
const
6112 return d_func()->currentColumn;
6115void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6117 Q_D(QQuickTableView);
6118 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6125 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6126 mode &= AlignTop | AlignBottom | AlignVCenter;
6127 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6128 }
else if (mode == Contain) {
6129 if (row < topRow()) {
6130 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6131 }
else if (row > bottomRow()) {
6132 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6133 }
else if (row == topRow()) {
6134 if (!subRect.isValid()) {
6135 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6137 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6138 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6139 if (subRectTop < d->viewportRect.y())
6140 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6141 else if (subRectBottom > d->viewportRect.bottom())
6142 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6144 }
else if (row == bottomRow()) {
6145 if (!subRect.isValid()) {
6146 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6150 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6151 if (subRectBottom > d->viewportRect.bottom())
6152 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6155 }
else if (mode == Visible) {
6156 if (row < topRow()) {
6157 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6158 }
else if (row > bottomRow()) {
6159 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6160 }
else if (subRect.isValid()) {
6161 if (row == topRow()) {
6162 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6163 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6164 if (subRectBottom < d->viewportRect.top())
6165 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6166 else if (subRectTop > d->viewportRect.bottom())
6167 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6168 }
else if (row == bottomRow()) {
6171 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6172 if (subRectTop > d->viewportRect.bottom())
6173 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6177 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6181void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6183 Q_D(QQuickTableView);
6184 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6191 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6192 mode &= AlignLeft | AlignRight | AlignHCenter;
6193 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6194 }
else if (mode == Contain) {
6195 if (column < leftColumn()) {
6196 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6197 }
else if (column > rightColumn()) {
6198 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6199 }
else if (column == leftColumn()) {
6200 if (!subRect.isValid()) {
6201 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6203 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6204 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6205 if (subRectLeft < d->viewportRect.left())
6206 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6207 else if (subRectRight > d->viewportRect.right())
6208 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6210 }
else if (column == rightColumn()) {
6211 if (!subRect.isValid()) {
6212 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6216 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6217 if (subRectRight > d->viewportRect.right())
6218 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6221 }
else if (mode == Visible) {
6222 if (column < leftColumn()) {
6223 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6224 }
else if (column > rightColumn()) {
6225 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6226 }
else if (subRect.isValid()) {
6227 if (column == leftColumn()) {
6228 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6229 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6230 if (subRectRight < d->viewportRect.left())
6231 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6232 else if (subRectLeft > d->viewportRect.right())
6233 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6234 }
else if (column == rightColumn()) {
6237 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6238 if (subRectLeft > d->viewportRect.right())
6239 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6243 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6247void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6249 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6250 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6251 if (!horizontalMode && !verticalMode) {
6252 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6257 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6259 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6262void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6264 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6265 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6266 if (!horizontalMode && !verticalMode) {
6267 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6272 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6274 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6277#if QT_DEPRECATED_SINCE(6
, 5
)
6278void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6280 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6281 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6282 if (!horizontalMode && !verticalMode) {
6283 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6288 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6290 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6294void QQuickTableView::moveColumn(
int source,
int destination)
6296 Q_D(QQuickTableView);
6297 d->moveSection(source, destination, Qt::Horizontal);
6300void QQuickTableView::moveRow(
int source,
int destination)
6302 Q_D(QQuickTableView);
6303 d->moveSection(source, destination, Qt::Vertical);
6306void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientations orientation)
6308 Q_Q(QQuickTableView);
6310 if (source < 0 || destination < 0 ||
6311 (orientation == Qt::Horizontal &&
6312 (source >= tableSize.width() || destination >= tableSize.width())) ||
6313 (orientation == Qt::Vertical &&
6314 (source >= tableSize.height() || destination >= tableSize.height())))
6317 if (source == destination)
6320 if (m_sectionState != SectionState::Moving) {
6321 m_sectionState = SectionState::Moving;
6323 syncView->d_func()->moveSection(source, destination, orientation);
6326 initializeIndexMapping();
6329 SectionData *visualIndex =
nullptr;
6330 SectionData *logicalIndex =
nullptr;
6332 if (orientation == Qt::Horizontal) {
6333 visualIndex = visualIndices[0].data();
6334 logicalIndex = logicalIndices[0].data();
6335 }
else if (orientation == Qt::Vertical) {
6336 visualIndex = visualIndices[1].data();
6337 logicalIndex = logicalIndices[1].data();
6340 const int logical = logicalIndex[source].index;
6341 int visual = source;
6343 if (destination > source) {
6344 while (visual < destination) {
6345 SectionData &visualData = visualIndex[logicalIndex[visual + 1].index];
6346 SectionData &logicalData = logicalIndex[visual];
6347 visualData.prevIndex = visualData.index;
6348 visualData.index = visual;
6349 logicalData.prevIndex = logicalData.index;
6350 logicalData.index = logicalIndex[visual + 1].index;
6354 while (visual > destination) {
6355 SectionData &visualData = visualIndex[logicalIndex[visual - 1].index];
6356 SectionData &logicalData = logicalIndex[visual];
6357 visualData.prevIndex = visualData.index;
6358 visualData.index = visual;
6359 logicalData.prevIndex = logicalData.index;
6360 logicalData.index = logicalIndex[visual - 1].index;
6365 visualIndex[logical].prevIndex = visualIndex[logical].index;
6366 visualIndex[logical].index = destination;
6367 logicalIndex[destination].prevIndex = logicalIndex[destination].index;
6368 logicalIndex[destination].index = logical;
6372 for (
auto syncChild : std::as_const(syncChildren)) {
6373 auto syncChild_d = syncChild->d_func();
6374 if (syncChild_d->m_sectionState != SectionState::Moving &&
6375 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6376 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6377 syncChild_d->moveSection(source, destination, orientation);
6382 scheduleRebuildTable(RebuildOption::ViewportOnly);
6383 m_sectionState = SectionState::Idle;
6386 const int startIndex = (source > destination) ? destination : source;
6387 const int endIndex = (source > destination) ? source : destination;
6388 const int mapIndex =
static_cast<
int>(orientation) - 1;
6389 for (
int index = startIndex; index <= endIndex; index++) {
6390 const SectionData *logicalDataIndices = (syncView ? syncView->d_func()->logicalIndices[mapIndex].constData() : logicalIndices[mapIndex].constData());
6391 const SectionData *visualDataIndices = syncView ? syncView->d_func()->visualIndices[mapIndex].constData() : visualIndices[mapIndex].constData();
6392 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6393 if (orientation == Qt::Horizontal)
6394 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6396 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6401void QQuickTableView::clearColumnReordering()
6403 Q_D(QQuickTableView);
6404 d->clearSection(Qt::Horizontal);
6407void QQuickTableView::clearRowReordering()
6409 Q_D(QQuickTableView);
6410 d->clearSection(Qt::Vertical);
6413void QQuickTableViewPrivate::clearSection(Qt::Orientations orientation)
6415 Q_Q(QQuickTableView);
6417 const int mapIndex =
static_cast<
int>(orientation) - 1;
6418 const QList<SectionData> oldLogicalIndices = syncView ? syncView->d_func()->logicalIndices[mapIndex] : logicalIndices[mapIndex];
6419 const QList<SectionData> oldVisualIndices = syncView ? syncView->d_func()->visualIndices[mapIndex] : visualIndices[mapIndex];;
6422 syncView->d_func()->clearSection(orientation);
6425 logicalIndices[mapIndex].clear();
6426 visualIndices[mapIndex].clear();
6427 scheduleRebuildTable(RebuildOption::ViewportOnly);
6431 for (
int index = 0; index < oldLogicalIndices.size(); index++) {
6432 const SectionData *logicalDataIndices = oldLogicalIndices.constData();
6433 const SectionData *visualDataIndices = oldVisualIndices.constData();
6434 if (logicalDataIndices[index].index != index) {
6435 const int currentIndex = logicalDataIndices[index].index;
6436 if (orientation == Qt::Horizontal)
6437 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6439 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6444void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6446 if (!modelIndex.isValid())
6449 const int cellIndex = modelIndexToCellIndex(modelIndex);
6450 if (!loadedItems.contains(cellIndex))
6452 const QPoint cell = cellAtModelIndex(cellIndex);
6453 QQuickItem *item = loadedTableItem(cell)->item;
6454 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6457QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6459 Q_D(
const QQuickTableView);
6460 const int modelIndex = d->modelIndexAtCell(cell);
6461 if (!d->loadedItems.contains(modelIndex))
6463 return d->loadedItems.value(modelIndex)->item;
6466#if QT_DEPRECATED_SINCE(6
, 5
)
6467QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6469 return itemAtCell(QPoint(column, row));
6473QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6475 Q_D(
const QQuickTableView);
6476 const int serializedIndex = d->modelIndexToCellIndex(index);
6477 if (!d->loadedItems.contains(serializedIndex))
6479 return d->loadedItems.value(serializedIndex)->item;
6482#if QT_DEPRECATED_SINCE(6
, 4
)
6483QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6485 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6488QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6490 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6494QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6496 return cellAtPosition(QPoint(x, y), includeSpacing);
6499QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6501 Q_D(
const QQuickTableView);
6503 if (!d->loadedTableOuterRect.contains(position))
6504 return QPoint(-1, -1);
6506 const qreal hSpace = d->cellSpacing.width();
6507 const qreal vSpace = d->cellSpacing.height();
6508 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6509 qreal currentRowEnd = d->loadedTableOuterRect.y();
6511 int foundColumn = -1;
6514 for (
const int column : d->loadedColumns) {
6515 currentColumnEnd += d->getEffectiveColumnWidth(column);
6516 if (position.x() < currentColumnEnd) {
6517 foundColumn = column;
6520 currentColumnEnd += hSpace;
6521 if (!includeSpacing && position.x() < currentColumnEnd) {
6523 return QPoint(-1, -1);
6524 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6525 foundColumn = column;
6530 for (
const int row : d->loadedRows) {
6531 currentRowEnd += d->getEffectiveRowHeight(row);
6532 if (position.y() < currentRowEnd) {
6536 currentRowEnd += vSpace;
6537 if (!includeSpacing && position.y() < currentRowEnd) {
6539 return QPoint(-1, -1);
6541 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6547 return QPoint(foundColumn, foundRow);
6550bool QQuickTableView::isColumnLoaded(
int column)
const
6552 Q_D(
const QQuickTableView);
6553 if (!d->loadedColumns.contains(column))
6556 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6559 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6566bool QQuickTableView::isRowLoaded(
int row)
const
6568 Q_D(
const QQuickTableView);
6569 if (!d->loadedRows.contains(row))
6572 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6575 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6582qreal QQuickTableView::columnWidth(
int column)
const
6584 Q_D(
const QQuickTableView);
6585 if (!isColumnLoaded(column))
6588 return d->getEffectiveColumnWidth(column);
6591qreal QQuickTableView::rowHeight(
int row)
const
6593 Q_D(
const QQuickTableView);
6594 if (!isRowLoaded(row))
6597 return d->getEffectiveRowHeight(row);
6600qreal QQuickTableView::implicitColumnWidth(
int column)
const
6602 Q_D(
const QQuickTableView);
6603 if (!isColumnLoaded(column))
6606 return d->sizeHintForColumn(column);
6609qreal QQuickTableView::implicitRowHeight(
int row)
const
6611 Q_D(
const QQuickTableView);
6612 if (!isRowLoaded(row))
6615 return d->sizeHintForRow(row);
6618void QQuickTableView::setColumnWidth(
int column, qreal size)
6620 Q_D(QQuickTableView);
6622 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6626 if (d->syncHorizontally) {
6627 d->syncView->setColumnWidth(column, size);
6631 if (qFuzzyCompare(explicitColumnWidth(column), size))
6635 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6637 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6639 if (d->loadedItems.isEmpty())
6642 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6643 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6644 d->forceLayout(
false);
6647void QQuickTableView::clearColumnWidths()
6649 Q_D(QQuickTableView);
6651 if (d->syncHorizontally) {
6652 d->syncView->clearColumnWidths();
6656 if (d->explicitColumnWidths.isEmpty())
6659 d->explicitColumnWidths.clear();
6660 d->forceLayout(
false);
6663qreal QQuickTableView::explicitColumnWidth(
int column)
const
6665 Q_D(
const QQuickTableView);
6667 if (d->syncHorizontally)
6668 return d->syncView->explicitColumnWidth(column);
6670 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6671 if (it != d->explicitColumnWidths.constEnd())
6676void QQuickTableView::setRowHeight(
int row, qreal size)
6678 Q_D(QQuickTableView);
6680 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
6684 if (d->syncVertically) {
6685 d->syncView->setRowHeight(row, size);
6689 if (qFuzzyCompare(explicitRowHeight(row), size))
6693 d->explicitRowHeights.remove(d->logicalRowIndex(row));
6695 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
6697 if (d->loadedItems.isEmpty())
6700 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
6701 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
6702 d->forceLayout(
false);
6705void QQuickTableView::clearRowHeights()
6707 Q_D(QQuickTableView);
6709 if (d->syncVertically) {
6710 d->syncView->clearRowHeights();
6714 if (d->explicitRowHeights.isEmpty())
6717 d->explicitRowHeights.clear();
6718 d->forceLayout(
false);
6721qreal QQuickTableView::explicitRowHeight(
int row)
const
6723 Q_D(
const QQuickTableView);
6725 if (d->syncVertically)
6726 return d->syncView->explicitRowHeight(row);
6728 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
6729 if (it != d->explicitRowHeights.constEnd())
6734QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
6736 Q_D(
const QQuickTableView);
6737 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
6740 auto const qaim = d->model->abstractItemModel();
6744 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
6747QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
6749 if (!index.isValid() || index.parent().isValid())
6751 Q_D(
const QQuickTableView);
6752 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
6755#if QT_DEPRECATED_SINCE(6
, 4
)
6756QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
6758 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
6764 return modelIndex({row, column});
6766 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
6767 "Use index(row, column) instead. For more information, see "
6768 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
6769 return modelIndex({column, row});
6774QModelIndex QQuickTableView::index(
int row,
int column)
const
6776 return modelIndex({column, row});
6779int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
6781 return cellAtIndex(index).y();
6784int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
6786 return cellAtIndex(index).x();
6789void QQuickTableView::forceLayout()
6791 d_func()->forceLayout(
true);
6794void QQuickTableView::edit(
const QModelIndex &index)
6796 Q_D(QQuickTableView);
6798 if (!d->canEdit(index,
true))
6801 if (d->editIndex == index)
6807 if (!d->editModel) {
6808 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
6809 d->editModel->useImportVersion(d->resolveImportVersion());
6810 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
6811 [
this, d] (
int serializedModelIndex, QObject *object) {
6817 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
6818 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
6819 d->editItem = qmlobject_cast<QQuickItem*>(object);
6823 d->initItemCallback(serializedModelIndex, object);
6824 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
6826 d->editItem->setParentItem(cellItem);
6833 if (d->selectionModel)
6834 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
6837 d->closeEditorAndCommit();
6839 const auto cellItem = itemAtCell(cellAtIndex(index));
6841 const auto attached = d->getAttachedObject(cellItem);
6844 d->editModel->setModel(d->tableModel->model());
6845 d->editModel->setDelegate(attached->editDelegate());
6847 const int cellIndex = d->getEditCellIndex(index);
6848 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
6850 d->editIndex = QModelIndex();
6851 d->editItem =
nullptr;
6852 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
6859 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
6860 d->editItem =
nullptr;
6861 d->editIndex = QModelIndex();
6862 d->editModel->release(object, QQmlInstanceModel::NotReusable);
6868 d->model->object(cellIndex, QQmlIncubator::Synchronous);
6871 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
6874 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
6875 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
6878void QQuickTableView::closeEditor()
6880 Q_D(QQuickTableView);
6885 QQuickItem *cellItem = d->editItem->parentItem();
6886 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
6887 d->editItem =
nullptr;
6890 const int cellIndex = d->getEditCellIndex(d->editIndex);
6891 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
6893 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
6895 if (d->editIndex.isValid()) {
6898 d->editIndex = QModelIndex();
6902QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
6904 return new QQuickTableViewAttached(obj);
6907void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
6909 Q_D(QQuickTableView);
6910 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
6912 if (d->tableModel) {
6915 d->tableModel->drainReusableItemsPool(0);
6918 d->forceLayout(
false);
6921void QQuickTableView::viewportMoved(Qt::Orientations orientation)
6923 Q_D(QQuickTableView);
6929 QQuickFlickable::viewportMoved(orientation);
6930 if (d->inSetLocalViewportPos)
6937 d->syncViewportPosRecursive();
6939 auto rootView = d->rootSyncView();
6940 auto rootView_d = rootView->d_func();
6942 rootView_d->scheduleRebuildIfFastFlick();
6944 if (!rootView_d->polishScheduled) {
6945 if (rootView_d->scheduledRebuildOptions) {
6952 const bool updated = rootView->d_func()->updateTableRecursive();
6962void QQuickTableView::keyPressEvent(QKeyEvent *e)
6964 Q_D(QQuickTableView);
6966 if (!d->keyNavigationEnabled) {
6967 QQuickFlickable::keyPressEvent(e);
6971 if (d->tableSize.isEmpty())
6974 if (d->editIndex.isValid()) {
6980 if (d->setCurrentIndexFromKeyEvent(e))
6983 if (d->editFromKeyEvent(e))
6986 QQuickFlickable::keyPressEvent(e);
6989bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
6991 Q_D(QQuickTableView);
6993 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
6996 return QQuickFlickable::eventFilter(obj, event);
6999 switch (event->type()) {
7000 case QEvent::KeyPress: {
7001 Q_ASSERT(d->editItem);
7002 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7003 switch (keyEvent->key()) {
7005 case Qt::Key_Return:
7006 d->closeEditorAndCommit();
7009 case Qt::Key_Backtab:
7010 if (activeFocusOnTab()) {
7011 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7012 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7013 if (d->canEdit(currentIndex,
false))
7019 case Qt::Key_Escape:
7024 case QEvent::FocusOut:
7027 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7028 d->closeEditorAndCommit();
7034 return QQuickFlickable::eventFilter(obj, event);
7037bool QQuickTableView::alternatingRows()
const
7039 return d_func()->alternatingRows;
7042void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7044 Q_D(QQuickTableView);
7045 if (d->alternatingRows == alternatingRows)
7048 d->alternatingRows = alternatingRows;
7049 emit alternatingRowsChanged();
7052QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7054 return d_func()->selectionBehavior;
7057void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7059 Q_D(QQuickTableView);
7060 if (d->selectionBehavior == selectionBehavior)
7063 d->selectionBehavior = selectionBehavior;
7064 emit selectionBehaviorChanged();
7067QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7069 return d_func()->selectionMode;
7072void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7074 Q_D(QQuickTableView);
7075 if (d->selectionMode == selectionMode)
7078 d->selectionMode = selectionMode;
7079 emit selectionModeChanged();
7082bool QQuickTableView::resizableColumns()
const
7084 return d_func()->resizableColumns;
7087void QQuickTableView::setResizableColumns(
bool enabled)
7089 Q_D(QQuickTableView);
7090 if (d->resizableColumns == enabled)
7093 d->resizableColumns = enabled;
7094 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7095 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7097 emit resizableColumnsChanged();
7100bool QQuickTableView::resizableRows()
const
7102 return d_func()->resizableRows;
7105void QQuickTableView::setResizableRows(
bool enabled)
7107 Q_D(QQuickTableView);
7108 if (d->resizableRows == enabled)
7111 d->resizableRows = enabled;
7112 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7113 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7115 emit resizableRowsChanged();
7120 : QQuickHoverHandler(view->contentItem())
7124 connect(
this, &QQuickHoverHandler::hoveredChanged, [
this] {
7125 if (!isHoveringGrid())
7129#if QT_CONFIG(cursor)
7130 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7131 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7132 tableViewPrivate->updateCursor();
7139 QQuickHoverHandler::handleEventPoint(event, point);
7141 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7142#if QT_CONFIG(cursor)
7143 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7146 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7147 const auto item = tableView->itemAtCell(cell);
7151#if QT_CONFIG(cursor)
7152 tableViewPrivate->updateCursor();
7157 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7158 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7159 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7160 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7161 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7162#if QT_CONFIG(cursor)
7163 tableViewPrivate->updateCursor();
7174 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7179 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7183 if (event->type() == QEvent::Type::Wheel)
7188 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7189 return !tableView->isMoving();
7198 setObjectName(
"tableViewResizeHandler");
7202 , QPointingDevice::GrabTransition transition
7204 , QEventPoint &point)
7206 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7208 switch (transition) {
7209 case QPointingDevice::GrabPassive:
7210 case QPointingDevice::GrabExclusive:
7212 case QPointingDevice::UngrabPassive:
7213 case QPointingDevice::UngrabExclusive:
7214 case QPointingDevice::CancelGrabPassive:
7215 case QPointingDevice::CancelGrabExclusive:
7216 case QPointingDevice::OverrideGrabPassive:
7217 if (m_state == DraggingStarted || m_state == Dragging) {
7218 m_state = DraggingFinished;
7219 updateDrag(ev, point);
7227 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7228 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7229 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7236 updateDrag(event, point);
7241 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7242 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7244 if (m_state == DraggingFinished)
7245 m_state = Listening;
7247 if (point.state() == QEventPoint::Pressed) {
7248 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7249 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7250 if (m_row != -1 || m_column != -1)
7252 }
else if (point.state() == QEventPoint::Released) {
7253 if (m_state == DraggingStarted || m_state == Dragging)
7254 m_state = DraggingFinished;
7256 m_state = Listening;
7257 }
else if (point.state() == QEventPoint::Updated) {
7262 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7263 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7264 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7265 if (dragDist > qApp->styleHints()->startDragDistance())
7266 m_state = DraggingStarted;
7268 case DraggingStarted:
7273 case DraggingFinished:
7283 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7284#if QT_CONFIG(cursor)
7285 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7292 setPassiveGrab(event, point,
true);
7296 tableView->setFiltersChildMouseEvents(
false);
7297 tableViewPrivate->setActivePointerHandler(
this);
7299 case DraggingStarted:
7300 setExclusiveGrab(event, point,
true);
7301 m_columnStartX = point.position().x();
7302 m_columnStartWidth = tableView->columnWidth(m_column);
7303 m_rowStartY = point.position().y();
7304 m_rowStartHeight = tableView->rowHeight(m_row);
7305#if QT_CONFIG(cursor)
7306 tableViewPrivate->updateCursor();
7310 const qreal distX = point.position().x() - m_columnStartX;
7311 const qreal distY = point.position().y() - m_rowStartY;
7313 tableView->setColumnWidth(m_column, qMax(0.001, m_columnStartWidth + distX));
7315 tableView->setRowHeight(m_row, qMax(0.001, m_rowStartHeight + distY));
7317 case DraggingFinished: {
7318 tableView->setFiltersChildMouseEvents(
true);
7319 tableViewPrivate->setActivePointerHandler(
nullptr);
7320#if QT_CONFIG(cursor)
7321 tableViewPrivate->updateCursor();
7328#if QT_CONFIG(quick_draganddrop)
7330QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7331 : QQuickTableViewPointerHandler(view)
7333 setObjectName(
"tableViewDragHandler");
7336QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7341void QQuickTableViewSectionDragHandler::resetDragData()
7343 if (m_state != Listening) {
7344 m_state = Listening;
7345 resetSectionOverlay();
7348 if (m_grabResult.data())
7349 m_grabResult.data()->disconnect();
7350 if (!m_drag.isNull()) {
7351 m_drag->disconnect();
7354 if (!m_dropArea.isNull()) {
7355 m_dropArea->disconnect();
7358 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7359 tableView->setFiltersChildMouseEvents(
true);
7363void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7365 if (m_destination != -1) {
7366 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7367 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7368 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7369 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7370 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7375void QQuickTableViewSectionDragHandler::grabSection()
7378 QPixmap pixmap(m_grabResult->image().size());
7379 pixmap.fill(Qt::transparent);
7380 QPainter painter(&pixmap);
7381 painter.setOpacity(0.6);
7382 painter.drawImage(0, 0, m_grabResult->image());
7386 auto *mimeData =
new QMimeData();
7387 mimeData->setImageData(pixmap);
7388 m_drag->setMimeData(mimeData);
7389 m_drag->setPixmap(pixmap);
7392void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7396 if (m_state == Dragging) {
7397 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7398 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7399 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7400 m_state = DraggingFinished;
7401 resetSectionOverlay();
7402 if (m_scrollTimer.isActive())
7403 m_scrollTimer.stop();
7408void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7412 if (m_state == Dragging) {
7413 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7414 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7415 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7416 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7418 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7419 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7420 if (newDestination != m_destination) {
7422 resetSectionOverlay();
7424 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7425 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7426 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7427 m_destination = newDestination;
7431 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7432 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7433 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7434 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7435 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7436 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7437 if (useStartPos || useEndPos) {
7438 if (!m_scrollTimer.isActive()) {
7439 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7440 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7441 m_scrollTimer.start(1);
7444 if (m_scrollTimer.isActive())
7445 m_scrollTimer.stop();
7450void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7454 if (action == Qt::IgnoreAction) {
7455 resetSectionOverlay();
7456 if (m_scrollTimer.isActive())
7457 m_scrollTimer.stop();
7461void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7463 QQuickSinglePointHandler::handleEventPoint(event, point);
7465 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7466 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7467 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7468 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7471 if (m_state == DraggingFinished) {
7472 if (m_scrollTimer.isActive())
7473 m_scrollTimer.stop();
7477 if (point.state() == QEventPoint::Pressed) {
7481 setPassiveGrab(event, point,
true);
7485 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7486 tableView->setFiltersChildMouseEvents(
false);
7488 }
else if (point.state() == QEventPoint::Released) {
7490 if (m_scrollTimer.isActive())
7491 m_scrollTimer.stop();
7493 }
else if (point.state() == QEventPoint::Updated) {
7495 const qreal distX = point.position().x() - point.pressPosition().x();
7496 const qreal distY = point.position().y() - point.pressPosition().y();
7497 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7498 if (dragDist > qApp->styleHints()->startDragDistance()) {
7502 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7503 auto *item = tableView->itemAtCell(cell);
7506 if (m_drag.isNull()) {
7507 m_drag =
new QDrag(item);
7508 connect(m_drag.data(), &QDrag::actionChanged,
this,
7509 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7512 QObject::connect(&m_scrollTimer, &QTimer::timeout, [&]{
7513 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7514 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7515 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7516 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7519 if (m_dropArea.isNull()) {
7520 m_dropArea =
new QQuickDropArea(tableView);
7521 m_dropArea->setSize(tableView->size());
7522 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7523 &QQuickTableViewSectionDragHandler::handleDrag);
7524 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7525 &QQuickTableViewSectionDragHandler::handleDrop);
7528 m_grabResult = item->grabToImage();
7529 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7530 &QQuickTableViewSectionDragHandler::grabSection);
7532 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7533 m_state = DraggingStarted;
7535 tableViewPrivate->setActivePointerHandler(
this);
7539 case DraggingStarted: {
7540 if (m_drag && m_drag->mimeData()) {
7541 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7543 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7545 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7549 if (m_state == Dragging)
7552 tableViewPrivate->setActivePointerHandler(
nullptr);
7566void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7568 if (!sectionDragHandler) {
7569 Q_Q(QQuickTableView);
7570 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7571 sectionDragHandler->setSectionOrientation(orientation);
7575void QQuickTableViewPrivate::destroySectionDragHandler()
7577 if (sectionDragHandler) {
7578 delete sectionDragHandler;
7579 sectionDragHandler =
nullptr;
7584void QQuickTableViewPrivate::initializeIndexMapping()
7586 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7587 visualIndex.resize(size);
7588 logicalIndex.resize(size);
7589 for (
int index = 0; index < size; ++index)
7590 visualIndex[index].index = logicalIndex[index].index = index;
7593 if (visualIndices[0].size() != tableSize.width()
7594 || logicalIndices[0].size() != tableSize.width())
7595 initIndices(visualIndices[0], logicalIndices[0], tableSize.width());
7597 if (visualIndices[1].size() != tableSize.height()
7598 || logicalIndices[1].size() != tableSize.height())
7599 initIndices(visualIndices[1], logicalIndices[1], tableSize.height());
7602void QQuickTableViewPrivate::clearIndexMapping()
7604 logicalIndices[0].clear();
7605 visualIndices[0].clear();
7607 logicalIndices[1].clear();
7608 visualIndices[1].clear();
7611int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7614 return syncView->d_func()->logicalRowIndex(visualIndex);
7615 if (logicalIndices[1].isEmpty() || visualIndex < 0)
7617 return logicalIndices[1].constData()[visualIndex].index;
7620int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7623 return syncView->d_func()->logicalColumnIndex(visualIndex);
7624 if (logicalIndices[0].isEmpty() || visualIndex < 0)
7626 return logicalIndices[0].constData()[visualIndex].index;
7629int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7632 return syncView->d_func()->visualRowIndex(logicalIndex);
7633 if (visualIndices[1].isEmpty() || logicalIndex < 0)
7634 return logicalIndex;
7635 return visualIndices[1].constData()[logicalIndex].index;
7638int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7641 return syncView->d_func()->visualColumnIndex(logicalIndex);
7642 if (visualIndices[0].isEmpty() || logicalIndex < 0)
7643 return logicalIndex;
7644 return visualIndices[0].constData()[logicalIndex].index;
7647int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7651 const bool hasProxyModel = (modelImpl() != assignedModel);
7652 return modelIndexToCellIndex(index, hasProxyModel);
7658 : QQuickTapHandler(view->contentItem())
7660 setObjectName(
"tableViewTapHandler");
7665 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7666 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7667 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
7672#include "moc_qquicktableview_p.cpp"
7673#include "moc_qquicktableview_p_p.cpp"
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override
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,...
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
#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