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;
2829 const int modelRow = isTransposed ? logicalColumnIndex(cell.y()) : logicalRowIndex(cell.y());
2830 const int modelColumn = isTransposed ? logicalRowIndex(cell.x()) : logicalColumnIndex(cell.x());
2831 const int modelIndex = modelIndexAtCell(QPoint(modelColumn, modelRow));
2833 QObject *object = model->object(modelIndex, incubationMode);
2836 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2842 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2843 object =
new QQuickItem();
2847 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2851 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2852 model->release(object);
2853 item =
new QQuickItem();
2856 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2857 if (anchors && anchors->activeDirections())
2858 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2859 <<
". Use implicitWidth and implicitHeight instead.";
2866 item->setImplicitWidth(kDefaultColumnWidth);
2867 item->setImplicitHeight(kDefaultRowHeight);
2868 item->setParentItem(q->contentItem());
2872 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
2873 fxTableItem->setVisible(
false);
2874 fxTableItem->cell = cell;
2875 fxTableItem->index = modelIndex;
2879FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2884 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
2886 incubationMode = QQmlIncubator::Asynchronous;
2891 QScopedValueRollback guard(blockItemCreatedCallback,
true);
2892 auto item = createFxTableItem(cell, incubationMode);
2893 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
2897void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
2900 auto const tmpList = loadedItems;
2901 loadedItems.clear();
2902 for (FxTableItem *item : tmpList)
2903 releaseItem(item, reusableFlag);
2906void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
2908 Q_Q(QQuickTableView);
2911 auto item = fxTableItem->item;
2913 if (fxTableItem->ownItem) {
2917 auto releaseFlag = model->release(item, reusableFlag);
2918 if (releaseFlag == QQmlInstanceModel::Pooled) {
2919 fxTableItem->setVisible(
false);
2923 if (QQuickWindow *window = item->window()) {
2924 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
2926 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
2928 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
2929 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
2939void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
2941 const int modelIndex = modelIndexAtCell(cell);
2943 releaseItem(loadedItems.take(modelIndex), reusableFlag);
2945 tableModel->commitReleasedItems();
2948bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2950 switch (tableEdge) {
2952 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
2954 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
2956 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
2957 case Qt::BottomEdge:
2958 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
2964bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2970 switch (tableEdge) {
2972 if (loadedColumns.count() <= 1)
2974 if (positionXAnimation.isRunning()) {
2975 const qreal to = positionXAnimation.to().toFloat();
2976 if (to < viewportRect.x())
2979 return loadedTableInnerRect.left() <= fillRect.left();
2981 if (loadedColumns.count() <= 1)
2983 if (positionXAnimation.isRunning()) {
2984 const qreal to = positionXAnimation.to().toFloat();
2985 if (to > viewportRect.x())
2988 return loadedTableInnerRect.right() >= fillRect.right();
2990 if (loadedRows.count() <= 1)
2992 if (positionYAnimation.isRunning()) {
2993 const qreal to = positionYAnimation.to().toFloat();
2994 if (to < viewportRect.y())
2997 return loadedTableInnerRect.top() <= fillRect.top();
2998 case Qt::BottomEdge:
2999 if (loadedRows.count() <= 1)
3001 if (positionYAnimation.isRunning()) {
3002 const qreal to = positionYAnimation.to().toFloat();
3003 if (to > viewportRect.y())
3006 return loadedTableInnerRect.bottom() >= fillRect.bottom();
3012Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
3014 for (Qt::Edge edge : allTableEdges) {
3015 if (!canLoadTableEdge(edge, rect))
3017 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3018 if (nextIndex == kEdgeIndexAtEnd)
3026Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3028 for (Qt::Edge edge : allTableEdges) {
3029 if (canUnloadTableEdge(edge, rect))
3035qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3039 auto const cellItem = loadedTableItem(cell)->item;
3040 return cellItem->implicitWidth();
3043qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3047 auto const cellItem = loadedTableItem(cell)->item;
3048 return cellItem->implicitHeight();
3051qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3054 qreal columnWidth = 0;
3055 for (
const int row : loadedRows)
3056 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3061qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3064 qreal rowHeight = 0;
3065 for (
const int column : loadedColumns)
3066 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3070QSize QQuickTableViewPrivate::calculateTableSize()
3074 size = QSize(tableModel->columns(), tableModel->rows());
3076 size = QSize(1, model->count());
3078 return isTransposed ? size.transposed() : size;
3081qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3088 const qreal explicitColumnWidth = getColumnWidth(column);
3089 if (explicitColumnWidth >= 0)
3090 return explicitColumnWidth;
3092 if (syncHorizontally) {
3093 if (syncView->d_func()->loadedColumns.contains(column))
3094 return syncView->d_func()->getColumnLayoutWidth(column);
3102 qreal columnWidth = sizeHintForColumn(column);
3104 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3105 if (!layoutWarningIssued) {
3106 layoutWarningIssued =
true;
3107 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3109 columnWidth = kDefaultColumnWidth;
3115qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3119 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3122qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3126 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3129qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3133 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3136qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3140 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3143qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3150 const qreal explicitRowHeight = getRowHeight(row);
3151 if (explicitRowHeight >= 0)
3152 return explicitRowHeight;
3154 if (syncVertically) {
3155 if (syncView->d_func()->loadedRows.contains(row))
3156 return syncView->d_func()->getRowLayoutHeight(row);
3164 qreal rowHeight = sizeHintForRow(row);
3166 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3167 if (!layoutWarningIssued) {
3168 layoutWarningIssued =
true;
3169 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3171 rowHeight = kDefaultRowHeight;
3177qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3183 Q_Q(
const QQuickTableView);
3185 const int noExplicitColumnWidth = -1;
3187 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3188 return cachedColumnWidth.size;
3190 if (syncHorizontally)
3191 return syncView->d_func()->getColumnWidth(column);
3193 if (columnWidthProvider.isUndefined()) {
3197 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3198 if (explicitColumnWidth >= 0)
3199 return explicitColumnWidth;
3200 return noExplicitColumnWidth;
3203 qreal columnWidth = noExplicitColumnWidth;
3205 if (columnWidthProvider.isCallable()) {
3206 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3207 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3208 if (qIsNaN(columnWidth) || columnWidth < 0)
3209 columnWidth = noExplicitColumnWidth;
3211 if (!layoutWarningIssued) {
3212 layoutWarningIssued =
true;
3213 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3215 columnWidth = noExplicitColumnWidth;
3218 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3219 cachedColumnWidth.size = columnWidth;
3223qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3229 Q_Q(
const QQuickTableView);
3231 const int noExplicitRowHeight = -1;
3233 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3234 return cachedRowHeight.size;
3237 return syncView->d_func()->getRowHeight(row);
3239 if (rowHeightProvider.isUndefined()) {
3243 qreal explicitRowHeight = q->explicitRowHeight(row);
3244 if (explicitRowHeight >= 0)
3245 return explicitRowHeight;
3246 return noExplicitRowHeight;
3249 qreal rowHeight = noExplicitRowHeight;
3251 if (rowHeightProvider.isCallable()) {
3252 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3253 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3254 if (qIsNaN(rowHeight) || rowHeight < 0)
3255 rowHeight = noExplicitRowHeight;
3257 if (!layoutWarningIssued) {
3258 layoutWarningIssued =
true;
3259 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3261 rowHeight = noExplicitRowHeight;
3264 cachedRowHeight.startIndex = logicalRowIndex(row);
3265 cachedRowHeight.size = rowHeight;
3269qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3271 Q_Q(QQuickTableView);
3274 const int columnX = getEffectiveColumnX(column);
3276 if (subRect.isValid()) {
3277 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3280 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3283 if (alignment & Qt::AlignLeft) {
3284 contentX = columnX + subRect.x() + offset;
3285 }
else if (alignment & Qt::AlignRight) {
3286 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3287 }
else if (alignment & Qt::AlignHCenter) {
3288 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3289 contentX = columnX + subRect.x() - centerDistance + offset;
3292 const int columnWidth = getEffectiveColumnWidth(column);
3293 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3294 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3296 if (alignment & Qt::AlignLeft) {
3297 contentX = columnX + offset;
3298 }
else if (alignment & Qt::AlignRight) {
3299 contentX = columnX + columnWidth - viewportRect.width() + offset;
3300 }
else if (alignment & Qt::AlignHCenter) {
3301 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3302 contentX = columnX - centerDistance + offset;
3307 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3312qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3314 Q_Q(QQuickTableView);
3317 const int rowY = getEffectiveRowY(row);
3319 if (subRect.isValid()) {
3320 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3323 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3326 if (alignment & Qt::AlignTop) {
3327 contentY = rowY + subRect.y() + offset;
3328 }
else if (alignment & Qt::AlignBottom) {
3329 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3330 }
else if (alignment & Qt::AlignVCenter) {
3331 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3332 contentY = rowY + subRect.y() - centerDistance + offset;
3335 const int rowHeight = getEffectiveRowHeight(row);
3336 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3337 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3339 if (alignment & Qt::AlignTop) {
3340 contentY = rowY + offset;
3341 }
else if (alignment & Qt::AlignBottom) {
3342 contentY = rowY + rowHeight - viewportRect.height() + offset;
3343 }
else if (alignment & Qt::AlignVCenter) {
3344 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3345 contentY = rowY - centerDistance + offset;
3350 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3355bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3359 return qFuzzyIsNull(getColumnWidth(column));
3362bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3366 return qFuzzyIsNull(getRowHeight(row));
3369void QQuickTableViewPrivate::relayoutTableItems()
3371 qCDebug(lcTableViewDelegateLifecycle);
3373 if (viewportRect.isEmpty()) {
3375 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3379 qreal nextColumnX = loadedTableOuterRect.x();
3380 qreal nextRowY = loadedTableOuterRect.y();
3382 for (
const int column : loadedColumns) {
3384 const qreal width = getColumnLayoutWidth(column);
3386 for (
const int row : loadedRows) {
3387 auto item = loadedTableItem(QPoint(column, row));
3388 QRectF geometry = item->geometry();
3389 geometry.moveLeft(nextColumnX);
3390 geometry.setWidth(width);
3391 item->setGeometry(geometry);
3395 nextColumnX += width + cellSpacing.width();
3398 for (
const int row : loadedRows) {
3400 const qreal height = getRowLayoutHeight(row);
3402 for (
const int column : loadedColumns) {
3403 auto item = loadedTableItem(QPoint(column, row));
3404 QRectF geometry = item->geometry();
3405 geometry.moveTop(nextRowY);
3406 geometry.setHeight(height);
3407 item->setGeometry(geometry);
3411 nextRowY += height + cellSpacing.height();
3414 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3415 for (
const int column : loadedColumns) {
3416 for (
const int row : loadedRows) {
3417 QPoint cell = QPoint(column, row);
3418 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3424void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3426 int columnThatNeedsLayout;
3427 int neighbourColumn;
3431 if (tableEdge == Qt::LeftEdge) {
3432 columnThatNeedsLayout = leftColumn();
3433 neighbourColumn = loadedColumns.values().at(1);
3434 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3435 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3436 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3438 columnThatNeedsLayout = rightColumn();
3439 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3440 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3441 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3442 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3445 for (
const int row : loadedRows) {
3446 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3447 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3448 const qreal rowY = neighbourItem->geometry().y();
3449 const qreal rowHeight = neighbourItem->geometry().height();
3451 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3452 fxTableItem->setVisible(
true);
3454 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3458void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3460 int rowThatNeedsLayout;
3463 if (tableEdge == Qt::TopEdge) {
3464 rowThatNeedsLayout = topRow();
3465 neighbourRow = loadedRows.values().at(1);
3467 rowThatNeedsLayout = bottomRow();
3468 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3473 for (
const int column : loadedColumns) {
3474 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3475 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3476 const qreal columnX = neighbourItem->geometry().x();
3477 const qreal columnWidth = neighbourItem->geometry().width();
3478 fxTableItem->item->setX(columnX);
3479 fxTableItem->item->setWidth(columnWidth);
3484 if (tableEdge == Qt::TopEdge) {
3485 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3486 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3487 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3489 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3490 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3491 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3494 for (
const int column : loadedColumns) {
3495 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3496 fxTableItem->item->setY(rowY);
3497 fxTableItem->item->setHeight(rowHeight);
3498 fxTableItem->setVisible(
true);
3500 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3504void QQuickTableViewPrivate::layoutTopLeftItem()
3506 const QPoint cell(loadRequest.column(), loadRequest.row());
3507 auto topLeftItem = loadedTableItem(cell);
3508 auto item = topLeftItem->item;
3510 item->setPosition(loadRequest.startPosition());
3511 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3512 topLeftItem->setVisible(
true);
3513 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3516void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3518 if (loadRequest.edge() == Qt::Edge(0)) {
3520 layoutTopLeftItem();
3524 switch (loadRequest.edge()) {
3527 layoutVerticalEdge(loadRequest.edge());
3530 case Qt::BottomEdge:
3531 layoutHorizontalEdge(loadRequest.edge());
3536void QQuickTableViewPrivate::processLoadRequest()
3538 Q_Q(QQuickTableView);
3541 while (loadRequest.hasCurrentCell()) {
3542 QPoint cell = loadRequest.currentCell();
3543 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3551 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3552 loadRequest.moveToNextCell();
3555 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3557 syncLoadedTableFromLoadRequest();
3558 layoutTableEdgeFromLoadRequest();
3559 syncLoadedTableRectFromLoadedTable();
3561 if (rebuildState == RebuildState::Done) {
3565 drainReusePoolAfterLoadRequest();
3567 switch (loadRequest.edge()) {
3569 emit q->leftColumnChanged();
3572 emit q->rightColumnChanged();
3575 emit q->topRowChanged();
3577 case Qt::BottomEdge:
3578 emit q->bottomRowChanged();
3582 if (editIndex.isValid())
3585 emit q->layoutChanged();
3588 loadRequest.markAsDone();
3590 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3591 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3592 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3595void QQuickTableViewPrivate::processRebuildTable()
3597 Q_Q(QQuickTableView);
3599 if (rebuildState == RebuildState::Begin) {
3600 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3601 tableSizeBeforeRebuild = tableSize;
3602 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins(-1,-1,-1,-1)
3603 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3606 moveToNextRebuildState();
3608 if (rebuildState == RebuildState::LoadInitalTable) {
3610 if (!moveToNextRebuildState())
3614 if (rebuildState == RebuildState::VerifyTable) {
3615 if (loadedItems.isEmpty()) {
3616 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3617 updateContentWidth();
3618 updateContentHeight();
3619 rebuildState = RebuildState::Done;
3620 }
else if (!moveToNextRebuildState()) {
3625 if (rebuildState == RebuildState::LayoutTable) {
3626 layoutAfterLoadingInitialTable();
3627 loadAndUnloadVisibleEdges();
3628 if (!moveToNextRebuildState())
3632 if (rebuildState == RebuildState::CancelOvershoot) {
3633 cancelOvershootAfterLayout();
3634 loadAndUnloadVisibleEdges();
3635 if (!moveToNextRebuildState())
3639 if (rebuildState == RebuildState::UpdateContentSize) {
3640 updateContentSize();
3641 if (!moveToNextRebuildState())
3645 const bool preload = (rebuildOptions & RebuildOption::All
3646 && reusableFlag == QQmlTableInstanceModel::Reusable);
3648 if (rebuildState == RebuildState::PreloadColumns) {
3649 if (preload && !atTableEnd(Qt::RightEdge))
3650 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3651 if (!moveToNextRebuildState())
3655 if (rebuildState == RebuildState::PreloadRows) {
3656 if (preload && !atTableEnd(Qt::BottomEdge))
3657 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3658 if (!moveToNextRebuildState())
3662 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3663 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3665 if (!moveToNextRebuildState())
3669 if (rebuildState == RebuildState::Done) {
3670 if (tableSizeBeforeRebuild.width() != tableSize.width())
3671 emit q->columnsChanged();
3672 if (tableSizeBeforeRebuild.height() != tableSize.height())
3673 emit q->rowsChanged();
3674 if (edgesBeforeRebuild.left() != q->leftColumn())
3675 emit q->leftColumnChanged();
3676 if (edgesBeforeRebuild.right() != q->rightColumn())
3677 emit q->rightColumnChanged();
3678 if (edgesBeforeRebuild.top() != q->topRow())
3679 emit q->topRowChanged();
3680 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3681 emit q->bottomRowChanged();
3683 if (editIndex.isValid())
3685 updateCurrentRowAndColumn();
3689 tableModel->commitReleasedItems();
3691 emit q->layoutChanged();
3693 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3694 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3695 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3696 qCDebug(lcTableViewDelegateLifecycle());
3702bool QQuickTableViewPrivate::moveToNextRebuildState()
3704 if (loadRequest.isActive()) {
3710 if (rebuildState == RebuildState::Begin
3711 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3712 rebuildState = RebuildState::LayoutTable;
3714 rebuildState = RebuildState(
int(rebuildState) + 1);
3716 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3720void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3722 if (tableSize.isEmpty()) {
3724 topLeftCell.rx() = kEdgeIndexAtEnd;
3725 topLeftCell.ry() = kEdgeIndexAtEnd;
3729 if (syncHorizontally || syncVertically) {
3730 const auto syncView_d = syncView->d_func();
3732 if (syncView_d->loadedItems.isEmpty()) {
3733 topLeftCell.rx() = 0;
3734 topLeftCell.ry() = 0;
3739 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3740 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3741 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3743 if (syncHorizontally) {
3744 topLeftCell.rx() = syncViewTopLeftCell.x();
3745 topLeftPos.rx() = syncViewTopLeftPos.x();
3747 if (topLeftCell.x() >= tableSize.width()) {
3749 topLeftCell.rx() = kEdgeIndexAtEnd;
3750 topLeftPos.rx() = kEdgeIndexAtEnd;
3754 if (syncVertically) {
3755 topLeftCell.ry() = syncViewTopLeftCell.y();
3756 topLeftPos.ry() = syncViewTopLeftPos.y();
3758 if (topLeftCell.y() >= tableSize.height()) {
3760 topLeftCell.ry() = kEdgeIndexAtEnd;
3761 topLeftPos.ry() = kEdgeIndexAtEnd;
3765 if (syncHorizontally && syncVertically) {
3776 if (!syncHorizontally) {
3777 if (rebuildOptions & RebuildOption::All) {
3779 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3780 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3784 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3786 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3787 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3788 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3789 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3790 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3791 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3794 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3798 topLeftPos.rx() = loadedTableOuterRect.x();
3802 if (!syncVertically) {
3803 if (rebuildOptions & RebuildOption::All) {
3805 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3806 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3810 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3812 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3813 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3814 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3815 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3816 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3817 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3819 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3820 topLeftPos.ry() = loadedTableOuterRect.y();
3825void QQuickTableViewPrivate::loadInitialTable()
3827 tableSize = calculateTableSize();
3829 if (positionXAnimation.isRunning()) {
3830 positionXAnimation.stop();
3831 setLocalViewportX(positionXAnimation.to().toReal());
3835 if (positionYAnimation.isRunning()) {
3836 positionYAnimation.stop();
3837 setLocalViewportY(positionYAnimation.to().toReal());
3843 calculateTopLeft(topLeft, topLeftPos);
3844 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3845 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3847 if (!loadedItems.isEmpty()) {
3848 if (rebuildOptions & RebuildOption::All)
3849 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3850 else if (rebuildOptions & RebuildOption::ViewportOnly)
3851 releaseLoadedItems(reusableFlag);
3854 if (rebuildOptions & RebuildOption::All) {
3855 origin = QPointF(0, 0);
3856 endExtent = QSizeF(0, 0);
3857 hData.markExtentsDirty();
3858 vData.markExtentsDirty();
3859 updateBeginningEnd();
3862 loadedColumns.clear();
3864 loadedTableOuterRect = QRect();
3865 loadedTableInnerRect = QRect();
3866 clearEdgeSizeCache();
3868 if (syncHorizontally)
3869 setLocalViewportX(syncView->contentX());
3872 setLocalViewportY(syncView->contentY());
3874 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
3875 setLocalViewportX(topLeftPos.x());
3877 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
3878 setLocalViewportY(topLeftPos.y());
3883 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
3887 if (model->count() == 0) {
3888 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
3892 if (tableModel && !tableModel->delegate()) {
3893 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
3897 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
3898 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
3902 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
3903 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
3907 if (viewportRect.isEmpty()) {
3908 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
3914 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
3915 processLoadRequest();
3916 loadAndUnloadVisibleEdges();
3919void QQuickTableViewPrivate::updateContentSize()
3921 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
3922 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
3923 updateAverageColumnWidth();
3924 updateContentWidth();
3927 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
3928 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
3929 updateAverageRowHeight();
3930 updateContentHeight();
3936void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
3938 clearEdgeSizeCache();
3939 relayoutTableItems();
3940 syncLoadedTableRectFromLoadedTable();
3942 updateContentSize();
3944 adjustViewportXAccordingToAlignment();
3945 adjustViewportYAccordingToAlignment();
3948void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
3951 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
3954 if (positionViewAtColumnAfterRebuild != leftColumn())
3957 const qreal newContentX = getAlignmentContentX(
3958 positionViewAtColumnAfterRebuild,
3959 positionViewAtColumnAlignment,
3960 positionViewAtColumnOffset,
3961 positionViewAtColumnSubRect);
3963 setLocalViewportX(newContentX);
3967void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
3970 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
3973 if (positionViewAtRowAfterRebuild != topRow())
3976 const qreal newContentY = getAlignmentContentY(
3977 positionViewAtRowAfterRebuild,
3978 positionViewAtRowAlignment,
3979 positionViewAtRowOffset,
3980 positionViewAtRowSubRect);
3982 setLocalViewportY(newContentY);
3986void QQuickTableViewPrivate::cancelOvershootAfterLayout()
3988 Q_Q(QQuickTableView);
3994 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
3995 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
3996 const bool cancelVertically = positionVertically && !syncVertically;
3997 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
3999 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
4000 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
4001 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
4005 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
4006 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
4007 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
4012void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
4014 Q_Q(QQuickTableView);
4015 qCDebug(lcTableViewDelegateLifecycle) << edge;
4018 case Qt::LeftEdge: {
4019 const int column = leftColumn();
4020 for (
int row : loadedRows)
4021 unloadItem(QPoint(column, row));
4022 loadedColumns.remove(column);
4023 syncLoadedTableRectFromLoadedTable();
4024 if (rebuildState == RebuildState::Done)
4025 emit q->leftColumnChanged();
4027 case Qt::RightEdge: {
4028 const int column = rightColumn();
4029 for (
int row : loadedRows)
4030 unloadItem(QPoint(column, row));
4031 loadedColumns.remove(column);
4032 syncLoadedTableRectFromLoadedTable();
4033 if (rebuildState == RebuildState::Done)
4034 emit q->rightColumnChanged();
4037 const int row = topRow();
4038 for (
int col : loadedColumns)
4039 unloadItem(QPoint(col, row));
4040 loadedRows.remove(row);
4041 syncLoadedTableRectFromLoadedTable();
4042 if (rebuildState == RebuildState::Done)
4043 emit q->topRowChanged();
4045 case Qt::BottomEdge: {
4046 const int row = bottomRow();
4047 for (
int col : loadedColumns)
4048 unloadItem(QPoint(col, row));
4049 loadedRows.remove(row);
4050 syncLoadedTableRectFromLoadedTable();
4051 if (rebuildState == RebuildState::Done)
4052 emit q->bottomRowChanged();
4056 if (rebuildState == RebuildState::Done)
4057 emit q->layoutChanged();
4059 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4062void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4064 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4065 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4067 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4068 ? loadedRows.values() : loadedColumns.values();
4069 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4070 processLoadRequest();
4073void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4085 if (loadRequest.isActive()) {
4091 if (loadedItems.isEmpty()) {
4101 tableModified =
false;
4103 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4104 tableModified =
true;
4108 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4109 tableModified =
true;
4110 loadEdge(edge, incubationMode);
4111 if (loadRequest.isActive())
4114 }
while (tableModified);
4118void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4120 Q_Q(QQuickTableView);
4122 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4125 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4155 const int w = loadedColumns.count();
4156 const int h = loadedRows.count();
4157 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4158 const int maxTime = minTime * 2;
4159 tableModel->drainReusableItemsPool(maxTime);
4162void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4163 if (!q_func()->isComponentComplete()) {
4168 scheduledRebuildOptions |= options;
4172QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4174 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4175 while (QQuickTableView *view = root->d_func()->syncView)
4180void QQuickTableViewPrivate::updatePolish()
4187 rootSyncView()->d_func()->updateTableRecursive();
4190bool QQuickTableViewPrivate::updateTableRecursive()
4200 const bool updateComplete = updateTable();
4201 if (!updateComplete)
4204 const auto children = syncChildren;
4205 for (
auto syncChild : children) {
4206 auto syncChild_d = syncChild->d_func();
4208 RebuildOption::PositionViewAtRow |
4209 RebuildOption::PositionViewAtColumn |
4210 RebuildOption::CalculateNewTopLeftRow |
4211 RebuildOption::CalculateNewTopLeftColumn;
4212 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4214 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4215 if (!descendantUpdateComplete)
4219 rebuildOptions = RebuildOption::None;
4224bool QQuickTableViewPrivate::updateTable()
4233 QScopedValueRollback polishGuard(polishing,
true);
4235 if (loadRequest.isActive()) {
4243 if (rebuildState != RebuildState::Done) {
4244 processRebuildTable();
4245 return rebuildState == RebuildState::Done;
4248 syncWithPendingChanges();
4250 if (rebuildState == RebuildState::Begin) {
4251 processRebuildTable();
4252 return rebuildState == RebuildState::Done;
4255 if (loadedItems.isEmpty())
4256 return !loadRequest.isActive();
4258 loadAndUnloadVisibleEdges();
4261 return !loadRequest.isActive();
4264void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4266 if (inUpdateContentSize) {
4278 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4281QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4283 const auto data = QQmlData::get(q_func());
4284 if (!data || !data->propertyCache)
4285 return QTypeRevision::zero();
4287 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4288 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4291 return qmlTypeView.metaObjectRevision();
4294void QQuickTableViewPrivate::createWrapperModel()
4296 Q_Q(QQuickTableView);
4302 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4303 tableModel->useImportVersion(resolveImportVersion());
4307bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4309 if (!selectionModel)
4312 QAbstractItemModel *model = selectionModel->model();
4316 return selectionModel->isSelected(q_func()->modelIndex(cell));
4319bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4321 if (!selectionModel)
4324 QAbstractItemModel *model = selectionModel->model();
4328 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4331void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4333 if (!inSelectionModelUpdate) {
4337 cancelSelectionTracking();
4340 const auto &selectedIndexes = selected.indexes();
4341 const auto &deselectedIndexes = deselected.indexes();
4342 for (
int i = 0; i < selectedIndexes.size(); ++i)
4343 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4344 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4345 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4348void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4350 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4351 qmlWarning(q_func())
4352 <<
"Cannot select cells: TableView.selectionModel.model is not "
4353 <<
"compatible with the model displayed in the view";
4357 const int cellIndex = modelIndexToCellIndex(modelIndex);
4358 if (!loadedItems.contains(cellIndex))
4360 const QPoint cell = cellAtModelIndex(cellIndex);
4361 QQuickItem *item = loadedTableItem(cell)->item;
4362 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4365QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4380 return qaim(modelImpl());
4383QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4386 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4387 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4388 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4391void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4393 updateCurrentRowAndColumn();
4395 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4396 const int cellIndex = *it;
4397 const QPoint cell = cellAtModelIndex(cellIndex);
4398 const bool selected = selectedInSelectionModel(cell);
4399 const bool current = currentInSelectionModel(cell);
4400 QQuickItem *item = loadedTableItem(cell)->item;
4401 const bool editing = editIndex == q_func()->modelIndex(cell);
4402 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4403 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4404 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4408void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4410 if (current.isValid() && current.model() != selectionSourceModel()) {
4411 qmlWarning(q_func())
4412 <<
"Cannot change current index: TableView.selectionModel.model is not "
4413 <<
"compatible with the model displayed in the view";
4417 updateCurrentRowAndColumn();
4418 setCurrentOnDelegateItem(previous,
false);
4419 setCurrentOnDelegateItem(current,
true);
4422void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4424 Q_Q(QQuickTableView);
4426 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4427 const QPoint currentCell = q->cellAtIndex(currentIndex);
4428 if (currentCell.x() != currentColumn) {
4429 currentColumn = currentCell.x();
4430 emit q->currentColumnChanged();
4433 if (currentCell.y() != currentRow) {
4434 currentRow = currentCell.y();
4435 emit q->currentRowChanged();
4439void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4441 const int cellIndex = modelIndexToCellIndex(index);
4442 if (!loadedItems.contains(cellIndex))
4445 const QPoint cell = cellAtModelIndex(cellIndex);
4446 QQuickItem *item = loadedTableItem(cell)->item;
4447 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4450void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4452 if (blockItemCreatedCallback)
4455 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4456 << cellAtModelIndex(modelIndex);
4462 processLoadRequest();
4463 loadAndUnloadVisibleEdges();
4467void QQuickTableViewPrivate::updateItemProperties(
int flatIndex, QObject *object,
bool init)
4469 Q_Q(QQuickTableView);
4470 const QPoint cell = cellAtModelIndex(flatIndex);
4471 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4472 const bool current = currentInSelectionModel(visualCell);
4473 const bool selected = selectedInSelectionModel(visualCell);
4475 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), flatIndex, object, init);
4476 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), flatIndex, object, init);
4477 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), flatIndex, object, init);
4478 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), flatIndex, object, init);
4479 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), flatIndex, object, init);
4482void QQuickTableViewPrivate::initItemCallback(
int flatIndex, QObject *object)
4484 Q_Q(QQuickTableView);
4485 Q_UNUSED(flatIndex);
4487 auto item = qobject_cast<QQuickItem*>(object);
4491 item->setParentItem(q->contentItem());
4494 if (
auto attached = getAttachedObject(item))
4495 attached->setView(q);
4498void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4500 Q_UNUSED(modelIndex);
4502 if (
auto attached = getAttachedObject(object))
4503 emit attached->pooled();
4506void QQuickTableViewPrivate::itemReusedCallback(
int flatIndex, QObject *object)
4508 Q_UNUSED(flatIndex);
4510 if (
auto item = qobject_cast<QQuickItem*>(object))
4511 QQuickItemPrivate::get(item)->setCulled(
false);
4513 if (
auto attached = getAttachedObject(object))
4514 emit attached->reused();
4517void QQuickTableViewPrivate::syncWithPendingChanges()
4527 syncDelegateModelAccess();
4531 syncRebuildOptions();
4534void QQuickTableViewPrivate::syncRebuildOptions()
4536 if (!scheduledRebuildOptions)
4539 rebuildState = RebuildState::Begin;
4540 rebuildOptions = scheduledRebuildOptions;
4541 scheduledRebuildOptions = RebuildOption::None;
4543 if (loadedItems.isEmpty())
4544 rebuildOptions.setFlag(RebuildOption::All);
4547 if (rebuildOptions.testFlag(RebuildOption::All)) {
4548 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4549 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4550 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4551 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4552 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4553 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4556 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4557 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4559 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4560 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4563void QQuickTableViewPrivate::syncDelegate()
4572 if (assignedDelegate != tableModel->delegate())
4573 tableModel->setDelegate(assignedDelegate);
4576void QQuickTableViewPrivate::syncDelegateModelAccess()
4585 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4588QVariant QQuickTableViewPrivate::modelImpl()
const
4590 if (needsModelSynchronization)
4591 return assignedModel;
4593 return tableModel->model();
4594 return QVariant::fromValue(model);
4597void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4599 assignedModel = newModel;
4600 needsModelSynchronization =
true;
4601 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4602 emit q_func()->modelChanged();
4605void QQuickTableViewPrivate::syncModel()
4608 if (tableModel->model() == assignedModel)
4610 }
else if (QVariant::fromValue(model) == assignedModel) {
4615 disconnectFromModel();
4616 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4619 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4620 qvariant_cast<QObject *>(assignedModel));
4622 if (instanceModel) {
4625 tableModel =
nullptr;
4627 model = instanceModel;
4630 createWrapperModel();
4631 tableModel->setModel(assignedModel);
4634 needsModelSynchronization =
false;
4638void QQuickTableViewPrivate::syncSyncView()
4640 Q_Q(QQuickTableView);
4642 if (assignedSyncView != syncView) {
4644 syncView->d_func()->syncChildren.removeOne(q);
4646 if (assignedSyncView) {
4647 QQuickTableView *view = assignedSyncView;
4651 if (!layoutWarningIssued) {
4652 layoutWarningIssued =
true;
4653 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4658 view = view->d_func()->syncView;
4661 assignedSyncView->d_func()->syncChildren.append(q);
4662 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4665 syncView = assignedSyncView;
4668 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4669 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4671 if (syncHorizontally) {
4672 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4673 q->setColumnSpacing(syncView->columnSpacing());
4674 q->setLeftMargin(syncView->leftMargin());
4675 q->setRightMargin(syncView->rightMargin());
4676 updateContentWidth();
4678 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4679 if (syncView->leftColumn() != q->leftColumn()
4680 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4687 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4688 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4693 if (syncVertically) {
4694 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4695 q->setRowSpacing(syncView->rowSpacing());
4696 q->setTopMargin(syncView->topMargin());
4697 q->setBottomMargin(syncView->bottomMargin());
4698 updateContentHeight();
4700 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4701 if (syncView->topRow() != q->topRow()
4702 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4709 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4710 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4715 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4721 const auto syncView_d = syncView->d_func();
4722 if (!syncView_d->loadedItems.isEmpty()) {
4723 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4724 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4725 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4726 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4731void QQuickTableViewPrivate::syncPositionView()
4737 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4738 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4741void QQuickTableViewPrivate::connectToModel()
4743 Q_Q(QQuickTableView);
4746 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4747 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4748 QObjectPrivate::connect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4749 QObjectPrivate::connect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4750 QObjectPrivate::connect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
4753 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4755 if (
auto const aim = model->abstractItemModel()) {
4761 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4762 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4763 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4764 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4765 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4766 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4767 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4768 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4769 connect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4771 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4775 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
4776 q, &QQuickTableView::modelChanged);
4780void QQuickTableViewPrivate::disconnectFromModel()
4782 Q_Q(QQuickTableView);
4785 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4786 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4787 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4788 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4789 QObjectPrivate::disconnect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
4791 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4793 if (
auto const aim = model->abstractItemModel()) {
4794 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4795 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4796 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4797 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4798 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4799 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4800 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4801 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4802 disconnect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4804 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4808 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
4809 q, &QQuickTableView::modelChanged);
4813void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
4815 Q_UNUSED(changeSet);
4819 scheduleRebuildTable(RebuildOption::ViewportOnly
4820 | RebuildOption::CalculateNewContentWidth
4821 | RebuildOption::CalculateNewContentHeight);
4824void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
4826 if (parent != QModelIndex())
4829 scheduleRebuildTable(RebuildOption::ViewportOnly);
4832void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
4834 if (parent != QModelIndex())
4837 scheduleRebuildTable(RebuildOption::ViewportOnly);
4840void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
4842 if (parent != QModelIndex())
4845 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4848void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
4850 Q_Q(QQuickTableView);
4852 if (parent != QModelIndex())
4856 if (!editIndex.isValid() && editItem)
4859 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4862void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
4864 if (parent != QModelIndex())
4872 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4875void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
4877 Q_Q(QQuickTableView);
4879 if (parent != QModelIndex())
4883 if (!editIndex.isValid() && editItem)
4886 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4889void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
4894 scheduleRebuildTable(RebuildOption::ViewportOnly);
4897void QQuickTableViewPrivate::fetchMoreData()
4899 if (tableModel && tableModel->canFetchMore()) {
4900 tableModel->fetchMore();
4901 scheduleRebuildTable(RebuildOption::ViewportOnly);
4905void QQuickTableViewPrivate::modelResetCallback()
4907 Q_Q(QQuickTableView);
4909 scheduleRebuildTable(RebuildOption::All);
4912void QQuickTableViewPrivate::dataChangedCallback(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles)
4914 const auto *chooser = qobject_cast<
const QQmlDelegateChooser *>(assignedDelegate);
4918 if (loadedItems.isEmpty()
4919 || topLeft.column() > rightColumn() || bottomRight.column() < leftColumn()
4920 || topLeft.row() > bottomRow() || bottomRight.row() < topRow()) {
4924 if (!roles.empty()) {
4925 const int roleIndex = topLeft.model()->roleNames().key(chooser->role().toUtf8());
4926 if (!roles.contains(roleIndex))
4930 scheduleRebuildTable(RebuildOption::ViewportOnly);
4933void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4935 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
4938 if (syncVertically) {
4939 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
4941 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
4943 assignedPositionViewAtRowAfterRebuild = row;
4944 positionViewAtRowAlignment = verticalAlignment;
4945 positionViewAtRowOffset = offset;
4946 positionViewAtRowSubRect = subRect;
4947 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4948 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
4953void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4955 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
4958 if (syncHorizontally) {
4959 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
4961 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
4963 assignedPositionViewAtColumnAfterRebuild = column;
4964 positionViewAtColumnAlignment = horizontalAlignment;
4965 positionViewAtColumnOffset = offset;
4966 positionViewAtColumnSubRect = subRect;
4967 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4968 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
4973bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4975 Q_Q(QQuickTableView);
4982 if (row < topRow()) {
4983 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
4985 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
4986 }
else if (row > bottomRow()) {
4987 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
4989 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
4990 }
else if (row < topRow() || row > bottomRow()) {
4994 if (!loadedRows.contains(row))
4997 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
4998 if (qFuzzyCompare(newContentY, q->contentY()))
5002 const qreal diffY = qAbs(newContentY - q->contentY());
5003 const qreal duration = qBound(700., diffY * 5, 1500.);
5004 positionYAnimation.setTo(newContentY);
5005 positionYAnimation.setDuration(duration);
5006 positionYAnimation.restart();
5008 positionYAnimation.stop();
5009 q->setContentY(newContentY);
5015bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5017 Q_Q(QQuickTableView);
5024 if (column < leftColumn()) {
5025 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
5027 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
5028 }
else if (column > rightColumn()) {
5029 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
5031 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
5032 }
else if (column < leftColumn() || column > rightColumn()) {
5036 if (!loadedColumns.contains(column))
5039 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5040 if (qFuzzyCompare(newContentX, q->contentX()))
5044 const qreal diffX = qAbs(newContentX - q->contentX());
5045 const qreal duration = qBound(700., diffX * 5, 1500.);
5046 positionXAnimation.setTo(newContentX);
5047 positionXAnimation.setDuration(duration);
5048 positionXAnimation.restart();
5050 positionXAnimation.stop();
5051 q->setContentX(newContentX);
5057void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5059 Q_Q(QQuickTableView);
5069 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5070 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5071 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5075 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5076 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5077 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5081void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5086 Q_Q(QQuickTableView);
5087 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5089 if (qFuzzyCompare(contentX, q->contentX()))
5092 q->setContentX(contentX);
5095void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5100 Q_Q(QQuickTableView);
5101 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5103 if (qFuzzyCompare(contentY, q->contentY()))
5106 q->setContentY(contentY);
5109void QQuickTableViewPrivate::syncViewportRect()
5117 Q_Q(QQuickTableView);
5119 qreal w = q->width();
5120 qreal h = q->height();
5122 for (
auto syncChild : std::as_const(syncChildren)) {
5123 auto syncChild_d = syncChild->d_func();
5124 if (syncChild_d->syncHorizontally)
5125 w = qMax(w, syncChild->width());
5126 if (syncChild_d->syncVertically)
5127 h = qMax(h, syncChild->height());
5130 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5133void QQuickTableViewPrivate::init()
5135 Q_Q(QQuickTableView);
5137 q->setFlag(QQuickItem::ItemIsFocusScope);
5138 q->setActiveFocusOnTab(
true);
5140 positionXAnimation.setTargetObject(q);
5141 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5142 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5144 positionYAnimation.setTargetObject(q);
5145 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5146 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5148 auto tapHandler =
new QQuickTableViewTapHandler(q);
5150 hoverHandler =
new QQuickTableViewHoverHandler(q);
5151 resizeHandler =
new QQuickTableViewResizeHandler(q);
5153 hoverHandler->setEnabled(resizableRows || resizableColumns);
5154 resizeHandler->setEnabled(resizableRows || resizableColumns);
5162 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, q, [
this, q, tapHandler] {
5163 if (!tapHandler->isPressed())
5166 positionXAnimation.stop();
5167 positionYAnimation.stop();
5169 if (!q->isInteractive())
5170 handleTap(tapHandler->point());
5173 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, q, [
this, q, tapHandler] {
5174 if (q->isInteractive())
5175 handleTap(tapHandler->point());
5178 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, q, [
this, q, tapHandler] {
5179 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5180 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5182 if (resizeRow || resizeColumn) {
5184 q->setRowHeight(hoverHandler->m_row, -1);
5186 q->setColumnWidth(hoverHandler->m_column, -1);
5187 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5188 const QPointF pos = tapHandler->point().pressPosition();
5189 const QPoint cell = q->cellAtPosition(pos);
5190 const QModelIndex index = q->modelIndex(cell);
5191 if (canEdit(index,
false))
5197void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5199 Q_Q(QQuickTableView);
5201 if (keyNavigationEnabled)
5202 q->forceActiveFocus(Qt::MouseFocusReason);
5204 if (point.modifiers() != Qt::NoModifier)
5206 if (resizableRows && hoverHandler->m_row != -1)
5208 if (resizableColumns && hoverHandler->m_column != -1)
5210 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5213 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5214 bool tappedCellIsSelected =
false;
5217 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5219 if (canEdit(tappedIndex,
false)) {
5220 if (editTriggers & QQuickTableView::SingleTapped) {
5221 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5223 q->edit(tappedIndex);
5225 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5226 q->edit(tappedIndex);
5233 if (pointerNavigationEnabled) {
5234 closeEditorAndCommit();
5235 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5237 cancelSelectionTracking();
5239 setCurrentIndexFromTap(point.position());
5243bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5247 Q_Q(QQuickTableView);
5249 if (!tappedIndex.isValid()) {
5251 qmlWarning(q) <<
"cannot edit: index is not valid!";
5255 auto const sourceModel = qaim(modelImpl());
5258 qmlWarning(q) <<
"cannot edit: TableView.model does not inherit QAbstractItemModel!";
5262 const QModelIndex buddyIndex = sourceModel->buddy(tappedIndex);
5263 if (!(sourceModel->flags(buddyIndex) & Qt::ItemIsEditable)) {
5265 if (buddyIndex != tappedIndex)
5266 qmlWarning(q) <<
"cannot edit: the buddy index flags don't include Qt::ItemIsEditable.";
5268 qmlWarning(q) <<
"cannot edit: the index flags don't include Qt::ItemIsEditable";
5273 const QPoint cell = q->cellAtIndex(buddyIndex);
5274 const QQuickItem *cellItem = q->itemAtCell(cell);
5277 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5281 auto attached = getAttachedObject(cellItem);
5282 if (!attached || !attached->editDelegate()) {
5284 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5291void QQuickTableViewPrivate::syncViewportPosRecursive()
5293 Q_Q(QQuickTableView);
5294 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5297 auto syncView_d = syncView->d_func();
5298 if (!syncView_d->inSyncViewportPosRecursive) {
5299 if (syncHorizontally)
5300 syncView_d->setLocalViewportX(q->contentX());
5302 syncView_d->setLocalViewportY(q->contentY());
5303 syncView_d->syncViewportPosRecursive();
5307 for (
auto syncChild : std::as_const(syncChildren)) {
5308 auto syncChild_d = syncChild->d_func();
5309 if (!syncChild_d->inSyncViewportPosRecursive) {
5310 if (syncChild_d->syncHorizontally)
5311 syncChild_d->setLocalViewportX(q->contentX());
5312 if (syncChild_d->syncVertically)
5313 syncChild_d->setLocalViewportY(q->contentY());
5314 syncChild_d->syncViewportPosRecursive();
5319void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5321 Q_Q(QQuickTableView);
5323 const QPoint cell = q->cellAtPosition(pos);
5324 if (!cellIsValid(cell))
5327 setCurrentIndex(cell);
5330void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5332 if (!selectionModel)
5335 const auto index = q_func()->modelIndex(cell);
5336 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5339bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5341 Q_Q(QQuickTableView);
5343 if (!selectionModel || !selectionModel->model())
5346 const QModelIndex currentIndex = selectionModel->currentIndex();
5347 const QPoint currentCell = q->cellAtIndex(currentIndex);
5349 if (!q->activeFocusOnTab()) {
5352 case Qt::Key_Backtab:
5357 if (!cellIsValid(currentCell)) {
5363 case Qt::Key_PageUp:
5364 case Qt::Key_PageDown:
5368 case Qt::Key_Backtab:
5369 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5372 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5373 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5380 auto beginMoveCurrentIndex = [&](){
5381 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5382 const bool startNewSelection = selectionRectangle().isEmpty();
5383 if (!shouldSelect) {
5385 cancelSelectionTracking();
5386 }
else if (startNewSelection) {
5390 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5391 if (loadedItems.contains(serializedStartIndex)) {
5392 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5393 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5394 setSelectionStartPos(startGeometry.center());
5395 if (selectableCallbackFunction)
5396 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5402 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5403 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5405 if (polishScheduled)
5407 const int serializedEndIndex = modelIndexAtCell(cell);
5408 if (loadedItems.contains(serializedEndIndex)) {
5409 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5410 setSelectionEndPos(endGeometry.center());
5411 if (selectableCallbackFunction)
5412 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5415 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5420 beginMoveCurrentIndex();
5421 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5422 if (nextRow == kEdgeIndexAtEnd)
5424 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5425 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5426 endMoveCurrentIndex({currentCell.x(), nextRow});
5428 case Qt::Key_Down: {
5429 beginMoveCurrentIndex();
5430 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5431 if (nextRow == kEdgeIndexAtEnd)
5433 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5434 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5435 endMoveCurrentIndex({currentCell.x(), nextRow});
5437 case Qt::Key_Left: {
5438 beginMoveCurrentIndex();
5439 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5440 if (nextColumn == kEdgeIndexAtEnd)
5442 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5443 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5444 endMoveCurrentIndex({nextColumn, currentCell.y()});
5446 case Qt::Key_Right: {
5447 beginMoveCurrentIndex();
5448 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5449 if (nextColumn == kEdgeIndexAtEnd)
5451 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5452 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5453 endMoveCurrentIndex({nextColumn, currentCell.y()});
5455 case Qt::Key_PageDown: {
5456 int newBottomRow = -1;
5457 beginMoveCurrentIndex();
5458 if (currentCell.y() < bottomRow()) {
5460 newBottomRow = bottomRow();
5461 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5463 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5464 positionYAnimation.complete();
5465 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5466 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5467 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5468 positionYAnimation.complete();
5470 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5472 case Qt::Key_PageUp: {
5474 beginMoveCurrentIndex();
5475 if (currentCell.y() > topRow()) {
5477 newTopRow = topRow();
5478 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5480 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5481 positionYAnimation.complete();
5482 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5483 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5484 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5485 positionYAnimation.complete();
5487 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5489 case Qt::Key_Home: {
5490 beginMoveCurrentIndex();
5491 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5492 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5493 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5496 beginMoveCurrentIndex();
5497 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5498 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5499 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5502 beginMoveCurrentIndex();
5503 int nextRow = currentCell.y();
5504 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5505 if (nextColumn == kEdgeIndexAtEnd) {
5506 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5507 if (nextRow == kEdgeIndexAtEnd)
5508 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5509 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5510 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5511 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5515 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5516 marginX = q->leftMargin();
5517 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5518 marginX = -q->leftMargin();
5520 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5521 endMoveCurrentIndex({nextColumn, nextRow});
5523 case Qt::Key_Backtab: {
5524 beginMoveCurrentIndex();
5525 int nextRow = currentCell.y();
5526 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5527 if (nextColumn == kEdgeIndexAtEnd) {
5528 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5529 if (nextRow == kEdgeIndexAtEnd)
5530 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5531 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5532 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5533 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5537 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5538 marginX = q->leftMargin();
5539 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5540 marginX = -q->leftMargin();
5542 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5543 endMoveCurrentIndex({nextColumn, nextRow});
5552bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5554 Q_Q(QQuickTableView);
5556 if (editTriggers == QQuickTableView::NoEditTriggers)
5558 if (!selectionModel || !selectionModel->model())
5561 const QModelIndex index = selectionModel->currentIndex();
5562 const QPoint cell = q->cellAtIndex(index);
5563 const QQuickItem *cellItem = q->itemAtCell(cell);
5567 auto attached = getAttachedObject(cellItem);
5568 if (!attached || !attached->editDelegate())
5571 bool anyKeyPressed =
false;
5572 bool editKeyPressed =
false;
5575 case Qt::Key_Return:
5580 anyKeyPressed =
true;
5581 editKeyPressed =
true;
5585 case Qt::Key_Control:
5588 case Qt::Key_Backtab:
5591 anyKeyPressed =
true;
5594 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5595 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5597 if (!(editKeyAccepted || anyKeyAccepted))
5600 if (!canEdit(index,
false)) {
5609 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5612 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5618QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5624 Q_Q(QQuickTableView);
5625 if (QObject *focusObject = editItem->window()->focusObject()) {
5626 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5627 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5628 focusItem->installEventFilter(q);
5635void QQuickTableViewPrivate::closeEditorAndCommit()
5640 if (
auto attached = getAttachedObject(editItem))
5641 emit attached->commit();
5643 q_func()->closeEditor();
5646#if QT_CONFIG(cursor)
5647void QQuickTableViewPrivate::updateCursor()
5649 int row = resizableRows ? hoverHandler->m_row : -1;
5650 int column = resizableColumns ? hoverHandler->m_column : -1;
5652 const auto resizeState = resizeHandler->state();
5653 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5654 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5657 row = resizeHandler->m_row;
5658 column = resizeHandler->m_column;
5661 if (row != -1 || column != -1) {
5662 Qt::CursorShape shape;
5663 if (row != -1 && column != -1)
5664 shape = Qt::SizeFDiagCursor;
5666 shape = Qt::SplitVCursor;
5668 shape = Qt::SplitHCursor;
5671 qApp->changeOverrideCursor(shape);
5673 qApp->setOverrideCursor(shape);
5676 }
else if (m_cursorSet) {
5677 qApp->restoreOverrideCursor();
5678 m_cursorSet =
false;
5683void QQuickTableViewPrivate::updateEditItem()
5685 Q_Q(QQuickTableView);
5690 const QPoint cell = q->cellAtIndex(editIndex);
5691 auto cellItem = q->itemAtCell(cell);
5702 editItem->parentItem()->setX(-editItem->width() - 10000);
5706QQuickTableView::QQuickTableView(QQuickItem *parent)
5707 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5712QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5713 : QQuickFlickable(dd, parent)
5718QQuickTableView::~QQuickTableView()
5720 Q_D(QQuickTableView);
5724 auto syncView_d = d->syncView->d_func();
5725 syncView_d->syncChildren.removeOne(
this);
5726 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5730void QQuickTableView::componentFinalized()
5744 Q_D(QQuickTableView);
5745 qCDebug(lcTableViewDelegateLifecycle);
5749qreal QQuickTableView::minXExtent()
const
5751 return QQuickFlickable::minXExtent() - d_func()->origin.x();
5754qreal QQuickTableView::maxXExtent()
const
5756 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
5759qreal QQuickTableView::minYExtent()
const
5761 return QQuickFlickable::minYExtent() - d_func()->origin.y();
5764qreal QQuickTableView::maxYExtent()
const
5766 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
5769int QQuickTableView::rows()
const
5771 return d_func()->tableSize.height();
5774int QQuickTableView::columns()
const
5776 return d_func()->tableSize.width();
5779qreal QQuickTableView::rowSpacing()
const
5781 return d_func()->cellSpacing.height();
5784void QQuickTableView::setRowSpacing(qreal spacing)
5786 Q_D(QQuickTableView);
5787 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5789 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
5792 d->cellSpacing.setHeight(spacing);
5793 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5794 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5795 emit rowSpacingChanged();
5798qreal QQuickTableView::columnSpacing()
const
5800 return d_func()->cellSpacing.width();
5803void QQuickTableView::setColumnSpacing(qreal spacing)
5805 Q_D(QQuickTableView);
5806 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5808 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
5811 d->cellSpacing.setWidth(spacing);
5812 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5813 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5814 emit columnSpacingChanged();
5817QJSValue QQuickTableView::rowHeightProvider()
const
5819 return d_func()->rowHeightProvider;
5822void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
5824 Q_D(QQuickTableView);
5825 if (provider.strictlyEquals(d->rowHeightProvider))
5828 d->rowHeightProvider = provider;
5829 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5830 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5831 emit rowHeightProviderChanged();
5834QJSValue QQuickTableView::columnWidthProvider()
const
5836 return d_func()->columnWidthProvider;
5839void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
5841 Q_D(QQuickTableView);
5842 if (provider.strictlyEquals(d->columnWidthProvider))
5845 d->columnWidthProvider = provider;
5846 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5847 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5848 emit columnWidthProviderChanged();
5851QVariant QQuickTableView::model()
const
5853 return d_func()->modelImpl();
5856void QQuickTableView::setModel(
const QVariant &newModel)
5858 Q_D(QQuickTableView);
5860 QVariant model = newModel;
5861 if (model.userType() == qMetaTypeId<QJSValue>())
5862 model = model.value<QJSValue>().toVariant();
5864 if (model == d->assignedModel)
5868 d->setModelImpl(model);
5869 if (d->selectionModel)
5870 d->selectionModel->setModel(d->selectionSourceModel());
5873QQmlComponent *QQuickTableView::delegate()
const
5875 return d_func()->assignedDelegate;
5878void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
5880 Q_D(QQuickTableView);
5881 if (newDelegate == d->assignedDelegate)
5884 d->assignedDelegate = newDelegate;
5885 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5887 emit delegateChanged();
5890QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
5892 return d_func()->editTriggers;
5895void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
5897 Q_D(QQuickTableView);
5898 if (editTriggers == d->editTriggers)
5901 d->editTriggers = editTriggers;
5903 emit editTriggersChanged();
5907
5908
5909
5910
5911
5912QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
5914 Q_D(
const QQuickTableView);
5915 return d->assignedDelegateModelAccess;
5918void QQuickTableView::setDelegateModelAccess(
5919 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
5921 Q_D(QQuickTableView);
5922 if (delegateModelAccess == d->assignedDelegateModelAccess)
5925 d->assignedDelegateModelAccess = delegateModelAccess;
5926 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5928 emit delegateModelAccessChanged();
5931bool QQuickTableView::reuseItems()
const
5933 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
5936void QQuickTableView::setReuseItems(
bool reuse)
5938 Q_D(QQuickTableView);
5939 if (reuseItems() == reuse)
5942 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
5944 if (!reuse && d->tableModel) {
5947 d->tableModel->drainReusableItemsPool(0);
5950 emit reuseItemsChanged();
5953void QQuickTableView::setContentWidth(qreal width)
5955 Q_D(QQuickTableView);
5956 d->explicitContentWidth = width;
5957 QQuickFlickable::setContentWidth(width);
5960void QQuickTableView::setContentHeight(qreal height)
5962 Q_D(QQuickTableView);
5963 d->explicitContentHeight = height;
5964 QQuickFlickable::setContentHeight(height);
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984QQuickTableView *QQuickTableView::syncView()
const
5986 return d_func()->assignedSyncView;
5989void QQuickTableView::setSyncView(QQuickTableView *view)
5991 Q_D(QQuickTableView);
5992 if (d->assignedSyncView == view)
5997 d->clearIndexMapping();
5999 d->assignedSyncView = view;
6000 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6002 emit syncViewChanged();
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023Qt::Orientations QQuickTableView::syncDirection()
const
6025 return d_func()->assignedSyncDirection;
6028void QQuickTableView::setSyncDirection(Qt::Orientations direction)
6030 Q_D(QQuickTableView);
6031 if (d->assignedSyncDirection == direction)
6034 d->assignedSyncDirection = direction;
6035 if (d->assignedSyncView)
6036 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6038 emit syncDirectionChanged();
6041QItemSelectionModel *QQuickTableView::selectionModel()
const
6043 return d_func()->selectionModel;
6046void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6048 Q_D(QQuickTableView);
6049 if (d->selectionModel == selectionModel)
6056 if (d->selectionModel) {
6057 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6058 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6059 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6060 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6063 d->selectionModel = selectionModel;
6065 if (d->selectionModel) {
6066 d->selectionModel->setModel(d->selectionSourceModel());
6067 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6068 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6069 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6070 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6073 d->updateSelectedOnAllDelegateItems();
6075 emit selectionModelChanged();
6078bool QQuickTableView::animate()
const
6080 return d_func()->animate;
6083void QQuickTableView::setAnimate(
bool animate)
6085 Q_D(QQuickTableView);
6086 if (d->animate == animate)
6089 d->animate = animate;
6091 d->positionXAnimation.stop();
6092 d->positionYAnimation.stop();
6095 emit animateChanged();
6098bool QQuickTableView::keyNavigationEnabled()
const
6100 return d_func()->keyNavigationEnabled;
6103void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6105 Q_D(QQuickTableView);
6106 if (d->keyNavigationEnabled == enabled)
6109 d->keyNavigationEnabled = enabled;
6111 emit keyNavigationEnabledChanged();
6114bool QQuickTableView::pointerNavigationEnabled()
const
6116 return d_func()->pointerNavigationEnabled;
6119void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6121 Q_D(QQuickTableView);
6122 if (d->pointerNavigationEnabled == enabled)
6125 d->pointerNavigationEnabled = enabled;
6127 emit pointerNavigationEnabledChanged();
6130int QQuickTableView::leftColumn()
const
6132 Q_D(
const QQuickTableView);
6133 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6136int QQuickTableView::rightColumn()
const
6138 Q_D(
const QQuickTableView);
6139 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6142int QQuickTableView::topRow()
const
6144 Q_D(
const QQuickTableView);
6145 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6148int QQuickTableView::bottomRow()
const
6150 Q_D(
const QQuickTableView);
6151 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6154int QQuickTableView::currentRow()
const
6156 return d_func()->currentRow;
6159int QQuickTableView::currentColumn()
const
6161 return d_func()->currentColumn;
6164void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6166 Q_D(QQuickTableView);
6167 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6174 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6175 mode &= AlignTop | AlignBottom | AlignVCenter;
6176 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6177 }
else if (mode == Contain) {
6178 if (row < topRow()) {
6179 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6180 }
else if (row > bottomRow()) {
6181 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6182 }
else if (row == topRow()) {
6183 if (!subRect.isValid()) {
6184 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6186 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6187 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6188 if (subRectTop < d->viewportRect.y())
6189 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6190 else if (subRectBottom > d->viewportRect.bottom())
6191 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6193 }
else if (row == bottomRow()) {
6194 if (!subRect.isValid()) {
6195 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6199 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6200 if (subRectBottom > d->viewportRect.bottom())
6201 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6204 }
else if (mode == Visible) {
6205 if (row < topRow()) {
6206 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6207 }
else if (row > bottomRow()) {
6208 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6209 }
else if (subRect.isValid()) {
6210 if (row == topRow()) {
6211 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6212 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6213 if (subRectBottom < d->viewportRect.top())
6214 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6215 else if (subRectTop > d->viewportRect.bottom())
6216 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6217 }
else if (row == bottomRow()) {
6220 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6221 if (subRectTop > d->viewportRect.bottom())
6222 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6226 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6230void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6232 Q_D(QQuickTableView);
6233 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6240 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6241 mode &= AlignLeft | AlignRight | AlignHCenter;
6242 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6243 }
else if (mode == Contain) {
6244 if (column < leftColumn()) {
6245 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6246 }
else if (column > rightColumn()) {
6247 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6248 }
else if (column == leftColumn()) {
6249 if (!subRect.isValid()) {
6250 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6252 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6253 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6254 if (subRectLeft < d->viewportRect.left())
6255 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6256 else if (subRectRight > d->viewportRect.right())
6257 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6259 }
else if (column == rightColumn()) {
6260 if (!subRect.isValid()) {
6261 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6265 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6266 if (subRectRight > d->viewportRect.right())
6267 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6270 }
else if (mode == Visible) {
6271 if (column < leftColumn()) {
6272 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6273 }
else if (column > rightColumn()) {
6274 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6275 }
else if (subRect.isValid()) {
6276 if (column == leftColumn()) {
6277 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6278 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6279 if (subRectRight < d->viewportRect.left())
6280 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6281 else if (subRectLeft > d->viewportRect.right())
6282 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6283 }
else if (column == rightColumn()) {
6286 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6287 if (subRectLeft > d->viewportRect.right())
6288 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6292 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6296void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6298 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6299 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6300 if (!horizontalMode && !verticalMode) {
6301 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6306 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6308 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6311void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6313 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6314 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6315 if (!horizontalMode && !verticalMode) {
6316 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6321 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6323 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6326#if QT_DEPRECATED_SINCE(6
, 5
)
6327void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6329 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6330 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6331 if (!horizontalMode && !verticalMode) {
6332 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6337 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6339 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6343void QQuickTableView::moveColumn(
int source,
int destination)
6345 Q_D(QQuickTableView);
6346 d->moveSection(source, destination, Qt::Horizontal);
6349void QQuickTableView::moveRow(
int source,
int destination)
6351 Q_D(QQuickTableView);
6352 d->moveSection(source, destination, Qt::Vertical);
6355void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientation orientation)
6357 Q_Q(QQuickTableView);
6359 if (source < 0 || destination < 0 ||
6360 (orientation == Qt::Horizontal &&
6361 (source >= tableSize.width() || destination >= tableSize.width())) ||
6362 (orientation == Qt::Vertical &&
6363 (source >= tableSize.height() || destination >= tableSize.height())))
6366 if (source == destination)
6369 if (m_sectionState != SectionState::Moving) {
6370 m_sectionState = SectionState::Moving;
6372 syncView->d_func()->moveSection(source, destination, orientation);
6375 initializeIndexMapping();
6378 auto &visualIndices = visualIndicesForOrientation(orientation);
6379 auto &logicalIndices = logicalIndicesForOrientation(orientation);
6381 const int logical = logicalIndices.at(source).index;
6382 int visual = source;
6384 if (destination > source) {
6385 while (visual < destination) {
6386 SectionData &visualData = visualIndices[logicalIndices[visual + 1].index];
6387 SectionData &logicalData = logicalIndices[visual];
6388 visualData.prevIndex = visualData.index;
6389 visualData.index = visual;
6390 logicalData.prevIndex = logicalData.index;
6391 logicalData.index = logicalIndices[visual + 1].index;
6395 while (visual > destination) {
6396 SectionData &visualData = visualIndices[logicalIndices[visual - 1].index];
6397 SectionData &logicalData = logicalIndices[visual];
6398 visualData.prevIndex = visualData.index;
6399 visualData.index = visual;
6400 logicalData.prevIndex = logicalData.index;
6401 logicalData.index = logicalIndices[visual - 1].index;
6406 visualIndices[logical].prevIndex = visualIndices[logical].index;
6407 visualIndices[logical].index = destination;
6408 logicalIndices[destination].prevIndex = logicalIndices[destination].index;
6409 logicalIndices[destination].index = logical;
6413 for (
auto syncChild : std::as_const(syncChildren)) {
6414 auto syncChild_d = syncChild->d_func();
6415 if (syncChild_d->m_sectionState != SectionState::Moving &&
6416 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6417 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6418 syncChild_d->moveSection(source, destination, orientation);
6423 scheduleRebuildTable(RebuildOption::ViewportOnly);
6424 m_sectionState = SectionState::Idle;
6427 const int startIndex = (source > destination) ? destination : source;
6428 const int endIndex = (source > destination) ? source : destination;
6429 const auto &logicalDataIndices = syncView
6430 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6431 : logicalIndicesForOrientation(orientation);
6432 const auto &visualDataIndices = syncView
6433 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6434 : visualIndicesForOrientation(orientation);
6435 for (
int index = startIndex; index <= endIndex; index++) {
6436 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6437 if (orientation == Qt::Horizontal)
6438 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6440 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6445void QQuickTableView::clearColumnReordering()
6447 Q_D(QQuickTableView);
6448 d->clearSection(Qt::Horizontal);
6451void QQuickTableView::clearRowReordering()
6453 Q_D(QQuickTableView);
6454 d->clearSection(Qt::Vertical);
6457void QQuickTableViewPrivate::clearSection(Qt::Orientation orientation)
6459 Q_Q(QQuickTableView);
6461 const auto &oldLogicalIndices = syncView
6462 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6463 : logicalIndicesForOrientation(orientation);
6464 const auto &oldVisualIndices = syncView
6465 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6466 : visualIndicesForOrientation(orientation);
6469 syncView->d_func()->clearSection(orientation);
6472 logicalIndicesForOrientation(orientation).clear();
6473 visualIndicesForOrientation(orientation).clear();
6474 scheduleRebuildTable(RebuildOption::ViewportOnly);
6478 for (
int index = 0; index <
int(oldLogicalIndices.size()); index++) {
6479 const auto &logicalDataIndices = oldLogicalIndices;
6480 const auto &visualDataIndices = oldVisualIndices;
6481 if (logicalDataIndices[index].index != index) {
6482 const int currentIndex = logicalDataIndices[index].index;
6483 if (orientation == Qt::Horizontal)
6484 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6486 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6491void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6493 if (!modelIndex.isValid())
6496 const int cellIndex = modelIndexToCellIndex(modelIndex);
6497 if (!loadedItems.contains(cellIndex))
6499 const QPoint cell = cellAtModelIndex(cellIndex);
6500 QQuickItem *item = loadedTableItem(cell)->item;
6501 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6504QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6506 Q_D(
const QQuickTableView);
6507 const int modelIndex = d->modelIndexAtCell(cell);
6508 if (!d->loadedItems.contains(modelIndex))
6510 return d->loadedItems.value(modelIndex)->item;
6513#if QT_DEPRECATED_SINCE(6
, 5
)
6514QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6516 return itemAtCell(QPoint(column, row));
6520QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6522 Q_D(
const QQuickTableView);
6523 const int serializedIndex = d->modelIndexToCellIndex(index);
6524 if (!d->loadedItems.contains(serializedIndex))
6526 return d->loadedItems.value(serializedIndex)->item;
6529#if QT_DEPRECATED_SINCE(6
, 4
)
6530QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6532 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6535QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6537 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6541QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6543 return cellAtPosition(QPoint(x, y), includeSpacing);
6546QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6548 Q_D(
const QQuickTableView);
6550 if (!d->loadedTableOuterRect.contains(position))
6551 return QPoint(-1, -1);
6553 const qreal hSpace = d->cellSpacing.width();
6554 const qreal vSpace = d->cellSpacing.height();
6555 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6556 qreal currentRowEnd = d->loadedTableOuterRect.y();
6558 int foundColumn = -1;
6561 for (
const int column : d->loadedColumns) {
6562 currentColumnEnd += d->getEffectiveColumnWidth(column);
6563 if (position.x() < currentColumnEnd) {
6564 foundColumn = column;
6567 currentColumnEnd += hSpace;
6568 if (!includeSpacing && position.x() < currentColumnEnd) {
6570 return QPoint(-1, -1);
6571 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6572 foundColumn = column;
6577 for (
const int row : d->loadedRows) {
6578 currentRowEnd += d->getEffectiveRowHeight(row);
6579 if (position.y() < currentRowEnd) {
6583 currentRowEnd += vSpace;
6584 if (!includeSpacing && position.y() < currentRowEnd) {
6586 return QPoint(-1, -1);
6588 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6594 return QPoint(foundColumn, foundRow);
6597bool QQuickTableView::isColumnLoaded(
int column)
const
6599 Q_D(
const QQuickTableView);
6600 if (!d->loadedColumns.contains(column))
6603 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6606 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6613bool QQuickTableView::isRowLoaded(
int row)
const
6615 Q_D(
const QQuickTableView);
6616 if (!d->loadedRows.contains(row))
6619 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6622 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6629qreal QQuickTableView::columnWidth(
int column)
const
6631 Q_D(
const QQuickTableView);
6632 if (!isColumnLoaded(column))
6635 return d->getEffectiveColumnWidth(column);
6638qreal QQuickTableView::rowHeight(
int row)
const
6640 Q_D(
const QQuickTableView);
6641 if (!isRowLoaded(row))
6644 return d->getEffectiveRowHeight(row);
6647qreal QQuickTableView::implicitColumnWidth(
int column)
const
6649 Q_D(
const QQuickTableView);
6650 if (!isColumnLoaded(column))
6653 return d->sizeHintForColumn(column);
6656qreal QQuickTableView::implicitRowHeight(
int row)
const
6658 Q_D(
const QQuickTableView);
6659 if (!isRowLoaded(row))
6662 return d->sizeHintForRow(row);
6665void QQuickTableView::setColumnWidth(
int column, qreal size)
6667 Q_D(QQuickTableView);
6669 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6673 if (d->syncHorizontally) {
6674 d->syncView->setColumnWidth(column, size);
6678 if (qFuzzyCompare(explicitColumnWidth(column), size))
6682 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6684 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6686 if (d->loadedItems.isEmpty())
6689 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6690 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6691 d->forceLayout(
false);
6694void QQuickTableView::clearColumnWidths()
6696 Q_D(QQuickTableView);
6698 if (d->syncHorizontally) {
6699 d->syncView->clearColumnWidths();
6703 if (d->explicitColumnWidths.isEmpty())
6706 d->explicitColumnWidths.clear();
6707 d->forceLayout(
false);
6710qreal QQuickTableView::explicitColumnWidth(
int column)
const
6712 Q_D(
const QQuickTableView);
6714 if (d->syncHorizontally)
6715 return d->syncView->explicitColumnWidth(column);
6717 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6718 if (it != d->explicitColumnWidths.constEnd())
6723void QQuickTableView::setRowHeight(
int row, qreal size)
6725 Q_D(QQuickTableView);
6727 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
6731 if (d->syncVertically) {
6732 d->syncView->setRowHeight(row, size);
6736 if (qFuzzyCompare(explicitRowHeight(row), size))
6740 d->explicitRowHeights.remove(d->logicalRowIndex(row));
6742 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
6744 if (d->loadedItems.isEmpty())
6747 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
6748 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
6749 d->forceLayout(
false);
6752void QQuickTableView::clearRowHeights()
6754 Q_D(QQuickTableView);
6756 if (d->syncVertically) {
6757 d->syncView->clearRowHeights();
6761 if (d->explicitRowHeights.isEmpty())
6764 d->explicitRowHeights.clear();
6765 d->forceLayout(
false);
6768qreal QQuickTableView::explicitRowHeight(
int row)
const
6770 Q_D(
const QQuickTableView);
6772 if (d->syncVertically)
6773 return d->syncView->explicitRowHeight(row);
6775 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
6776 if (it != d->explicitRowHeights.constEnd())
6781QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
6783 Q_D(
const QQuickTableView);
6784 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
6787 auto const qaim = d->model->abstractItemModel();
6791 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
6794QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
6796 if (!index.isValid() || index.parent().isValid())
6798 Q_D(
const QQuickTableView);
6799 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
6802#if QT_DEPRECATED_SINCE(6
, 4
)
6803QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
6805 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
6811 return modelIndex({row, column});
6813 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
6814 "Use index(row, column) instead. For more information, see "
6815 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
6816 return modelIndex({column, row});
6821QModelIndex QQuickTableView::index(
int row,
int column)
const
6823 return modelIndex({column, row});
6826int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
6828 return cellAtIndex(index).y();
6831int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
6833 return cellAtIndex(index).x();
6836void QQuickTableView::forceLayout()
6838 d_func()->forceLayout(
true);
6841void QQuickTableView::edit(
const QModelIndex &requestedIndex)
6843 Q_D(QQuickTableView);
6846 if (!d->canEdit(requestedIndex,
true))
6849 const auto *aim = d->qaim(d->modelImpl());
6854 const QModelIndex index = aim->buddy(requestedIndex);
6856 if (d->editIndex == index)
6862 if (!d->editModel) {
6863 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
6864 d->editModel->useImportVersion(d->resolveImportVersion());
6865 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
this,
6866 [
this, d] (
int serializedModelIndex, QObject *object) {
6872 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
6873 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
6874 d->editItem = qmlobject_cast<QQuickItem*>(object);
6878 const bool init =
true;
6879 d->updateItemProperties(serializedModelIndex, object, init);
6880 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
6882 d->editItem->setParentItem(cellItem);
6889 if (d->selectionModel)
6890 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
6893 d->closeEditorAndCommit();
6895 const auto cellItem = itemAtCell(cellAtIndex(index));
6897 const auto attached = d->getAttachedObject(cellItem);
6900 d->editModel->setModel(d->tableModel->model());
6901 d->editModel->setDelegate(attached->editDelegate());
6903 const int cellIndex = d->getEditCellIndex(index);
6904 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
6906 d->editIndex = QModelIndex();
6907 d->editItem =
nullptr;
6908 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
6915 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
6916 d->editItem =
nullptr;
6917 d->editIndex = QModelIndex();
6918 d->editModel->release(object, QQmlInstanceModel::NotReusable);
6924 d->model->object(cellIndex, QQmlIncubator::Synchronous);
6927 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
6930 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
6931 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
6934void QQuickTableView::closeEditor()
6936 Q_D(QQuickTableView);
6941 QQuickItem *cellItem = d->editItem->parentItem();
6942 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
6943 d->editItem =
nullptr;
6946 const int cellIndex = d->getEditCellIndex(d->editIndex);
6947 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
6949 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
6951 if (d->editIndex.isValid()) {
6954 d->editIndex = QModelIndex();
6958QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
6960 return new QQuickTableViewAttached(obj);
6963void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
6965 Q_D(QQuickTableView);
6966 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
6968 if (d->tableModel) {
6971 d->tableModel->drainReusableItemsPool(0);
6974 d->forceLayout(
false);
6977void QQuickTableView::viewportMoved(Qt::Orientations orientation)
6979 Q_D(QQuickTableView);
6985 QQuickFlickable::viewportMoved(orientation);
6986 if (d->inSetLocalViewportPos)
6993 d->syncViewportPosRecursive();
6995 auto rootView = d->rootSyncView();
6996 auto rootView_d = rootView->d_func();
6998 rootView_d->scheduleRebuildIfFastFlick();
7000 if (!rootView_d->polishScheduled) {
7001 if (rootView_d->scheduledRebuildOptions) {
7008 const bool updated = rootView->d_func()->updateTableRecursive();
7018void QQuickTableView::keyPressEvent(QKeyEvent *e)
7020 Q_D(QQuickTableView);
7022 if (!d->keyNavigationEnabled) {
7023 QQuickFlickable::keyPressEvent(e);
7027 if (d->tableSize.isEmpty())
7030 if (d->editIndex.isValid()) {
7036 if (d->setCurrentIndexFromKeyEvent(e))
7039 if (d->editFromKeyEvent(e))
7042 QQuickFlickable::keyPressEvent(e);
7045bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
7047 Q_D(QQuickTableView);
7049 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
7052 return QQuickFlickable::eventFilter(obj, event);
7055 switch (event->type()) {
7056 case QEvent::KeyPress: {
7057 Q_ASSERT(d->editItem);
7058 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7059 switch (keyEvent->key()) {
7061 case Qt::Key_Return:
7062 d->closeEditorAndCommit();
7065 case Qt::Key_Backtab:
7066 if (activeFocusOnTab()) {
7067 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7068 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7069 if (d->canEdit(currentIndex,
false))
7075 case Qt::Key_Escape:
7080 case QEvent::FocusOut:
7083 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7084 d->closeEditorAndCommit();
7090 return QQuickFlickable::eventFilter(obj, event);
7093bool QQuickTableView::alternatingRows()
const
7095 return d_func()->alternatingRows;
7098void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7100 Q_D(QQuickTableView);
7101 if (d->alternatingRows == alternatingRows)
7104 d->alternatingRows = alternatingRows;
7105 emit alternatingRowsChanged();
7108QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7110 return d_func()->selectionBehavior;
7113void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7115 Q_D(QQuickTableView);
7116 if (d->selectionBehavior == selectionBehavior)
7119 d->selectionBehavior = selectionBehavior;
7120 emit selectionBehaviorChanged();
7123QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7125 return d_func()->selectionMode;
7128void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7130 Q_D(QQuickTableView);
7131 if (d->selectionMode == selectionMode)
7134 d->selectionMode = selectionMode;
7135 emit selectionModeChanged();
7138bool QQuickTableView::resizableColumns()
const
7140 return d_func()->resizableColumns;
7143void QQuickTableView::setResizableColumns(
bool enabled)
7145 Q_D(QQuickTableView);
7146 if (d->resizableColumns == enabled)
7149 d->resizableColumns = enabled;
7150 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7151 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7153 emit resizableColumnsChanged();
7156bool QQuickTableView::resizableRows()
const
7158 return d_func()->resizableRows;
7161void QQuickTableView::setResizableRows(
bool enabled)
7163 Q_D(QQuickTableView);
7164 if (d->resizableRows == enabled)
7167 d->resizableRows = enabled;
7168 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7169 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7171 emit resizableRowsChanged();
7176 : QQuickHoverHandler(view->contentItem())
7180 connect(
this, &QQuickHoverHandler::hoveredChanged,
this, [
this] {
7185#if QT_CONFIG(cursor)
7186 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7187 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7188 tableViewPrivate->updateCursor();
7195 QQuickHoverHandler::handleEventPoint(event, point);
7197 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7198#if QT_CONFIG(cursor)
7199 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7202 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7203 const auto item = tableView->itemAtCell(cell);
7207#if QT_CONFIG(cursor)
7208 tableViewPrivate->updateCursor();
7213 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7214 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7215 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7216 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7217 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7218#if QT_CONFIG(cursor)
7219 tableViewPrivate->updateCursor();
7230 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7235 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7239 if (event->type() == QEvent::Type::Wheel)
7244 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7245 return !tableView->isMoving();
7254 setObjectName(
"tableViewResizeHandler");
7258 , QPointingDevice::GrabTransition transition
7260 , QEventPoint &point)
7262 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7264 switch (transition) {
7265 case QPointingDevice::GrabPassive:
7266 case QPointingDevice::GrabExclusive:
7268 case QPointingDevice::UngrabPassive:
7269 case QPointingDevice::UngrabExclusive:
7270 case QPointingDevice::CancelGrabPassive:
7271 case QPointingDevice::CancelGrabExclusive:
7272 case QPointingDevice::OverrideGrabPassive:
7273 if (m_state == DraggingStarted || m_state == Dragging) {
7274 m_state = DraggingFinished;
7275 updateDrag(ev, point);
7283 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7284 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7285 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7292 updateDrag(event, point);
7297 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7298 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7300 if (m_state == DraggingFinished)
7301 m_state = Listening;
7303 if (point.state() == QEventPoint::Pressed) {
7304 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7305 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7306 if (m_row != -1 || m_column != -1)
7308 }
else if (point.state() == QEventPoint::Released) {
7309 if (m_state == DraggingStarted || m_state == Dragging)
7310 m_state = DraggingFinished;
7312 m_state = Listening;
7313 }
else if (point.state() == QEventPoint::Updated) {
7318 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7319 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7320 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7321 if (dragDist > qApp->styleHints()->startDragDistance())
7322 m_state = DraggingStarted;
7324 case DraggingStarted:
7329 case DraggingFinished:
7339 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7340#if QT_CONFIG(cursor)
7341 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7348 setPassiveGrab(event, point,
true);
7352 tableView->setFiltersChildMouseEvents(
false);
7353#if QT_CONFIG(cursor)
7354 tableViewPrivate->setActivePointerHandler(
this);
7357 case DraggingStarted:
7358 setExclusiveGrab(event, point,
true);
7359 m_columnStartX = point.position().x();
7360 m_columnStartWidth = tableView->columnWidth(m_column);
7361 m_rowStartY = point.position().y();
7362 m_rowStartHeight = tableView->rowHeight(m_row);
7363#if QT_CONFIG(cursor)
7364 tableViewPrivate->updateCursor();
7368 const qreal distX = point.position().x() - m_columnStartX;
7369 const qreal distY = point.position().y() - m_rowStartY;
7371 tableView->setColumnWidth(
m_column, qMax(0.001, m_columnStartWidth + distX));
7373 tableView->setRowHeight(
m_row, qMax(0.001, m_rowStartHeight + distY));
7375 case DraggingFinished: {
7376 tableView->setFiltersChildMouseEvents(
true);
7377#if QT_CONFIG(cursor)
7378 tableViewPrivate->setActivePointerHandler(
nullptr);
7379 tableViewPrivate->updateCursor();
7386#if QT_CONFIG(quick_draganddrop)
7388QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7389 : QQuickTableViewPointerHandler(view)
7391 setObjectName(
"tableViewDragHandler");
7394QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7399void QQuickTableViewSectionDragHandler::resetDragData()
7401 if (m_state != Listening) {
7402 m_state = Listening;
7403 resetSectionOverlay();
7406 if (m_grabResult.data())
7407 m_grabResult.data()->disconnect();
7408 if (!m_drag.isNull()) {
7409 m_drag->disconnect();
7412 if (!m_dropArea.isNull()) {
7413 m_dropArea->disconnect();
7416 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7417 tableView->setFiltersChildMouseEvents(
true);
7421void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7423 if (m_destination != -1) {
7424 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7425 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7426 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7427 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7428 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7433void QQuickTableViewSectionDragHandler::grabSection()
7436 QPixmap pixmap(m_grabResult->image().size());
7437 pixmap.fill(Qt::transparent);
7438 QPainter painter(&pixmap);
7439 painter.setOpacity(0.6);
7440 painter.drawImage(0, 0, m_grabResult->image());
7444 auto *mimeData =
new QMimeData();
7445 mimeData->setImageData(pixmap);
7446 m_drag->setMimeData(mimeData);
7447 m_drag->setPixmap(pixmap);
7450void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7454 if (m_state == Dragging) {
7455 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7456 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7457 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7458 m_state = DraggingFinished;
7459 resetSectionOverlay();
7460 if (m_scrollTimer.isActive())
7461 m_scrollTimer.stop();
7466void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7470 if (m_state == Dragging) {
7471 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7472 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7473 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7474 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7476 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7477 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7478 if (newDestination != m_destination) {
7480 resetSectionOverlay();
7482 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7483 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7484 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7485 m_destination = newDestination;
7489 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7490 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7491 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7492 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7493 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7494 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7495 if (useStartPos || useEndPos) {
7496 if (!m_scrollTimer.isActive()) {
7497 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7498 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7499 m_scrollTimer.start(1);
7502 if (m_scrollTimer.isActive())
7503 m_scrollTimer.stop();
7508void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7512 if (action == Qt::IgnoreAction) {
7513 resetSectionOverlay();
7514 if (m_scrollTimer.isActive())
7515 m_scrollTimer.stop();
7519void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7521 QQuickSinglePointHandler::handleEventPoint(event, point);
7523 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7524 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7525 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7526 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7529 if (m_state == DraggingFinished) {
7530 if (m_scrollTimer.isActive())
7531 m_scrollTimer.stop();
7535 if (point.state() == QEventPoint::Pressed) {
7539 setPassiveGrab(event, point,
true);
7543 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7544 tableView->setFiltersChildMouseEvents(
false);
7546 }
else if (point.state() == QEventPoint::Released) {
7548 if (m_scrollTimer.isActive())
7549 m_scrollTimer.stop();
7551 }
else if (point.state() == QEventPoint::Updated) {
7553 const qreal distX = point.position().x() - point.pressPosition().x();
7554 const qreal distY = point.position().y() - point.pressPosition().y();
7555 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7556 if (dragDist > qApp->styleHints()->startDragDistance()) {
7560 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7561 auto *item = tableView->itemAtCell(cell);
7564 if (m_drag.isNull()) {
7565 m_drag =
new QDrag(item);
7566 connect(m_drag.data(), &QDrag::actionChanged,
this,
7567 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7570 QObject::connect(&m_scrollTimer, &QTimer::timeout,
this, [&]{
7571 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7572 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7573 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7574 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7577 if (m_dropArea.isNull()) {
7578 m_dropArea =
new QQuickDropArea(tableView);
7579 m_dropArea->setSize(tableView->size());
7580 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7581 &QQuickTableViewSectionDragHandler::handleDrag);
7582 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7583 &QQuickTableViewSectionDragHandler::handleDrop);
7586 m_grabResult = item->grabToImage();
7587 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7588 &QQuickTableViewSectionDragHandler::grabSection);
7590 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7591 m_state = DraggingStarted;
7593 tableViewPrivate->setActivePointerHandler(
this);
7597 case DraggingStarted: {
7598 if (m_drag && m_drag->mimeData()) {
7599 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7601 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7603 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7607 if (m_state == Dragging)
7610 tableViewPrivate->setActivePointerHandler(
nullptr);
7624void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7626 if (!sectionDragHandler) {
7627 Q_Q(QQuickTableView);
7628 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7629 sectionDragHandler->setSectionOrientation(orientation);
7633void QQuickTableViewPrivate::destroySectionDragHandler()
7635 if (sectionDragHandler) {
7636 delete sectionDragHandler;
7637 sectionDragHandler =
nullptr;
7642void QQuickTableViewPrivate::initializeIndexMapping()
7644 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7645 visualIndex.resize(size);
7646 logicalIndex.resize(size);
7647 for (
int index = 0; index < size; ++index)
7648 visualIndex[index].index = logicalIndex[index].index = index;
7651 if (horizontalVisualIndices.size() != size_t(tableSize.width())
7652 || horizontalLogicalIndices.size() != size_t(tableSize.width()))
7653 initIndices(horizontalVisualIndices, horizontalLogicalIndices, tableSize.width());
7655 if (verticalVisualIndices.size() != size_t(tableSize.height())
7656 || verticalLogicalIndices.size() != size_t(tableSize.height()))
7657 initIndices(verticalVisualIndices, verticalLogicalIndices, tableSize.height());
7660void QQuickTableViewPrivate::clearIndexMapping()
7662 horizontalLogicalIndices.clear();
7663 horizontalVisualIndices.clear();
7665 verticalLogicalIndices.clear();
7666 verticalVisualIndices.clear();
7669int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7672 return syncView->d_func()->logicalRowIndex(visualIndex);
7673 if (verticalLogicalIndices.empty() || visualIndex < 0)
7675 return verticalLogicalIndices.at(visualIndex).index;
7678int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7681 return syncView->d_func()->logicalColumnIndex(visualIndex);
7682 if (horizontalLogicalIndices.empty() || visualIndex < 0)
7684 return horizontalLogicalIndices.at(visualIndex).index;
7687int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7690 return syncView->d_func()->visualRowIndex(logicalIndex);
7691 if (verticalVisualIndices.empty() || logicalIndex < 0)
7692 return logicalIndex;
7693 return verticalVisualIndices.at(logicalIndex).index;
7696int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7699 return syncView->d_func()->visualColumnIndex(logicalIndex);
7700 if (horizontalVisualIndices.empty() || logicalIndex < 0)
7701 return logicalIndex;
7702 return horizontalVisualIndices.at(logicalIndex).index;
7705int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7709 const bool hasProxyModel = (modelImpl() != assignedModel);
7710 return modelIndexToCellIndex(index, hasProxyModel);
7716 : QQuickTapHandler(view->contentItem())
7718 setObjectName(
"tableViewTapHandler");
7723 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7724 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7725 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
7730#include "moc_qquicktableview_p.cpp"
7731#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