8#include <QtCore/qdir.h>
9#include <QtCore/qmimedata.h>
10#include <QtCore/qtimer.h>
11#include <QtQml/private/qqmlincubator_p.h>
12#include <QtQml/qqmlinfo.h>
13#include <QtQmlModels/private/qqmlchangeset_p.h>
14#include <QtQmlModels/private/qqmldelegatecomponent_p.h>
15#include <QtQmlModels/private/qqmldelegatemodel_p.h>
16#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
17#include <QtQuick/qquickitemgrabresult.h>
19#include <QtQuick/private/qquickflickable_p_p.h>
20#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
21#include <QtQuick/private/qquicktaphandler_p.h>
23#include <QtCore/qtyperevision.h>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
387
388
389
390
391
392
393
394
395
396
399
400
401
402
403
404
405
406
407
408
409
410
413
414
415
416
417
418
421
422
423
424
425
426
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
477
478
479
480
481
482
483
484
485
486
487
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
543
544
545
546
547
548
549
550
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
627
628
629
630
631
632
635
636
637
638
639
640
643
644
645
646
647
648
651
652
653
654
655
656
659
660
661
662
663
664
665
666
667
668
669
672
673
674
675
676
677
678
679
680
681
682
685
686
687
688
689
690
691
692
693
694
695
696
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
720
721
722
723
724
725
726
727
728
729
730
731
732
735
736
737
738
739
740
741
742
743
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
793
794
795
796
797
798
801
802
803
804
805
806
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
925
926
927
928
929
930
931
932
933
934
935
936
939
940
941
942
943
944
945
946
947
948
949
950
951
954
955
956
957
958
959
960
961
962
963
964
965
966
969
970
971
972
973
976
977
978
979
980
981
982
983
984
985
988
989
990
991
992
993
994
995
996
997
1000
1001
1002
1003
1004
1005
1006
1007
1008
1011
1012
1013
1014
1015
1016
1017
1018
1021
1022
1023
1024
1025
1026
1027
1028
1029
1032
1033
1034
1035
1036
1037
1038
1039
1042
1043
1044
1045
1046
1047
1048
1049
1050
1053
1054
1055
1056
1057
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1078
1079
1080
1081
1082
1085
1086
1087
1088
1089
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1111
1112
1113
1114
1117
1118
1119
1120
1121
1122
1123
1124
1127
1128
1129
1130
1131
1132
1133
1134
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1209
1210
1211
1212
1213
1214
1215
1216
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1281
1282
1283
1284
1285
1286
1287
1288
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1353
1354
1355
1356
1357
1358
1359
1362
1363
1364
1365
1366
1367
1368
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1407
1408
1409
1410
1411
1412
1413
1414
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1433
1434
1435
1436
1437
1438
1439
1442
1443
1444
1445
1446
1447
1448
1451
1452
1453
1454
1455
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1573QQuickSelectable::~QQuickSelectable() { }
1577#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
1578#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
1591#define TV_REBUILDSTATE(STATE)
1592 case QQuickTableViewPrivate::RebuildState::STATE:
1593 dbg << QStringLiteral(#STATE); break;
1613#define TV_REBUILDOPTION(OPTION)
1614 if (options & QQuickTableViewPrivate::RebuildOption::OPTION)
1615 dbg << QStringLiteral(#OPTION)
1617 if (options == QQuickTableViewPrivate::RebuildOption::None) {
1618 dbg << QStringLiteral(
"None");
1634QQuickTableViewPrivate::EdgeRange::EdgeRange()
1635 : startIndex(kEdgeIndexNotSet)
1636 , endIndex(kEdgeIndexNotSet)
1640bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge,
int index)
1642 if (startIndex == kEdgeIndexNotSet)
1645 if (endIndex == kEdgeIndexAtEnd) {
1649 return index <= startIndex;
1651 case Qt::BottomEdge:
1652 return index >= startIndex;
1656 const int s = std::min(startIndex, endIndex);
1657 const int e = std::max(startIndex, endIndex);
1658 return index >= s && index <= e;
1661QQuickTableViewPrivate::QQuickTableViewPrivate()
1662 : QQuickFlickablePrivate()
1666QQuickTableViewPrivate::~QQuickTableViewPrivate()
1669 QQuickItem *cellItem = editItem->parentItem();
1671 editModel->dispose(editItem);
1672 tableModel->release(cellItem, QQmlInstanceModel::NotReusable);
1678 for (
auto *fxTableItem : loadedItems) {
1679 if (
auto item = fxTableItem->item) {
1680 if (fxTableItem->ownItem)
1682 else if (tableModel)
1683 tableModel->dispose(item);
1692QString QQuickTableViewPrivate::tableLayoutToString()
const
1694 if (loadedItems.isEmpty())
1695 return QLatin1String(
"table is empty!");
1696 return QString(QLatin1String(
"table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
1697 .arg(leftColumn()).arg(topRow())
1698 .arg(rightColumn()).arg(bottomRow())
1699 .arg(loadedItems.size())
1700 .arg(loadedTableOuterRect.x())
1701 .arg(loadedTableOuterRect.y())
1702 .arg(loadedTableOuterRect.width())
1703 .arg(loadedTableOuterRect.height());
1706void QQuickTableViewPrivate::dumpTable()
const
1708 auto listCopy = loadedItems.values();
1709 std::stable_sort(listCopy.begin(), listCopy.end(),
1710 [](
const FxTableItem *lhs,
const FxTableItem *rhs)
1711 {
return lhs->index < rhs->index; });
1713 qWarning() << QStringLiteral(
"******* TABLE DUMP *******");
1714 for (
int i = 0; i < listCopy.size(); ++i)
1715 qWarning() <<
static_cast<FxTableItem *>(listCopy.at(i))->cell;
1716 qWarning() << tableLayoutToString();
1718 const QString filename = QStringLiteral(
"QQuickTableView_dumptable_capture.png");
1719 const QString path = QDir::current().absoluteFilePath(filename);
1720 if (q_func()->window() && q_func()->window()->grabWindow().save(path))
1721 qWarning() <<
"Window capture saved to:" << path;
1724void QQuickTableViewPrivate::setRequiredProperty(
const char *property,
1725 const QVariant &value,
int serializedModelIndex, QObject *object,
bool init)
1727 Q_Q(QQuickTableView);
1729 QQmlTableInstanceModel *tableInstanceModel = qobject_cast<QQmlTableInstanceModel *>(model);
1730 if (!tableInstanceModel) {
1740 const QString propertyName = QString::fromUtf8(property);
1743 bool wasRequired =
false;
1744 if (object == editItem) {
1747 wasRequired = editModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1749 wasRequired = tableInstanceModel->setRequiredProperty(serializedModelIndex, propertyName, value);
1752 QStringList propertyList = object->property(kRequiredProperties).toStringList();
1753 object->setProperty(kRequiredProperties, propertyList << propertyName);
1757 const QStringList propertyList = object->property(kRequiredProperties).toStringList();
1758 if (propertyList.contains(propertyName)) {
1759 const auto metaObject = object->metaObject();
1760 const int propertyIndex = metaObject->indexOfProperty(property);
1761 const auto metaProperty = metaObject->property(propertyIndex);
1762 metaProperty.write(object, value);
1772 const QModelIndex modelIndex = q->modelIndex(cellAtModelIndex(serializedModelIndex));
1773 if (modelIndex == editIndex) {
1774 const QStringList propertyList = editItem->property(kRequiredProperties).toStringList();
1775 if (propertyList.contains(propertyName)) {
1776 const auto metaObject = editItem->metaObject();
1777 const int propertyIndex = metaObject->indexOfProperty(property);
1778 const auto metaProperty = metaObject->property(propertyIndex);
1779 metaProperty.write(editItem, value);
1787QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget()
const
1789 return const_cast<QQuickTableView *>(q_func())->contentItem();
1792bool QQuickTableViewPrivate::hasSelection()
const
1794 return selectionModel && selectionModel->hasSelection();
1797bool QQuickTableViewPrivate::startSelection(
const QPointF &pos, Qt::KeyboardModifiers modifiers)
1799 Q_Q(QQuickTableView);
1800 if (!selectionModel) {
1801 if (warnNoSelectionModel)
1802 qmlWarning(q_func()) <<
"Cannot start selection: no SelectionModel assigned!";
1803 warnNoSelectionModel =
false;
1807 if (selectionBehavior == QQuickTableView::SelectionDisabled) {
1808 qmlWarning(q) <<
"Cannot start selection: TableView.selectionBehavior == TableView.SelectionDisabled";
1813 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
1819 if (selectionMode == QQuickTableView::SingleSelection
1820 || selectionMode == QQuickTableView::ContiguousSelection
1821 || modifiers == Qt::NoModifier)
1823 else if (selectionModel)
1824 existingSelection = selectionModel->selection();
1830 selectionFlag = QItemSelectionModel::Select;
1831 if (modifiers & Qt::ControlModifier) {
1832 QPoint startCell = clampedCellAtPos(pos);
1833 if (!cellIsValid(startCell))
1835 const QModelIndex startIndex = q->index(startCell.y(), startCell.x());
1836 if (selectionModel->isSelected(startIndex))
1837 selectionFlag = QItemSelectionModel::Deselect;
1840 selectionStartCell = QPoint(-1, -1);
1841 selectionEndCell = QPoint(-1, -1);
1842 closeEditorAndCommit();
1846void QQuickTableViewPrivate::setSelectionStartPos(
const QPointF &pos)
1848 Q_Q(QQuickTableView);
1849 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1850 if (loadedItems.isEmpty())
1852 if (!selectionModel) {
1853 if (warnNoSelectionModel)
1854 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1855 warnNoSelectionModel =
false;
1858 const QAbstractItemModel *qaim = selectionModel->model();
1862 if (selectionMode == QQuickTableView::SingleSelection
1863 && cellIsValid(selectionStartCell)) {
1867 const QRect prevSelection = selection();
1870 if (pos.x() == -1) {
1872 clampedCell = q->cellAtIndex(selectionModel->currentIndex());
1874 clampedCell = clampedCellAtPos(pos);
1875 if (cellIsValid(clampedCell))
1876 setCurrentIndex(clampedCell);
1879 if (!cellIsValid(clampedCell))
1882 switch (selectionBehavior) {
1883 case QQuickTableView::SelectCells:
1884 selectionStartCell = clampedCell;
1886 case QQuickTableView::SelectRows:
1887 selectionStartCell = QPoint(0, clampedCell.y());
1889 case QQuickTableView::SelectColumns:
1890 selectionStartCell = QPoint(clampedCell.x(), 0);
1892 case QQuickTableView::SelectionDisabled:
1896 if (!cellIsValid(selectionEndCell))
1900 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1901 updateSelection(prevSelection, selection());
1904void QQuickTableViewPrivate::setSelectionEndPos(
const QPointF &pos)
1906 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1907 if (loadedItems.isEmpty())
1909 if (!selectionModel) {
1910 if (warnNoSelectionModel)
1911 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1912 warnNoSelectionModel =
false;
1915 const QAbstractItemModel *qaim = selectionModel->model();
1919 const QRect prevSelection = selection();
1922 if (selectionMode == QQuickTableView::SingleSelection) {
1923 clampedCell = selectionStartCell;
1925 clampedCell = clampedCellAtPos(pos);
1926 if (!cellIsValid(clampedCell))
1930 setCurrentIndex(clampedCell);
1932 switch (selectionBehavior) {
1933 case QQuickTableView::SelectCells:
1934 selectionEndCell = clampedCell;
1936 case QQuickTableView::SelectRows:
1937 selectionEndCell = QPoint(tableSize.width() - 1, clampedCell.y());
1939 case QQuickTableView::SelectColumns:
1940 selectionEndCell = QPoint(clampedCell.x(), tableSize.height() - 1);
1942 case QQuickTableView::SelectionDisabled:
1946 if (!cellIsValid(selectionStartCell))
1950 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1951 updateSelection(prevSelection, selection());
1954QPoint QQuickTableViewPrivate::clampedCellAtPos(
const QPointF &pos)
const
1956 Q_Q(
const QQuickTableView);
1959 QPoint cell = q->cellAtPosition(pos,
true);
1960 if (cellIsValid(cell))
1963 if (loadedTableOuterRect.width() == 0 || loadedTableOuterRect.height() == 0)
1964 return QPoint(-1, -1);
1968 qBound(loadedTableOuterRect.x(), pos.x(), loadedTableOuterRect.right() - 1),
1969 qBound(loadedTableOuterRect.y(), pos.y(), loadedTableOuterRect.bottom() - 1));
1970 QPointF clampedPosInView = q->mapFromItem(selectionPointerHandlerTarget(), clampedPos);
1971 clampedPosInView.rx() = qBound(0., clampedPosInView.x(), viewportRect.width());
1972 clampedPosInView.ry() = qBound(0., clampedPosInView.y(), viewportRect.height());
1973 clampedPos = q->mapToItem(selectionPointerHandlerTarget(), clampedPosInView);
1975 return q->cellAtPosition(clampedPos,
true);
1978void QQuickTableViewPrivate::updateSelection(
const QRect &oldSelection,
const QRect &newSelection)
1980 if (oldSelection == newSelection)
1983 const QAbstractItemModel *qaim = selectionModel->model();
1984 const QRect oldRect = oldSelection.normalized();
1985 const QRect newRect = newSelection.normalized();
1987 const auto &columnMapping = syncView ? syncView->d_func()->horizontalLogicalIndices
1988 : horizontalLogicalIndices;
1989 const auto &rowMapping = syncView ? syncView->d_func()->verticalLogicalIndices
1990 : verticalLogicalIndices;
1991 const bool hasMapping = !columnMapping.empty() || !rowMapping.empty();
1993 QItemSelection select;
1994 QItemSelection deselect;
1996 const auto mergeInto =
1997 [
this, qaim, hasMapping](QItemSelection &selection,
1998 const QModelIndex &startIndex,
const QModelIndex &endIndex)
2001 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2002 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()),
2003 logicalColumnIndex(modelIndex.column()));
2004 selection.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2007 selection.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
2013 const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
2014 const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
2015 mergeInto(select, startIndex, endIndex);
2019 if (oldRect.x() < newRect.x()) {
2020 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2021 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
2022 mergeInto(deselect, startIndex, endIndex);
2023 }
else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
2024 const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
2025 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2026 mergeInto(deselect, startIndex, endIndex);
2029 if (oldRect.y() < newRect.y()) {
2030 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2031 const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
2032 mergeInto(deselect, startIndex, endIndex);
2033 }
else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
2034 const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
2035 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2036 mergeInto(deselect, startIndex, endIndex);
2039 if (selectionFlag == QItemSelectionModel::Select) {
2041 deselect.merge(existingSelection, QItemSelectionModel::Deselect);
2042 selectionModel->select(deselect, QItemSelectionModel::Deselect);
2043 selectionModel->select(select, QItemSelectionModel::Select);
2044 }
else if (selectionFlag == QItemSelectionModel::Deselect){
2045 QItemSelection oldSelection = existingSelection;
2046 oldSelection.merge(select, QItemSelectionModel::Deselect);
2047 selectionModel->select(oldSelection, QItemSelectionModel::Select);
2048 selectionModel->select(select, QItemSelectionModel::Deselect);
2054void QQuickTableViewPrivate::cancelSelectionTracking()
2057 selectionStartCell = QPoint(-1, -1);
2058 selectionEndCell = QPoint(-1, -1);
2059 existingSelection.clear();
2060 selectionFlag = QItemSelectionModel::NoUpdate;
2061 if (selectableCallbackFunction)
2062 selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
2065void QQuickTableViewPrivate::clearSelection()
2067 if (!selectionModel)
2069 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2070 selectionModel->clearSelection();
2073void QQuickTableViewPrivate::normalizeSelection()
2079 if (selectionEndCell.x() < selectionStartCell.x())
2080 std::swap(selectionStartCell.rx(), selectionEndCell.rx());
2081 if (selectionEndCell.y() < selectionStartCell.y())
2082 std::swap(selectionStartCell.ry(), selectionEndCell.ry());
2085QRectF QQuickTableViewPrivate::selectionRectangle()
const
2087 Q_Q(
const QQuickTableView);
2089 if (loadedColumns.isEmpty() || loadedRows.isEmpty())
2092 QPoint topLeftCell = selectionStartCell;
2093 QPoint bottomRightCell = selectionEndCell;
2094 if (bottomRightCell.x() < topLeftCell.x())
2095 std::swap(topLeftCell.rx(), bottomRightCell.rx());
2096 if (selectionEndCell.y() < topLeftCell.y())
2097 std::swap(topLeftCell.ry(), bottomRightCell.ry());
2099 const QPoint leftCell(topLeftCell.x(), topRow());
2100 const QPoint topCell(leftColumn(), topLeftCell.y());
2101 const QPoint rightCell(bottomRightCell.x(), topRow());
2102 const QPoint bottomCell(leftColumn(), bottomRightCell.y());
2115 if (loadedItems.contains(modelIndexAtCell(leftCell)))
2116 left = loadedTableItem(leftCell)->geometry().left();
2117 else if (leftCell.x() > rightColumn())
2118 left = q->contentWidth();
2120 if (loadedItems.contains(modelIndexAtCell(topCell)))
2121 top = loadedTableItem(topCell)->geometry().top();
2122 else if (topCell.y() > bottomRow())
2123 top = q->contentHeight();
2125 if (loadedItems.contains(modelIndexAtCell(rightCell)))
2126 right = loadedTableItem(rightCell)->geometry().right();
2127 else if (rightCell.x() > rightColumn())
2128 right = q->contentWidth();
2130 if (loadedItems.contains(modelIndexAtCell(bottomCell)))
2131 bottom = loadedTableItem(bottomCell)->geometry().bottom();
2132 else if (bottomCell.y() > bottomRow())
2133 bottom = q->contentHeight();
2135 return QRectF(left, top, right - left, bottom - top);
2138QRect QQuickTableViewPrivate::selection()
const
2140 const qreal w = selectionEndCell.x() - selectionStartCell.x();
2141 const qreal h = selectionEndCell.y() - selectionStartCell.y();
2142 return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
2145QSizeF QQuickTableViewPrivate::scrollTowardsPoint(
const QPointF &pos,
const QSizeF &step)
2147 Q_Q(QQuickTableView);
2149 if (loadedItems.isEmpty())
2159 const bool outsideLeft = pos.x() < viewportRect.x();
2160 const bool outsideRight = pos.x() >= viewportRect.right() - 1;
2161 const bool outsideTop = pos.y() < viewportRect.y();
2162 const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
2165 const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
2166 const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
2167 if (remainingDist > 0 || !firstColumnLoaded) {
2168 qreal stepX = step.width();
2169 if (firstColumnLoaded)
2170 stepX = qMin(stepX, remainingDist);
2171 q->setContentX(q->contentX() - stepX);
2172 dist.setWidth(pos.x() - viewportRect.left() - 1);
2174 }
else if (outsideRight) {
2175 const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
2176 const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
2177 if (remainingDist > 0 || !lastColumnLoaded) {
2178 qreal stepX = step.width();
2179 if (lastColumnLoaded)
2180 stepX = qMin(stepX, remainingDist);
2181 q->setContentX(q->contentX() + stepX);
2182 dist.setWidth(pos.x() - viewportRect.right() - 1);
2187 const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
2188 const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
2189 if (remainingDist > 0 || !firstRowLoaded) {
2190 qreal stepY = step.height();
2192 stepY = qMin(stepY, remainingDist);
2193 q->setContentY(q->contentY() - stepY);
2194 dist.setHeight(pos.y() - viewportRect.top() - 1);
2196 }
else if (outsideBottom) {
2197 const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
2198 const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
2199 if (remainingDist > 0 || !lastRowLoaded) {
2200 qreal stepY = step.height();
2202 stepY = qMin(stepY, remainingDist);
2203 q->setContentY(q->contentY() + stepY);
2204 dist.setHeight(pos.y() - viewportRect.bottom() - 1);
2211void QQuickTableViewPrivate::setCallback(std::function<
void (CallBackFlag)> func)
2213 selectableCallbackFunction = func;
2216QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(
const QObject *object)
const
2218 QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object,
false);
2219 return static_cast<QQuickTableViewAttached *>(attachedObject);
2222QQuickTableViewAttached::QQuickTableViewAttached(QObject *parent)
2225 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
2232 for (
int i = 0; i < 3; ++i) {
2233 parentItem = parentItem->parentItem();
2236 if (
auto tableView = qobject_cast<QQuickTableView *>(parentItem)) {
2243int QQuickTableViewPrivate::modelIndexAtCell(
const QPoint &cell)
const
2249 int availableColumns = tableSize.width();
2250 return (cell.y() * availableColumns) + cell.x();
2252 int availableRows = tableSize.height();
2253 return (cell.x() * availableRows) + cell.y();
2257QPoint QQuickTableViewPrivate::cellAtModelIndex(
int modelIndex)
const
2263 int availableColumns = tableSize.width();
2264 int row =
int(modelIndex / availableColumns);
2265 int column = modelIndex % availableColumns;
2266 return QPoint(column, row);
2268 int availableRows = tableSize.height();
2269 int column =
int(modelIndex / availableRows);
2270 int row = modelIndex % availableRows;
2271 return QPoint(column, row);
2275int QQuickTableViewPrivate::modelIndexToCellIndex(
const QModelIndex &modelIndex,
bool visualIndex)
const
2279 const QPoint cell = q_func()->cellAtIndex(modelIndex);
2280 if (!cellIsValid(cell))
2282 return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
2285int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
const
2287 return int(log2(
float(edge)));
2290void QQuickTableViewPrivate::clearEdgeSizeCache()
2292 cachedColumnWidth.startIndex = kEdgeIndexNotSet;
2293 cachedRowHeight.startIndex = kEdgeIndexNotSet;
2295 for (Qt::Edge edge : allTableEdges)
2296 cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
2299int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
const
2303 int startIndex = -1;
2305 case Qt::LeftEdge: startIndex = leftColumn() - 1;
break;
2306 case Qt::RightEdge: startIndex = rightColumn() + 1;
break;
2307 case Qt::TopEdge: startIndex = topRow() - 1;
break;
2308 case Qt::BottomEdge: startIndex = bottomRow() + 1;
break;
2311 return nextVisibleEdgeIndex(edge, startIndex);
2314int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge,
int startIndex)
const
2320 auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
2321 if (cachedResult.containsIndex(edge, startIndex))
2322 return cachedResult.endIndex;
2326 int foundIndex = kEdgeIndexNotSet;
2327 int testIndex = startIndex;
2330 case Qt::LeftEdge: {
2332 if (testIndex < 0) {
2333 foundIndex = kEdgeIndexAtEnd;
2337 if (!isColumnHidden(testIndex)) {
2338 foundIndex = testIndex;
2345 case Qt::RightEdge: {
2347 if (testIndex > tableSize.width() - 1) {
2348 foundIndex = kEdgeIndexAtEnd;
2352 if (!isColumnHidden(testIndex)) {
2353 foundIndex = testIndex;
2362 if (testIndex < 0) {
2363 foundIndex = kEdgeIndexAtEnd;
2367 if (!isRowHidden(testIndex)) {
2368 foundIndex = testIndex;
2375 case Qt::BottomEdge: {
2377 if (testIndex > tableSize.height() - 1) {
2378 foundIndex = kEdgeIndexAtEnd;
2382 if (!isRowHidden(testIndex)) {
2383 foundIndex = testIndex;
2392 cachedResult.startIndex = startIndex;
2393 cachedResult.endIndex = foundIndex;
2397void QQuickTableViewPrivate::updateContentWidth()
2408 Q_Q(QQuickTableView);
2410 if (syncHorizontally) {
2411 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2412 q->QQuickFlickable::setContentWidth(syncView->contentWidth());
2416 if (explicitContentWidth.isValid()) {
2422 if (loadedItems.isEmpty()) {
2423 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2424 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2425 q->QQuickFlickable::setContentWidth(kDefaultColumnWidth);
2427 q->QQuickFlickable::setContentWidth(0);
2431 const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2432 const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
2433 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2434 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2435 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2436 const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
2438 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2439 q->QQuickFlickable::setContentWidth(estimatedWidth);
2442void QQuickTableViewPrivate::updateContentHeight()
2444 Q_Q(QQuickTableView);
2446 if (syncVertically) {
2447 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2448 q->QQuickFlickable::setContentHeight(syncView->contentHeight());
2452 if (explicitContentHeight.isValid()) {
2458 if (loadedItems.isEmpty()) {
2459 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2460 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2461 q->QQuickFlickable::setContentHeight(kDefaultRowHeight);
2463 q->QQuickFlickable::setContentHeight(0);
2467 const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2468 const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
2469 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2470 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2471 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2472 const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
2474 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2475 q->QQuickFlickable::setContentHeight(estimatedHeight);
2478void QQuickTableViewPrivate::updateExtents()
2491 Q_Q(QQuickTableView);
2493 bool tableMovedHorizontally =
false;
2494 bool tableMovedVertically =
false;
2496 const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
2497 const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2498 const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
2499 const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2501 QPointF prevOrigin = origin;
2502 QSizeF prevEndExtent = endExtent;
2504 if (syncHorizontally) {
2505 const auto syncView_d = syncView->d_func();
2506 origin.rx() = syncView_d->origin.x();
2507 endExtent.rwidth() = syncView_d->endExtent.width();
2508 }
else if (nextLeftColumn == kEdgeIndexAtEnd) {
2511 if (loadedTableOuterRect.left() > viewportRect.left()) {
2516 if (loadedTableOuterRect.left() > origin.x()) {
2517 const qreal diff = loadedTableOuterRect.left() - origin.x();
2518 loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
2519 loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
2520 tableMovedHorizontally =
true;
2523 origin.rx() = loadedTableOuterRect.left();
2524 }
else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
2528 const int columnsRemaining = nextLeftColumn + 1;
2529 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2530 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2531 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2532 origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
2533 }
else if (nextRightColumn == kEdgeIndexAtEnd) {
2536 if (loadedTableOuterRect.right() < viewportRect.right()) {
2541 const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
2542 if (loadedTableOuterRect.right() < w) {
2543 const qreal diff = loadedTableOuterRect.right() - w;
2544 loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
2545 loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
2546 tableMovedHorizontally =
true;
2549 endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
2550 }
else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
2554 const int columnsRemaining = tableSize.width() - nextRightColumn;
2555 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2556 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2557 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2558 const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
2559 endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
2562 if (syncVertically) {
2563 const auto syncView_d = syncView->d_func();
2564 origin.ry() = syncView_d->origin.y();
2565 endExtent.rheight() = syncView_d->endExtent.height();
2566 }
else if (nextTopRow == kEdgeIndexAtEnd) {
2569 if (loadedTableOuterRect.top() > viewportRect.top()) {
2574 if (loadedTableOuterRect.top() > origin.y()) {
2575 const qreal diff = loadedTableOuterRect.top() - origin.y();
2576 loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
2577 loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
2578 tableMovedVertically =
true;
2581 origin.ry() = loadedTableOuterRect.top();
2582 }
else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
2586 const int rowsRemaining = nextTopRow + 1;
2587 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2588 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2589 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2590 origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
2591 }
else if (nextBottomRow == kEdgeIndexAtEnd) {
2594 if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
2599 const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
2600 if (loadedTableOuterRect.bottom() < h) {
2601 const qreal diff = loadedTableOuterRect.bottom() - h;
2602 loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
2603 loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
2604 tableMovedVertically =
true;
2607 endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
2608 }
else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
2612 const int rowsRemaining = tableSize.height() - nextBottomRow;
2613 const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
2614 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2615 const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
2616 const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
2617 endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
2620 if (tableMovedHorizontally || tableMovedVertically) {
2621 qCDebug(lcTableViewDelegateLifecycle) <<
"move table to" << loadedTableOuterRect;
2625 relayoutTableItems();
2628 for (
auto syncChild : std::as_const(syncChildren)) {
2629 auto syncChild_d = syncChild->d_func();
2630 syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
2631 if (tableMovedHorizontally)
2632 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
2633 if (tableMovedVertically)
2634 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
2638 if (prevOrigin != origin || prevEndExtent != endExtent) {
2639 if (prevOrigin != origin)
2640 qCDebug(lcTableViewDelegateLifecycle) <<
"move origin to:" << origin;
2641 if (prevEndExtent != endExtent)
2642 qCDebug(lcTableViewDelegateLifecycle) <<
"move endExtent to:" << endExtent;
2646 hData.markExtentsDirty();
2647 vData.markExtentsDirty();
2648 updateBeginningEnd();
2649 if (!q->isMoving()) {
2653 q->returnToBounds();
2658void QQuickTableViewPrivate::updateAverageColumnWidth()
2660 if (explicitContentWidth.isValid()) {
2661 const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
2662 averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
2664 const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
2665 averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
2669void QQuickTableViewPrivate::updateAverageRowHeight()
2671 if (explicitContentHeight.isValid()) {
2672 const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
2673 averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
2675 const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
2676 averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
2680void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
2682 const QPoint topLeft = QPoint(leftColumn(), topRow());
2683 const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
2684 QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
2685 QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
2686 loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
2687 loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
2690QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
2696 if (loadedItems.isEmpty()) {
2698 return RebuildOption::None;
2701 RebuildOptions rebuildOptions = RebuildOption::None;
2703 if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
2707 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2708 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2713 for (
int column = leftColumn(); column <= rightColumn(); ++column) {
2714 const bool wasVisibleFromBefore = loadedColumns.contains(column);
2715 const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
2716 if (wasVisibleFromBefore == isVisibleNow)
2721 qCDebug(lcTableViewDelegateLifecycle) <<
"Column" << column <<
"changed visibility to" << isVisibleNow;
2722 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2723 if (column == leftColumn()) {
2726 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2732 if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
2736 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2737 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2742 for (
int row = topRow(); row <= bottomRow(); ++row) {
2743 const bool wasVisibleFromBefore = loadedRows.contains(row);
2744 const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
2745 if (wasVisibleFromBefore == isVisibleNow)
2750 qCDebug(lcTableViewDelegateLifecycle) <<
"Row" << row <<
"changed visibility to" << isVisibleNow;
2751 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2752 if (row == topRow())
2753 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2758 return rebuildOptions;
2761void QQuickTableViewPrivate::forceLayout(
bool immediate)
2763 clearEdgeSizeCache();
2764 RebuildOptions rebuildOptions = RebuildOption::None;
2766 const QSize actualTableSize = calculateTableSize();
2767 if (tableSize != actualTableSize) {
2771 rebuildOptions |= RebuildOption::ViewportOnly;
2779 rebuildOptions |= RebuildOption::LayoutOnly
2780 | RebuildOption::CalculateNewContentWidth
2781 | RebuildOption::CalculateNewContentHeight
2782 | checkForVisibilityChanges();
2784 scheduleRebuildTable(rebuildOptions);
2787 auto rootView = rootSyncView();
2788 const bool updated = rootView->d_func()->updateTableRecursive();
2790 qWarning() <<
"TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
2796void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
2798 if (loadRequest.edge() == Qt::Edge(0)) {
2800 loadedColumns.insert(loadRequest.column());
2801 loadedRows.insert(loadRequest.row());
2805 switch (loadRequest.edge()) {
2808 loadedColumns.insert(loadRequest.column());
2811 case Qt::BottomEdge:
2812 loadedRows.insert(loadRequest.row());
2817FxTableItem *QQuickTableViewPrivate::loadedTableItem(
const QPoint &cell)
const
2819 const int modelIndex = modelIndexAtCell(cell);
2821 return loadedItems.value(modelIndex);
2824FxTableItem *QQuickTableViewPrivate::createFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2826 Q_Q(QQuickTableView);
2828 bool ownItem =
false;
2830 int modelIndex = modelIndexAtCell(isTransposed ? QPoint(logicalRowIndex(cell.x()), logicalColumnIndex(cell.y())) :
2831 QPoint(logicalColumnIndex(cell.x()), logicalRowIndex(cell.y())));
2833 QObject* object = model->object(modelIndex, incubationMode);
2835 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2841 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2842 object =
new QQuickItem();
2846 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2850 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2851 model->release(object);
2852 item =
new QQuickItem();
2855 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2856 if (anchors && anchors->activeDirections())
2857 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2858 <<
". Use implicitWidth and implicitHeight instead.";
2865 item->setImplicitWidth(kDefaultColumnWidth);
2866 item->setImplicitHeight(kDefaultRowHeight);
2867 item->setParentItem(q->contentItem());
2871 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
2872 fxTableItem->setVisible(
false);
2873 fxTableItem->cell = cell;
2874 fxTableItem->index = modelIndex;
2878FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2883 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
2885 incubationMode = QQmlIncubator::Asynchronous;
2890 QScopedValueRollback guard(blockItemCreatedCallback,
true);
2891 auto item = createFxTableItem(cell, incubationMode);
2892 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
2896void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
2899 auto const tmpList = loadedItems;
2900 loadedItems.clear();
2901 for (FxTableItem *item : tmpList)
2902 releaseItem(item, reusableFlag);
2905void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
2907 Q_Q(QQuickTableView);
2910 auto item = fxTableItem->item;
2912 if (fxTableItem->ownItem) {
2916 auto releaseFlag = model->release(item, reusableFlag);
2917 if (releaseFlag == QQmlInstanceModel::Pooled) {
2918 fxTableItem->setVisible(
false);
2922 if (QQuickWindow *window = item->window()) {
2923 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
2925 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
2927 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
2928 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
2938void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
2940 const int modelIndex = modelIndexAtCell(cell);
2942 releaseItem(loadedItems.take(modelIndex), reusableFlag);
2945bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2947 switch (tableEdge) {
2949 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
2951 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
2953 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
2954 case Qt::BottomEdge:
2955 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
2961bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2967 switch (tableEdge) {
2969 if (loadedColumns.count() <= 1)
2971 if (positionXAnimation.isRunning()) {
2972 const qreal to = positionXAnimation.to().toFloat();
2973 if (to < viewportRect.x())
2976 return loadedTableInnerRect.left() <= fillRect.left();
2978 if (loadedColumns.count() <= 1)
2980 if (positionXAnimation.isRunning()) {
2981 const qreal to = positionXAnimation.to().toFloat();
2982 if (to > viewportRect.x())
2985 return loadedTableInnerRect.right() >= fillRect.right();
2987 if (loadedRows.count() <= 1)
2989 if (positionYAnimation.isRunning()) {
2990 const qreal to = positionYAnimation.to().toFloat();
2991 if (to < viewportRect.y())
2994 return loadedTableInnerRect.top() <= fillRect.top();
2995 case Qt::BottomEdge:
2996 if (loadedRows.count() <= 1)
2998 if (positionYAnimation.isRunning()) {
2999 const qreal to = positionYAnimation.to().toFloat();
3000 if (to > viewportRect.y())
3003 return loadedTableInnerRect.bottom() >= fillRect.bottom();
3009Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
3011 for (Qt::Edge edge : allTableEdges) {
3012 if (!canLoadTableEdge(edge, rect))
3014 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3015 if (nextIndex == kEdgeIndexAtEnd)
3023Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3025 for (Qt::Edge edge : allTableEdges) {
3026 if (canUnloadTableEdge(edge, rect))
3032qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3036 auto const cellItem = loadedTableItem(cell)->item;
3037 return cellItem->implicitWidth();
3040qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3044 auto const cellItem = loadedTableItem(cell)->item;
3045 return cellItem->implicitHeight();
3048qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3051 qreal columnWidth = 0;
3052 for (
const int row : loadedRows)
3053 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3058qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3061 qreal rowHeight = 0;
3062 for (
const int column : loadedColumns)
3063 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3067QSize QQuickTableViewPrivate::calculateTableSize()
3071 size = QSize(tableModel->columns(), tableModel->rows());
3073 size = QSize(1, model->count());
3075 return isTransposed ? size.transposed() : size;
3078qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3085 const qreal explicitColumnWidth = getColumnWidth(column);
3086 if (explicitColumnWidth >= 0)
3087 return explicitColumnWidth;
3089 if (syncHorizontally) {
3090 if (syncView->d_func()->loadedColumns.contains(column))
3091 return syncView->d_func()->getColumnLayoutWidth(column);
3099 qreal columnWidth = sizeHintForColumn(column);
3101 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3102 if (!layoutWarningIssued) {
3103 layoutWarningIssued =
true;
3104 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3106 columnWidth = kDefaultColumnWidth;
3112qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3116 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3119qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3123 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3126qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3130 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3133qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3137 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3140qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3147 const qreal explicitRowHeight = getRowHeight(row);
3148 if (explicitRowHeight >= 0)
3149 return explicitRowHeight;
3151 if (syncVertically) {
3152 if (syncView->d_func()->loadedRows.contains(row))
3153 return syncView->d_func()->getRowLayoutHeight(row);
3161 qreal rowHeight = sizeHintForRow(row);
3163 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3164 if (!layoutWarningIssued) {
3165 layoutWarningIssued =
true;
3166 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3168 rowHeight = kDefaultRowHeight;
3174qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3180 Q_Q(
const QQuickTableView);
3182 const int noExplicitColumnWidth = -1;
3184 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3185 return cachedColumnWidth.size;
3187 if (syncHorizontally)
3188 return syncView->d_func()->getColumnWidth(column);
3190 if (columnWidthProvider.isUndefined()) {
3194 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3195 if (explicitColumnWidth >= 0)
3196 return explicitColumnWidth;
3197 return noExplicitColumnWidth;
3200 qreal columnWidth = noExplicitColumnWidth;
3202 if (columnWidthProvider.isCallable()) {
3203 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3204 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3205 if (qIsNaN(columnWidth) || columnWidth < 0)
3206 columnWidth = noExplicitColumnWidth;
3208 if (!layoutWarningIssued) {
3209 layoutWarningIssued =
true;
3210 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3212 columnWidth = noExplicitColumnWidth;
3215 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3216 cachedColumnWidth.size = columnWidth;
3220qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3226 Q_Q(
const QQuickTableView);
3228 const int noExplicitRowHeight = -1;
3230 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3231 return cachedRowHeight.size;
3234 return syncView->d_func()->getRowHeight(row);
3236 if (rowHeightProvider.isUndefined()) {
3240 qreal explicitRowHeight = q->explicitRowHeight(row);
3241 if (explicitRowHeight >= 0)
3242 return explicitRowHeight;
3243 return noExplicitRowHeight;
3246 qreal rowHeight = noExplicitRowHeight;
3248 if (rowHeightProvider.isCallable()) {
3249 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3250 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3251 if (qIsNaN(rowHeight) || rowHeight < 0)
3252 rowHeight = noExplicitRowHeight;
3254 if (!layoutWarningIssued) {
3255 layoutWarningIssued =
true;
3256 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3258 rowHeight = noExplicitRowHeight;
3261 cachedRowHeight.startIndex = logicalRowIndex(row);
3262 cachedRowHeight.size = rowHeight;
3266qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3268 Q_Q(QQuickTableView);
3271 const int columnX = getEffectiveColumnX(column);
3273 if (subRect.isValid()) {
3274 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3277 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3280 if (alignment & Qt::AlignLeft) {
3281 contentX = columnX + subRect.x() + offset;
3282 }
else if (alignment & Qt::AlignRight) {
3283 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3284 }
else if (alignment & Qt::AlignHCenter) {
3285 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3286 contentX = columnX + subRect.x() - centerDistance + offset;
3289 const int columnWidth = getEffectiveColumnWidth(column);
3290 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3291 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3293 if (alignment & Qt::AlignLeft) {
3294 contentX = columnX + offset;
3295 }
else if (alignment & Qt::AlignRight) {
3296 contentX = columnX + columnWidth - viewportRect.width() + offset;
3297 }
else if (alignment & Qt::AlignHCenter) {
3298 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3299 contentX = columnX - centerDistance + offset;
3304 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3309qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3311 Q_Q(QQuickTableView);
3314 const int rowY = getEffectiveRowY(row);
3316 if (subRect.isValid()) {
3317 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3320 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3323 if (alignment & Qt::AlignTop) {
3324 contentY = rowY + subRect.y() + offset;
3325 }
else if (alignment & Qt::AlignBottom) {
3326 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3327 }
else if (alignment & Qt::AlignVCenter) {
3328 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3329 contentY = rowY + subRect.y() - centerDistance + offset;
3332 const int rowHeight = getEffectiveRowHeight(row);
3333 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3334 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3336 if (alignment & Qt::AlignTop) {
3337 contentY = rowY + offset;
3338 }
else if (alignment & Qt::AlignBottom) {
3339 contentY = rowY + rowHeight - viewportRect.height() + offset;
3340 }
else if (alignment & Qt::AlignVCenter) {
3341 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3342 contentY = rowY - centerDistance + offset;
3347 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3352bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3356 return qFuzzyIsNull(getColumnWidth(column));
3359bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3363 return qFuzzyIsNull(getRowHeight(row));
3366void QQuickTableViewPrivate::relayoutTableItems()
3368 qCDebug(lcTableViewDelegateLifecycle);
3370 if (viewportRect.isEmpty()) {
3372 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3376 qreal nextColumnX = loadedTableOuterRect.x();
3377 qreal nextRowY = loadedTableOuterRect.y();
3379 for (
const int column : loadedColumns) {
3381 const qreal width = getColumnLayoutWidth(column);
3383 for (
const int row : loadedRows) {
3384 auto item = loadedTableItem(QPoint(column, row));
3385 QRectF geometry = item->geometry();
3386 geometry.moveLeft(nextColumnX);
3387 geometry.setWidth(width);
3388 item->setGeometry(geometry);
3392 nextColumnX += width + cellSpacing.width();
3395 for (
const int row : loadedRows) {
3397 const qreal height = getRowLayoutHeight(row);
3399 for (
const int column : loadedColumns) {
3400 auto item = loadedTableItem(QPoint(column, row));
3401 QRectF geometry = item->geometry();
3402 geometry.moveTop(nextRowY);
3403 geometry.setHeight(height);
3404 item->setGeometry(geometry);
3408 nextRowY += height + cellSpacing.height();
3411 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3412 for (
const int column : loadedColumns) {
3413 for (
const int row : loadedRows) {
3414 QPoint cell = QPoint(column, row);
3415 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3421void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3423 int columnThatNeedsLayout;
3424 int neighbourColumn;
3428 if (tableEdge == Qt::LeftEdge) {
3429 columnThatNeedsLayout = leftColumn();
3430 neighbourColumn = loadedColumns.values().at(1);
3431 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3432 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3433 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3435 columnThatNeedsLayout = rightColumn();
3436 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3437 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3438 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3439 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3442 for (
const int row : loadedRows) {
3443 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3444 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3445 const qreal rowY = neighbourItem->geometry().y();
3446 const qreal rowHeight = neighbourItem->geometry().height();
3448 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3449 fxTableItem->setVisible(
true);
3451 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3455void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3457 int rowThatNeedsLayout;
3460 if (tableEdge == Qt::TopEdge) {
3461 rowThatNeedsLayout = topRow();
3462 neighbourRow = loadedRows.values().at(1);
3464 rowThatNeedsLayout = bottomRow();
3465 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3470 for (
const int column : loadedColumns) {
3471 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3472 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3473 const qreal columnX = neighbourItem->geometry().x();
3474 const qreal columnWidth = neighbourItem->geometry().width();
3475 fxTableItem->item->setX(columnX);
3476 fxTableItem->item->setWidth(columnWidth);
3481 if (tableEdge == Qt::TopEdge) {
3482 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3483 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3484 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3486 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3487 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3488 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3491 for (
const int column : loadedColumns) {
3492 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3493 fxTableItem->item->setY(rowY);
3494 fxTableItem->item->setHeight(rowHeight);
3495 fxTableItem->setVisible(
true);
3497 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3501void QQuickTableViewPrivate::layoutTopLeftItem()
3503 const QPoint cell(loadRequest.column(), loadRequest.row());
3504 auto topLeftItem = loadedTableItem(cell);
3505 auto item = topLeftItem->item;
3507 item->setPosition(loadRequest.startPosition());
3508 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3509 topLeftItem->setVisible(
true);
3510 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3513void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3515 if (loadRequest.edge() == Qt::Edge(0)) {
3517 layoutTopLeftItem();
3521 switch (loadRequest.edge()) {
3524 layoutVerticalEdge(loadRequest.edge());
3527 case Qt::BottomEdge:
3528 layoutHorizontalEdge(loadRequest.edge());
3533void QQuickTableViewPrivate::processLoadRequest()
3535 Q_Q(QQuickTableView);
3538 while (loadRequest.hasCurrentCell()) {
3539 QPoint cell = loadRequest.currentCell();
3540 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3548 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3549 loadRequest.moveToNextCell();
3552 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3554 syncLoadedTableFromLoadRequest();
3555 layoutTableEdgeFromLoadRequest();
3556 syncLoadedTableRectFromLoadedTable();
3558 if (rebuildState == RebuildState::Done) {
3562 drainReusePoolAfterLoadRequest();
3564 switch (loadRequest.edge()) {
3566 emit q->leftColumnChanged();
3569 emit q->rightColumnChanged();
3572 emit q->topRowChanged();
3574 case Qt::BottomEdge:
3575 emit q->bottomRowChanged();
3579 if (editIndex.isValid())
3582 emit q->layoutChanged();
3585 loadRequest.markAsDone();
3587 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3588 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3589 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3592void QQuickTableViewPrivate::processRebuildTable()
3594 Q_Q(QQuickTableView);
3596 if (rebuildState == RebuildState::Begin) {
3597 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3598 tableSizeBeforeRebuild = tableSize;
3599 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins(-1,-1,-1,-1)
3600 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3603 moveToNextRebuildState();
3605 if (rebuildState == RebuildState::LoadInitalTable) {
3607 if (!moveToNextRebuildState())
3611 if (rebuildState == RebuildState::VerifyTable) {
3612 if (loadedItems.isEmpty()) {
3613 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3614 updateContentWidth();
3615 updateContentHeight();
3616 rebuildState = RebuildState::Done;
3617 }
else if (!moveToNextRebuildState()) {
3622 if (rebuildState == RebuildState::LayoutTable) {
3623 layoutAfterLoadingInitialTable();
3624 loadAndUnloadVisibleEdges();
3625 if (!moveToNextRebuildState())
3629 if (rebuildState == RebuildState::CancelOvershoot) {
3630 cancelOvershootAfterLayout();
3631 loadAndUnloadVisibleEdges();
3632 if (!moveToNextRebuildState())
3636 if (rebuildState == RebuildState::UpdateContentSize) {
3637 updateContentSize();
3638 if (!moveToNextRebuildState())
3642 const bool preload = (rebuildOptions & RebuildOption::All
3643 && reusableFlag == QQmlTableInstanceModel::Reusable);
3645 if (rebuildState == RebuildState::PreloadColumns) {
3646 if (preload && !atTableEnd(Qt::RightEdge))
3647 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3648 if (!moveToNextRebuildState())
3652 if (rebuildState == RebuildState::PreloadRows) {
3653 if (preload && !atTableEnd(Qt::BottomEdge))
3654 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3655 if (!moveToNextRebuildState())
3659 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3660 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3662 if (!moveToNextRebuildState())
3666 if (rebuildState == RebuildState::Done) {
3667 if (tableSizeBeforeRebuild.width() != tableSize.width())
3668 emit q->columnsChanged();
3669 if (tableSizeBeforeRebuild.height() != tableSize.height())
3670 emit q->rowsChanged();
3671 if (edgesBeforeRebuild.left() != q->leftColumn())
3672 emit q->leftColumnChanged();
3673 if (edgesBeforeRebuild.right() != q->rightColumn())
3674 emit q->rightColumnChanged();
3675 if (edgesBeforeRebuild.top() != q->topRow())
3676 emit q->topRowChanged();
3677 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3678 emit q->bottomRowChanged();
3680 if (editIndex.isValid())
3682 updateCurrentRowAndColumn();
3684 emit q->layoutChanged();
3686 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3687 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3688 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3689 qCDebug(lcTableViewDelegateLifecycle());
3695bool QQuickTableViewPrivate::moveToNextRebuildState()
3697 if (loadRequest.isActive()) {
3703 if (rebuildState == RebuildState::Begin
3704 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3705 rebuildState = RebuildState::LayoutTable;
3707 rebuildState = RebuildState(
int(rebuildState) + 1);
3709 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3713void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3715 if (tableSize.isEmpty()) {
3717 topLeftCell.rx() = kEdgeIndexAtEnd;
3718 topLeftCell.ry() = kEdgeIndexAtEnd;
3722 if (syncHorizontally || syncVertically) {
3723 const auto syncView_d = syncView->d_func();
3725 if (syncView_d->loadedItems.isEmpty()) {
3726 topLeftCell.rx() = 0;
3727 topLeftCell.ry() = 0;
3732 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3733 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3734 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3736 if (syncHorizontally) {
3737 topLeftCell.rx() = syncViewTopLeftCell.x();
3738 topLeftPos.rx() = syncViewTopLeftPos.x();
3740 if (topLeftCell.x() >= tableSize.width()) {
3742 topLeftCell.rx() = kEdgeIndexAtEnd;
3743 topLeftPos.rx() = kEdgeIndexAtEnd;
3747 if (syncVertically) {
3748 topLeftCell.ry() = syncViewTopLeftCell.y();
3749 topLeftPos.ry() = syncViewTopLeftPos.y();
3751 if (topLeftCell.y() >= tableSize.height()) {
3753 topLeftCell.ry() = kEdgeIndexAtEnd;
3754 topLeftPos.ry() = kEdgeIndexAtEnd;
3758 if (syncHorizontally && syncVertically) {
3769 if (!syncHorizontally) {
3770 if (rebuildOptions & RebuildOption::All) {
3772 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3773 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3777 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3779 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3780 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3781 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3782 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3783 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3784 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3787 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3791 topLeftPos.rx() = loadedTableOuterRect.x();
3795 if (!syncVertically) {
3796 if (rebuildOptions & RebuildOption::All) {
3798 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3799 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3803 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3805 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3806 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3807 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3808 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3809 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3810 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3812 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3813 topLeftPos.ry() = loadedTableOuterRect.y();
3818void QQuickTableViewPrivate::loadInitialTable()
3820 tableSize = calculateTableSize();
3822 if (positionXAnimation.isRunning()) {
3823 positionXAnimation.stop();
3824 setLocalViewportX(positionXAnimation.to().toReal());
3828 if (positionYAnimation.isRunning()) {
3829 positionYAnimation.stop();
3830 setLocalViewportY(positionYAnimation.to().toReal());
3836 calculateTopLeft(topLeft, topLeftPos);
3837 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3838 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3840 if (!loadedItems.isEmpty()) {
3841 if (rebuildOptions & RebuildOption::All)
3842 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3843 else if (rebuildOptions & RebuildOption::ViewportOnly)
3844 releaseLoadedItems(reusableFlag);
3847 if (rebuildOptions & RebuildOption::All) {
3848 origin = QPointF(0, 0);
3849 endExtent = QSizeF(0, 0);
3850 hData.markExtentsDirty();
3851 vData.markExtentsDirty();
3852 updateBeginningEnd();
3855 loadedColumns.clear();
3857 loadedTableOuterRect = QRect();
3858 loadedTableInnerRect = QRect();
3859 clearEdgeSizeCache();
3861 if (syncHorizontally)
3862 setLocalViewportX(syncView->contentX());
3865 setLocalViewportY(syncView->contentY());
3867 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
3868 setLocalViewportX(topLeftPos.x());
3870 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
3871 setLocalViewportY(topLeftPos.y());
3876 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
3880 if (model->count() == 0) {
3881 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
3885 if (tableModel && !tableModel->delegate()) {
3886 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
3890 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
3891 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
3895 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
3896 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
3900 if (viewportRect.isEmpty()) {
3901 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
3907 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
3908 processLoadRequest();
3909 loadAndUnloadVisibleEdges();
3912void QQuickTableViewPrivate::updateContentSize()
3914 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
3915 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
3916 updateAverageColumnWidth();
3917 updateContentWidth();
3920 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
3921 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
3922 updateAverageRowHeight();
3923 updateContentHeight();
3929void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
3931 clearEdgeSizeCache();
3932 relayoutTableItems();
3933 syncLoadedTableRectFromLoadedTable();
3935 updateContentSize();
3937 adjustViewportXAccordingToAlignment();
3938 adjustViewportYAccordingToAlignment();
3941void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
3944 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
3947 if (positionViewAtColumnAfterRebuild != leftColumn())
3950 const qreal newContentX = getAlignmentContentX(
3951 positionViewAtColumnAfterRebuild,
3952 positionViewAtColumnAlignment,
3953 positionViewAtColumnOffset,
3954 positionViewAtColumnSubRect);
3956 setLocalViewportX(newContentX);
3960void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
3963 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
3966 if (positionViewAtRowAfterRebuild != topRow())
3969 const qreal newContentY = getAlignmentContentY(
3970 positionViewAtRowAfterRebuild,
3971 positionViewAtRowAlignment,
3972 positionViewAtRowOffset,
3973 positionViewAtRowSubRect);
3975 setLocalViewportY(newContentY);
3979void QQuickTableViewPrivate::cancelOvershootAfterLayout()
3981 Q_Q(QQuickTableView);
3987 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
3988 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
3989 const bool cancelVertically = positionVertically && !syncVertically;
3990 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
3992 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
3993 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
3994 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
3998 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
3999 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
4000 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
4005void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
4007 Q_Q(QQuickTableView);
4008 qCDebug(lcTableViewDelegateLifecycle) << edge;
4011 case Qt::LeftEdge: {
4012 const int column = leftColumn();
4013 for (
int row : loadedRows)
4014 unloadItem(QPoint(column, row));
4015 loadedColumns.remove(column);
4016 syncLoadedTableRectFromLoadedTable();
4017 if (rebuildState == RebuildState::Done)
4018 emit q->leftColumnChanged();
4020 case Qt::RightEdge: {
4021 const int column = rightColumn();
4022 for (
int row : loadedRows)
4023 unloadItem(QPoint(column, row));
4024 loadedColumns.remove(column);
4025 syncLoadedTableRectFromLoadedTable();
4026 if (rebuildState == RebuildState::Done)
4027 emit q->rightColumnChanged();
4030 const int row = topRow();
4031 for (
int col : loadedColumns)
4032 unloadItem(QPoint(col, row));
4033 loadedRows.remove(row);
4034 syncLoadedTableRectFromLoadedTable();
4035 if (rebuildState == RebuildState::Done)
4036 emit q->topRowChanged();
4038 case Qt::BottomEdge: {
4039 const int row = bottomRow();
4040 for (
int col : loadedColumns)
4041 unloadItem(QPoint(col, row));
4042 loadedRows.remove(row);
4043 syncLoadedTableRectFromLoadedTable();
4044 if (rebuildState == RebuildState::Done)
4045 emit q->bottomRowChanged();
4049 if (rebuildState == RebuildState::Done)
4050 emit q->layoutChanged();
4052 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4055void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4057 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4058 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4060 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4061 ? loadedRows.values() : loadedColumns.values();
4062 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4063 processLoadRequest();
4066void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4078 if (loadRequest.isActive()) {
4084 if (loadedItems.isEmpty()) {
4094 tableModified =
false;
4096 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4097 tableModified =
true;
4101 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4102 tableModified =
true;
4103 loadEdge(edge, incubationMode);
4104 if (loadRequest.isActive())
4107 }
while (tableModified);
4111void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4113 Q_Q(QQuickTableView);
4115 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4118 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4148 const int w = loadedColumns.count();
4149 const int h = loadedRows.count();
4150 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4151 const int maxTime = minTime * 2;
4152 tableModel->drainReusableItemsPool(maxTime);
4155void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4156 if (!q_func()->isComponentComplete()) {
4161 scheduledRebuildOptions |= options;
4165QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4167 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4168 while (QQuickTableView *view = root->d_func()->syncView)
4173void QQuickTableViewPrivate::updatePolish()
4180 rootSyncView()->d_func()->updateTableRecursive();
4183bool QQuickTableViewPrivate::updateTableRecursive()
4193 const bool updateComplete = updateTable();
4194 if (!updateComplete)
4197 const auto children = syncChildren;
4198 for (
auto syncChild : children) {
4199 auto syncChild_d = syncChild->d_func();
4201 RebuildOption::PositionViewAtRow |
4202 RebuildOption::PositionViewAtColumn |
4203 RebuildOption::CalculateNewTopLeftRow |
4204 RebuildOption::CalculateNewTopLeftColumn;
4205 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4207 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4208 if (!descendantUpdateComplete)
4212 rebuildOptions = RebuildOption::None;
4217bool QQuickTableViewPrivate::updateTable()
4226 QScopedValueRollback polishGuard(polishing,
true);
4228 if (loadRequest.isActive()) {
4236 if (rebuildState != RebuildState::Done) {
4237 processRebuildTable();
4238 return rebuildState == RebuildState::Done;
4241 syncWithPendingChanges();
4243 if (rebuildState == RebuildState::Begin) {
4244 processRebuildTable();
4245 return rebuildState == RebuildState::Done;
4248 if (loadedItems.isEmpty())
4249 return !loadRequest.isActive();
4251 loadAndUnloadVisibleEdges();
4254 return !loadRequest.isActive();
4257void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4259 if (inUpdateContentSize) {
4271 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4274QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4276 const auto data = QQmlData::get(q_func());
4277 if (!data || !data->propertyCache)
4278 return QTypeRevision::zero();
4280 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4281 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4284 return qmlTypeView.metaObjectRevision();
4287void QQuickTableViewPrivate::createWrapperModel()
4289 Q_Q(QQuickTableView);
4295 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4296 tableModel->useImportVersion(resolveImportVersion());
4300bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4302 if (!selectionModel)
4305 QAbstractItemModel *model = selectionModel->model();
4309 return selectionModel->isSelected(q_func()->modelIndex(cell));
4312bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4314 if (!selectionModel)
4317 QAbstractItemModel *model = selectionModel->model();
4321 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4324void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4326 if (!inSelectionModelUpdate) {
4330 cancelSelectionTracking();
4333 const auto &selectedIndexes = selected.indexes();
4334 const auto &deselectedIndexes = deselected.indexes();
4335 for (
int i = 0; i < selectedIndexes.size(); ++i)
4336 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4337 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4338 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4341void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4343 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4344 qmlWarning(q_func())
4345 <<
"Cannot select cells: TableView.selectionModel.model is not "
4346 <<
"compatible with the model displayed in the view";
4350 const int cellIndex = modelIndexToCellIndex(modelIndex);
4351 if (!loadedItems.contains(cellIndex))
4353 const QPoint cell = cellAtModelIndex(cellIndex);
4354 QQuickItem *item = loadedTableItem(cell)->item;
4355 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4358QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4373 return qaim(modelImpl());
4376QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4379 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4380 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4381 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4384void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4386 updateCurrentRowAndColumn();
4388 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4389 const int cellIndex = *it;
4390 const QPoint cell = cellAtModelIndex(cellIndex);
4391 const bool selected = selectedInSelectionModel(cell);
4392 const bool current = currentInSelectionModel(cell);
4393 QQuickItem *item = loadedTableItem(cell)->item;
4394 const bool editing = editIndex == q_func()->modelIndex(cell);
4395 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4396 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4397 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4401void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4403 if (current.isValid() && current.model() != selectionSourceModel()) {
4404 qmlWarning(q_func())
4405 <<
"Cannot change current index: TableView.selectionModel.model is not "
4406 <<
"compatible with the model displayed in the view";
4410 updateCurrentRowAndColumn();
4411 setCurrentOnDelegateItem(previous,
false);
4412 setCurrentOnDelegateItem(current,
true);
4415void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4417 Q_Q(QQuickTableView);
4419 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4420 const QPoint currentCell = q->cellAtIndex(currentIndex);
4421 if (currentCell.x() != currentColumn) {
4422 currentColumn = currentCell.x();
4423 emit q->currentColumnChanged();
4426 if (currentCell.y() != currentRow) {
4427 currentRow = currentCell.y();
4428 emit q->currentRowChanged();
4432void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4434 const int cellIndex = modelIndexToCellIndex(index);
4435 if (!loadedItems.contains(cellIndex))
4438 const QPoint cell = cellAtModelIndex(cellIndex);
4439 QQuickItem *item = loadedTableItem(cell)->item;
4440 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4443void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4445 if (blockItemCreatedCallback)
4448 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4449 << cellAtModelIndex(modelIndex);
4455 processLoadRequest();
4456 loadAndUnloadVisibleEdges();
4460void QQuickTableViewPrivate::initItemCallback(
int modelIndex, QObject *object)
4462 Q_Q(QQuickTableView);
4464 auto item = qobject_cast<QQuickItem*>(object);
4468 item->setParentItem(q->contentItem());
4471 if (
auto attached = getAttachedObject(item))
4472 attached->setView(q);
4474 const QPoint cell = cellAtModelIndex(modelIndex);
4475 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4476 const bool current = currentInSelectionModel(visualCell);
4477 const bool selected = selectedInSelectionModel(visualCell);
4479 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), modelIndex, item,
true);
4480 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object,
true);
4481 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object,
true);
4482 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), modelIndex, item,
true);
4483 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), modelIndex, item,
true);
4486void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4488 Q_UNUSED(modelIndex);
4490 if (
auto attached = getAttachedObject(object))
4491 emit attached->pooled();
4494void QQuickTableViewPrivate::itemReusedCallback(
int modelIndex, QObject *object)
4496 Q_Q(QQuickTableView);
4498 const QPoint cell = cellAtModelIndex(modelIndex);
4499 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4500 const bool current = currentInSelectionModel(visualCell);
4501 const bool selected = selectedInSelectionModel(visualCell);
4503 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), modelIndex, object,
false);
4504 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object,
false);
4505 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object,
false);
4507 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), modelIndex, object,
false);
4509 if (
auto item = qobject_cast<QQuickItem*>(object))
4510 QQuickItemPrivate::get(item)->setCulled(
false);
4512 if (
auto attached = getAttachedObject(object))
4513 emit attached->reused();
4516void QQuickTableViewPrivate::syncWithPendingChanges()
4526 syncDelegateModelAccess();
4530 syncRebuildOptions();
4533void QQuickTableViewPrivate::syncRebuildOptions()
4535 if (!scheduledRebuildOptions)
4538 rebuildState = RebuildState::Begin;
4539 rebuildOptions = scheduledRebuildOptions;
4540 scheduledRebuildOptions = RebuildOption::None;
4542 if (loadedItems.isEmpty())
4543 rebuildOptions.setFlag(RebuildOption::All);
4546 if (rebuildOptions.testFlag(RebuildOption::All)) {
4547 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4548 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4549 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4550 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4551 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4552 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4555 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4556 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4558 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4559 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4562void QQuickTableViewPrivate::syncDelegate()
4571 if (assignedDelegate != tableModel->delegate())
4572 tableModel->setDelegate(assignedDelegate);
4575void QQuickTableViewPrivate::syncDelegateModelAccess()
4584 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4587QVariant QQuickTableViewPrivate::modelImpl()
const
4589 if (needsModelSynchronization)
4590 return assignedModel;
4592 return tableModel->model();
4593 return QVariant::fromValue(model);
4596void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4598 assignedModel = newModel;
4599 needsModelSynchronization =
true;
4600 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4601 emit q_func()->modelChanged();
4604void QQuickTableViewPrivate::syncModel()
4607 if (tableModel->model() == assignedModel)
4609 }
else if (QVariant::fromValue(model) == assignedModel) {
4614 disconnectFromModel();
4615 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4618 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4619 qvariant_cast<QObject *>(assignedModel));
4621 if (instanceModel) {
4624 tableModel =
nullptr;
4626 model = instanceModel;
4629 createWrapperModel();
4630 tableModel->setModel(assignedModel);
4633 needsModelSynchronization =
false;
4637void QQuickTableViewPrivate::syncSyncView()
4639 Q_Q(QQuickTableView);
4641 if (assignedSyncView != syncView) {
4643 syncView->d_func()->syncChildren.removeOne(q);
4645 if (assignedSyncView) {
4646 QQuickTableView *view = assignedSyncView;
4650 if (!layoutWarningIssued) {
4651 layoutWarningIssued =
true;
4652 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4657 view = view->d_func()->syncView;
4660 assignedSyncView->d_func()->syncChildren.append(q);
4661 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4664 syncView = assignedSyncView;
4667 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4668 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4670 if (syncHorizontally) {
4671 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4672 q->setColumnSpacing(syncView->columnSpacing());
4673 q->setLeftMargin(syncView->leftMargin());
4674 q->setRightMargin(syncView->rightMargin());
4675 updateContentWidth();
4677 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4678 if (syncView->leftColumn() != q->leftColumn()
4679 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4686 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4687 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4692 if (syncVertically) {
4693 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4694 q->setRowSpacing(syncView->rowSpacing());
4695 q->setTopMargin(syncView->topMargin());
4696 q->setBottomMargin(syncView->bottomMargin());
4697 updateContentHeight();
4699 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4700 if (syncView->topRow() != q->topRow()
4701 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4708 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4709 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4714 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4720 const auto syncView_d = syncView->d_func();
4721 if (!syncView_d->loadedItems.isEmpty()) {
4722 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4723 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4724 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4725 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4730void QQuickTableViewPrivate::syncPositionView()
4736 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4737 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4740void QQuickTableViewPrivate::connectToModel()
4742 Q_Q(QQuickTableView);
4745 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4746 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4747 QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4748 QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4751 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4753 if (
auto const aim = model->abstractItemModel()) {
4759 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4760 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4761 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4762 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4763 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4764 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4765 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4766 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4767 connect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4769 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4773 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
4774 q, &QQuickTableView::modelChanged);
4778void QQuickTableViewPrivate::disconnectFromModel()
4780 Q_Q(QQuickTableView);
4783 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4784 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4785 QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4786 QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4788 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4790 if (
auto const aim = model->abstractItemModel()) {
4791 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4792 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4793 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4794 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4795 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4796 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4797 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4798 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4799 disconnect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4801 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4805 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
4806 q, &QQuickTableView::modelChanged);
4810void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
4812 Q_UNUSED(changeSet);
4816 scheduleRebuildTable(RebuildOption::ViewportOnly
4817 | RebuildOption::CalculateNewContentWidth
4818 | RebuildOption::CalculateNewContentHeight);
4821void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
4823 if (parent != QModelIndex())
4826 scheduleRebuildTable(RebuildOption::ViewportOnly);
4829void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
4831 if (parent != QModelIndex())
4834 scheduleRebuildTable(RebuildOption::ViewportOnly);
4837void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
4839 if (parent != QModelIndex())
4842 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4845void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
4847 Q_Q(QQuickTableView);
4849 if (parent != QModelIndex())
4853 if (!editIndex.isValid() && editItem)
4856 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4859void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
4861 if (parent != QModelIndex())
4869 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4872void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
4874 Q_Q(QQuickTableView);
4876 if (parent != QModelIndex())
4880 if (!editIndex.isValid() && editItem)
4883 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4886void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
4891 scheduleRebuildTable(RebuildOption::ViewportOnly);
4894void QQuickTableViewPrivate::fetchMoreData()
4896 if (tableModel && tableModel->canFetchMore()) {
4897 tableModel->fetchMore();
4898 scheduleRebuildTable(RebuildOption::ViewportOnly);
4902void QQuickTableViewPrivate::modelResetCallback()
4904 Q_Q(QQuickTableView);
4906 scheduleRebuildTable(RebuildOption::All);
4909void QQuickTableViewPrivate::dataChangedCallback(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles)
4911 const auto *chooser = qobject_cast<
const QQmlDelegateChooser *>(assignedDelegate);
4915 if (loadedItems.isEmpty()
4916 || topLeft.column() > rightColumn() || bottomRight.column() < leftColumn()
4917 || topLeft.row() > bottomRow() || bottomRight.row() < topRow()) {
4921 if (!roles.empty()) {
4922 const int roleIndex = topLeft.model()->roleNames().key(chooser->role().toUtf8());
4923 if (!roles.contains(roleIndex))
4927 scheduleRebuildTable(RebuildOption::ViewportOnly);
4930void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4932 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
4935 if (syncVertically) {
4936 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
4938 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
4940 assignedPositionViewAtRowAfterRebuild = row;
4941 positionViewAtRowAlignment = verticalAlignment;
4942 positionViewAtRowOffset = offset;
4943 positionViewAtRowSubRect = subRect;
4944 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4945 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
4950void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4952 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
4955 if (syncHorizontally) {
4956 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
4958 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
4960 assignedPositionViewAtColumnAfterRebuild = column;
4961 positionViewAtColumnAlignment = horizontalAlignment;
4962 positionViewAtColumnOffset = offset;
4963 positionViewAtColumnSubRect = subRect;
4964 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4965 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
4970bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4972 Q_Q(QQuickTableView);
4979 if (row < topRow()) {
4980 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
4982 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
4983 }
else if (row > bottomRow()) {
4984 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
4986 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
4987 }
else if (row < topRow() || row > bottomRow()) {
4991 if (!loadedRows.contains(row))
4994 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
4995 if (qFuzzyCompare(newContentY, q->contentY()))
4999 const qreal diffY = qAbs(newContentY - q->contentY());
5000 const qreal duration = qBound(700., diffY * 5, 1500.);
5001 positionYAnimation.setTo(newContentY);
5002 positionYAnimation.setDuration(duration);
5003 positionYAnimation.restart();
5005 positionYAnimation.stop();
5006 q->setContentY(newContentY);
5012bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5014 Q_Q(QQuickTableView);
5021 if (column < leftColumn()) {
5022 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
5024 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
5025 }
else if (column > rightColumn()) {
5026 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
5028 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
5029 }
else if (column < leftColumn() || column > rightColumn()) {
5033 if (!loadedColumns.contains(column))
5036 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5037 if (qFuzzyCompare(newContentX, q->contentX()))
5041 const qreal diffX = qAbs(newContentX - q->contentX());
5042 const qreal duration = qBound(700., diffX * 5, 1500.);
5043 positionXAnimation.setTo(newContentX);
5044 positionXAnimation.setDuration(duration);
5045 positionXAnimation.restart();
5047 positionXAnimation.stop();
5048 q->setContentX(newContentX);
5054void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5056 Q_Q(QQuickTableView);
5066 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5067 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5068 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5072 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5073 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5074 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5078void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5083 Q_Q(QQuickTableView);
5084 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5086 if (qFuzzyCompare(contentX, q->contentX()))
5089 q->setContentX(contentX);
5092void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5097 Q_Q(QQuickTableView);
5098 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5100 if (qFuzzyCompare(contentY, q->contentY()))
5103 q->setContentY(contentY);
5106void QQuickTableViewPrivate::syncViewportRect()
5114 Q_Q(QQuickTableView);
5116 qreal w = q->width();
5117 qreal h = q->height();
5119 for (
auto syncChild : std::as_const(syncChildren)) {
5120 auto syncChild_d = syncChild->d_func();
5121 if (syncChild_d->syncHorizontally)
5122 w = qMax(w, syncChild->width());
5123 if (syncChild_d->syncVertically)
5124 h = qMax(h, syncChild->height());
5127 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5130void QQuickTableViewPrivate::init()
5132 Q_Q(QQuickTableView);
5134 q->setFlag(QQuickItem::ItemIsFocusScope);
5135 q->setActiveFocusOnTab(
true);
5137 positionXAnimation.setTargetObject(q);
5138 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5139 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5141 positionYAnimation.setTargetObject(q);
5142 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5143 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5145 auto tapHandler =
new QQuickTableViewTapHandler(q);
5147 hoverHandler =
new QQuickTableViewHoverHandler(q);
5148 resizeHandler =
new QQuickTableViewResizeHandler(q);
5150 hoverHandler->setEnabled(resizableRows || resizableColumns);
5151 resizeHandler->setEnabled(resizableRows || resizableColumns);
5159 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, q, [
this, q, tapHandler] {
5160 if (!tapHandler->isPressed())
5163 positionXAnimation.stop();
5164 positionYAnimation.stop();
5166 if (!q->isInteractive())
5167 handleTap(tapHandler->point());
5170 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, q, [
this, q, tapHandler] {
5171 if (q->isInteractive())
5172 handleTap(tapHandler->point());
5175 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, q, [
this, q, tapHandler] {
5176 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5177 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5179 if (resizeRow || resizeColumn) {
5181 q->setRowHeight(hoverHandler->m_row, -1);
5183 q->setColumnWidth(hoverHandler->m_column, -1);
5184 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5185 const QPointF pos = tapHandler->point().pressPosition();
5186 const QPoint cell = q->cellAtPosition(pos);
5187 const QModelIndex index = q->modelIndex(cell);
5188 if (canEdit(index,
false))
5194void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5196 Q_Q(QQuickTableView);
5198 if (keyNavigationEnabled)
5199 q->forceActiveFocus(Qt::MouseFocusReason);
5201 if (point.modifiers() != Qt::NoModifier)
5203 if (resizableRows && hoverHandler->m_row != -1)
5205 if (resizableColumns && hoverHandler->m_column != -1)
5207 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5210 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5211 bool tappedCellIsSelected =
false;
5214 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5216 if (canEdit(tappedIndex,
false)) {
5217 if (editTriggers & QQuickTableView::SingleTapped) {
5218 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5220 q->edit(tappedIndex);
5222 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5223 q->edit(tappedIndex);
5230 if (pointerNavigationEnabled) {
5231 closeEditorAndCommit();
5232 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5234 cancelSelectionTracking();
5236 setCurrentIndexFromTap(point.position());
5240bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5244 Q_Q(QQuickTableView);
5246 if (!tappedIndex.isValid()) {
5248 qmlWarning(q) <<
"cannot edit: index is not valid!";
5252 if (
auto const sourceModel = qaim(modelImpl())) {
5253 if (!(sourceModel->flags(tappedIndex) & Qt::ItemIsEditable)) {
5255 qmlWarning(q) <<
"cannot edit: QAbstractItemModel::flags(index) doesn't contain Qt::ItemIsEditable";
5260 const QPoint cell = q->cellAtIndex(tappedIndex);
5261 const QQuickItem *cellItem = q->itemAtCell(cell);
5264 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5268 auto attached = getAttachedObject(cellItem);
5269 if (!attached || !attached->editDelegate()) {
5271 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5278void QQuickTableViewPrivate::syncViewportPosRecursive()
5280 Q_Q(QQuickTableView);
5281 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5284 auto syncView_d = syncView->d_func();
5285 if (!syncView_d->inSyncViewportPosRecursive) {
5286 if (syncHorizontally)
5287 syncView_d->setLocalViewportX(q->contentX());
5289 syncView_d->setLocalViewportY(q->contentY());
5290 syncView_d->syncViewportPosRecursive();
5294 for (
auto syncChild : std::as_const(syncChildren)) {
5295 auto syncChild_d = syncChild->d_func();
5296 if (!syncChild_d->inSyncViewportPosRecursive) {
5297 if (syncChild_d->syncHorizontally)
5298 syncChild_d->setLocalViewportX(q->contentX());
5299 if (syncChild_d->syncVertically)
5300 syncChild_d->setLocalViewportY(q->contentY());
5301 syncChild_d->syncViewportPosRecursive();
5306void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5308 Q_Q(QQuickTableView);
5310 const QPoint cell = q->cellAtPosition(pos);
5311 if (!cellIsValid(cell))
5314 setCurrentIndex(cell);
5317void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5319 if (!selectionModel)
5322 const auto index = q_func()->modelIndex(cell);
5323 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5326bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5328 Q_Q(QQuickTableView);
5330 if (!selectionModel || !selectionModel->model())
5333 const QModelIndex currentIndex = selectionModel->currentIndex();
5334 const QPoint currentCell = q->cellAtIndex(currentIndex);
5336 if (!q->activeFocusOnTab()) {
5339 case Qt::Key_Backtab:
5344 if (!cellIsValid(currentCell)) {
5350 case Qt::Key_PageUp:
5351 case Qt::Key_PageDown:
5355 case Qt::Key_Backtab:
5356 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5359 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5360 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5367 auto beginMoveCurrentIndex = [&](){
5368 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5369 const bool startNewSelection = selectionRectangle().isEmpty();
5370 if (!shouldSelect) {
5372 cancelSelectionTracking();
5373 }
else if (startNewSelection) {
5377 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5378 if (loadedItems.contains(serializedStartIndex)) {
5379 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5380 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5381 setSelectionStartPos(startGeometry.center());
5382 if (selectableCallbackFunction)
5383 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5389 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5390 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5392 if (polishScheduled)
5394 const int serializedEndIndex = modelIndexAtCell(cell);
5395 if (loadedItems.contains(serializedEndIndex)) {
5396 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5397 setSelectionEndPos(endGeometry.center());
5398 if (selectableCallbackFunction)
5399 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5402 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5407 beginMoveCurrentIndex();
5408 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5409 if (nextRow == kEdgeIndexAtEnd)
5411 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5412 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5413 endMoveCurrentIndex({currentCell.x(), nextRow});
5415 case Qt::Key_Down: {
5416 beginMoveCurrentIndex();
5417 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5418 if (nextRow == kEdgeIndexAtEnd)
5420 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5421 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5422 endMoveCurrentIndex({currentCell.x(), nextRow});
5424 case Qt::Key_Left: {
5425 beginMoveCurrentIndex();
5426 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5427 if (nextColumn == kEdgeIndexAtEnd)
5429 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5430 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5431 endMoveCurrentIndex({nextColumn, currentCell.y()});
5433 case Qt::Key_Right: {
5434 beginMoveCurrentIndex();
5435 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5436 if (nextColumn == kEdgeIndexAtEnd)
5438 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5439 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5440 endMoveCurrentIndex({nextColumn, currentCell.y()});
5442 case Qt::Key_PageDown: {
5443 int newBottomRow = -1;
5444 beginMoveCurrentIndex();
5445 if (currentCell.y() < bottomRow()) {
5447 newBottomRow = bottomRow();
5448 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5450 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5451 positionYAnimation.complete();
5452 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5453 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5454 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5455 positionYAnimation.complete();
5457 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5459 case Qt::Key_PageUp: {
5461 beginMoveCurrentIndex();
5462 if (currentCell.y() > topRow()) {
5464 newTopRow = topRow();
5465 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5467 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5468 positionYAnimation.complete();
5469 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5470 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5471 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5472 positionYAnimation.complete();
5474 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5476 case Qt::Key_Home: {
5477 beginMoveCurrentIndex();
5478 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5479 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5480 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5483 beginMoveCurrentIndex();
5484 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5485 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5486 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5489 beginMoveCurrentIndex();
5490 int nextRow = currentCell.y();
5491 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5492 if (nextColumn == kEdgeIndexAtEnd) {
5493 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5494 if (nextRow == kEdgeIndexAtEnd)
5495 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5496 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5497 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5498 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5502 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5503 marginX = q->leftMargin();
5504 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5505 marginX = -q->leftMargin();
5507 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5508 endMoveCurrentIndex({nextColumn, nextRow});
5510 case Qt::Key_Backtab: {
5511 beginMoveCurrentIndex();
5512 int nextRow = currentCell.y();
5513 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5514 if (nextColumn == kEdgeIndexAtEnd) {
5515 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5516 if (nextRow == kEdgeIndexAtEnd)
5517 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5518 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5519 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5520 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5524 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5525 marginX = q->leftMargin();
5526 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5527 marginX = -q->leftMargin();
5529 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5530 endMoveCurrentIndex({nextColumn, nextRow});
5539bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5541 Q_Q(QQuickTableView);
5543 if (editTriggers == QQuickTableView::NoEditTriggers)
5545 if (!selectionModel || !selectionModel->model())
5548 const QModelIndex index = selectionModel->currentIndex();
5549 const QPoint cell = q->cellAtIndex(index);
5550 const QQuickItem *cellItem = q->itemAtCell(cell);
5554 auto attached = getAttachedObject(cellItem);
5555 if (!attached || !attached->editDelegate())
5558 bool anyKeyPressed =
false;
5559 bool editKeyPressed =
false;
5562 case Qt::Key_Return:
5567 anyKeyPressed =
true;
5568 editKeyPressed =
true;
5572 case Qt::Key_Control:
5575 case Qt::Key_Backtab:
5578 anyKeyPressed =
true;
5581 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5582 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5584 if (!(editKeyAccepted || anyKeyAccepted))
5587 if (!canEdit(index,
false)) {
5596 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5599 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5605QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5611 Q_Q(QQuickTableView);
5612 if (QObject *focusObject = editItem->window()->focusObject()) {
5613 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5614 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5615 focusItem->installEventFilter(q);
5622void QQuickTableViewPrivate::closeEditorAndCommit()
5627 if (
auto attached = getAttachedObject(editItem))
5628 emit attached->commit();
5630 q_func()->closeEditor();
5633#if QT_CONFIG(cursor)
5634void QQuickTableViewPrivate::updateCursor()
5636 int row = resizableRows ? hoverHandler->m_row : -1;
5637 int column = resizableColumns ? hoverHandler->m_column : -1;
5639 const auto resizeState = resizeHandler->state();
5640 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5641 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5644 row = resizeHandler->m_row;
5645 column = resizeHandler->m_column;
5648 if (row != -1 || column != -1) {
5649 Qt::CursorShape shape;
5650 if (row != -1 && column != -1)
5651 shape = Qt::SizeFDiagCursor;
5653 shape = Qt::SplitVCursor;
5655 shape = Qt::SplitHCursor;
5658 qApp->changeOverrideCursor(shape);
5660 qApp->setOverrideCursor(shape);
5663 }
else if (m_cursorSet) {
5664 qApp->restoreOverrideCursor();
5665 m_cursorSet =
false;
5670void QQuickTableViewPrivate::updateEditItem()
5672 Q_Q(QQuickTableView);
5677 const QPoint cell = q->cellAtIndex(editIndex);
5678 auto cellItem = q->itemAtCell(cell);
5689 editItem->parentItem()->setX(-editItem->width() - 10000);
5693QQuickTableView::QQuickTableView(QQuickItem *parent)
5694 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5699QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5700 : QQuickFlickable(dd, parent)
5705QQuickTableView::~QQuickTableView()
5707 Q_D(QQuickTableView);
5711 auto syncView_d = d->syncView->d_func();
5712 syncView_d->syncChildren.removeOne(
this);
5713 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5717void QQuickTableView::componentFinalized()
5731 Q_D(QQuickTableView);
5732 qCDebug(lcTableViewDelegateLifecycle);
5736qreal QQuickTableView::minXExtent()
const
5738 return QQuickFlickable::minXExtent() - d_func()->origin.x();
5741qreal QQuickTableView::maxXExtent()
const
5743 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
5746qreal QQuickTableView::minYExtent()
const
5748 return QQuickFlickable::minYExtent() - d_func()->origin.y();
5751qreal QQuickTableView::maxYExtent()
const
5753 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
5756int QQuickTableView::rows()
const
5758 return d_func()->tableSize.height();
5761int QQuickTableView::columns()
const
5763 return d_func()->tableSize.width();
5766qreal QQuickTableView::rowSpacing()
const
5768 return d_func()->cellSpacing.height();
5771void QQuickTableView::setRowSpacing(qreal spacing)
5773 Q_D(QQuickTableView);
5774 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5776 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
5779 d->cellSpacing.setHeight(spacing);
5780 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5781 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5782 emit rowSpacingChanged();
5785qreal QQuickTableView::columnSpacing()
const
5787 return d_func()->cellSpacing.width();
5790void QQuickTableView::setColumnSpacing(qreal spacing)
5792 Q_D(QQuickTableView);
5793 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5795 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
5798 d->cellSpacing.setWidth(spacing);
5799 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5800 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5801 emit columnSpacingChanged();
5804QJSValue QQuickTableView::rowHeightProvider()
const
5806 return d_func()->rowHeightProvider;
5809void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
5811 Q_D(QQuickTableView);
5812 if (provider.strictlyEquals(d->rowHeightProvider))
5815 d->rowHeightProvider = provider;
5816 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5817 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5818 emit rowHeightProviderChanged();
5821QJSValue QQuickTableView::columnWidthProvider()
const
5823 return d_func()->columnWidthProvider;
5826void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
5828 Q_D(QQuickTableView);
5829 if (provider.strictlyEquals(d->columnWidthProvider))
5832 d->columnWidthProvider = provider;
5833 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5834 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5835 emit columnWidthProviderChanged();
5838QVariant QQuickTableView::model()
const
5840 return d_func()->modelImpl();
5843void QQuickTableView::setModel(
const QVariant &newModel)
5845 Q_D(QQuickTableView);
5847 QVariant model = newModel;
5848 if (model.userType() == qMetaTypeId<QJSValue>())
5849 model = model.value<QJSValue>().toVariant();
5851 if (model == d->assignedModel)
5855 d->setModelImpl(model);
5856 if (d->selectionModel)
5857 d->selectionModel->setModel(d->selectionSourceModel());
5860QQmlComponent *QQuickTableView::delegate()
const
5862 return d_func()->assignedDelegate;
5865void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
5867 Q_D(QQuickTableView);
5868 if (newDelegate == d->assignedDelegate)
5871 d->assignedDelegate = newDelegate;
5872 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5874 emit delegateChanged();
5877QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
5879 return d_func()->editTriggers;
5882void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
5884 Q_D(QQuickTableView);
5885 if (editTriggers == d->editTriggers)
5888 d->editTriggers = editTriggers;
5890 emit editTriggersChanged();
5894
5895
5896
5897
5898
5899QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
5901 Q_D(
const QQuickTableView);
5902 return d->assignedDelegateModelAccess;
5905void QQuickTableView::setDelegateModelAccess(
5906 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
5908 Q_D(QQuickTableView);
5909 if (delegateModelAccess == d->assignedDelegateModelAccess)
5912 d->assignedDelegateModelAccess = delegateModelAccess;
5913 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5915 emit delegateModelAccessChanged();
5918bool QQuickTableView::reuseItems()
const
5920 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
5923void QQuickTableView::setReuseItems(
bool reuse)
5925 Q_D(QQuickTableView);
5926 if (reuseItems() == reuse)
5929 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
5931 if (!reuse && d->tableModel) {
5934 d->tableModel->drainReusableItemsPool(0);
5937 emit reuseItemsChanged();
5940void QQuickTableView::setContentWidth(qreal width)
5942 Q_D(QQuickTableView);
5943 d->explicitContentWidth = width;
5944 QQuickFlickable::setContentWidth(width);
5947void QQuickTableView::setContentHeight(qreal height)
5949 Q_D(QQuickTableView);
5950 d->explicitContentHeight = height;
5951 QQuickFlickable::setContentHeight(height);
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971QQuickTableView *QQuickTableView::syncView()
const
5973 return d_func()->assignedSyncView;
5976void QQuickTableView::setSyncView(QQuickTableView *view)
5978 Q_D(QQuickTableView);
5979 if (d->assignedSyncView == view)
5984 d->clearIndexMapping();
5986 d->assignedSyncView = view;
5987 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5989 emit syncViewChanged();
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010Qt::Orientations QQuickTableView::syncDirection()
const
6012 return d_func()->assignedSyncDirection;
6015void QQuickTableView::setSyncDirection(Qt::Orientations direction)
6017 Q_D(QQuickTableView);
6018 if (d->assignedSyncDirection == direction)
6021 d->assignedSyncDirection = direction;
6022 if (d->assignedSyncView)
6023 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6025 emit syncDirectionChanged();
6028QItemSelectionModel *QQuickTableView::selectionModel()
const
6030 return d_func()->selectionModel;
6033void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6035 Q_D(QQuickTableView);
6036 if (d->selectionModel == selectionModel)
6043 if (d->selectionModel) {
6044 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6045 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6046 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6047 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6050 d->selectionModel = selectionModel;
6052 if (d->selectionModel) {
6053 d->selectionModel->setModel(d->selectionSourceModel());
6054 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6055 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6056 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6057 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6060 d->updateSelectedOnAllDelegateItems();
6062 emit selectionModelChanged();
6065bool QQuickTableView::animate()
const
6067 return d_func()->animate;
6070void QQuickTableView::setAnimate(
bool animate)
6072 Q_D(QQuickTableView);
6073 if (d->animate == animate)
6076 d->animate = animate;
6078 d->positionXAnimation.stop();
6079 d->positionYAnimation.stop();
6082 emit animateChanged();
6085bool QQuickTableView::keyNavigationEnabled()
const
6087 return d_func()->keyNavigationEnabled;
6090void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6092 Q_D(QQuickTableView);
6093 if (d->keyNavigationEnabled == enabled)
6096 d->keyNavigationEnabled = enabled;
6098 emit keyNavigationEnabledChanged();
6101bool QQuickTableView::pointerNavigationEnabled()
const
6103 return d_func()->pointerNavigationEnabled;
6106void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6108 Q_D(QQuickTableView);
6109 if (d->pointerNavigationEnabled == enabled)
6112 d->pointerNavigationEnabled = enabled;
6114 emit pointerNavigationEnabledChanged();
6117int QQuickTableView::leftColumn()
const
6119 Q_D(
const QQuickTableView);
6120 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6123int QQuickTableView::rightColumn()
const
6125 Q_D(
const QQuickTableView);
6126 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6129int QQuickTableView::topRow()
const
6131 Q_D(
const QQuickTableView);
6132 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6135int QQuickTableView::bottomRow()
const
6137 Q_D(
const QQuickTableView);
6138 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6141int QQuickTableView::currentRow()
const
6143 return d_func()->currentRow;
6146int QQuickTableView::currentColumn()
const
6148 return d_func()->currentColumn;
6151void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6153 Q_D(QQuickTableView);
6154 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6161 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6162 mode &= AlignTop | AlignBottom | AlignVCenter;
6163 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6164 }
else if (mode == Contain) {
6165 if (row < topRow()) {
6166 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6167 }
else if (row > bottomRow()) {
6168 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6169 }
else if (row == topRow()) {
6170 if (!subRect.isValid()) {
6171 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6173 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6174 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6175 if (subRectTop < d->viewportRect.y())
6176 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6177 else if (subRectBottom > d->viewportRect.bottom())
6178 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6180 }
else if (row == bottomRow()) {
6181 if (!subRect.isValid()) {
6182 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6186 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6187 if (subRectBottom > d->viewportRect.bottom())
6188 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6191 }
else if (mode == Visible) {
6192 if (row < topRow()) {
6193 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6194 }
else if (row > bottomRow()) {
6195 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6196 }
else if (subRect.isValid()) {
6197 if (row == topRow()) {
6198 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6199 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6200 if (subRectBottom < d->viewportRect.top())
6201 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6202 else if (subRectTop > d->viewportRect.bottom())
6203 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6204 }
else if (row == bottomRow()) {
6207 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6208 if (subRectTop > d->viewportRect.bottom())
6209 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6213 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6217void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6219 Q_D(QQuickTableView);
6220 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6227 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6228 mode &= AlignLeft | AlignRight | AlignHCenter;
6229 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6230 }
else if (mode == Contain) {
6231 if (column < leftColumn()) {
6232 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6233 }
else if (column > rightColumn()) {
6234 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6235 }
else if (column == leftColumn()) {
6236 if (!subRect.isValid()) {
6237 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6239 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6240 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6241 if (subRectLeft < d->viewportRect.left())
6242 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6243 else if (subRectRight > d->viewportRect.right())
6244 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6246 }
else if (column == rightColumn()) {
6247 if (!subRect.isValid()) {
6248 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6252 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6253 if (subRectRight > d->viewportRect.right())
6254 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6257 }
else if (mode == Visible) {
6258 if (column < leftColumn()) {
6259 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6260 }
else if (column > rightColumn()) {
6261 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6262 }
else if (subRect.isValid()) {
6263 if (column == leftColumn()) {
6264 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6265 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6266 if (subRectRight < d->viewportRect.left())
6267 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6268 else if (subRectLeft > d->viewportRect.right())
6269 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6270 }
else if (column == rightColumn()) {
6273 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6274 if (subRectLeft > d->viewportRect.right())
6275 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6279 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6283void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6285 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6286 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6287 if (!horizontalMode && !verticalMode) {
6288 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6293 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6295 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6298void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6300 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6301 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6302 if (!horizontalMode && !verticalMode) {
6303 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6308 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6310 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6313#if QT_DEPRECATED_SINCE(6
, 5
)
6314void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6316 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6317 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6318 if (!horizontalMode && !verticalMode) {
6319 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6324 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6326 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6330void QQuickTableView::moveColumn(
int source,
int destination)
6332 Q_D(QQuickTableView);
6333 d->moveSection(source, destination, Qt::Horizontal);
6336void QQuickTableView::moveRow(
int source,
int destination)
6338 Q_D(QQuickTableView);
6339 d->moveSection(source, destination, Qt::Vertical);
6342void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientation orientation)
6344 Q_Q(QQuickTableView);
6346 if (source < 0 || destination < 0 ||
6347 (orientation == Qt::Horizontal &&
6348 (source >= tableSize.width() || destination >= tableSize.width())) ||
6349 (orientation == Qt::Vertical &&
6350 (source >= tableSize.height() || destination >= tableSize.height())))
6353 if (source == destination)
6356 if (m_sectionState != SectionState::Moving) {
6357 m_sectionState = SectionState::Moving;
6359 syncView->d_func()->moveSection(source, destination, orientation);
6362 initializeIndexMapping();
6365 auto &visualIndices = visualIndicesForOrientation(orientation);
6366 auto &logicalIndices = logicalIndicesForOrientation(orientation);
6368 const int logical = logicalIndices.at(source).index;
6369 int visual = source;
6371 if (destination > source) {
6372 while (visual < destination) {
6373 SectionData &visualData = visualIndices[logicalIndices[visual + 1].index];
6374 SectionData &logicalData = logicalIndices[visual];
6375 visualData.prevIndex = visualData.index;
6376 visualData.index = visual;
6377 logicalData.prevIndex = logicalData.index;
6378 logicalData.index = logicalIndices[visual + 1].index;
6382 while (visual > destination) {
6383 SectionData &visualData = visualIndices[logicalIndices[visual - 1].index];
6384 SectionData &logicalData = logicalIndices[visual];
6385 visualData.prevIndex = visualData.index;
6386 visualData.index = visual;
6387 logicalData.prevIndex = logicalData.index;
6388 logicalData.index = logicalIndices[visual - 1].index;
6393 visualIndices[logical].prevIndex = visualIndices[logical].index;
6394 visualIndices[logical].index = destination;
6395 logicalIndices[destination].prevIndex = logicalIndices[destination].index;
6396 logicalIndices[destination].index = logical;
6400 for (
auto syncChild : std::as_const(syncChildren)) {
6401 auto syncChild_d = syncChild->d_func();
6402 if (syncChild_d->m_sectionState != SectionState::Moving &&
6403 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6404 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6405 syncChild_d->moveSection(source, destination, orientation);
6410 scheduleRebuildTable(RebuildOption::ViewportOnly);
6411 m_sectionState = SectionState::Idle;
6414 const int startIndex = (source > destination) ? destination : source;
6415 const int endIndex = (source > destination) ? source : destination;
6416 const auto &logicalDataIndices = syncView
6417 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6418 : logicalIndicesForOrientation(orientation);
6419 const auto &visualDataIndices = syncView
6420 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6421 : visualIndicesForOrientation(orientation);
6422 for (
int index = startIndex; index <= endIndex; index++) {
6423 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6424 if (orientation == Qt::Horizontal)
6425 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6427 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6432void QQuickTableView::clearColumnReordering()
6434 Q_D(QQuickTableView);
6435 d->clearSection(Qt::Horizontal);
6438void QQuickTableView::clearRowReordering()
6440 Q_D(QQuickTableView);
6441 d->clearSection(Qt::Vertical);
6444void QQuickTableViewPrivate::clearSection(Qt::Orientation orientation)
6446 Q_Q(QQuickTableView);
6448 const auto &oldLogicalIndices = syncView
6449 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6450 : logicalIndicesForOrientation(orientation);
6451 const auto &oldVisualIndices = syncView
6452 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6453 : visualIndicesForOrientation(orientation);
6456 syncView->d_func()->clearSection(orientation);
6459 logicalIndicesForOrientation(orientation).clear();
6460 visualIndicesForOrientation(orientation).clear();
6461 scheduleRebuildTable(RebuildOption::ViewportOnly);
6465 for (
int index = 0; index <
int(oldLogicalIndices.size()); index++) {
6466 const auto &logicalDataIndices = oldLogicalIndices;
6467 const auto &visualDataIndices = oldVisualIndices;
6468 if (logicalDataIndices[index].index != index) {
6469 const int currentIndex = logicalDataIndices[index].index;
6470 if (orientation == Qt::Horizontal)
6471 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6473 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6478void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6480 if (!modelIndex.isValid())
6483 const int cellIndex = modelIndexToCellIndex(modelIndex);
6484 if (!loadedItems.contains(cellIndex))
6486 const QPoint cell = cellAtModelIndex(cellIndex);
6487 QQuickItem *item = loadedTableItem(cell)->item;
6488 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6491QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6493 Q_D(
const QQuickTableView);
6494 const int modelIndex = d->modelIndexAtCell(cell);
6495 if (!d->loadedItems.contains(modelIndex))
6497 return d->loadedItems.value(modelIndex)->item;
6500#if QT_DEPRECATED_SINCE(6
, 5
)
6501QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6503 return itemAtCell(QPoint(column, row));
6507QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6509 Q_D(
const QQuickTableView);
6510 const int serializedIndex = d->modelIndexToCellIndex(index);
6511 if (!d->loadedItems.contains(serializedIndex))
6513 return d->loadedItems.value(serializedIndex)->item;
6516#if QT_DEPRECATED_SINCE(6
, 4
)
6517QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6519 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6522QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6524 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6528QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6530 return cellAtPosition(QPoint(x, y), includeSpacing);
6533QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6535 Q_D(
const QQuickTableView);
6537 if (!d->loadedTableOuterRect.contains(position))
6538 return QPoint(-1, -1);
6540 const qreal hSpace = d->cellSpacing.width();
6541 const qreal vSpace = d->cellSpacing.height();
6542 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6543 qreal currentRowEnd = d->loadedTableOuterRect.y();
6545 int foundColumn = -1;
6548 for (
const int column : d->loadedColumns) {
6549 currentColumnEnd += d->getEffectiveColumnWidth(column);
6550 if (position.x() < currentColumnEnd) {
6551 foundColumn = column;
6554 currentColumnEnd += hSpace;
6555 if (!includeSpacing && position.x() < currentColumnEnd) {
6557 return QPoint(-1, -1);
6558 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6559 foundColumn = column;
6564 for (
const int row : d->loadedRows) {
6565 currentRowEnd += d->getEffectiveRowHeight(row);
6566 if (position.y() < currentRowEnd) {
6570 currentRowEnd += vSpace;
6571 if (!includeSpacing && position.y() < currentRowEnd) {
6573 return QPoint(-1, -1);
6575 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6581 return QPoint(foundColumn, foundRow);
6584bool QQuickTableView::isColumnLoaded(
int column)
const
6586 Q_D(
const QQuickTableView);
6587 if (!d->loadedColumns.contains(column))
6590 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6593 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6600bool QQuickTableView::isRowLoaded(
int row)
const
6602 Q_D(
const QQuickTableView);
6603 if (!d->loadedRows.contains(row))
6606 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6609 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6616qreal QQuickTableView::columnWidth(
int column)
const
6618 Q_D(
const QQuickTableView);
6619 if (!isColumnLoaded(column))
6622 return d->getEffectiveColumnWidth(column);
6625qreal QQuickTableView::rowHeight(
int row)
const
6627 Q_D(
const QQuickTableView);
6628 if (!isRowLoaded(row))
6631 return d->getEffectiveRowHeight(row);
6634qreal QQuickTableView::implicitColumnWidth(
int column)
const
6636 Q_D(
const QQuickTableView);
6637 if (!isColumnLoaded(column))
6640 return d->sizeHintForColumn(column);
6643qreal QQuickTableView::implicitRowHeight(
int row)
const
6645 Q_D(
const QQuickTableView);
6646 if (!isRowLoaded(row))
6649 return d->sizeHintForRow(row);
6652void QQuickTableView::setColumnWidth(
int column, qreal size)
6654 Q_D(QQuickTableView);
6656 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6660 if (d->syncHorizontally) {
6661 d->syncView->setColumnWidth(column, size);
6665 if (qFuzzyCompare(explicitColumnWidth(column), size))
6669 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6671 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6673 if (d->loadedItems.isEmpty())
6676 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6677 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6678 d->forceLayout(
false);
6681void QQuickTableView::clearColumnWidths()
6683 Q_D(QQuickTableView);
6685 if (d->syncHorizontally) {
6686 d->syncView->clearColumnWidths();
6690 if (d->explicitColumnWidths.isEmpty())
6693 d->explicitColumnWidths.clear();
6694 d->forceLayout(
false);
6697qreal QQuickTableView::explicitColumnWidth(
int column)
const
6699 Q_D(
const QQuickTableView);
6701 if (d->syncHorizontally)
6702 return d->syncView->explicitColumnWidth(column);
6704 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6705 if (it != d->explicitColumnWidths.constEnd())
6710void QQuickTableView::setRowHeight(
int row, qreal size)
6712 Q_D(QQuickTableView);
6714 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
6718 if (d->syncVertically) {
6719 d->syncView->setRowHeight(row, size);
6723 if (qFuzzyCompare(explicitRowHeight(row), size))
6727 d->explicitRowHeights.remove(d->logicalRowIndex(row));
6729 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
6731 if (d->loadedItems.isEmpty())
6734 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
6735 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
6736 d->forceLayout(
false);
6739void QQuickTableView::clearRowHeights()
6741 Q_D(QQuickTableView);
6743 if (d->syncVertically) {
6744 d->syncView->clearRowHeights();
6748 if (d->explicitRowHeights.isEmpty())
6751 d->explicitRowHeights.clear();
6752 d->forceLayout(
false);
6755qreal QQuickTableView::explicitRowHeight(
int row)
const
6757 Q_D(
const QQuickTableView);
6759 if (d->syncVertically)
6760 return d->syncView->explicitRowHeight(row);
6762 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
6763 if (it != d->explicitRowHeights.constEnd())
6768QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
6770 Q_D(
const QQuickTableView);
6771 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
6774 auto const qaim = d->model->abstractItemModel();
6778 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
6781QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
6783 if (!index.isValid() || index.parent().isValid())
6785 Q_D(
const QQuickTableView);
6786 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
6789#if QT_DEPRECATED_SINCE(6
, 4
)
6790QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
6792 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
6798 return modelIndex({row, column});
6800 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
6801 "Use index(row, column) instead. For more information, see "
6802 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
6803 return modelIndex({column, row});
6808QModelIndex QQuickTableView::index(
int row,
int column)
const
6810 return modelIndex({column, row});
6813int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
6815 return cellAtIndex(index).y();
6818int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
6820 return cellAtIndex(index).x();
6823void QQuickTableView::forceLayout()
6825 d_func()->forceLayout(
true);
6828void QQuickTableView::edit(
const QModelIndex &index)
6830 Q_D(QQuickTableView);
6832 if (!d->canEdit(index,
true))
6835 if (d->editIndex == index)
6841 if (!d->editModel) {
6842 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
6843 d->editModel->useImportVersion(d->resolveImportVersion());
6844 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
this,
6845 [
this, d] (
int serializedModelIndex, QObject *object) {
6851 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
6852 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
6853 d->editItem = qmlobject_cast<QQuickItem*>(object);
6857 d->initItemCallback(serializedModelIndex, object);
6858 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
6860 d->editItem->setParentItem(cellItem);
6867 if (d->selectionModel)
6868 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
6871 d->closeEditorAndCommit();
6873 const auto cellItem = itemAtCell(cellAtIndex(index));
6875 const auto attached = d->getAttachedObject(cellItem);
6878 d->editModel->setModel(d->tableModel->model());
6879 d->editModel->setDelegate(attached->editDelegate());
6881 const int cellIndex = d->getEditCellIndex(index);
6882 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
6884 d->editIndex = QModelIndex();
6885 d->editItem =
nullptr;
6886 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
6893 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
6894 d->editItem =
nullptr;
6895 d->editIndex = QModelIndex();
6896 d->editModel->release(object, QQmlInstanceModel::NotReusable);
6902 d->model->object(cellIndex, QQmlIncubator::Synchronous);
6905 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
6908 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
6909 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
6912void QQuickTableView::closeEditor()
6914 Q_D(QQuickTableView);
6919 QQuickItem *cellItem = d->editItem->parentItem();
6920 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
6921 d->editItem =
nullptr;
6924 const int cellIndex = d->getEditCellIndex(d->editIndex);
6925 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
6927 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
6929 if (d->editIndex.isValid()) {
6932 d->editIndex = QModelIndex();
6936QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
6938 return new QQuickTableViewAttached(obj);
6941void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
6943 Q_D(QQuickTableView);
6944 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
6946 if (d->tableModel) {
6949 d->tableModel->drainReusableItemsPool(0);
6952 d->forceLayout(
false);
6955void QQuickTableView::viewportMoved(Qt::Orientations orientation)
6957 Q_D(QQuickTableView);
6963 QQuickFlickable::viewportMoved(orientation);
6964 if (d->inSetLocalViewportPos)
6971 d->syncViewportPosRecursive();
6973 auto rootView = d->rootSyncView();
6974 auto rootView_d = rootView->d_func();
6976 rootView_d->scheduleRebuildIfFastFlick();
6978 if (!rootView_d->polishScheduled) {
6979 if (rootView_d->scheduledRebuildOptions) {
6986 const bool updated = rootView->d_func()->updateTableRecursive();
6996void QQuickTableView::keyPressEvent(QKeyEvent *e)
6998 Q_D(QQuickTableView);
7000 if (!d->keyNavigationEnabled) {
7001 QQuickFlickable::keyPressEvent(e);
7005 if (d->tableSize.isEmpty())
7008 if (d->editIndex.isValid()) {
7014 if (d->setCurrentIndexFromKeyEvent(e))
7017 if (d->editFromKeyEvent(e))
7020 QQuickFlickable::keyPressEvent(e);
7023bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
7025 Q_D(QQuickTableView);
7027 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
7030 return QQuickFlickable::eventFilter(obj, event);
7033 switch (event->type()) {
7034 case QEvent::KeyPress: {
7035 Q_ASSERT(d->editItem);
7036 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7037 switch (keyEvent->key()) {
7039 case Qt::Key_Return:
7040 d->closeEditorAndCommit();
7043 case Qt::Key_Backtab:
7044 if (activeFocusOnTab()) {
7045 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7046 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7047 if (d->canEdit(currentIndex,
false))
7053 case Qt::Key_Escape:
7058 case QEvent::FocusOut:
7061 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7062 d->closeEditorAndCommit();
7068 return QQuickFlickable::eventFilter(obj, event);
7071bool QQuickTableView::alternatingRows()
const
7073 return d_func()->alternatingRows;
7076void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7078 Q_D(QQuickTableView);
7079 if (d->alternatingRows == alternatingRows)
7082 d->alternatingRows = alternatingRows;
7083 emit alternatingRowsChanged();
7086QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7088 return d_func()->selectionBehavior;
7091void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7093 Q_D(QQuickTableView);
7094 if (d->selectionBehavior == selectionBehavior)
7097 d->selectionBehavior = selectionBehavior;
7098 emit selectionBehaviorChanged();
7101QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7103 return d_func()->selectionMode;
7106void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7108 Q_D(QQuickTableView);
7109 if (d->selectionMode == selectionMode)
7112 d->selectionMode = selectionMode;
7113 emit selectionModeChanged();
7116bool QQuickTableView::resizableColumns()
const
7118 return d_func()->resizableColumns;
7121void QQuickTableView::setResizableColumns(
bool enabled)
7123 Q_D(QQuickTableView);
7124 if (d->resizableColumns == enabled)
7127 d->resizableColumns = enabled;
7128 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7129 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7131 emit resizableColumnsChanged();
7134bool QQuickTableView::resizableRows()
const
7136 return d_func()->resizableRows;
7139void QQuickTableView::setResizableRows(
bool enabled)
7141 Q_D(QQuickTableView);
7142 if (d->resizableRows == enabled)
7145 d->resizableRows = enabled;
7146 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7147 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7149 emit resizableRowsChanged();
7154 : QQuickHoverHandler(view->contentItem())
7158 connect(
this, &QQuickHoverHandler::hoveredChanged,
this, [
this] {
7163#if QT_CONFIG(cursor)
7164 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7165 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7166 tableViewPrivate->updateCursor();
7173 QQuickHoverHandler::handleEventPoint(event, point);
7175 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7176#if QT_CONFIG(cursor)
7177 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7180 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7181 const auto item = tableView->itemAtCell(cell);
7185#if QT_CONFIG(cursor)
7186 tableViewPrivate->updateCursor();
7191 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7192 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7193 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7194 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7195 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7196#if QT_CONFIG(cursor)
7197 tableViewPrivate->updateCursor();
7208 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7213 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7217 if (event->type() == QEvent::Type::Wheel)
7222 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7223 return !tableView->isMoving();
7232 setObjectName(
"tableViewResizeHandler");
7236 , QPointingDevice::GrabTransition transition
7238 , QEventPoint &point)
7240 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7242 switch (transition) {
7243 case QPointingDevice::GrabPassive:
7244 case QPointingDevice::GrabExclusive:
7246 case QPointingDevice::UngrabPassive:
7247 case QPointingDevice::UngrabExclusive:
7248 case QPointingDevice::CancelGrabPassive:
7249 case QPointingDevice::CancelGrabExclusive:
7250 case QPointingDevice::OverrideGrabPassive:
7251 if (m_state == DraggingStarted || m_state == Dragging) {
7252 m_state = DraggingFinished;
7253 updateDrag(ev, point);
7261 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7262 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7263 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7270 updateDrag(event, point);
7275 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7276 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7278 if (m_state == DraggingFinished)
7279 m_state = Listening;
7281 if (point.state() == QEventPoint::Pressed) {
7282 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7283 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7284 if (m_row != -1 || m_column != -1)
7286 }
else if (point.state() == QEventPoint::Released) {
7287 if (m_state == DraggingStarted || m_state == Dragging)
7288 m_state = DraggingFinished;
7290 m_state = Listening;
7291 }
else if (point.state() == QEventPoint::Updated) {
7296 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7297 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7298 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7299 if (dragDist > qApp->styleHints()->startDragDistance())
7300 m_state = DraggingStarted;
7302 case DraggingStarted:
7307 case DraggingFinished:
7317 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7318#if QT_CONFIG(cursor)
7319 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7326 setPassiveGrab(event, point,
true);
7330 tableView->setFiltersChildMouseEvents(
false);
7331#if QT_CONFIG(cursor)
7332 tableViewPrivate->setActivePointerHandler(
this);
7335 case DraggingStarted:
7336 setExclusiveGrab(event, point,
true);
7337 m_columnStartX = point.position().x();
7338 m_columnStartWidth = tableView->columnWidth(m_column);
7339 m_rowStartY = point.position().y();
7340 m_rowStartHeight = tableView->rowHeight(m_row);
7341#if QT_CONFIG(cursor)
7342 tableViewPrivate->updateCursor();
7346 const qreal distX = point.position().x() - m_columnStartX;
7347 const qreal distY = point.position().y() - m_rowStartY;
7349 tableView->setColumnWidth(
m_column, qMax(0.001, m_columnStartWidth + distX));
7351 tableView->setRowHeight(
m_row, qMax(0.001, m_rowStartHeight + distY));
7353 case DraggingFinished: {
7354 tableView->setFiltersChildMouseEvents(
true);
7355#if QT_CONFIG(cursor)
7356 tableViewPrivate->setActivePointerHandler(
nullptr);
7357 tableViewPrivate->updateCursor();
7364#if QT_CONFIG(quick_draganddrop)
7366QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7367 : QQuickTableViewPointerHandler(view)
7369 setObjectName(
"tableViewDragHandler");
7372QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7377void QQuickTableViewSectionDragHandler::resetDragData()
7379 if (m_state != Listening) {
7380 m_state = Listening;
7381 resetSectionOverlay();
7384 if (m_grabResult.data())
7385 m_grabResult.data()->disconnect();
7386 if (!m_drag.isNull()) {
7387 m_drag->disconnect();
7390 if (!m_dropArea.isNull()) {
7391 m_dropArea->disconnect();
7394 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7395 tableView->setFiltersChildMouseEvents(
true);
7399void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7401 if (m_destination != -1) {
7402 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7403 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7404 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7405 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7406 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7411void QQuickTableViewSectionDragHandler::grabSection()
7414 QPixmap pixmap(m_grabResult->image().size());
7415 pixmap.fill(Qt::transparent);
7416 QPainter painter(&pixmap);
7417 painter.setOpacity(0.6);
7418 painter.drawImage(0, 0, m_grabResult->image());
7422 auto *mimeData =
new QMimeData();
7423 mimeData->setImageData(pixmap);
7424 m_drag->setMimeData(mimeData);
7425 m_drag->setPixmap(pixmap);
7428void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7432 if (m_state == Dragging) {
7433 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7434 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7435 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7436 m_state = DraggingFinished;
7437 resetSectionOverlay();
7438 if (m_scrollTimer.isActive())
7439 m_scrollTimer.stop();
7444void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7448 if (m_state == Dragging) {
7449 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7450 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7451 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7452 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7454 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7455 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7456 if (newDestination != m_destination) {
7458 resetSectionOverlay();
7460 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7461 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7462 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7463 m_destination = newDestination;
7467 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7468 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7469 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7470 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7471 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7472 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7473 if (useStartPos || useEndPos) {
7474 if (!m_scrollTimer.isActive()) {
7475 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7476 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7477 m_scrollTimer.start(1);
7480 if (m_scrollTimer.isActive())
7481 m_scrollTimer.stop();
7486void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7490 if (action == Qt::IgnoreAction) {
7491 resetSectionOverlay();
7492 if (m_scrollTimer.isActive())
7493 m_scrollTimer.stop();
7497void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7499 QQuickSinglePointHandler::handleEventPoint(event, point);
7501 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7502 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7503 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7504 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7507 if (m_state == DraggingFinished) {
7508 if (m_scrollTimer.isActive())
7509 m_scrollTimer.stop();
7513 if (point.state() == QEventPoint::Pressed) {
7517 setPassiveGrab(event, point,
true);
7521 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7522 tableView->setFiltersChildMouseEvents(
false);
7524 }
else if (point.state() == QEventPoint::Released) {
7526 if (m_scrollTimer.isActive())
7527 m_scrollTimer.stop();
7529 }
else if (point.state() == QEventPoint::Updated) {
7531 const qreal distX = point.position().x() - point.pressPosition().x();
7532 const qreal distY = point.position().y() - point.pressPosition().y();
7533 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7534 if (dragDist > qApp->styleHints()->startDragDistance()) {
7538 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7539 auto *item = tableView->itemAtCell(cell);
7542 if (m_drag.isNull()) {
7543 m_drag =
new QDrag(item);
7544 connect(m_drag.data(), &QDrag::actionChanged,
this,
7545 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7548 QObject::connect(&m_scrollTimer, &QTimer::timeout,
this, [&]{
7549 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7550 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7551 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7552 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7555 if (m_dropArea.isNull()) {
7556 m_dropArea =
new QQuickDropArea(tableView);
7557 m_dropArea->setSize(tableView->size());
7558 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7559 &QQuickTableViewSectionDragHandler::handleDrag);
7560 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7561 &QQuickTableViewSectionDragHandler::handleDrop);
7564 m_grabResult = item->grabToImage();
7565 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7566 &QQuickTableViewSectionDragHandler::grabSection);
7568 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7569 m_state = DraggingStarted;
7571 tableViewPrivate->setActivePointerHandler(
this);
7575 case DraggingStarted: {
7576 if (m_drag && m_drag->mimeData()) {
7577 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7579 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7581 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7585 if (m_state == Dragging)
7588 tableViewPrivate->setActivePointerHandler(
nullptr);
7602void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7604 if (!sectionDragHandler) {
7605 Q_Q(QQuickTableView);
7606 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7607 sectionDragHandler->setSectionOrientation(orientation);
7611void QQuickTableViewPrivate::destroySectionDragHandler()
7613 if (sectionDragHandler) {
7614 delete sectionDragHandler;
7615 sectionDragHandler =
nullptr;
7620void QQuickTableViewPrivate::initializeIndexMapping()
7622 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7623 visualIndex.resize(size);
7624 logicalIndex.resize(size);
7625 for (
int index = 0; index < size; ++index)
7626 visualIndex[index].index = logicalIndex[index].index = index;
7629 if (horizontalVisualIndices.size() != size_t(tableSize.width())
7630 || horizontalLogicalIndices.size() != size_t(tableSize.width()))
7631 initIndices(horizontalVisualIndices, horizontalLogicalIndices, tableSize.width());
7633 if (verticalVisualIndices.size() != size_t(tableSize.height())
7634 || verticalLogicalIndices.size() != size_t(tableSize.height()))
7635 initIndices(verticalVisualIndices, verticalLogicalIndices, tableSize.height());
7638void QQuickTableViewPrivate::clearIndexMapping()
7640 horizontalLogicalIndices.clear();
7641 horizontalVisualIndices.clear();
7643 verticalLogicalIndices.clear();
7644 verticalVisualIndices.clear();
7647int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7650 return syncView->d_func()->logicalRowIndex(visualIndex);
7651 if (verticalLogicalIndices.empty() || visualIndex < 0)
7653 return verticalLogicalIndices.at(visualIndex).index;
7656int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7659 return syncView->d_func()->logicalColumnIndex(visualIndex);
7660 if (horizontalLogicalIndices.empty() || visualIndex < 0)
7662 return horizontalLogicalIndices.at(visualIndex).index;
7665int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7668 return syncView->d_func()->visualRowIndex(logicalIndex);
7669 if (verticalVisualIndices.empty() || logicalIndex < 0)
7670 return logicalIndex;
7671 return verticalVisualIndices.at(logicalIndex).index;
7674int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7677 return syncView->d_func()->visualColumnIndex(logicalIndex);
7678 if (horizontalVisualIndices.empty() || logicalIndex < 0)
7679 return logicalIndex;
7680 return horizontalVisualIndices.at(logicalIndex).index;
7683int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7687 const bool hasProxyModel = (modelImpl() != assignedModel);
7688 return modelIndexToCellIndex(index, hasProxyModel);
7694 : QQuickTapHandler(view->contentItem())
7696 setObjectName(
"tableViewTapHandler");
7701 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7702 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7703 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
7708#include "moc_qquicktableview_p.cpp"
7709#include "moc_qquicktableview_p_p.cpp"
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override
bool isHoveringGrid() const
QQuickTableViewPointerHandler(QQuickTableView *view)
bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override
Returns true if the given point (as part of event) could be relevant at all to this handler,...
void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *ev, QEventPoint &point) override
Notification that the grab has changed in some way which is relevant to this handler.
void updateState(QEventPoint &point)
void updateDrag(QPointerEvent *event, QEventPoint &point)
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override
bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override
Returns true if the given point (as part of event) could be relevant at all to this handler,...
QDebug operator<<(QDebug debug, QDir::Filters filters)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
#define TV_REBUILDOPTION(OPTION)
static const Qt::Edge allTableEdges[]
#define Q_TABLEVIEW_ASSERT(cond, output)
#define Q_TABLEVIEW_UNREACHABLE(output)
#define TV_REBUILDSTATE(STATE)
static const char * kRequiredProperty_current
static const char * kRequiredProperty_tableView
static const char * kRequiredProperty_editing
static const char * kRequiredProperty_selected
static const char * kRequiredProperty_containsDrag
static const char * kRequiredProperties