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
5863
5864QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
5866 Q_D(
const QQuickTableView);
5867 return d->assignedDelegateModelAccess;
5870void QQuickTableView::setDelegateModelAccess(
5871 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
5873 Q_D(QQuickTableView);
5874 if (delegateModelAccess == d->assignedDelegateModelAccess)
5877 d->assignedDelegateModelAccess = delegateModelAccess;
5878 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5880 emit delegateModelAccessChanged();
5883bool QQuickTableView::reuseItems()
const
5885 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
5888void QQuickTableView::setReuseItems(
bool reuse)
5890 Q_D(QQuickTableView);
5891 if (reuseItems() == reuse)
5894 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
5896 if (!reuse && d->tableModel) {
5899 d->tableModel->drainReusableItemsPool(0);
5902 emit reuseItemsChanged();
5905void QQuickTableView::setContentWidth(qreal width)
5907 Q_D(QQuickTableView);
5908 d->explicitContentWidth = width;
5909 QQuickFlickable::setContentWidth(width);
5912void QQuickTableView::setContentHeight(qreal height)
5914 Q_D(QQuickTableView);
5915 d->explicitContentHeight = height;
5916 QQuickFlickable::setContentHeight(height);
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936QQuickTableView *QQuickTableView::syncView()
const
5938 return d_func()->assignedSyncView;
5941void QQuickTableView::setSyncView(QQuickTableView *view)
5943 Q_D(QQuickTableView);
5944 if (d->assignedSyncView == view)
5949 d->clearIndexMapping();
5951 d->assignedSyncView = view;
5952 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5954 emit syncViewChanged();
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975Qt::Orientations QQuickTableView::syncDirection()
const
5977 return d_func()->assignedSyncDirection;
5980void QQuickTableView::setSyncDirection(Qt::Orientations direction)
5982 Q_D(QQuickTableView);
5983 if (d->assignedSyncDirection == direction)
5986 d->assignedSyncDirection = direction;
5987 if (d->assignedSyncView)
5988 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5990 emit syncDirectionChanged();
5993QItemSelectionModel *QQuickTableView::selectionModel()
const
5995 return d_func()->selectionModel;
5998void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6000 Q_D(QQuickTableView);
6001 if (d->selectionModel == selectionModel)
6008 if (d->selectionModel) {
6009 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6010 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6011 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6012 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6015 d->selectionModel = selectionModel;
6017 if (d->selectionModel) {
6018 d->selectionModel->setModel(d->selectionSourceModel());
6019 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6020 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6021 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6022 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6025 d->updateSelectedOnAllDelegateItems();
6027 emit selectionModelChanged();
6030bool QQuickTableView::animate()
const
6032 return d_func()->animate;
6035void QQuickTableView::setAnimate(
bool animate)
6037 Q_D(QQuickTableView);
6038 if (d->animate == animate)
6041 d->animate = animate;
6043 d->positionXAnimation.stop();
6044 d->positionYAnimation.stop();
6047 emit animateChanged();
6050bool QQuickTableView::keyNavigationEnabled()
const
6052 return d_func()->keyNavigationEnabled;
6055void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6057 Q_D(QQuickTableView);
6058 if (d->keyNavigationEnabled == enabled)
6061 d->keyNavigationEnabled = enabled;
6063 emit keyNavigationEnabledChanged();
6066bool QQuickTableView::pointerNavigationEnabled()
const
6068 return d_func()->pointerNavigationEnabled;
6071void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6073 Q_D(QQuickTableView);
6074 if (d->pointerNavigationEnabled == enabled)
6077 d->pointerNavigationEnabled = enabled;
6079 emit pointerNavigationEnabledChanged();
6082int QQuickTableView::leftColumn()
const
6084 Q_D(
const QQuickTableView);
6085 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6088int QQuickTableView::rightColumn()
const
6090 Q_D(
const QQuickTableView);
6091 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6094int QQuickTableView::topRow()
const
6096 Q_D(
const QQuickTableView);
6097 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6100int QQuickTableView::bottomRow()
const
6102 Q_D(
const QQuickTableView);
6103 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6106int QQuickTableView::currentRow()
const
6108 return d_func()->currentRow;
6111int QQuickTableView::currentColumn()
const
6113 return d_func()->currentColumn;
6116void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6118 Q_D(QQuickTableView);
6119 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6126 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6127 mode &= AlignTop | AlignBottom | AlignVCenter;
6128 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6129 }
else if (mode == Contain) {
6130 if (row < topRow()) {
6131 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6132 }
else if (row > bottomRow()) {
6133 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6134 }
else if (row == topRow()) {
6135 if (!subRect.isValid()) {
6136 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6138 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6139 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6140 if (subRectTop < d->viewportRect.y())
6141 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6142 else if (subRectBottom > d->viewportRect.bottom())
6143 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6145 }
else if (row == bottomRow()) {
6146 if (!subRect.isValid()) {
6147 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6151 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6152 if (subRectBottom > d->viewportRect.bottom())
6153 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6156 }
else if (mode == Visible) {
6157 if (row < topRow()) {
6158 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6159 }
else if (row > bottomRow()) {
6160 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6161 }
else if (subRect.isValid()) {
6162 if (row == topRow()) {
6163 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6164 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6165 if (subRectBottom < d->viewportRect.top())
6166 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6167 else if (subRectTop > d->viewportRect.bottom())
6168 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6169 }
else if (row == bottomRow()) {
6172 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6173 if (subRectTop > d->viewportRect.bottom())
6174 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6178 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6182void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6184 Q_D(QQuickTableView);
6185 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6192 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6193 mode &= AlignLeft | AlignRight | AlignHCenter;
6194 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6195 }
else if (mode == Contain) {
6196 if (column < leftColumn()) {
6197 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6198 }
else if (column > rightColumn()) {
6199 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6200 }
else if (column == leftColumn()) {
6201 if (!subRect.isValid()) {
6202 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6204 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6205 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6206 if (subRectLeft < d->viewportRect.left())
6207 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6208 else if (subRectRight > d->viewportRect.right())
6209 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6211 }
else if (column == rightColumn()) {
6212 if (!subRect.isValid()) {
6213 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6217 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6218 if (subRectRight > d->viewportRect.right())
6219 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6222 }
else if (mode == Visible) {
6223 if (column < leftColumn()) {
6224 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6225 }
else if (column > rightColumn()) {
6226 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6227 }
else if (subRect.isValid()) {
6228 if (column == leftColumn()) {
6229 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6230 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6231 if (subRectRight < d->viewportRect.left())
6232 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6233 else if (subRectLeft > d->viewportRect.right())
6234 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6235 }
else if (column == rightColumn()) {
6238 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6239 if (subRectLeft > d->viewportRect.right())
6240 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6244 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6248void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6250 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6251 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6252 if (!horizontalMode && !verticalMode) {
6253 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6258 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6260 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6263void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6265 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6266 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6267 if (!horizontalMode && !verticalMode) {
6268 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6273 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6275 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6278#if QT_DEPRECATED_SINCE(6
, 5
)
6279void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6281 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6282 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6283 if (!horizontalMode && !verticalMode) {
6284 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6289 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6291 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6295void QQuickTableView::moveColumn(
int source,
int destination)
6297 Q_D(QQuickTableView);
6298 d->moveSection(source, destination, Qt::Horizontal);
6301void QQuickTableView::moveRow(
int source,
int destination)
6303 Q_D(QQuickTableView);
6304 d->moveSection(source, destination, Qt::Vertical);
6307void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientations orientation)
6309 Q_Q(QQuickTableView);
6311 if (source < 0 || destination < 0 ||
6312 (orientation == Qt::Horizontal &&
6313 (source >= tableSize.width() || destination >= tableSize.width())) ||
6314 (orientation == Qt::Vertical &&
6315 (source >= tableSize.height() || destination >= tableSize.height())))
6318 if (source == destination)
6321 if (m_sectionState != SectionState::Moving) {
6322 m_sectionState = SectionState::Moving;
6324 syncView->d_func()->moveSection(source, destination, orientation);
6327 initializeIndexMapping();
6330 SectionData *visualIndex =
nullptr;
6331 SectionData *logicalIndex =
nullptr;
6333 if (orientation == Qt::Horizontal) {
6334 visualIndex = visualIndices[0].data();
6335 logicalIndex = logicalIndices[0].data();
6336 }
else if (orientation == Qt::Vertical) {
6337 visualIndex = visualIndices[1].data();
6338 logicalIndex = logicalIndices[1].data();
6341 const int logical = logicalIndex[source].index;
6342 int visual = source;
6344 if (destination > source) {
6345 while (visual < destination) {
6346 SectionData &visualData = visualIndex[logicalIndex[visual + 1].index];
6347 SectionData &logicalData = logicalIndex[visual];
6348 visualData.prevIndex = visualData.index;
6349 visualData.index = visual;
6350 logicalData.prevIndex = logicalData.index;
6351 logicalData.index = logicalIndex[visual + 1].index;
6355 while (visual > destination) {
6356 SectionData &visualData = visualIndex[logicalIndex[visual - 1].index];
6357 SectionData &logicalData = logicalIndex[visual];
6358 visualData.prevIndex = visualData.index;
6359 visualData.index = visual;
6360 logicalData.prevIndex = logicalData.index;
6361 logicalData.index = logicalIndex[visual - 1].index;
6366 visualIndex[logical].prevIndex = visualIndex[logical].index;
6367 visualIndex[logical].index = destination;
6368 logicalIndex[destination].prevIndex = logicalIndex[destination].index;
6369 logicalIndex[destination].index = logical;
6373 for (
auto syncChild : std::as_const(syncChildren)) {
6374 auto syncChild_d = syncChild->d_func();
6375 if (syncChild_d->m_sectionState != SectionState::Moving &&
6376 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6377 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6378 syncChild_d->moveSection(source, destination, orientation);
6383 scheduleRebuildTable(RebuildOption::ViewportOnly);
6384 m_sectionState = SectionState::Idle;
6387 const int startIndex = (source > destination) ? destination : source;
6388 const int endIndex = (source > destination) ? source : destination;
6389 const int mapIndex =
static_cast<
int>(orientation) - 1;
6390 for (
int index = startIndex; index <= endIndex; index++) {
6391 const SectionData *logicalDataIndices = (syncView ? syncView->d_func()->logicalIndices[mapIndex].constData() : logicalIndices[mapIndex].constData());
6392 const SectionData *visualDataIndices = syncView ? syncView->d_func()->visualIndices[mapIndex].constData() : visualIndices[mapIndex].constData();
6393 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6394 if (orientation == Qt::Horizontal)
6395 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6397 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6402void QQuickTableView::clearColumnReordering()
6404 Q_D(QQuickTableView);
6405 d->clearSection(Qt::Horizontal);
6408void QQuickTableView::clearRowReordering()
6410 Q_D(QQuickTableView);
6411 d->clearSection(Qt::Vertical);
6414void QQuickTableViewPrivate::clearSection(Qt::Orientations orientation)
6416 Q_Q(QQuickTableView);
6418 const int mapIndex =
static_cast<
int>(orientation) - 1;
6419 const QList<SectionData> oldLogicalIndices = syncView ? syncView->d_func()->logicalIndices[mapIndex] : logicalIndices[mapIndex];
6420 const QList<SectionData> oldVisualIndices = syncView ? syncView->d_func()->visualIndices[mapIndex] : visualIndices[mapIndex];;
6423 syncView->d_func()->clearSection(orientation);
6426 logicalIndices[mapIndex].clear();
6427 visualIndices[mapIndex].clear();
6428 scheduleRebuildTable(RebuildOption::ViewportOnly);
6432 for (
int index = 0; index < oldLogicalIndices.size(); index++) {
6433 const SectionData *logicalDataIndices = oldLogicalIndices.constData();
6434 const SectionData *visualDataIndices = oldVisualIndices.constData();
6435 if (logicalDataIndices[index].index != index) {
6436 const int currentIndex = logicalDataIndices[index].index;
6437 if (orientation == Qt::Horizontal)
6438 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6440 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6445void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6447 if (!modelIndex.isValid())
6450 const int cellIndex = modelIndexToCellIndex(modelIndex);
6451 if (!loadedItems.contains(cellIndex))
6453 const QPoint cell = cellAtModelIndex(cellIndex);
6454 QQuickItem *item = loadedTableItem(cell)->item;
6455 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6458QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6460 Q_D(
const QQuickTableView);
6461 const int modelIndex = d->modelIndexAtCell(cell);
6462 if (!d->loadedItems.contains(modelIndex))
6464 return d->loadedItems.value(modelIndex)->item;
6467#if QT_DEPRECATED_SINCE(6
, 5
)
6468QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6470 return itemAtCell(QPoint(column, row));
6474QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6476 Q_D(
const QQuickTableView);
6477 const int serializedIndex = d->modelIndexToCellIndex(index);
6478 if (!d->loadedItems.contains(serializedIndex))
6480 return d->loadedItems.value(serializedIndex)->item;
6483#if QT_DEPRECATED_SINCE(6
, 4
)
6484QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6486 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6489QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6491 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6495QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6497 return cellAtPosition(QPoint(x, y), includeSpacing);
6500QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6502 Q_D(
const QQuickTableView);
6504 if (!d->loadedTableOuterRect.contains(position))
6505 return QPoint(-1, -1);
6507 const qreal hSpace = d->cellSpacing.width();
6508 const qreal vSpace = d->cellSpacing.height();
6509 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6510 qreal currentRowEnd = d->loadedTableOuterRect.y();
6512 int foundColumn = -1;
6515 for (
const int column : d->loadedColumns) {
6516 currentColumnEnd += d->getEffectiveColumnWidth(column);
6517 if (position.x() < currentColumnEnd) {
6518 foundColumn = column;
6521 currentColumnEnd += hSpace;
6522 if (!includeSpacing && position.x() < currentColumnEnd) {
6524 return QPoint(-1, -1);
6525 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6526 foundColumn = column;
6531 for (
const int row : d->loadedRows) {
6532 currentRowEnd += d->getEffectiveRowHeight(row);
6533 if (position.y() < currentRowEnd) {
6537 currentRowEnd += vSpace;
6538 if (!includeSpacing && position.y() < currentRowEnd) {
6540 return QPoint(-1, -1);
6542 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6548 return QPoint(foundColumn, foundRow);
6551bool QQuickTableView::isColumnLoaded(
int column)
const
6553 Q_D(
const QQuickTableView);
6554 if (!d->loadedColumns.contains(column))
6557 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6560 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6567bool QQuickTableView::isRowLoaded(
int row)
const
6569 Q_D(
const QQuickTableView);
6570 if (!d->loadedRows.contains(row))
6573 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6576 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6583qreal QQuickTableView::columnWidth(
int column)
const
6585 Q_D(
const QQuickTableView);
6586 if (!isColumnLoaded(column))
6589 return d->getEffectiveColumnWidth(column);
6592qreal QQuickTableView::rowHeight(
int row)
const
6594 Q_D(
const QQuickTableView);
6595 if (!isRowLoaded(row))
6598 return d->getEffectiveRowHeight(row);
6601qreal QQuickTableView::implicitColumnWidth(
int column)
const
6603 Q_D(
const QQuickTableView);
6604 if (!isColumnLoaded(column))
6607 return d->sizeHintForColumn(column);
6610qreal QQuickTableView::implicitRowHeight(
int row)
const
6612 Q_D(
const QQuickTableView);
6613 if (!isRowLoaded(row))
6616 return d->sizeHintForRow(row);
6619void QQuickTableView::setColumnWidth(
int column, qreal size)
6621 Q_D(QQuickTableView);
6623 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6627 if (d->syncHorizontally) {
6628 d->syncView->setColumnWidth(column, size);
6632 if (qFuzzyCompare(explicitColumnWidth(column), size))
6636 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6638 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6640 if (d->loadedItems.isEmpty())
6643 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6644 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6645 d->forceLayout(
false);
6648void QQuickTableView::clearColumnWidths()
6650 Q_D(QQuickTableView);
6652 if (d->syncHorizontally) {
6653 d->syncView->clearColumnWidths();
6657 if (d->explicitColumnWidths.isEmpty())
6660 d->explicitColumnWidths.clear();
6661 d->forceLayout(
false);
6664qreal QQuickTableView::explicitColumnWidth(
int column)
const
6666 Q_D(
const QQuickTableView);
6668 if (d->syncHorizontally)
6669 return d->syncView->explicitColumnWidth(column);
6671 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6672 if (it != d->explicitColumnWidths.constEnd())
6677void QQuickTableView::setRowHeight(
int row, qreal size)
6679 Q_D(QQuickTableView);
6681 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
6685 if (d->syncVertically) {
6686 d->syncView->setRowHeight(row, size);
6690 if (qFuzzyCompare(explicitRowHeight(row), size))
6694 d->explicitRowHeights.remove(d->logicalRowIndex(row));
6696 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
6698 if (d->loadedItems.isEmpty())
6701 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
6702 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
6703 d->forceLayout(
false);
6706void QQuickTableView::clearRowHeights()
6708 Q_D(QQuickTableView);
6710 if (d->syncVertically) {
6711 d->syncView->clearRowHeights();
6715 if (d->explicitRowHeights.isEmpty())
6718 d->explicitRowHeights.clear();
6719 d->forceLayout(
false);
6722qreal QQuickTableView::explicitRowHeight(
int row)
const
6724 Q_D(
const QQuickTableView);
6726 if (d->syncVertically)
6727 return d->syncView->explicitRowHeight(row);
6729 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
6730 if (it != d->explicitRowHeights.constEnd())
6735QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
6737 Q_D(
const QQuickTableView);
6738 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
6741 auto const qaim = d->model->abstractItemModel();
6745 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
6748QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
6750 if (!index.isValid() || index.parent().isValid())
6752 Q_D(
const QQuickTableView);
6753 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
6756#if QT_DEPRECATED_SINCE(6
, 4
)
6757QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
6759 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
6765 return modelIndex({row, column});
6767 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
6768 "Use index(row, column) instead. For more information, see "
6769 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
6770 return modelIndex({column, row});
6775QModelIndex QQuickTableView::index(
int row,
int column)
const
6777 return modelIndex({column, row});
6780int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
6782 return cellAtIndex(index).y();
6785int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
6787 return cellAtIndex(index).x();
6790void QQuickTableView::forceLayout()
6792 d_func()->forceLayout(
true);
6795void QQuickTableView::edit(
const QModelIndex &index)
6797 Q_D(QQuickTableView);
6799 if (!d->canEdit(index,
true))
6802 if (d->editIndex == index)
6808 if (!d->editModel) {
6809 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
6810 d->editModel->useImportVersion(d->resolveImportVersion());
6811 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
6812 [
this, d] (
int serializedModelIndex, QObject *object) {
6818 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
6819 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
6820 d->editItem = qmlobject_cast<QQuickItem*>(object);
6824 d->initItemCallback(serializedModelIndex, object);
6825 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
6827 d->editItem->setParentItem(cellItem);
6834 if (d->selectionModel)
6835 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
6838 d->closeEditorAndCommit();
6840 const auto cellItem = itemAtCell(cellAtIndex(index));
6842 const auto attached = d->getAttachedObject(cellItem);
6845 d->editModel->setModel(d->tableModel->model());
6846 d->editModel->setDelegate(attached->editDelegate());
6848 const int cellIndex = d->getEditCellIndex(index);
6849 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
6851 d->editIndex = QModelIndex();
6852 d->editItem =
nullptr;
6853 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
6860 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
6861 d->editItem =
nullptr;
6862 d->editIndex = QModelIndex();
6863 d->editModel->release(object, QQmlInstanceModel::NotReusable);
6869 d->model->object(cellIndex, QQmlIncubator::Synchronous);
6872 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
6875 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
6876 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
6879void QQuickTableView::closeEditor()
6881 Q_D(QQuickTableView);
6886 QQuickItem *cellItem = d->editItem->parentItem();
6887 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
6888 d->editItem =
nullptr;
6891 const int cellIndex = d->getEditCellIndex(d->editIndex);
6892 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
6894 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
6896 if (d->editIndex.isValid()) {
6899 d->editIndex = QModelIndex();
6903QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
6905 return new QQuickTableViewAttached(obj);
6908void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
6910 Q_D(QQuickTableView);
6911 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
6913 if (d->tableModel) {
6916 d->tableModel->drainReusableItemsPool(0);
6919 d->forceLayout(
false);
6922void QQuickTableView::viewportMoved(Qt::Orientations orientation)
6924 Q_D(QQuickTableView);
6930 QQuickFlickable::viewportMoved(orientation);
6931 if (d->inSetLocalViewportPos)
6938 d->syncViewportPosRecursive();
6940 auto rootView = d->rootSyncView();
6941 auto rootView_d = rootView->d_func();
6943 rootView_d->scheduleRebuildIfFastFlick();
6945 if (!rootView_d->polishScheduled) {
6946 if (rootView_d->scheduledRebuildOptions) {
6953 const bool updated = rootView->d_func()->updateTableRecursive();
6963void QQuickTableView::keyPressEvent(QKeyEvent *e)
6965 Q_D(QQuickTableView);
6967 if (!d->keyNavigationEnabled) {
6968 QQuickFlickable::keyPressEvent(e);
6972 if (d->tableSize.isEmpty())
6975 if (d->editIndex.isValid()) {
6981 if (d->setCurrentIndexFromKeyEvent(e))
6984 if (d->editFromKeyEvent(e))
6987 QQuickFlickable::keyPressEvent(e);
6990bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
6992 Q_D(QQuickTableView);
6994 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
6997 return QQuickFlickable::eventFilter(obj, event);
7000 switch (event->type()) {
7001 case QEvent::KeyPress: {
7002 Q_ASSERT(d->editItem);
7003 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7004 switch (keyEvent->key()) {
7006 case Qt::Key_Return:
7007 d->closeEditorAndCommit();
7010 case Qt::Key_Backtab:
7011 if (activeFocusOnTab()) {
7012 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7013 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7014 if (d->canEdit(currentIndex,
false))
7020 case Qt::Key_Escape:
7025 case QEvent::FocusOut:
7028 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7029 d->closeEditorAndCommit();
7035 return QQuickFlickable::eventFilter(obj, event);
7038bool QQuickTableView::alternatingRows()
const
7040 return d_func()->alternatingRows;
7043void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7045 Q_D(QQuickTableView);
7046 if (d->alternatingRows == alternatingRows)
7049 d->alternatingRows = alternatingRows;
7050 emit alternatingRowsChanged();
7053QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7055 return d_func()->selectionBehavior;
7058void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7060 Q_D(QQuickTableView);
7061 if (d->selectionBehavior == selectionBehavior)
7064 d->selectionBehavior = selectionBehavior;
7065 emit selectionBehaviorChanged();
7068QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7070 return d_func()->selectionMode;
7073void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7075 Q_D(QQuickTableView);
7076 if (d->selectionMode == selectionMode)
7079 d->selectionMode = selectionMode;
7080 emit selectionModeChanged();
7083bool QQuickTableView::resizableColumns()
const
7085 return d_func()->resizableColumns;
7088void QQuickTableView::setResizableColumns(
bool enabled)
7090 Q_D(QQuickTableView);
7091 if (d->resizableColumns == enabled)
7094 d->resizableColumns = enabled;
7095 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7096 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7098 emit resizableColumnsChanged();
7101bool QQuickTableView::resizableRows()
const
7103 return d_func()->resizableRows;
7106void QQuickTableView::setResizableRows(
bool enabled)
7108 Q_D(QQuickTableView);
7109 if (d->resizableRows == enabled)
7112 d->resizableRows = enabled;
7113 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7114 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7116 emit resizableRowsChanged();
7121 : QQuickHoverHandler(view->contentItem())
7125 connect(
this, &QQuickHoverHandler::hoveredChanged, [
this] {
7126 if (!isHoveringGrid())
7130#if QT_CONFIG(cursor)
7131 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7132 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7133 tableViewPrivate->updateCursor();
7140 QQuickHoverHandler::handleEventPoint(event, point);
7142 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7143#if QT_CONFIG(cursor)
7144 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7147 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7148 const auto item = tableView->itemAtCell(cell);
7152#if QT_CONFIG(cursor)
7153 tableViewPrivate->updateCursor();
7158 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7159 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7160 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7161 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7162 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7163#if QT_CONFIG(cursor)
7164 tableViewPrivate->updateCursor();
7175 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7180 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7184 if (event->type() == QEvent::Type::Wheel)
7189 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7190 return !tableView->isMoving();
7199 setObjectName(
"tableViewResizeHandler");
7203 , QPointingDevice::GrabTransition transition
7205 , QEventPoint &point)
7207 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7209 switch (transition) {
7210 case QPointingDevice::GrabPassive:
7211 case QPointingDevice::GrabExclusive:
7213 case QPointingDevice::UngrabPassive:
7214 case QPointingDevice::UngrabExclusive:
7215 case QPointingDevice::CancelGrabPassive:
7216 case QPointingDevice::CancelGrabExclusive:
7217 case QPointingDevice::OverrideGrabPassive:
7218 if (m_state == DraggingStarted || m_state == Dragging) {
7219 m_state = DraggingFinished;
7220 updateDrag(ev, point);
7228 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7229 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7230 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7237 updateDrag(event, point);
7242 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7243 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7245 if (m_state == DraggingFinished)
7246 m_state = Listening;
7248 if (point.state() == QEventPoint::Pressed) {
7249 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7250 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7251 if (m_row != -1 || m_column != -1)
7253 }
else if (point.state() == QEventPoint::Released) {
7254 if (m_state == DraggingStarted || m_state == Dragging)
7255 m_state = DraggingFinished;
7257 m_state = Listening;
7258 }
else if (point.state() == QEventPoint::Updated) {
7263 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7264 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7265 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7266 if (dragDist > qApp->styleHints()->startDragDistance())
7267 m_state = DraggingStarted;
7269 case DraggingStarted:
7274 case DraggingFinished:
7284 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7285#if QT_CONFIG(cursor)
7286 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7293 setPassiveGrab(event, point,
true);
7297 tableView->setFiltersChildMouseEvents(
false);
7298 tableViewPrivate->setActivePointerHandler(
this);
7300 case DraggingStarted:
7301 setExclusiveGrab(event, point,
true);
7302 m_columnStartX = point.position().x();
7303 m_columnStartWidth = tableView->columnWidth(m_column);
7304 m_rowStartY = point.position().y();
7305 m_rowStartHeight = tableView->rowHeight(m_row);
7306#if QT_CONFIG(cursor)
7307 tableViewPrivate->updateCursor();
7311 const qreal distX = point.position().x() - m_columnStartX;
7312 const qreal distY = point.position().y() - m_rowStartY;
7314 tableView->setColumnWidth(m_column, qMax(0.001, m_columnStartWidth + distX));
7316 tableView->setRowHeight(m_row, qMax(0.001, m_rowStartHeight + distY));
7318 case DraggingFinished: {
7319 tableView->setFiltersChildMouseEvents(
true);
7320 tableViewPrivate->setActivePointerHandler(
nullptr);
7321#if QT_CONFIG(cursor)
7322 tableViewPrivate->updateCursor();
7329#if QT_CONFIG(quick_draganddrop)
7331QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7332 : QQuickTableViewPointerHandler(view)
7334 setObjectName(
"tableViewDragHandler");
7337QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7342void QQuickTableViewSectionDragHandler::resetDragData()
7344 if (m_state != Listening) {
7345 m_state = Listening;
7346 resetSectionOverlay();
7349 if (m_grabResult.data())
7350 m_grabResult.data()->disconnect();
7351 if (!m_drag.isNull()) {
7352 m_drag->disconnect();
7355 if (!m_dropArea.isNull()) {
7356 m_dropArea->disconnect();
7359 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7360 tableView->setFiltersChildMouseEvents(
true);
7364void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7366 if (m_destination != -1) {
7367 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7368 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7369 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7370 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7371 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7376void QQuickTableViewSectionDragHandler::grabSection()
7379 QPixmap pixmap(m_grabResult->image().size());
7380 pixmap.fill(Qt::transparent);
7381 QPainter painter(&pixmap);
7382 painter.setOpacity(0.6);
7383 painter.drawImage(0, 0, m_grabResult->image());
7387 auto *mimeData =
new QMimeData();
7388 mimeData->setImageData(pixmap);
7389 m_drag->setMimeData(mimeData);
7390 m_drag->setPixmap(pixmap);
7393void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7397 if (m_state == Dragging) {
7398 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7399 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7400 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7401 m_state = DraggingFinished;
7402 resetSectionOverlay();
7403 if (m_scrollTimer.isActive())
7404 m_scrollTimer.stop();
7409void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7413 if (m_state == Dragging) {
7414 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7415 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7416 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7417 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7419 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7420 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7421 if (newDestination != m_destination) {
7423 resetSectionOverlay();
7425 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7426 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7427 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7428 m_destination = newDestination;
7432 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7433 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7434 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7435 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7436 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7437 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7438 if (useStartPos || useEndPos) {
7439 if (!m_scrollTimer.isActive()) {
7440 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7441 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7442 m_scrollTimer.start(1);
7445 if (m_scrollTimer.isActive())
7446 m_scrollTimer.stop();
7451void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7455 if (action == Qt::IgnoreAction) {
7456 resetSectionOverlay();
7457 if (m_scrollTimer.isActive())
7458 m_scrollTimer.stop();
7462void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7464 QQuickSinglePointHandler::handleEventPoint(event, point);
7466 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7467 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7468 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7469 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7472 if (m_state == DraggingFinished) {
7473 if (m_scrollTimer.isActive())
7474 m_scrollTimer.stop();
7478 if (point.state() == QEventPoint::Pressed) {
7482 setPassiveGrab(event, point,
true);
7486 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7487 tableView->setFiltersChildMouseEvents(
false);
7489 }
else if (point.state() == QEventPoint::Released) {
7491 if (m_scrollTimer.isActive())
7492 m_scrollTimer.stop();
7494 }
else if (point.state() == QEventPoint::Updated) {
7496 const qreal distX = point.position().x() - point.pressPosition().x();
7497 const qreal distY = point.position().y() - point.pressPosition().y();
7498 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7499 if (dragDist > qApp->styleHints()->startDragDistance()) {
7503 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7504 auto *item = tableView->itemAtCell(cell);
7507 if (m_drag.isNull()) {
7508 m_drag =
new QDrag(item);
7509 connect(m_drag.data(), &QDrag::actionChanged,
this,
7510 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7513 QObject::connect(&m_scrollTimer, &QTimer::timeout, [&]{
7514 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7515 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7516 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7517 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7520 if (m_dropArea.isNull()) {
7521 m_dropArea =
new QQuickDropArea(tableView);
7522 m_dropArea->setSize(tableView->size());
7523 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7524 &QQuickTableViewSectionDragHandler::handleDrag);
7525 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7526 &QQuickTableViewSectionDragHandler::handleDrop);
7529 m_grabResult = item->grabToImage();
7530 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7531 &QQuickTableViewSectionDragHandler::grabSection);
7533 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7534 m_state = DraggingStarted;
7536 tableViewPrivate->setActivePointerHandler(
this);
7540 case DraggingStarted: {
7541 if (m_drag && m_drag->mimeData()) {
7542 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7544 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7546 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7550 if (m_state == Dragging)
7553 tableViewPrivate->setActivePointerHandler(
nullptr);
7567void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7569 if (!sectionDragHandler) {
7570 Q_Q(QQuickTableView);
7571 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7572 sectionDragHandler->setSectionOrientation(orientation);
7576void QQuickTableViewPrivate::destroySectionDragHandler()
7578 if (sectionDragHandler) {
7579 delete sectionDragHandler;
7580 sectionDragHandler =
nullptr;
7585void QQuickTableViewPrivate::initializeIndexMapping()
7587 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7588 visualIndex.resize(size);
7589 logicalIndex.resize(size);
7590 for (
int index = 0; index < size; ++index)
7591 visualIndex[index].index = logicalIndex[index].index = index;
7594 if (visualIndices[0].size() != tableSize.width()
7595 || logicalIndices[0].size() != tableSize.width())
7596 initIndices(visualIndices[0], logicalIndices[0], tableSize.width());
7598 if (visualIndices[1].size() != tableSize.height()
7599 || logicalIndices[1].size() != tableSize.height())
7600 initIndices(visualIndices[1], logicalIndices[1], tableSize.height());
7603void QQuickTableViewPrivate::clearIndexMapping()
7605 logicalIndices[0].clear();
7606 visualIndices[0].clear();
7608 logicalIndices[1].clear();
7609 visualIndices[1].clear();
7612int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7615 return syncView->d_func()->logicalRowIndex(visualIndex);
7616 if (logicalIndices[1].isEmpty() || visualIndex < 0)
7618 return logicalIndices[1].constData()[visualIndex].index;
7621int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7624 return syncView->d_func()->logicalColumnIndex(visualIndex);
7625 if (logicalIndices[0].isEmpty() || visualIndex < 0)
7627 return logicalIndices[0].constData()[visualIndex].index;
7630int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7633 return syncView->d_func()->visualRowIndex(logicalIndex);
7634 if (visualIndices[1].isEmpty() || logicalIndex < 0)
7635 return logicalIndex;
7636 return visualIndices[1].constData()[logicalIndex].index;
7639int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7642 return syncView->d_func()->visualColumnIndex(logicalIndex);
7643 if (visualIndices[0].isEmpty() || logicalIndex < 0)
7644 return logicalIndex;
7645 return visualIndices[0].constData()[logicalIndex].index;
7648int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7652 const bool hasProxyModel = (modelImpl() != assignedModel);
7653 return modelIndexToCellIndex(index, hasProxyModel);
7659 : QQuickTapHandler(view->contentItem())
7661 setObjectName(
"tableViewTapHandler");
7666 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7667 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7668 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
7673#include "moc_qquicktableview_p.cpp"
7674#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