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();
1869 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1872 if (pos.x() == -1) {
1874 clampedCell = q->cellAtIndex(selectionModel->currentIndex());
1876 clampedCell = clampedCellAtPos(pos);
1877 if (cellIsValid(clampedCell))
1878 setCurrentIndex(clampedCell);
1881 if (!cellIsValid(clampedCell))
1884 switch (selectionBehavior) {
1885 case QQuickTableView::SelectCells:
1886 selectionStartCell = clampedCell;
1888 case QQuickTableView::SelectRows:
1889 selectionStartCell = QPoint(0, clampedCell.y());
1891 case QQuickTableView::SelectColumns:
1892 selectionStartCell = QPoint(clampedCell.x(), 0);
1894 case QQuickTableView::SelectionDisabled:
1898 if (!cellIsValid(selectionEndCell))
1902 updateSelection(prevSelection, selection());
1905void QQuickTableViewPrivate::setSelectionEndPos(
const QPointF &pos)
1907 Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
1908 if (loadedItems.isEmpty())
1910 if (!selectionModel) {
1911 if (warnNoSelectionModel)
1912 qmlWarning(q_func()) <<
"Cannot set selection: no SelectionModel assigned!";
1913 warnNoSelectionModel =
false;
1916 const QAbstractItemModel *qaim = selectionModel->model();
1920 const QRect prevSelection = selection();
1923 if (selectionMode == QQuickTableView::SingleSelection) {
1924 clampedCell = selectionStartCell;
1926 clampedCell = clampedCellAtPos(pos);
1927 if (!cellIsValid(clampedCell))
1931 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
1933 setCurrentIndex(clampedCell);
1935 switch (selectionBehavior) {
1936 case QQuickTableView::SelectCells:
1937 selectionEndCell = clampedCell;
1939 case QQuickTableView::SelectRows:
1940 selectionEndCell = QPoint(tableSize.width() - 1, clampedCell.y());
1942 case QQuickTableView::SelectColumns:
1943 selectionEndCell = QPoint(clampedCell.x(), tableSize.height() - 1);
1945 case QQuickTableView::SelectionDisabled:
1949 if (!cellIsValid(selectionStartCell))
1953 updateSelection(prevSelection, selection());
1956QPoint QQuickTableViewPrivate::clampedCellAtPos(
const QPointF &pos)
const
1958 Q_Q(
const QQuickTableView);
1961 QPoint cell = q->cellAtPosition(pos,
true);
1962 if (cellIsValid(cell))
1965 if (loadedTableOuterRect.width() == 0 || loadedTableOuterRect.height() == 0)
1966 return QPoint(-1, -1);
1970 qBound(loadedTableOuterRect.x(), pos.x(), loadedTableOuterRect.right() - 1),
1971 qBound(loadedTableOuterRect.y(), pos.y(), loadedTableOuterRect.bottom() - 1));
1972 QPointF clampedPosInView = q->mapFromItem(selectionPointerHandlerTarget(), clampedPos);
1973 clampedPosInView.rx() = qBound(0., clampedPosInView.x(), viewportRect.width());
1974 clampedPosInView.ry() = qBound(0., clampedPosInView.y(), viewportRect.height());
1975 clampedPos = q->mapToItem(selectionPointerHandlerTarget(), clampedPosInView);
1977 return q->cellAtPosition(clampedPos,
true);
1980void QQuickTableViewPrivate::updateSelection(
const QRect &oldSelection,
const QRect &newSelection)
1982 if (oldSelection == newSelection)
1985 const QAbstractItemModel *qaim = selectionModel->model();
1986 const QRect oldRect = oldSelection.normalized();
1987 const QRect newRect = newSelection.normalized();
1989 const auto &columnMapping = syncView ? syncView->d_func()->horizontalLogicalIndices
1990 : horizontalLogicalIndices;
1991 const auto &rowMapping = syncView ? syncView->d_func()->verticalLogicalIndices
1992 : verticalLogicalIndices;
1993 const bool hasMapping = !columnMapping.empty() || !rowMapping.empty();
1995 QItemSelection select;
1996 QItemSelection deselect;
1998 const auto mergeInto =
1999 [
this, qaim, hasMapping](QItemSelection &selection,
2000 const QModelIndex &startIndex,
const QModelIndex &endIndex)
2003 for (
const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
2004 const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()),
2005 logicalColumnIndex(modelIndex.column()));
2006 selection.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
2009 selection.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
2015 const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
2016 const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
2017 mergeInto(select, startIndex, endIndex);
2021 if (oldRect.x() < newRect.x()) {
2022 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2023 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
2024 mergeInto(deselect, startIndex, endIndex);
2025 }
else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
2026 const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
2027 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2028 mergeInto(deselect, startIndex, endIndex);
2031 if (oldRect.y() < newRect.y()) {
2032 const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
2033 const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
2034 mergeInto(deselect, startIndex, endIndex);
2035 }
else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
2036 const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
2037 const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
2038 mergeInto(deselect, startIndex, endIndex);
2041 if (selectionFlag == QItemSelectionModel::Select) {
2043 deselect.merge(existingSelection, QItemSelectionModel::Deselect);
2044 selectionModel->select(deselect, QItemSelectionModel::Deselect);
2045 selectionModel->select(select, QItemSelectionModel::Select);
2046 }
else if (selectionFlag == QItemSelectionModel::Deselect){
2047 QItemSelection oldSelection = existingSelection;
2048 oldSelection.merge(select, QItemSelectionModel::Deselect);
2049 selectionModel->select(oldSelection, QItemSelectionModel::Select);
2050 selectionModel->select(select, QItemSelectionModel::Deselect);
2056void QQuickTableViewPrivate::cancelSelectionTracking()
2059 selectionStartCell = QPoint(-1, -1);
2060 selectionEndCell = QPoint(-1, -1);
2061 existingSelection.clear();
2062 selectionFlag = QItemSelectionModel::NoUpdate;
2063 if (selectableCallbackFunction)
2064 selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
2067void QQuickTableViewPrivate::clearSelection()
2069 if (!selectionModel)
2071 QScopedValueRollback callbackGuard(inSelectionModelUpdate,
true);
2072 selectionModel->clearSelection();
2075void QQuickTableViewPrivate::normalizeSelection()
2081 if (selectionEndCell.x() < selectionStartCell.x())
2082 std::swap(selectionStartCell.rx(), selectionEndCell.rx());
2083 if (selectionEndCell.y() < selectionStartCell.y())
2084 std::swap(selectionStartCell.ry(), selectionEndCell.ry());
2087QRectF QQuickTableViewPrivate::selectionRectangle()
const
2089 Q_Q(
const QQuickTableView);
2091 if (loadedColumns.isEmpty() || loadedRows.isEmpty())
2094 QPoint topLeftCell = selectionStartCell;
2095 QPoint bottomRightCell = selectionEndCell;
2096 if (bottomRightCell.x() < topLeftCell.x())
2097 std::swap(topLeftCell.rx(), bottomRightCell.rx());
2098 if (selectionEndCell.y() < topLeftCell.y())
2099 std::swap(topLeftCell.ry(), bottomRightCell.ry());
2101 const QPoint leftCell(topLeftCell.x(), topRow());
2102 const QPoint topCell(leftColumn(), topLeftCell.y());
2103 const QPoint rightCell(bottomRightCell.x(), topRow());
2104 const QPoint bottomCell(leftColumn(), bottomRightCell.y());
2117 if (loadedItems.contains(modelIndexAtCell(leftCell)))
2118 left = loadedTableItem(leftCell)->geometry().left();
2119 else if (leftCell.x() > rightColumn())
2120 left = q->contentWidth();
2122 if (loadedItems.contains(modelIndexAtCell(topCell)))
2123 top = loadedTableItem(topCell)->geometry().top();
2124 else if (topCell.y() > bottomRow())
2125 top = q->contentHeight();
2127 if (loadedItems.contains(modelIndexAtCell(rightCell)))
2128 right = loadedTableItem(rightCell)->geometry().right();
2129 else if (rightCell.x() > rightColumn())
2130 right = q->contentWidth();
2132 if (loadedItems.contains(modelIndexAtCell(bottomCell)))
2133 bottom = loadedTableItem(bottomCell)->geometry().bottom();
2134 else if (bottomCell.y() > bottomRow())
2135 bottom = q->contentHeight();
2137 return QRectF(left, top, right - left, bottom - top);
2140QRect QQuickTableViewPrivate::selection()
const
2142 const qreal w = selectionEndCell.x() - selectionStartCell.x();
2143 const qreal h = selectionEndCell.y() - selectionStartCell.y();
2144 return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
2147QSizeF QQuickTableViewPrivate::scrollTowardsPoint(
const QPointF &pos,
const QSizeF &step)
2149 Q_Q(QQuickTableView);
2151 if (loadedItems.isEmpty())
2161 const bool outsideLeft = pos.x() < viewportRect.x();
2162 const bool outsideRight = pos.x() >= viewportRect.right() - 1;
2163 const bool outsideTop = pos.y() < viewportRect.y();
2164 const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
2167 const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
2168 const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
2169 if (remainingDist > 0 || !firstColumnLoaded) {
2170 qreal stepX = step.width();
2171 if (firstColumnLoaded)
2172 stepX = qMin(stepX, remainingDist);
2173 q->setContentX(q->contentX() - stepX);
2174 dist.setWidth(pos.x() - viewportRect.left() - 1);
2176 }
else if (outsideRight) {
2177 const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
2178 const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
2179 if (remainingDist > 0 || !lastColumnLoaded) {
2180 qreal stepX = step.width();
2181 if (lastColumnLoaded)
2182 stepX = qMin(stepX, remainingDist);
2183 q->setContentX(q->contentX() + stepX);
2184 dist.setWidth(pos.x() - viewportRect.right() - 1);
2189 const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
2190 const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
2191 if (remainingDist > 0 || !firstRowLoaded) {
2192 qreal stepY = step.height();
2194 stepY = qMin(stepY, remainingDist);
2195 q->setContentY(q->contentY() - stepY);
2196 dist.setHeight(pos.y() - viewportRect.top() - 1);
2198 }
else if (outsideBottom) {
2199 const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
2200 const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
2201 if (remainingDist > 0 || !lastRowLoaded) {
2202 qreal stepY = step.height();
2204 stepY = qMin(stepY, remainingDist);
2205 q->setContentY(q->contentY() + stepY);
2206 dist.setHeight(pos.y() - viewportRect.bottom() - 1);
2213void QQuickTableViewPrivate::setCallback(std::function<
void (CallBackFlag)> func)
2215 selectableCallbackFunction = func;
2218QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(
const QObject *object)
const
2220 QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object,
false);
2221 return static_cast<QQuickTableViewAttached *>(attachedObject);
2224QQuickTableViewAttached::QQuickTableViewAttached(QObject *parent)
2227 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
2234 for (
int i = 0; i < 3; ++i) {
2235 parentItem = parentItem->parentItem();
2238 if (
auto tableView = qobject_cast<QQuickTableView *>(parentItem)) {
2245int QQuickTableViewPrivate::modelIndexAtCell(
const QPoint &cell)
const
2251 int availableColumns = tableSize.width();
2252 return (cell.y() * availableColumns) + cell.x();
2254 int availableRows = tableSize.height();
2255 return (cell.x() * availableRows) + cell.y();
2259QPoint QQuickTableViewPrivate::cellAtModelIndex(
int modelIndex)
const
2265 int availableColumns = tableSize.width();
2266 int row =
int(modelIndex / availableColumns);
2267 int column = modelIndex % availableColumns;
2268 return QPoint(column, row);
2270 int availableRows = tableSize.height();
2271 int column =
int(modelIndex / availableRows);
2272 int row = modelIndex % availableRows;
2273 return QPoint(column, row);
2277int QQuickTableViewPrivate::modelIndexToCellIndex(
const QModelIndex &modelIndex,
bool visualIndex)
const
2281 const QPoint cell = q_func()->cellAtIndex(modelIndex);
2282 if (!cellIsValid(cell))
2284 return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
2287int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
const
2289 return int(log2(
float(edge)));
2292void QQuickTableViewPrivate::clearEdgeSizeCache()
2294 cachedColumnWidth.startIndex = kEdgeIndexNotSet;
2295 cachedRowHeight.startIndex = kEdgeIndexNotSet;
2297 for (Qt::Edge edge : allTableEdges)
2298 cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
2301int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
const
2305 int startIndex = -1;
2307 case Qt::LeftEdge: startIndex = leftColumn() - 1;
break;
2308 case Qt::RightEdge: startIndex = rightColumn() + 1;
break;
2309 case Qt::TopEdge: startIndex = topRow() - 1;
break;
2310 case Qt::BottomEdge: startIndex = bottomRow() + 1;
break;
2313 return nextVisibleEdgeIndex(edge, startIndex);
2316int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge,
int startIndex)
const
2322 auto &cachedResult = cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)];
2323 if (cachedResult.containsIndex(edge, startIndex))
2324 return cachedResult.endIndex;
2328 int foundIndex = kEdgeIndexNotSet;
2329 int testIndex = startIndex;
2332 case Qt::LeftEdge: {
2334 if (testIndex < 0) {
2335 foundIndex = kEdgeIndexAtEnd;
2339 if (!isColumnHidden(testIndex)) {
2340 foundIndex = testIndex;
2347 case Qt::RightEdge: {
2349 if (testIndex > tableSize.width() - 1) {
2350 foundIndex = kEdgeIndexAtEnd;
2354 if (!isColumnHidden(testIndex)) {
2355 foundIndex = testIndex;
2364 if (testIndex < 0) {
2365 foundIndex = kEdgeIndexAtEnd;
2369 if (!isRowHidden(testIndex)) {
2370 foundIndex = testIndex;
2377 case Qt::BottomEdge: {
2379 if (testIndex > tableSize.height() - 1) {
2380 foundIndex = kEdgeIndexAtEnd;
2384 if (!isRowHidden(testIndex)) {
2385 foundIndex = testIndex;
2394 cachedResult.startIndex = startIndex;
2395 cachedResult.endIndex = foundIndex;
2399void QQuickTableViewPrivate::updateContentWidth()
2410 Q_Q(QQuickTableView);
2412 if (syncHorizontally) {
2413 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2414 q->QQuickFlickable::setContentWidth(syncView->contentWidth());
2418 if (explicitContentWidth.isValid()) {
2424 if (loadedItems.isEmpty()) {
2425 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2426 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2427 q->QQuickFlickable::setContentWidth(kDefaultColumnWidth);
2429 q->QQuickFlickable::setContentWidth(0);
2433 const int nextColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2434 const int columnsRemaining = nextColumn == kEdgeIndexAtEnd ? 0 : tableSize.width() - nextColumn;
2435 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2436 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2437 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2438 const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth;
2440 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2441 q->QQuickFlickable::setContentWidth(estimatedWidth);
2444void QQuickTableViewPrivate::updateContentHeight()
2446 Q_Q(QQuickTableView);
2448 if (syncVertically) {
2449 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2450 q->QQuickFlickable::setContentHeight(syncView->contentHeight());
2454 if (explicitContentHeight.isValid()) {
2460 if (loadedItems.isEmpty()) {
2461 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2462 if (model && model->count() > 0 && tableModel && tableModel->delegate())
2463 q->QQuickFlickable::setContentHeight(kDefaultRowHeight);
2465 q->QQuickFlickable::setContentHeight(0);
2469 const int nextRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2470 const int rowsRemaining = nextRow == kEdgeIndexAtEnd ? 0 : tableSize.height() - nextRow;
2471 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2472 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2473 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2474 const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight;
2476 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
2477 q->QQuickFlickable::setContentHeight(estimatedHeight);
2480void QQuickTableViewPrivate::updateExtents()
2493 Q_Q(QQuickTableView);
2495 bool tableMovedHorizontally =
false;
2496 bool tableMovedVertically =
false;
2498 const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge);
2499 const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge);
2500 const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge);
2501 const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge);
2503 QPointF prevOrigin = origin;
2504 QSizeF prevEndExtent = endExtent;
2506 if (syncHorizontally) {
2507 const auto syncView_d = syncView->d_func();
2508 origin.rx() = syncView_d->origin.x();
2509 endExtent.rwidth() = syncView_d->endExtent.width();
2510 }
else if (nextLeftColumn == kEdgeIndexAtEnd) {
2513 if (loadedTableOuterRect.left() > viewportRect.left()) {
2518 if (loadedTableOuterRect.left() > origin.x()) {
2519 const qreal diff = loadedTableOuterRect.left() - origin.x();
2520 loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff);
2521 loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff);
2522 tableMovedHorizontally =
true;
2525 origin.rx() = loadedTableOuterRect.left();
2526 }
else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) {
2530 const int columnsRemaining = nextLeftColumn + 1;
2531 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2532 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2533 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2534 origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth;
2535 }
else if (nextRightColumn == kEdgeIndexAtEnd) {
2538 if (loadedTableOuterRect.right() < viewportRect.right()) {
2543 const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width());
2544 if (loadedTableOuterRect.right() < w) {
2545 const qreal diff = loadedTableOuterRect.right() - w;
2546 loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff);
2547 loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff);
2548 tableMovedHorizontally =
true;
2551 endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth();
2552 }
else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) {
2556 const int columnsRemaining = tableSize.width() - nextRightColumn;
2557 const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width();
2558 const qreal remainingSpacing = columnsRemaining * cellSpacing.width();
2559 const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing;
2560 const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth();
2561 endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth;
2564 if (syncVertically) {
2565 const auto syncView_d = syncView->d_func();
2566 origin.ry() = syncView_d->origin.y();
2567 endExtent.rheight() = syncView_d->endExtent.height();
2568 }
else if (nextTopRow == kEdgeIndexAtEnd) {
2571 if (loadedTableOuterRect.top() > viewportRect.top()) {
2576 if (loadedTableOuterRect.top() > origin.y()) {
2577 const qreal diff = loadedTableOuterRect.top() - origin.y();
2578 loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff);
2579 loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff);
2580 tableMovedVertically =
true;
2583 origin.ry() = loadedTableOuterRect.top();
2584 }
else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) {
2588 const int rowsRemaining = nextTopRow + 1;
2589 const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height();
2590 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2591 const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing;
2592 origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight;
2593 }
else if (nextBottomRow == kEdgeIndexAtEnd) {
2596 if (loadedTableOuterRect.bottom() < viewportRect.bottom()) {
2601 const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height());
2602 if (loadedTableOuterRect.bottom() < h) {
2603 const qreal diff = loadedTableOuterRect.bottom() - h;
2604 loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff);
2605 loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff);
2606 tableMovedVertically =
true;
2609 endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight();
2610 }
else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) {
2614 const int rowsRemaining = tableSize.height() - nextBottomRow;
2615 const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height();
2616 const qreal remainingSpacing = rowsRemaining * cellSpacing.height();
2617 const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing;
2618 const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight();
2619 endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight;
2622 if (tableMovedHorizontally || tableMovedVertically) {
2623 qCDebug(lcTableViewDelegateLifecycle) <<
"move table to" << loadedTableOuterRect;
2627 relayoutTableItems();
2630 for (
auto syncChild : std::as_const(syncChildren)) {
2631 auto syncChild_d = syncChild->d_func();
2632 syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly;
2633 if (tableMovedHorizontally)
2634 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
2635 if (tableMovedVertically)
2636 syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
2640 if (prevOrigin != origin || prevEndExtent != endExtent) {
2641 if (prevOrigin != origin)
2642 qCDebug(lcTableViewDelegateLifecycle) <<
"move origin to:" << origin;
2643 if (prevEndExtent != endExtent)
2644 qCDebug(lcTableViewDelegateLifecycle) <<
"move endExtent to:" << endExtent;
2648 hData.markExtentsDirty();
2649 vData.markExtentsDirty();
2650 updateBeginningEnd();
2651 if (!q->isMoving()) {
2655 q->returnToBounds();
2660void QQuickTableViewPrivate::updateAverageColumnWidth()
2662 if (explicitContentWidth.isValid()) {
2663 const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width();
2664 averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width());
2666 const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width();
2667 averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count());
2671void QQuickTableViewPrivate::updateAverageRowHeight()
2673 if (explicitContentHeight.isValid()) {
2674 const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height();
2675 averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height());
2677 const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height();
2678 averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count());
2682void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
2684 const QPoint topLeft = QPoint(leftColumn(), topRow());
2685 const QPoint bottomRight = QPoint(rightColumn(), bottomRow());
2686 QRectF topLeftRect = loadedTableItem(topLeft)->geometry();
2687 QRectF bottomRightRect = loadedTableItem(bottomRight)->geometry();
2688 loadedTableOuterRect = QRectF(topLeftRect.topLeft(), bottomRightRect.bottomRight());
2689 loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
2692QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
2698 if (loadedItems.isEmpty()) {
2700 return RebuildOption::None;
2703 RebuildOptions rebuildOptions = RebuildOption::None;
2705 if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) {
2709 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2710 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2715 for (
int column = leftColumn(); column <= rightColumn(); ++column) {
2716 const bool wasVisibleFromBefore = loadedColumns.contains(column);
2717 const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column));
2718 if (wasVisibleFromBefore == isVisibleNow)
2723 qCDebug(lcTableViewDelegateLifecycle) <<
"Column" << column <<
"changed visibility to" << isVisibleNow;
2724 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2725 if (column == leftColumn()) {
2728 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn);
2734 if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) {
2738 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2739 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2744 for (
int row = topRow(); row <= bottomRow(); ++row) {
2745 const bool wasVisibleFromBefore = loadedRows.contains(row);
2746 const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row));
2747 if (wasVisibleFromBefore == isVisibleNow)
2752 qCDebug(lcTableViewDelegateLifecycle) <<
"Row" << row <<
"changed visibility to" << isVisibleNow;
2753 rebuildOptions.setFlag(RebuildOption::ViewportOnly);
2754 if (row == topRow())
2755 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow);
2760 return rebuildOptions;
2763void QQuickTableViewPrivate::forceLayout(
bool immediate)
2765 clearEdgeSizeCache();
2766 RebuildOptions rebuildOptions = RebuildOption::None;
2768 const QSize actualTableSize = calculateTableSize();
2769 if (tableSize != actualTableSize) {
2773 rebuildOptions |= RebuildOption::ViewportOnly;
2781 rebuildOptions |= RebuildOption::LayoutOnly
2782 | RebuildOption::CalculateNewContentWidth
2783 | RebuildOption::CalculateNewContentHeight
2784 | checkForVisibilityChanges();
2786 scheduleRebuildTable(rebuildOptions);
2789 auto rootView = rootSyncView();
2790 const bool updated = rootView->d_func()->updateTableRecursive();
2792 qWarning() <<
"TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!";
2798void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
2800 if (loadRequest.edge() == Qt::Edge(0)) {
2802 loadedColumns.insert(loadRequest.column());
2803 loadedRows.insert(loadRequest.row());
2807 switch (loadRequest.edge()) {
2810 loadedColumns.insert(loadRequest.column());
2813 case Qt::BottomEdge:
2814 loadedRows.insert(loadRequest.row());
2819FxTableItem *QQuickTableViewPrivate::loadedTableItem(
const QPoint &cell)
const
2821 const int modelIndex = modelIndexAtCell(cell);
2823 return loadedItems.value(modelIndex);
2826FxTableItem *QQuickTableViewPrivate::createFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2828 Q_Q(QQuickTableView);
2830 bool ownItem =
false;
2831 const int modelRow = isTransposed ? logicalColumnIndex(cell.y()) : logicalRowIndex(cell.y());
2832 const int modelColumn = isTransposed ? logicalRowIndex(cell.x()) : logicalColumnIndex(cell.x());
2833 const int modelIndex = modelIndexAtCell(QPoint(modelColumn, modelRow));
2835 QObject *object = model->object(modelIndex, incubationMode);
2838 if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
2844 qWarning() <<
"TableView: failed loading index:" << modelIndex;
2845 object =
new QQuickItem();
2849 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2853 qWarning() <<
"TableView: delegate is not an item:" << modelIndex;
2854 model->release(object);
2855 item =
new QQuickItem();
2858 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
2859 if (anchors && anchors->activeDirections())
2860 qmlWarning(item) <<
"TableView: detected anchors on delegate with index: " << modelIndex
2861 <<
". Use implicitWidth and implicitHeight instead.";
2868 item->setImplicitWidth(kDefaultColumnWidth);
2869 item->setImplicitHeight(kDefaultRowHeight);
2870 item->setParentItem(q->contentItem());
2874 FxTableItem *fxTableItem =
new FxTableItem(item, q, ownItem);
2875 fxTableItem->setVisible(
false);
2876 fxTableItem->cell = cell;
2877 fxTableItem->index = modelIndex;
2881FxTableItem *QQuickTableViewPrivate::loadFxTableItem(
const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
2886 static const bool forcedAsync = forcedIncubationMode == QLatin1String(
"async");
2888 incubationMode = QQmlIncubator::Asynchronous;
2893 QScopedValueRollback guard(blockItemCreatedCallback,
true);
2894 auto item = createFxTableItem(cell, incubationMode);
2895 qCDebug(lcTableViewDelegateLifecycle) << cell <<
"ready?" <<
bool(item);
2899void QQuickTableViewPrivate::releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag) {
2902 auto const tmpList = loadedItems;
2903 loadedItems.clear();
2904 for (FxTableItem *item : tmpList)
2905 releaseItem(item, reusableFlag);
2908void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag)
2910 Q_Q(QQuickTableView);
2913 auto item = fxTableItem->item;
2915 if (fxTableItem->ownItem) {
2919 auto releaseFlag = model->release(item, reusableFlag);
2920 if (releaseFlag == QQmlInstanceModel::Pooled) {
2921 fxTableItem->setVisible(
false);
2925 if (QQuickWindow *window = item->window()) {
2926 const auto focusItem = qobject_cast<QQuickItem *>(window->focusObject());
2928 const bool hasFocus = item == focusItem || item->isAncestorOf(focusItem);
2930 const auto focusChild = QQuickItemPrivate::get(q)->subFocusItem;
2931 deliveryAgentPrivate()->clearFocusInScope(q, focusChild, Qt::OtherFocusReason);
2941void QQuickTableViewPrivate::unloadItem(
const QPoint &cell)
2943 const int modelIndex = modelIndexAtCell(cell);
2945 releaseItem(loadedItems.take(modelIndex), reusableFlag);
2947 tableModel->commitReleasedItems();
2950bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2952 switch (tableEdge) {
2954 return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
2956 return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
2958 return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
2959 case Qt::BottomEdge:
2960 return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
2966bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge,
const QRectF fillRect)
const
2972 switch (tableEdge) {
2974 if (loadedColumns.count() <= 1)
2976 if (positionXAnimation.isRunning()) {
2977 const qreal to = positionXAnimation.to().toFloat();
2978 if (to < viewportRect.x())
2981 return loadedTableInnerRect.left() <= fillRect.left();
2983 if (loadedColumns.count() <= 1)
2985 if (positionXAnimation.isRunning()) {
2986 const qreal to = positionXAnimation.to().toFloat();
2987 if (to > viewportRect.x())
2990 return loadedTableInnerRect.right() >= fillRect.right();
2992 if (loadedRows.count() <= 1)
2994 if (positionYAnimation.isRunning()) {
2995 const qreal to = positionYAnimation.to().toFloat();
2996 if (to < viewportRect.y())
2999 return loadedTableInnerRect.top() <= fillRect.top();
3000 case Qt::BottomEdge:
3001 if (loadedRows.count() <= 1)
3003 if (positionYAnimation.isRunning()) {
3004 const qreal to = positionYAnimation.to().toFloat();
3005 if (to > viewportRect.y())
3008 return loadedTableInnerRect.bottom() >= fillRect.bottom();
3014Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(
const QRectF rect)
3016 for (Qt::Edge edge : allTableEdges) {
3017 if (!canLoadTableEdge(edge, rect))
3019 const int nextIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
3020 if (nextIndex == kEdgeIndexAtEnd)
3028Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(
const QRectF rect)
3030 for (Qt::Edge edge : allTableEdges) {
3031 if (canUnloadTableEdge(edge, rect))
3037qreal QQuickTableViewPrivate::cellWidth(
const QPoint& cell)
const
3041 auto const cellItem = loadedTableItem(cell)->item;
3042 return cellItem->implicitWidth();
3045qreal QQuickTableViewPrivate::cellHeight(
const QPoint& cell)
const
3049 auto const cellItem = loadedTableItem(cell)->item;
3050 return cellItem->implicitHeight();
3053qreal QQuickTableViewPrivate::sizeHintForColumn(
int column)
const
3056 qreal columnWidth = 0;
3057 for (
const int row : loadedRows)
3058 columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
3063qreal QQuickTableViewPrivate::sizeHintForRow(
int row)
const
3066 qreal rowHeight = 0;
3067 for (
const int column : loadedColumns)
3068 rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
3072QSize QQuickTableViewPrivate::calculateTableSize()
3076 size = QSize(tableModel->columns(), tableModel->rows());
3078 size = QSize(1, model->count());
3080 return isTransposed ? size.transposed() : size;
3083qreal QQuickTableViewPrivate::getColumnLayoutWidth(
int column)
3090 const qreal explicitColumnWidth = getColumnWidth(column);
3091 if (explicitColumnWidth >= 0)
3092 return explicitColumnWidth;
3094 if (syncHorizontally) {
3095 if (syncView->d_func()->loadedColumns.contains(column))
3096 return syncView->d_func()->getColumnLayoutWidth(column);
3104 qreal columnWidth = sizeHintForColumn(column);
3106 if (qIsNaN(columnWidth) || columnWidth <= 0) {
3107 if (!layoutWarningIssued) {
3108 layoutWarningIssued =
true;
3109 qmlWarning(q_func()) <<
"the delegate's implicitWidth needs to be greater than zero";
3111 columnWidth = kDefaultColumnWidth;
3117qreal QQuickTableViewPrivate::getEffectiveRowY(
int row)
const
3121 return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
3124qreal QQuickTableViewPrivate::getEffectiveRowHeight(
int row)
const
3128 return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
3131qreal QQuickTableViewPrivate::getEffectiveColumnX(
int column)
const
3135 return loadedTableItem(QPoint(column, topRow()))->geometry().x();
3138qreal QQuickTableViewPrivate::getEffectiveColumnWidth(
int column)
const
3142 return loadedTableItem(QPoint(column, topRow()))->geometry().width();
3145qreal QQuickTableViewPrivate::getRowLayoutHeight(
int row)
3152 const qreal explicitRowHeight = getRowHeight(row);
3153 if (explicitRowHeight >= 0)
3154 return explicitRowHeight;
3156 if (syncVertically) {
3157 if (syncView->d_func()->loadedRows.contains(row))
3158 return syncView->d_func()->getRowLayoutHeight(row);
3166 qreal rowHeight = sizeHintForRow(row);
3168 if (qIsNaN(rowHeight) || rowHeight <= 0) {
3169 if (!layoutWarningIssued) {
3170 layoutWarningIssued =
true;
3171 qmlWarning(q_func()) <<
"the delegate's implicitHeight needs to be greater than zero";
3173 rowHeight = kDefaultRowHeight;
3179qreal QQuickTableViewPrivate::getColumnWidth(
int column)
const
3185 Q_Q(
const QQuickTableView);
3187 const int noExplicitColumnWidth = -1;
3189 if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
3190 return cachedColumnWidth.size;
3192 if (syncHorizontally)
3193 return syncView->d_func()->getColumnWidth(column);
3195 if (columnWidthProvider.isUndefined()) {
3199 qreal explicitColumnWidth = q->explicitColumnWidth(column);
3200 if (explicitColumnWidth >= 0)
3201 return explicitColumnWidth;
3202 return noExplicitColumnWidth;
3205 qreal columnWidth = noExplicitColumnWidth;
3207 if (columnWidthProvider.isCallable()) {
3208 auto const columnAsArgument = QJSValueList() << QJSValue(column);
3209 columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
3210 if (qIsNaN(columnWidth) || columnWidth < 0)
3211 columnWidth = noExplicitColumnWidth;
3213 if (!layoutWarningIssued) {
3214 layoutWarningIssued =
true;
3215 qmlWarning(q_func()) <<
"columnWidthProvider doesn't contain a function";
3217 columnWidth = noExplicitColumnWidth;
3220 cachedColumnWidth.startIndex = logicalColumnIndex(column);
3221 cachedColumnWidth.size = columnWidth;
3225qreal QQuickTableViewPrivate::getRowHeight(
int row)
const
3231 Q_Q(
const QQuickTableView);
3233 const int noExplicitRowHeight = -1;
3235 if (cachedRowHeight.startIndex == logicalRowIndex(row))
3236 return cachedRowHeight.size;
3239 return syncView->d_func()->getRowHeight(row);
3241 if (rowHeightProvider.isUndefined()) {
3245 qreal explicitRowHeight = q->explicitRowHeight(row);
3246 if (explicitRowHeight >= 0)
3247 return explicitRowHeight;
3248 return noExplicitRowHeight;
3251 qreal rowHeight = noExplicitRowHeight;
3253 if (rowHeightProvider.isCallable()) {
3254 auto const rowAsArgument = QJSValueList() << QJSValue(row);
3255 rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
3256 if (qIsNaN(rowHeight) || rowHeight < 0)
3257 rowHeight = noExplicitRowHeight;
3259 if (!layoutWarningIssued) {
3260 layoutWarningIssued =
true;
3261 qmlWarning(q_func()) <<
"rowHeightProvider doesn't contain a function";
3263 rowHeight = noExplicitRowHeight;
3266 cachedRowHeight.startIndex = logicalRowIndex(row);
3267 cachedRowHeight.size = rowHeight;
3271qreal QQuickTableViewPrivate::getAlignmentContentX(
int column, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3273 Q_Q(QQuickTableView);
3276 const int columnX = getEffectiveColumnX(column);
3278 if (subRect.isValid()) {
3279 if (alignment == (Qt::AlignLeft | Qt::AlignRight)) {
3282 alignment = subRect.width() > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3285 if (alignment & Qt::AlignLeft) {
3286 contentX = columnX + subRect.x() + offset;
3287 }
else if (alignment & Qt::AlignRight) {
3288 contentX = columnX + subRect.right() - viewportRect.width() + offset;
3289 }
else if (alignment & Qt::AlignHCenter) {
3290 const qreal centerDistance = (viewportRect.width() - subRect.width()) / 2;
3291 contentX = columnX + subRect.x() - centerDistance + offset;
3294 const int columnWidth = getEffectiveColumnWidth(column);
3295 if (alignment == (Qt::AlignLeft | Qt::AlignRight))
3296 alignment = columnWidth > q->width() ? Qt::AlignLeft : Qt::AlignRight;
3298 if (alignment & Qt::AlignLeft) {
3299 contentX = columnX + offset;
3300 }
else if (alignment & Qt::AlignRight) {
3301 contentX = columnX + columnWidth - viewportRect.width() + offset;
3302 }
else if (alignment & Qt::AlignHCenter) {
3303 const qreal centerDistance = (viewportRect.width() - columnWidth) / 2;
3304 contentX = columnX - centerDistance + offset;
3309 contentX = qBound(-q->minXExtent(), contentX, -q->maxXExtent());
3314qreal QQuickTableViewPrivate::getAlignmentContentY(
int row, Qt::Alignment alignment,
const qreal offset,
const QRectF &subRect)
3316 Q_Q(QQuickTableView);
3319 const int rowY = getEffectiveRowY(row);
3321 if (subRect.isValid()) {
3322 if (alignment == (Qt::AlignTop | Qt::AlignBottom)) {
3325 alignment = subRect.height() > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3328 if (alignment & Qt::AlignTop) {
3329 contentY = rowY + subRect.y() + offset;
3330 }
else if (alignment & Qt::AlignBottom) {
3331 contentY = rowY + subRect.bottom() - viewportRect.height() + offset;
3332 }
else if (alignment & Qt::AlignVCenter) {
3333 const qreal centerDistance = (viewportRect.height() - subRect.height()) / 2;
3334 contentY = rowY + subRect.y() - centerDistance + offset;
3337 const int rowHeight = getEffectiveRowHeight(row);
3338 if (alignment == (Qt::AlignTop | Qt::AlignBottom))
3339 alignment = rowHeight > q->height() ? Qt::AlignTop : Qt::AlignBottom;
3341 if (alignment & Qt::AlignTop) {
3342 contentY = rowY + offset;
3343 }
else if (alignment & Qt::AlignBottom) {
3344 contentY = rowY + rowHeight - viewportRect.height() + offset;
3345 }
else if (alignment & Qt::AlignVCenter) {
3346 const qreal centerDistance = (viewportRect.height() - rowHeight) / 2;
3347 contentY = rowY - centerDistance + offset;
3352 contentY = qBound(-q->minYExtent(), contentY, -q->maxYExtent());
3357bool QQuickTableViewPrivate::isColumnHidden(
int column)
const
3361 return qFuzzyIsNull(getColumnWidth(column));
3364bool QQuickTableViewPrivate::isRowHidden(
int row)
const
3368 return qFuzzyIsNull(getRowHeight(row));
3371void QQuickTableViewPrivate::relayoutTableItems()
3373 qCDebug(lcTableViewDelegateLifecycle);
3375 if (viewportRect.isEmpty()) {
3377 qCDebug(lcTableViewDelegateLifecycle()) <<
"Skipping relayout, viewport has zero size";
3381 qreal nextColumnX = loadedTableOuterRect.x();
3382 qreal nextRowY = loadedTableOuterRect.y();
3384 for (
const int column : loadedColumns) {
3386 const qreal width = getColumnLayoutWidth(column);
3388 for (
const int row : loadedRows) {
3389 auto item = loadedTableItem(QPoint(column, row));
3390 QRectF geometry = item->geometry();
3391 geometry.moveLeft(nextColumnX);
3392 geometry.setWidth(width);
3393 item->setGeometry(geometry);
3397 nextColumnX += width + cellSpacing.width();
3400 for (
const int row : loadedRows) {
3402 const qreal height = getRowLayoutHeight(row);
3404 for (
const int column : loadedColumns) {
3405 auto item = loadedTableItem(QPoint(column, row));
3406 QRectF geometry = item->geometry();
3407 geometry.moveTop(nextRowY);
3408 geometry.setHeight(height);
3409 item->setGeometry(geometry);
3413 nextRowY += height + cellSpacing.height();
3416 if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
3417 for (
const int column : loadedColumns) {
3418 for (
const int row : loadedRows) {
3419 QPoint cell = QPoint(column, row);
3420 qCDebug(lcTableViewDelegateLifecycle()) <<
"relayout item:" << cell << loadedTableItem(cell)->geometry();
3426void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
3428 int columnThatNeedsLayout;
3429 int neighbourColumn;
3433 if (tableEdge == Qt::LeftEdge) {
3434 columnThatNeedsLayout = leftColumn();
3435 neighbourColumn = loadedColumns.values().at(1);
3436 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3437 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3438 columnX = neighbourItem->geometry().left() - cellSpacing.width() - columnWidth;
3440 columnThatNeedsLayout = rightColumn();
3441 neighbourColumn = loadedColumns.values().at(loadedColumns.count() - 2);
3442 columnWidth = getColumnLayoutWidth(columnThatNeedsLayout);
3443 const auto neighbourItem = loadedTableItem(QPoint(neighbourColumn, topRow()));
3444 columnX = neighbourItem->geometry().right() + cellSpacing.width();
3447 for (
const int row : loadedRows) {
3448 auto fxTableItem = loadedTableItem(QPoint(columnThatNeedsLayout, row));
3449 auto const neighbourItem = loadedTableItem(QPoint(neighbourColumn, row));
3450 const qreal rowY = neighbourItem->geometry().y();
3451 const qreal rowHeight = neighbourItem->geometry().height();
3453 fxTableItem->setGeometry(QRectF(columnX, rowY, columnWidth, rowHeight));
3454 fxTableItem->setVisible(
true);
3456 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(columnThatNeedsLayout, row) << fxTableItem->geometry();
3460void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
3462 int rowThatNeedsLayout;
3465 if (tableEdge == Qt::TopEdge) {
3466 rowThatNeedsLayout = topRow();
3467 neighbourRow = loadedRows.values().at(1);
3469 rowThatNeedsLayout = bottomRow();
3470 neighbourRow = loadedRows.values().at(loadedRows.count() - 2);
3475 for (
const int column : loadedColumns) {
3476 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3477 auto const neighbourItem = loadedTableItem(QPoint(column, neighbourRow));
3478 const qreal columnX = neighbourItem->geometry().x();
3479 const qreal columnWidth = neighbourItem->geometry().width();
3480 fxTableItem->item->setX(columnX);
3481 fxTableItem->item->setWidth(columnWidth);
3486 if (tableEdge == Qt::TopEdge) {
3487 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3488 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3489 rowY = neighbourItem->geometry().top() - cellSpacing.height() - rowHeight;
3491 rowHeight = getRowLayoutHeight(rowThatNeedsLayout);
3492 const auto neighbourItem = loadedTableItem(QPoint(leftColumn(), neighbourRow));
3493 rowY = neighbourItem->geometry().bottom() + cellSpacing.height();
3496 for (
const int column : loadedColumns) {
3497 auto fxTableItem = loadedTableItem(QPoint(column, rowThatNeedsLayout));
3498 fxTableItem->item->setY(rowY);
3499 fxTableItem->item->setHeight(rowHeight);
3500 fxTableItem->setVisible(
true);
3502 qCDebug(lcTableViewDelegateLifecycle()) <<
"layout item:" << QPoint(column, rowThatNeedsLayout) << fxTableItem->geometry();
3506void QQuickTableViewPrivate::layoutTopLeftItem()
3508 const QPoint cell(loadRequest.column(), loadRequest.row());
3509 auto topLeftItem = loadedTableItem(cell);
3510 auto item = topLeftItem->item;
3512 item->setPosition(loadRequest.startPosition());
3513 item->setSize(QSizeF(getColumnLayoutWidth(cell.x()), getRowLayoutHeight(cell.y())));
3514 topLeftItem->setVisible(
true);
3515 qCDebug(lcTableViewDelegateLifecycle) <<
"geometry:" << topLeftItem->geometry();
3518void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
3520 if (loadRequest.edge() == Qt::Edge(0)) {
3522 layoutTopLeftItem();
3526 switch (loadRequest.edge()) {
3529 layoutVerticalEdge(loadRequest.edge());
3532 case Qt::BottomEdge:
3533 layoutHorizontalEdge(loadRequest.edge());
3538void QQuickTableViewPrivate::processLoadRequest()
3540 Q_Q(QQuickTableView);
3543 while (loadRequest.hasCurrentCell()) {
3544 QPoint cell = loadRequest.currentCell();
3545 FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
3553 loadedItems.insert(modelIndexAtCell(cell), fxTableItem);
3554 loadRequest.moveToNextCell();
3557 qCDebug(lcTableViewDelegateLifecycle()) <<
"all items loaded!";
3559 syncLoadedTableFromLoadRequest();
3560 layoutTableEdgeFromLoadRequest();
3561 syncLoadedTableRectFromLoadedTable();
3563 if (rebuildState == RebuildState::Done) {
3567 drainReusePoolAfterLoadRequest();
3569 switch (loadRequest.edge()) {
3571 emit q->leftColumnChanged();
3574 emit q->rightColumnChanged();
3577 emit q->topRowChanged();
3579 case Qt::BottomEdge:
3580 emit q->bottomRowChanged();
3584 if (editIndex.isValid())
3587 emit q->layoutChanged();
3590 loadRequest.markAsDone();
3592 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3593 qCDebug(lcTableViewDelegateLifecycle()) <<
"Load request completed!";
3594 qCDebug(lcTableViewDelegateLifecycle()) <<
"****************************************";
3597void QQuickTableViewPrivate::processRebuildTable()
3599 Q_Q(QQuickTableView);
3601 if (rebuildState == RebuildState::Begin) {
3602 qCDebug(lcTableViewDelegateLifecycle()) <<
"begin rebuild:" << q <<
"options:" << rebuildOptions;
3603 tableSizeBeforeRebuild = tableSize;
3604 edgesBeforeRebuild = loadedItems.isEmpty() ? QMargins(-1,-1,-1,-1)
3605 : QMargins(q->leftColumn(), q->topRow(), q->rightColumn(), q->bottomRow());
3608 moveToNextRebuildState();
3610 if (rebuildState == RebuildState::LoadInitalTable) {
3612 if (!moveToNextRebuildState())
3616 if (rebuildState == RebuildState::VerifyTable) {
3617 if (loadedItems.isEmpty()) {
3618 qCDebug(lcTableViewDelegateLifecycle()) <<
"no items loaded!";
3619 updateContentWidth();
3620 updateContentHeight();
3621 rebuildState = RebuildState::Done;
3622 }
else if (!moveToNextRebuildState()) {
3627 if (rebuildState == RebuildState::LayoutTable) {
3628 layoutAfterLoadingInitialTable();
3629 loadAndUnloadVisibleEdges();
3630 if (!moveToNextRebuildState())
3634 if (rebuildState == RebuildState::CancelOvershoot) {
3635 cancelOvershootAfterLayout();
3636 loadAndUnloadVisibleEdges();
3637 if (!moveToNextRebuildState())
3641 if (rebuildState == RebuildState::UpdateContentSize) {
3642 updateContentSize();
3643 if (!moveToNextRebuildState())
3647 const bool preload = (rebuildOptions & RebuildOption::All
3648 && reusableFlag == QQmlTableInstanceModel::Reusable);
3650 if (rebuildState == RebuildState::PreloadColumns) {
3651 if (preload && !atTableEnd(Qt::RightEdge))
3652 loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
3653 if (!moveToNextRebuildState())
3657 if (rebuildState == RebuildState::PreloadRows) {
3658 if (preload && !atTableEnd(Qt::BottomEdge))
3659 loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
3660 if (!moveToNextRebuildState())
3664 if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
3665 while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
3667 if (!moveToNextRebuildState())
3671 if (rebuildState == RebuildState::Done) {
3672 if (tableSizeBeforeRebuild.width() != tableSize.width())
3673 emit q->columnsChanged();
3674 if (tableSizeBeforeRebuild.height() != tableSize.height())
3675 emit q->rowsChanged();
3676 if (edgesBeforeRebuild.left() != q->leftColumn())
3677 emit q->leftColumnChanged();
3678 if (edgesBeforeRebuild.right() != q->rightColumn())
3679 emit q->rightColumnChanged();
3680 if (edgesBeforeRebuild.top() != q->topRow())
3681 emit q->topRowChanged();
3682 if (edgesBeforeRebuild.bottom() != q->bottomRow())
3683 emit q->bottomRowChanged();
3685 if (editIndex.isValid())
3687 updateCurrentRowAndColumn();
3691 tableModel->commitReleasedItems();
3693 emit q->layoutChanged();
3695 qCDebug(lcTableViewDelegateLifecycle()) <<
"current table:" << tableLayoutToString();
3696 qCDebug(lcTableViewDelegateLifecycle()) <<
"rebuild completed!";
3697 qCDebug(lcTableViewDelegateLifecycle()) <<
"################################################";
3698 qCDebug(lcTableViewDelegateLifecycle());
3704bool QQuickTableViewPrivate::moveToNextRebuildState()
3706 if (loadRequest.isActive()) {
3712 if (rebuildState == RebuildState::Begin
3713 && rebuildOptions.testFlag(RebuildOption::LayoutOnly))
3714 rebuildState = RebuildState::LayoutTable;
3716 rebuildState = RebuildState(
int(rebuildState) + 1);
3718 qCDebug(lcTableViewDelegateLifecycle()) << rebuildState;
3722void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
3724 if (tableSize.isEmpty()) {
3726 topLeftCell.rx() = kEdgeIndexAtEnd;
3727 topLeftCell.ry() = kEdgeIndexAtEnd;
3731 if (syncHorizontally || syncVertically) {
3732 const auto syncView_d = syncView->d_func();
3734 if (syncView_d->loadedItems.isEmpty()) {
3735 topLeftCell.rx() = 0;
3736 topLeftCell.ry() = 0;
3741 const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
3742 const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
3743 const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
3745 if (syncHorizontally) {
3746 topLeftCell.rx() = syncViewTopLeftCell.x();
3747 topLeftPos.rx() = syncViewTopLeftPos.x();
3749 if (topLeftCell.x() >= tableSize.width()) {
3751 topLeftCell.rx() = kEdgeIndexAtEnd;
3752 topLeftPos.rx() = kEdgeIndexAtEnd;
3756 if (syncVertically) {
3757 topLeftCell.ry() = syncViewTopLeftCell.y();
3758 topLeftPos.ry() = syncViewTopLeftPos.y();
3760 if (topLeftCell.y() >= tableSize.height()) {
3762 topLeftCell.ry() = kEdgeIndexAtEnd;
3763 topLeftPos.ry() = kEdgeIndexAtEnd;
3767 if (syncHorizontally && syncVertically) {
3778 if (!syncHorizontally) {
3779 if (rebuildOptions & RebuildOption::All) {
3781 topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
3782 if (topLeftCell.x() == kEdgeIndexAtEnd) {
3786 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
3788 const int newColumn =
int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
3789 topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
3790 topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
3791 }
else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
3792 topLeftCell.rx() = qBound(0, positionViewAtColumnAfterRebuild, tableSize.width() - 1);
3793 topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
3796 topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
3800 topLeftPos.rx() = loadedTableOuterRect.x();
3804 if (!syncVertically) {
3805 if (rebuildOptions & RebuildOption::All) {
3807 topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
3808 if (topLeftCell.y() == kEdgeIndexAtEnd) {
3812 }
else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
3814 const int newRow =
int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
3815 topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
3816 topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
3817 }
else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
3818 topLeftCell.ry() = qBound(0, positionViewAtRowAfterRebuild, tableSize.height() - 1);
3819 topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
3821 topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
3822 topLeftPos.ry() = loadedTableOuterRect.y();
3827void QQuickTableViewPrivate::loadInitialTable()
3829 tableSize = calculateTableSize();
3831 if (positionXAnimation.isRunning()) {
3832 positionXAnimation.stop();
3833 setLocalViewportX(positionXAnimation.to().toReal());
3837 if (positionYAnimation.isRunning()) {
3838 positionYAnimation.stop();
3839 setLocalViewportY(positionYAnimation.to().toReal());
3845 calculateTopLeft(topLeft, topLeftPos);
3846 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial viewport rect:" << viewportRect;
3847 qCDebug(lcTableViewDelegateLifecycle()) <<
"initial top left cell:" << topLeft <<
", pos:" << topLeftPos;
3849 if (!loadedItems.isEmpty()) {
3850 if (rebuildOptions & RebuildOption::All)
3851 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
3852 else if (rebuildOptions & RebuildOption::ViewportOnly)
3853 releaseLoadedItems(reusableFlag);
3856 if (rebuildOptions & RebuildOption::All) {
3857 origin = QPointF(0, 0);
3858 endExtent = QSizeF(0, 0);
3859 hData.markExtentsDirty();
3860 vData.markExtentsDirty();
3861 updateBeginningEnd();
3864 loadedColumns.clear();
3866 loadedTableOuterRect = QRect();
3867 loadedTableInnerRect = QRect();
3868 clearEdgeSizeCache();
3870 if (syncHorizontally)
3871 setLocalViewportX(syncView->contentX());
3874 setLocalViewportY(syncView->contentY());
3876 if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
3877 setLocalViewportX(topLeftPos.x());
3879 if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
3880 setLocalViewportY(topLeftPos.y());
3885 qCDebug(lcTableViewDelegateLifecycle()) <<
"no model found, leaving table empty";
3889 if (model->count() == 0) {
3890 qCDebug(lcTableViewDelegateLifecycle()) <<
"empty model found, leaving table empty";
3894 if (tableModel && !tableModel->delegate()) {
3895 qCDebug(lcTableViewDelegateLifecycle()) <<
"no delegate found, leaving table empty";
3899 if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
3900 qCDebug(lcTableViewDelegateLifecycle()) <<
"no visible row or column found, leaving table empty";
3904 if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
3905 qCDebug(lcTableViewDelegateLifecycle()) <<
"could not resolve top-left item, leaving table empty";
3909 if (viewportRect.isEmpty()) {
3910 qCDebug(lcTableViewDelegateLifecycle()) <<
"viewport has zero size, leaving table empty";
3916 loadRequest.begin(topLeft, topLeftPos, QQmlIncubator::AsynchronousIfNested);
3917 processLoadRequest();
3918 loadAndUnloadVisibleEdges();
3921void QQuickTableViewPrivate::updateContentSize()
3923 const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
3924 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
3925 updateAverageColumnWidth();
3926 updateContentWidth();
3929 const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
3930 if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
3931 updateAverageRowHeight();
3932 updateContentHeight();
3938void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
3940 clearEdgeSizeCache();
3941 relayoutTableItems();
3942 syncLoadedTableRectFromLoadedTable();
3944 updateContentSize();
3946 adjustViewportXAccordingToAlignment();
3947 adjustViewportYAccordingToAlignment();
3950void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
3953 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
3956 if (positionViewAtColumnAfterRebuild != leftColumn())
3959 const qreal newContentX = getAlignmentContentX(
3960 positionViewAtColumnAfterRebuild,
3961 positionViewAtColumnAlignment,
3962 positionViewAtColumnOffset,
3963 positionViewAtColumnSubRect);
3965 setLocalViewportX(newContentX);
3969void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
3972 if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
3975 if (positionViewAtRowAfterRebuild != topRow())
3978 const qreal newContentY = getAlignmentContentY(
3979 positionViewAtRowAfterRebuild,
3980 positionViewAtRowAlignment,
3981 positionViewAtRowOffset,
3982 positionViewAtRowSubRect);
3984 setLocalViewportY(newContentY);
3988void QQuickTableViewPrivate::cancelOvershootAfterLayout()
3990 Q_Q(QQuickTableView);
3996 const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
3997 const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
3998 const bool cancelVertically = positionVertically && !syncVertically;
3999 const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
4001 if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
4002 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot horizontally:" << q->horizontalOvershoot();
4003 setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
4007 if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
4008 qCDebug(lcTableViewDelegateLifecycle()) <<
"cancelling overshoot vertically:" << q->verticalOvershoot();
4009 setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
4014void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
4016 Q_Q(QQuickTableView);
4017 qCDebug(lcTableViewDelegateLifecycle) << edge;
4020 case Qt::LeftEdge: {
4021 const int column = leftColumn();
4022 for (
int row : loadedRows)
4023 unloadItem(QPoint(column, row));
4024 loadedColumns.remove(column);
4025 syncLoadedTableRectFromLoadedTable();
4026 if (rebuildState == RebuildState::Done)
4027 emit q->leftColumnChanged();
4029 case Qt::RightEdge: {
4030 const int column = rightColumn();
4031 for (
int row : loadedRows)
4032 unloadItem(QPoint(column, row));
4033 loadedColumns.remove(column);
4034 syncLoadedTableRectFromLoadedTable();
4035 if (rebuildState == RebuildState::Done)
4036 emit q->rightColumnChanged();
4039 const int row = topRow();
4040 for (
int col : loadedColumns)
4041 unloadItem(QPoint(col, row));
4042 loadedRows.remove(row);
4043 syncLoadedTableRectFromLoadedTable();
4044 if (rebuildState == RebuildState::Done)
4045 emit q->topRowChanged();
4047 case Qt::BottomEdge: {
4048 const int row = bottomRow();
4049 for (
int col : loadedColumns)
4050 unloadItem(QPoint(col, row));
4051 loadedRows.remove(row);
4052 syncLoadedTableRectFromLoadedTable();
4053 if (rebuildState == RebuildState::Done)
4054 emit q->bottomRowChanged();
4058 if (rebuildState == RebuildState::Done)
4059 emit q->layoutChanged();
4061 qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
4064void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
4066 const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
4067 qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
4069 const auto &visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
4070 ? loadedRows.values() : loadedColumns.values();
4071 loadRequest.begin(edge, edgeIndex, visibleCells, incubationMode);
4072 processLoadRequest();
4075void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
4087 if (loadRequest.isActive()) {
4093 if (loadedItems.isEmpty()) {
4103 tableModified =
false;
4105 if (Qt::Edge edge = nextEdgeToUnload(viewportRect)) {
4106 tableModified =
true;
4110 if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
4111 tableModified =
true;
4112 loadEdge(edge, incubationMode);
4113 if (loadRequest.isActive())
4116 }
while (tableModified);
4120void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
4122 Q_Q(QQuickTableView);
4124 if (reusableFlag == QQmlTableInstanceModel::NotReusable || !tableModel)
4127 if (!qFuzzyIsNull(q->verticalOvershoot()) || !qFuzzyIsNull(q->horizontalOvershoot())) {
4157 const int w = loadedColumns.count();
4158 const int h = loadedRows.count();
4159 const int minTime =
int(std::ceil(w > h ? qreal(w + 1) / h : qreal(h + 1) / w));
4160 const int maxTime = minTime * 2;
4161 tableModel->drainReusableItemsPool(maxTime);
4164void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
4165 if (!q_func()->isComponentComplete()) {
4170 scheduledRebuildOptions |= options;
4174QQuickTableView *QQuickTableViewPrivate::rootSyncView()
const
4176 QQuickTableView *root =
const_cast<QQuickTableView *>(q_func());
4177 while (QQuickTableView *view = root->d_func()->syncView)
4182void QQuickTableViewPrivate::updatePolish()
4189 rootSyncView()->d_func()->updateTableRecursive();
4192bool QQuickTableViewPrivate::updateTableRecursive()
4202 const bool updateComplete = updateTable();
4203 if (!updateComplete)
4206 const auto children = syncChildren;
4207 for (
auto syncChild : children) {
4208 auto syncChild_d = syncChild->d_func();
4210 RebuildOption::PositionViewAtRow |
4211 RebuildOption::PositionViewAtColumn |
4212 RebuildOption::CalculateNewTopLeftRow |
4213 RebuildOption::CalculateNewTopLeftColumn;
4214 syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
4216 const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
4217 if (!descendantUpdateComplete)
4221 rebuildOptions = RebuildOption::None;
4226bool QQuickTableViewPrivate::updateTable()
4235 QScopedValueRollback polishGuard(polishing,
true);
4237 if (loadRequest.isActive()) {
4245 if (rebuildState != RebuildState::Done) {
4246 processRebuildTable();
4247 return rebuildState == RebuildState::Done;
4250 syncWithPendingChanges();
4252 if (rebuildState == RebuildState::Begin) {
4253 processRebuildTable();
4254 return rebuildState == RebuildState::Done;
4257 if (loadedItems.isEmpty())
4258 return !loadRequest.isActive();
4260 loadAndUnloadVisibleEdges();
4263 return !loadRequest.isActive();
4266void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
4268 if (inUpdateContentSize) {
4280 QQuickFlickablePrivate::fixup(data, minExtent, maxExtent);
4283QTypeRevision QQuickTableViewPrivate::resolveImportVersion()
4285 const auto data = QQmlData::get(q_func());
4286 if (!data || !data->propertyCache)
4287 return QTypeRevision::zero();
4289 const auto cppMetaObject = data->propertyCache->firstCppMetaObject();
4290 const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject);
4293 return qmlTypeView.metaObjectRevision();
4296void QQuickTableViewPrivate::createWrapperModel()
4298 Q_Q(QQuickTableView);
4304 tableModel =
new QQmlTableInstanceModel(qmlContext(q));
4305 tableModel->useImportVersion(resolveImportVersion());
4309bool QQuickTableViewPrivate::selectedInSelectionModel(
const QPoint &cell)
const
4311 if (!selectionModel)
4314 QAbstractItemModel *model = selectionModel->model();
4318 return selectionModel->isSelected(q_func()->modelIndex(cell));
4321bool QQuickTableViewPrivate::currentInSelectionModel(
const QPoint &cell)
const
4323 if (!selectionModel)
4326 QAbstractItemModel *model = selectionModel->model();
4330 return selectionModel->currentIndex() == q_func()->modelIndex(cell);
4333void QQuickTableViewPrivate::selectionChangedInSelectionModel(
const QItemSelection &selected,
const QItemSelection &deselected)
4335 if (!inSelectionModelUpdate) {
4339 cancelSelectionTracking();
4342 const auto &selectedIndexes = selected.indexes();
4343 const auto &deselectedIndexes = deselected.indexes();
4344 for (
int i = 0; i < selectedIndexes.size(); ++i)
4345 setSelectedOnDelegateItem(selectedIndexes.at(i),
true);
4346 for (
int i = 0; i < deselectedIndexes.size(); ++i)
4347 setSelectedOnDelegateItem(deselectedIndexes.at(i),
false);
4350void QQuickTableViewPrivate::setSelectedOnDelegateItem(
const QModelIndex &modelIndex,
bool select)
4352 if (modelIndex.isValid() && modelIndex.model() != selectionSourceModel()) {
4353 qmlWarning(q_func())
4354 <<
"Cannot select cells: TableView.selectionModel.model is not "
4355 <<
"compatible with the model displayed in the view";
4359 const int cellIndex = modelIndexToCellIndex(modelIndex);
4360 if (!loadedItems.contains(cellIndex))
4362 const QPoint cell = cellAtModelIndex(cellIndex);
4363 QQuickItem *item = loadedTableItem(cell)->item;
4364 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item,
false);
4367QAbstractItemModel *QQuickTableViewPrivate::selectionSourceModel()
4382 return qaim(modelImpl());
4385QAbstractItemModel *QQuickTableViewPrivate::qaim(QVariant modelAsVariant)
const
4388 if (modelAsVariant.userType() == qMetaTypeId<QJSValue>())
4389 modelAsVariant = modelAsVariant.value<QJSValue>().toVariant();
4390 return qvariant_cast<QAbstractItemModel *>(modelAsVariant);
4393void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
4395 updateCurrentRowAndColumn();
4397 for (
auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
4398 const int cellIndex = *it;
4399 const QPoint cell = cellAtModelIndex(cellIndex);
4400 const bool selected = selectedInSelectionModel(cell);
4401 const bool current = currentInSelectionModel(cell);
4402 QQuickItem *item = loadedTableItem(cell)->item;
4403 const bool editing = editIndex == q_func()->modelIndex(cell);
4404 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item,
false);
4405 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), cellIndex, item,
false);
4406 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(editing), cellIndex, item,
false);
4410void QQuickTableViewPrivate::currentChangedInSelectionModel(
const QModelIndex ¤t,
const QModelIndex &previous)
4412 if (current.isValid() && current.model() != selectionSourceModel()) {
4413 qmlWarning(q_func())
4414 <<
"Cannot change current index: TableView.selectionModel.model is not "
4415 <<
"compatible with the model displayed in the view";
4419 updateCurrentRowAndColumn();
4420 setCurrentOnDelegateItem(previous,
false);
4421 setCurrentOnDelegateItem(current,
true);
4424void QQuickTableViewPrivate::updateCurrentRowAndColumn()
4426 Q_Q(QQuickTableView);
4428 const QModelIndex currentIndex = selectionModel ? selectionModel->currentIndex() : QModelIndex();
4429 const QPoint currentCell = q->cellAtIndex(currentIndex);
4430 if (currentCell.x() != currentColumn) {
4431 currentColumn = currentCell.x();
4432 emit q->currentColumnChanged();
4435 if (currentCell.y() != currentRow) {
4436 currentRow = currentCell.y();
4437 emit q->currentRowChanged();
4441void QQuickTableViewPrivate::setCurrentOnDelegateItem(
const QModelIndex &index,
bool isCurrent)
4443 const int cellIndex = modelIndexToCellIndex(index);
4444 if (!loadedItems.contains(cellIndex))
4447 const QPoint cell = cellAtModelIndex(cellIndex);
4448 QQuickItem *item = loadedTableItem(cell)->item;
4449 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(isCurrent), cellIndex, item,
false);
4452void QQuickTableViewPrivate::itemCreatedCallback(
int modelIndex, QObject*)
4454 if (blockItemCreatedCallback)
4457 qCDebug(lcTableViewDelegateLifecycle) <<
"item done loading:"
4458 << cellAtModelIndex(modelIndex);
4464 processLoadRequest();
4465 loadAndUnloadVisibleEdges();
4469void QQuickTableViewPrivate::updateItemProperties(
int flatIndex, QObject *object,
bool init)
4471 Q_Q(QQuickTableView);
4472 const QPoint cell = cellAtModelIndex(flatIndex);
4473 const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
4474 const bool current = currentInSelectionModel(visualCell);
4475 const bool selected = selectedInSelectionModel(visualCell);
4477 setRequiredProperty(kRequiredProperty_tableView, QVariant::fromValue(q), flatIndex, object, init);
4478 setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), flatIndex, object, init);
4479 setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), flatIndex, object, init);
4480 setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), flatIndex, object, init);
4481 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(
false), flatIndex, object, init);
4484void QQuickTableViewPrivate::initItemCallback(
int flatIndex, QObject *object)
4486 Q_Q(QQuickTableView);
4487 Q_UNUSED(flatIndex);
4489 auto item = qobject_cast<QQuickItem*>(object);
4493 item->setParentItem(q->contentItem());
4496 if (
auto attached = getAttachedObject(item))
4497 attached->setView(q);
4500void QQuickTableViewPrivate::itemPooledCallback(
int modelIndex, QObject *object)
4502 Q_UNUSED(modelIndex);
4504 if (
auto attached = getAttachedObject(object))
4505 emit attached->pooled();
4508void QQuickTableViewPrivate::itemReusedCallback(
int flatIndex, QObject *object)
4510 Q_UNUSED(flatIndex);
4512 if (
auto item = qobject_cast<QQuickItem*>(object))
4513 QQuickItemPrivate::get(item)->setCulled(
false);
4515 if (
auto attached = getAttachedObject(object))
4516 emit attached->reused();
4519void QQuickTableViewPrivate::syncWithPendingChanges()
4529 syncDelegateModelAccess();
4533 syncRebuildOptions();
4536void QQuickTableViewPrivate::syncRebuildOptions()
4538 if (!scheduledRebuildOptions)
4541 rebuildState = RebuildState::Begin;
4542 rebuildOptions = scheduledRebuildOptions;
4543 scheduledRebuildOptions = RebuildOption::None;
4545 if (loadedItems.isEmpty())
4546 rebuildOptions.setFlag(RebuildOption::All);
4549 if (rebuildOptions.testFlag(RebuildOption::All)) {
4550 rebuildOptions.setFlag(RebuildOption::ViewportOnly,
false);
4551 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4552 rebuildOptions.setFlag(RebuildOption::CalculateNewContentWidth);
4553 rebuildOptions.setFlag(RebuildOption::CalculateNewContentHeight);
4554 }
else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
4555 rebuildOptions.setFlag(RebuildOption::LayoutOnly,
false);
4558 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
4559 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow,
false);
4561 if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
4562 rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn,
false);
4565void QQuickTableViewPrivate::syncDelegate()
4574 if (assignedDelegate != tableModel->delegate())
4575 tableModel->setDelegate(assignedDelegate);
4578void QQuickTableViewPrivate::syncDelegateModelAccess()
4587 tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
4590QVariant QQuickTableViewPrivate::modelImpl()
const
4592 if (needsModelSynchronization)
4593 return assignedModel;
4595 return tableModel->model();
4596 return QVariant::fromValue(model);
4599void QQuickTableViewPrivate::setModelImpl(
const QVariant &newModel)
4601 assignedModel = newModel;
4602 needsModelSynchronization =
true;
4603 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
4604 emit q_func()->modelChanged();
4607void QQuickTableViewPrivate::syncModel()
4610 if (tableModel->model() == assignedModel)
4612 }
else if (QVariant::fromValue(model) == assignedModel) {
4617 disconnectFromModel();
4618 releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
4621 const auto instanceModel = qobject_cast<QQmlInstanceModel *>(
4622 qvariant_cast<QObject *>(assignedModel));
4624 if (instanceModel) {
4627 tableModel =
nullptr;
4629 model = instanceModel;
4632 createWrapperModel();
4633 tableModel->setModel(assignedModel);
4636 needsModelSynchronization =
false;
4640void QQuickTableViewPrivate::syncSyncView()
4642 Q_Q(QQuickTableView);
4644 if (assignedSyncView != syncView) {
4646 syncView->d_func()->syncChildren.removeOne(q);
4648 if (assignedSyncView) {
4649 QQuickTableView *view = assignedSyncView;
4653 if (!layoutWarningIssued) {
4654 layoutWarningIssued =
true;
4655 qmlWarning(q) <<
"TableView: recursive syncView connection detected!";
4660 view = view->d_func()->syncView;
4663 assignedSyncView->d_func()->syncChildren.append(q);
4664 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
4667 syncView = assignedSyncView;
4670 syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
4671 syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
4673 if (syncHorizontally) {
4674 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4675 q->setColumnSpacing(syncView->columnSpacing());
4676 q->setLeftMargin(syncView->leftMargin());
4677 q->setRightMargin(syncView->rightMargin());
4678 updateContentWidth();
4680 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4681 if (syncView->leftColumn() != q->leftColumn()
4682 || syncView->d_func()->loadedTableOuterRect.left() != loadedTableOuterRect.left()) {
4689 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
4690 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4695 if (syncVertically) {
4696 QScopedValueRollback fixupGuard(inUpdateContentSize,
true);
4697 q->setRowSpacing(syncView->rowSpacing());
4698 q->setTopMargin(syncView->topMargin());
4699 q->setBottomMargin(syncView->bottomMargin());
4700 updateContentHeight();
4702 if (scheduledRebuildOptions & RebuildOption::LayoutOnly) {
4703 if (syncView->topRow() != q->topRow()
4704 || syncView->d_func()->loadedTableOuterRect.top() != loadedTableOuterRect.top()) {
4711 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
4712 scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
4717 if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
4723 const auto syncView_d = syncView->d_func();
4724 if (!syncView_d->loadedItems.isEmpty()) {
4725 if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1)
4726 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4727 else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1)
4728 scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
4733void QQuickTableViewPrivate::syncPositionView()
4739 positionViewAtRowAfterRebuild = assignedPositionViewAtRowAfterRebuild;
4740 positionViewAtColumnAfterRebuild = assignedPositionViewAtColumnAfterRebuild;
4743void QQuickTableViewPrivate::connectToModel()
4745 Q_Q(QQuickTableView);
4748 QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4749 QObjectPrivate::connect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4750 QObjectPrivate::connect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4751 QObjectPrivate::connect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4752 QObjectPrivate::connect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
4755 QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4757 if (
auto const aim = model->abstractItemModel()) {
4763 connect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4764 connect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4765 connect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4766 connect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4767 connect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4768 connect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4769 connect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4770 connect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4771 connect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4773 QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4777 QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged,
4778 q, &QQuickTableView::modelChanged);
4782void QQuickTableViewPrivate::disconnectFromModel()
4784 Q_Q(QQuickTableView);
4787 QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem,
this, &QQuickTableViewPrivate::itemCreatedCallback);
4788 QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem,
this, &QQuickTableViewPrivate::initItemCallback);
4789 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemPooled,
this, &QQuickTableViewPrivate::itemPooledCallback);
4790 QObjectPrivate::disconnect(model, &QQmlInstanceModel::itemReused,
this, &QQuickTableViewPrivate::itemReusedCallback);
4791 QObjectPrivate::disconnect(model, &QQmlInstanceModel::updateItemProperties,
this, &QQuickTableViewPrivate::updateItemProperties);
4793 QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged,
this, &QQuickTableViewPrivate::fetchMoreData);
4795 if (
auto const aim = model->abstractItemModel()) {
4796 disconnect(aim, &QAbstractItemModel::rowsMoved,
this, &QQuickTableViewPrivate::rowsMovedCallback);
4797 disconnect(aim, &QAbstractItemModel::columnsMoved,
this, &QQuickTableViewPrivate::columnsMovedCallback);
4798 disconnect(aim, &QAbstractItemModel::rowsInserted,
this, &QQuickTableViewPrivate::rowsInsertedCallback);
4799 disconnect(aim, &QAbstractItemModel::rowsRemoved,
this, &QQuickTableViewPrivate::rowsRemovedCallback);
4800 disconnect(aim, &QAbstractItemModel::columnsInserted,
this, &QQuickTableViewPrivate::columnsInsertedCallback);
4801 disconnect(aim, &QAbstractItemModel::columnsRemoved,
this, &QQuickTableViewPrivate::columnsRemovedCallback);
4802 disconnect(aim, &QAbstractItemModel::modelReset,
this, &QQuickTableViewPrivate::modelResetCallback);
4803 disconnect(aim, &QAbstractItemModel::layoutChanged,
this, &QQuickTableViewPrivate::layoutChangedCallback);
4804 disconnect(aim, &QAbstractItemModel::dataChanged,
this, &QQuickTableViewPrivate::dataChangedCallback);
4806 QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated,
this, &QQuickTableViewPrivate::modelUpdated);
4810 QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged,
4811 q, &QQuickTableView::modelChanged);
4815void QQuickTableViewPrivate::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
4817 Q_UNUSED(changeSet);
4821 scheduleRebuildTable(RebuildOption::ViewportOnly
4822 | RebuildOption::CalculateNewContentWidth
4823 | RebuildOption::CalculateNewContentHeight);
4826void QQuickTableViewPrivate::rowsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int )
4828 if (parent != QModelIndex())
4831 scheduleRebuildTable(RebuildOption::ViewportOnly);
4834void QQuickTableViewPrivate::columnsMovedCallback(
const QModelIndex &parent,
int,
int,
const QModelIndex &,
int)
4836 if (parent != QModelIndex())
4839 scheduleRebuildTable(RebuildOption::ViewportOnly);
4842void QQuickTableViewPrivate::rowsInsertedCallback(
const QModelIndex &parent,
int,
int)
4844 if (parent != QModelIndex())
4847 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4850void QQuickTableViewPrivate::rowsRemovedCallback(
const QModelIndex &parent,
int,
int)
4852 Q_Q(QQuickTableView);
4854 if (parent != QModelIndex())
4858 if (!editIndex.isValid() && editItem)
4861 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentHeight);
4864void QQuickTableViewPrivate::columnsInsertedCallback(
const QModelIndex &parent,
int,
int)
4866 if (parent != QModelIndex())
4874 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4877void QQuickTableViewPrivate::columnsRemovedCallback(
const QModelIndex &parent,
int,
int)
4879 Q_Q(QQuickTableView);
4881 if (parent != QModelIndex())
4885 if (!editIndex.isValid() && editItem)
4888 scheduleRebuildTable(RebuildOption::ViewportOnly | RebuildOption::CalculateNewContentWidth);
4891void QQuickTableViewPrivate::layoutChangedCallback(
const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
4896 scheduleRebuildTable(RebuildOption::ViewportOnly);
4899void QQuickTableViewPrivate::fetchMoreData()
4901 if (tableModel && tableModel->canFetchMore()) {
4902 tableModel->fetchMore();
4903 scheduleRebuildTable(RebuildOption::ViewportOnly);
4907void QQuickTableViewPrivate::modelResetCallback()
4909 Q_Q(QQuickTableView);
4911 scheduleRebuildTable(RebuildOption::All);
4914void QQuickTableViewPrivate::dataChangedCallback(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles)
4916 const auto *chooser = qobject_cast<
const QQmlDelegateChooser *>(assignedDelegate);
4920 if (loadedItems.isEmpty()
4921 || topLeft.column() > rightColumn() || bottomRight.column() < leftColumn()
4922 || topLeft.row() > bottomRow() || bottomRight.row() < topRow()) {
4926 if (!roles.empty()) {
4927 const int roleIndex = topLeft.model()->roleNames().key(chooser->role().toUtf8());
4928 if (!roles.contains(roleIndex))
4932 scheduleRebuildTable(RebuildOption::ViewportOnly);
4935void QQuickTableViewPrivate::positionViewAtRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4937 Qt::Alignment verticalAlignment = alignment & (Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
4940 if (syncVertically) {
4941 syncView->d_func()->positionViewAtRow(row, verticalAlignment, offset, subRect);
4943 if (!scrollToRow(row, verticalAlignment, offset, subRect)) {
4945 assignedPositionViewAtRowAfterRebuild = row;
4946 positionViewAtRowAlignment = verticalAlignment;
4947 positionViewAtRowOffset = offset;
4948 positionViewAtRowSubRect = subRect;
4949 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4950 QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
4955void QQuickTableViewPrivate::positionViewAtColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4957 Qt::Alignment horizontalAlignment = alignment & (Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
4960 if (syncHorizontally) {
4961 syncView->d_func()->positionViewAtColumn(column, horizontalAlignment, offset, subRect);
4963 if (!scrollToColumn(column, horizontalAlignment, offset, subRect)) {
4965 assignedPositionViewAtColumnAfterRebuild = column;
4966 positionViewAtColumnAlignment = horizontalAlignment;
4967 positionViewAtColumnOffset = offset;
4968 positionViewAtColumnSubRect = subRect;
4969 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
4970 QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
4975bool QQuickTableViewPrivate::scrollToRow(
int row, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
4977 Q_Q(QQuickTableView);
4984 if (row < topRow()) {
4985 if (row != nextVisibleEdgeIndex(Qt::TopEdge, topRow() - 1))
4987 loadEdge(Qt::TopEdge, QQmlIncubator::Synchronous);
4988 }
else if (row > bottomRow()) {
4989 if (row != nextVisibleEdgeIndex(Qt::BottomEdge, bottomRow() + 1))
4991 loadEdge(Qt::BottomEdge, QQmlIncubator::Synchronous);
4992 }
else if (row < topRow() || row > bottomRow()) {
4996 if (!loadedRows.contains(row))
4999 const qreal newContentY = getAlignmentContentY(row, alignment, offset, subRect);
5000 if (qFuzzyCompare(newContentY, q->contentY()))
5004 const qreal diffY = qAbs(newContentY - q->contentY());
5005 const qreal duration = qBound(700., diffY * 5, 1500.);
5006 positionYAnimation.setTo(newContentY);
5007 positionYAnimation.setDuration(duration);
5008 positionYAnimation.restart();
5010 positionYAnimation.stop();
5011 q->setContentY(newContentY);
5017bool QQuickTableViewPrivate::scrollToColumn(
int column, Qt::Alignment alignment, qreal offset,
const QRectF subRect)
5019 Q_Q(QQuickTableView);
5026 if (column < leftColumn()) {
5027 if (column != nextVisibleEdgeIndex(Qt::LeftEdge, leftColumn() - 1))
5029 loadEdge(Qt::LeftEdge, QQmlIncubator::Synchronous);
5030 }
else if (column > rightColumn()) {
5031 if (column != nextVisibleEdgeIndex(Qt::RightEdge, rightColumn() + 1))
5033 loadEdge(Qt::RightEdge, QQmlIncubator::Synchronous);
5034 }
else if (column < leftColumn() || column > rightColumn()) {
5038 if (!loadedColumns.contains(column))
5041 const qreal newContentX = getAlignmentContentX(column, alignment, offset, subRect);
5042 if (qFuzzyCompare(newContentX, q->contentX()))
5046 const qreal diffX = qAbs(newContentX - q->contentX());
5047 const qreal duration = qBound(700., diffX * 5, 1500.);
5048 positionXAnimation.setTo(newContentX);
5049 positionXAnimation.setDuration(duration);
5050 positionXAnimation.restart();
5052 positionXAnimation.stop();
5053 q->setContentX(newContentX);
5059void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
5061 Q_Q(QQuickTableView);
5071 if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
5072 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
5073 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5077 if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
5078 scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
5079 scheduledRebuildOptions |= RebuildOption::ViewportOnly;
5083void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
5088 Q_Q(QQuickTableView);
5089 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5091 if (qFuzzyCompare(contentX, q->contentX()))
5094 q->setContentX(contentX);
5097void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
5102 Q_Q(QQuickTableView);
5103 QScopedValueRollback blocker(inSetLocalViewportPos,
true);
5105 if (qFuzzyCompare(contentY, q->contentY()))
5108 q->setContentY(contentY);
5111void QQuickTableViewPrivate::syncViewportRect()
5119 Q_Q(QQuickTableView);
5121 qreal w = q->width();
5122 qreal h = q->height();
5124 for (
auto syncChild : std::as_const(syncChildren)) {
5125 auto syncChild_d = syncChild->d_func();
5126 if (syncChild_d->syncHorizontally)
5127 w = qMax(w, syncChild->width());
5128 if (syncChild_d->syncVertically)
5129 h = qMax(h, syncChild->height());
5132 viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
5135void QQuickTableViewPrivate::init()
5137 Q_Q(QQuickTableView);
5139 q->setFlag(QQuickItem::ItemIsFocusScope);
5140 q->setActiveFocusOnTab(
true);
5142 positionXAnimation.setTargetObject(q);
5143 positionXAnimation.setProperty(QStringLiteral(
"contentX"));
5144 positionXAnimation.setEasing(QEasingCurve::OutQuart);
5146 positionYAnimation.setTargetObject(q);
5147 positionYAnimation.setProperty(QStringLiteral(
"contentY"));
5148 positionYAnimation.setEasing(QEasingCurve::OutQuart);
5150 auto tapHandler =
new QQuickTableViewTapHandler(q);
5152 hoverHandler =
new QQuickTableViewHoverHandler(q);
5153 resizeHandler =
new QQuickTableViewResizeHandler(q);
5155 hoverHandler->setEnabled(resizableRows || resizableColumns);
5156 resizeHandler->setEnabled(resizableRows || resizableColumns);
5164 QObject::connect(tapHandler, &QQuickTapHandler::pressedChanged, q, [
this, q, tapHandler] {
5165 if (!tapHandler->isPressed())
5168 positionXAnimation.stop();
5169 positionYAnimation.stop();
5171 if (!q->isInteractive())
5172 handleTap(tapHandler->point());
5175 QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, q, [
this, q, tapHandler] {
5176 if (q->isInteractive())
5177 handleTap(tapHandler->point());
5180 QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, q, [
this, q, tapHandler] {
5181 const bool resizeRow = resizableRows && hoverHandler->m_row != -1;
5182 const bool resizeColumn = resizableColumns && hoverHandler->m_column != -1;
5184 if (resizeRow || resizeColumn) {
5186 q->setRowHeight(hoverHandler->m_row, -1);
5188 q->setColumnWidth(hoverHandler->m_column, -1);
5189 }
else if (editTriggers & QQuickTableView::DoubleTapped) {
5190 const QPointF pos = tapHandler->point().pressPosition();
5191 const QPoint cell = q->cellAtPosition(pos);
5192 const QModelIndex index = q->modelIndex(cell);
5193 if (canEdit(index,
false))
5199void QQuickTableViewPrivate::handleTap(
const QQuickHandlerPoint &point)
5201 Q_Q(QQuickTableView);
5203 if (keyNavigationEnabled)
5204 q->forceActiveFocus(Qt::MouseFocusReason);
5206 if (point.modifiers() != Qt::NoModifier)
5208 if (resizableRows && hoverHandler->m_row != -1)
5210 if (resizableColumns && hoverHandler->m_column != -1)
5212 if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
5215 const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
5216 bool tappedCellIsSelected =
false;
5219 tappedCellIsSelected = selectionModel->isSelected(tappedIndex);
5221 if (canEdit(tappedIndex,
false)) {
5222 if (editTriggers & QQuickTableView::SingleTapped) {
5223 if (selectionBehavior != QQuickTableView::SelectionDisabled)
5225 q->edit(tappedIndex);
5227 }
else if (editTriggers & QQuickTableView::SelectedTapped && tappedCellIsSelected) {
5228 q->edit(tappedIndex);
5235 if (pointerNavigationEnabled) {
5236 closeEditorAndCommit();
5237 if (selectionBehavior != QQuickTableView::SelectionDisabled) {
5239 cancelSelectionTracking();
5241 setCurrentIndexFromTap(point.position());
5245bool QQuickTableViewPrivate::canEdit(
const QModelIndex tappedIndex,
bool warn)
5249 Q_Q(QQuickTableView);
5251 if (!tappedIndex.isValid()) {
5253 qmlWarning(q) <<
"cannot edit: index is not valid!";
5257 auto const sourceModel = qaim(modelImpl());
5260 qmlWarning(q) <<
"cannot edit: TableView.model does not inherit QAbstractItemModel!";
5264 const QModelIndex buddyIndex = sourceModel->buddy(tappedIndex);
5265 if (!(sourceModel->flags(buddyIndex) & Qt::ItemIsEditable)) {
5267 if (buddyIndex != tappedIndex)
5268 qmlWarning(q) <<
"cannot edit: the buddy index flags don't include Qt::ItemIsEditable.";
5270 qmlWarning(q) <<
"cannot edit: the index flags don't include Qt::ItemIsEditable";
5275 const QPoint cell = q->cellAtIndex(buddyIndex);
5276 const QQuickItem *cellItem = q->itemAtCell(cell);
5279 qmlWarning(q) <<
"cannot edit: the cell to edit is not inside the viewport!";
5283 auto attached = getAttachedObject(cellItem);
5284 if (!attached || !attached->editDelegate()) {
5286 qmlWarning(q) <<
"cannot edit: no TableView.editDelegate set!";
5293void QQuickTableViewPrivate::syncViewportPosRecursive()
5295 Q_Q(QQuickTableView);
5296 QScopedValueRollback recursionGuard(inSyncViewportPosRecursive,
true);
5299 auto syncView_d = syncView->d_func();
5300 if (!syncView_d->inSyncViewportPosRecursive) {
5301 if (syncHorizontally)
5302 syncView_d->setLocalViewportX(q->contentX());
5304 syncView_d->setLocalViewportY(q->contentY());
5305 syncView_d->syncViewportPosRecursive();
5309 for (
auto syncChild : std::as_const(syncChildren)) {
5310 auto syncChild_d = syncChild->d_func();
5311 if (!syncChild_d->inSyncViewportPosRecursive) {
5312 if (syncChild_d->syncHorizontally)
5313 syncChild_d->setLocalViewportX(q->contentX());
5314 if (syncChild_d->syncVertically)
5315 syncChild_d->setLocalViewportY(q->contentY());
5316 syncChild_d->syncViewportPosRecursive();
5321void QQuickTableViewPrivate::setCurrentIndexFromTap(
const QPointF &pos)
5323 Q_Q(QQuickTableView);
5325 const QPoint cell = q->cellAtPosition(pos);
5326 if (!cellIsValid(cell))
5329 setCurrentIndex(cell);
5332void QQuickTableViewPrivate::setCurrentIndex(
const QPoint &cell)
5334 if (!selectionModel)
5337 const auto index = q_func()->modelIndex(cell);
5338 selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
5341bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
5343 Q_Q(QQuickTableView);
5345 if (!selectionModel || !selectionModel->model())
5348 const QModelIndex currentIndex = selectionModel->currentIndex();
5349 const QPoint currentCell = q->cellAtIndex(currentIndex);
5351 if (!q->activeFocusOnTab()) {
5354 case Qt::Key_Backtab:
5359 if (!cellIsValid(currentCell)) {
5365 case Qt::Key_PageUp:
5366 case Qt::Key_PageDown:
5370 case Qt::Key_Backtab:
5371 if (!loadedRows.isEmpty() && !loadedColumns.isEmpty()) {
5374 const QModelIndex topLeftIndex = q->index(topRow(), leftColumn());
5375 selectionModel->setCurrentIndex(topLeftIndex, QItemSelectionModel::NoUpdate);
5382 auto beginMoveCurrentIndex = [&](){
5383 const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
5384 const bool startNewSelection = selectionRectangle().isEmpty();
5385 if (!shouldSelect) {
5387 cancelSelectionTracking();
5388 }
else if (startNewSelection) {
5392 const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
5393 if (loadedItems.contains(serializedStartIndex)) {
5394 const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
5395 if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
5396 setSelectionStartPos(startGeometry.center());
5397 if (selectableCallbackFunction)
5398 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5404 auto endMoveCurrentIndex = [&](
const QPoint &cell){
5405 const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
5407 if (polishScheduled)
5409 const int serializedEndIndex = modelIndexAtCell(cell);
5410 if (loadedItems.contains(serializedEndIndex)) {
5411 const QRectF endGeometry = loadedItems.value(serializedEndIndex)->geometry();
5412 setSelectionEndPos(endGeometry.center());
5413 if (selectableCallbackFunction)
5414 selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
5417 selectionModel->setCurrentIndex(q->modelIndex(cell), QItemSelectionModel::NoUpdate);
5422 beginMoveCurrentIndex();
5423 const int nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5424 if (nextRow == kEdgeIndexAtEnd)
5426 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5427 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5428 endMoveCurrentIndex({currentCell.x(), nextRow});
5430 case Qt::Key_Down: {
5431 beginMoveCurrentIndex();
5432 const int nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5433 if (nextRow == kEdgeIndexAtEnd)
5435 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5436 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5437 endMoveCurrentIndex({currentCell.x(), nextRow});
5439 case Qt::Key_Left: {
5440 beginMoveCurrentIndex();
5441 const int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5442 if (nextColumn == kEdgeIndexAtEnd)
5444 const qreal marginX = atTableEnd(Qt::LeftEdge, nextColumn - 1) ? -q->leftMargin() : 0;
5445 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5446 endMoveCurrentIndex({nextColumn, currentCell.y()});
5448 case Qt::Key_Right: {
5449 beginMoveCurrentIndex();
5450 const int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5451 if (nextColumn == kEdgeIndexAtEnd)
5453 const qreal marginX = atTableEnd(Qt::RightEdge, nextColumn + 1) ? q->rightMargin() : 0;
5454 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5455 endMoveCurrentIndex({nextColumn, currentCell.y()});
5457 case Qt::Key_PageDown: {
5458 int newBottomRow = -1;
5459 beginMoveCurrentIndex();
5460 if (currentCell.y() < bottomRow()) {
5462 newBottomRow = bottomRow();
5463 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignBottom, 0);
5465 q->positionViewAtRow(bottomRow(), QQuickTableView::AlignTop, 0);
5466 positionYAnimation.complete();
5467 newBottomRow = topRow() != bottomRow() ? bottomRow() : bottomRow() + 1;
5468 const qreal marginY = atTableEnd(Qt::BottomEdge, newBottomRow + 1) ? q->bottomMargin() : 0;
5469 q->positionViewAtRow(newBottomRow, QQuickTableView::AlignTop | QQuickTableView::AlignBottom, marginY);
5470 positionYAnimation.complete();
5472 endMoveCurrentIndex(QPoint(currentCell.x(), newBottomRow));
5474 case Qt::Key_PageUp: {
5476 beginMoveCurrentIndex();
5477 if (currentCell.y() > topRow()) {
5479 newTopRow = topRow();
5480 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, 0);
5482 q->positionViewAtRow(topRow(), QQuickTableView::AlignBottom, 0);
5483 positionYAnimation.complete();
5484 newTopRow = topRow() != bottomRow() ? topRow() : topRow() - 1;
5485 const qreal marginY = atTableEnd(Qt::TopEdge, newTopRow - 1) ? -q->topMargin() : 0;
5486 q->positionViewAtRow(newTopRow, QQuickTableView::AlignTop, marginY);
5487 positionYAnimation.complete();
5489 endMoveCurrentIndex(QPoint(currentCell.x(), newTopRow));
5491 case Qt::Key_Home: {
5492 beginMoveCurrentIndex();
5493 const int firstColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5494 q->positionViewAtColumn(firstColumn, QQuickTableView::AlignLeft, -q->leftMargin());
5495 endMoveCurrentIndex(QPoint(firstColumn, currentCell.y()));
5498 beginMoveCurrentIndex();
5499 const int lastColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5500 q->positionViewAtColumn(lastColumn, QQuickTableView::AlignRight, q->rightMargin());
5501 endMoveCurrentIndex(QPoint(lastColumn, currentCell.y()));
5504 beginMoveCurrentIndex();
5505 int nextRow = currentCell.y();
5506 int nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, currentCell.x() + 1);
5507 if (nextColumn == kEdgeIndexAtEnd) {
5508 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, currentCell.y() + 1);
5509 if (nextRow == kEdgeIndexAtEnd)
5510 nextRow = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
5511 nextColumn = nextVisibleEdgeIndex(Qt::RightEdge, 0);
5512 const qreal marginY = atTableEnd(Qt::BottomEdge, nextRow + 1) ? q->bottomMargin() : 0;
5513 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5517 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5518 marginX = q->leftMargin();
5519 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5520 marginX = -q->leftMargin();
5522 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5523 endMoveCurrentIndex({nextColumn, nextRow});
5525 case Qt::Key_Backtab: {
5526 beginMoveCurrentIndex();
5527 int nextRow = currentCell.y();
5528 int nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, currentCell.x() - 1);
5529 if (nextColumn == kEdgeIndexAtEnd) {
5530 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, currentCell.y() - 1);
5531 if (nextRow == kEdgeIndexAtEnd)
5532 nextRow = nextVisibleEdgeIndex(Qt::TopEdge, tableSize.height() - 1);
5533 nextColumn = nextVisibleEdgeIndex(Qt::LeftEdge, tableSize.width() - 1);
5534 const qreal marginY = atTableEnd(Qt::TopEdge, nextRow - 1) ? -q->topMargin() : 0;
5535 q->positionViewAtRow(nextRow, QQuickTableView::Contain, marginY);
5539 if (atTableEnd(Qt::RightEdge, nextColumn + 1))
5540 marginX = q->leftMargin();
5541 else if (atTableEnd(Qt::LeftEdge, nextColumn - 1))
5542 marginX = -q->leftMargin();
5544 q->positionViewAtColumn(nextColumn, QQuickTableView::Contain, marginX);
5545 endMoveCurrentIndex({nextColumn, nextRow});
5554bool QQuickTableViewPrivate::editFromKeyEvent(QKeyEvent *e)
5556 Q_Q(QQuickTableView);
5558 if (editTriggers == QQuickTableView::NoEditTriggers)
5560 if (!selectionModel || !selectionModel->model())
5563 const QModelIndex index = selectionModel->currentIndex();
5564 const QPoint cell = q->cellAtIndex(index);
5565 const QQuickItem *cellItem = q->itemAtCell(cell);
5569 auto attached = getAttachedObject(cellItem);
5570 if (!attached || !attached->editDelegate())
5573 bool anyKeyPressed =
false;
5574 bool editKeyPressed =
false;
5577 case Qt::Key_Return:
5582 anyKeyPressed =
true;
5583 editKeyPressed =
true;
5587 case Qt::Key_Control:
5590 case Qt::Key_Backtab:
5593 anyKeyPressed =
true;
5596 const bool anyKeyAccepted = anyKeyPressed && (editTriggers & QQuickTableView::AnyKeyPressed);
5597 const bool editKeyAccepted = editKeyPressed && (editTriggers & QQuickTableView::EditKeyPressed);
5599 if (!(editKeyAccepted || anyKeyAccepted))
5602 if (!canEdit(index,
false)) {
5611 if (editIndex.isValid() && anyKeyAccepted && !editKeyPressed) {
5614 QGuiApplication::sendEvent(QGuiApplication::focusObject(), e);
5620QObject *QQuickTableViewPrivate::installEventFilterOnFocusObjectInsideEditItem()
5626 Q_Q(QQuickTableView);
5627 if (QObject *focusObject = editItem->window()->focusObject()) {
5628 QQuickItem *focusItem = qobject_cast<QQuickItem *>(focusObject);
5629 if (focusItem == editItem || editItem->isAncestorOf(focusItem)) {
5630 focusItem->installEventFilter(q);
5637void QQuickTableViewPrivate::closeEditorAndCommit()
5642 if (
auto attached = getAttachedObject(editItem))
5643 emit attached->commit();
5645 q_func()->closeEditor();
5648#if QT_CONFIG(cursor)
5649void QQuickTableViewPrivate::updateCursor()
5651 int row = resizableRows ? hoverHandler->m_row : -1;
5652 int column = resizableColumns ? hoverHandler->m_column : -1;
5654 const auto resizeState = resizeHandler->state();
5655 if (resizeState == QQuickTableViewResizeHandler::DraggingStarted
5656 || resizeState == QQuickTableViewResizeHandler::Dragging) {
5659 row = resizeHandler->m_row;
5660 column = resizeHandler->m_column;
5663 if (row != -1 || column != -1) {
5664 Qt::CursorShape shape;
5665 if (row != -1 && column != -1)
5666 shape = Qt::SizeFDiagCursor;
5668 shape = Qt::SplitVCursor;
5670 shape = Qt::SplitHCursor;
5673 qApp->changeOverrideCursor(shape);
5675 qApp->setOverrideCursor(shape);
5678 }
else if (m_cursorSet) {
5679 qApp->restoreOverrideCursor();
5680 m_cursorSet =
false;
5685void QQuickTableViewPrivate::updateEditItem()
5687 Q_Q(QQuickTableView);
5692 const QPoint cell = q->cellAtIndex(editIndex);
5693 auto cellItem = q->itemAtCell(cell);
5704 editItem->parentItem()->setX(-editItem->width() - 10000);
5708QQuickTableView::QQuickTableView(QQuickItem *parent)
5709 : QQuickFlickable(*(
new QQuickTableViewPrivate), parent)
5714QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent)
5715 : QQuickFlickable(dd, parent)
5720QQuickTableView::~QQuickTableView()
5722 Q_D(QQuickTableView);
5726 auto syncView_d = d->syncView->d_func();
5727 syncView_d->syncChildren.removeOne(
this);
5728 syncView_d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
5732void QQuickTableView::componentFinalized()
5746 Q_D(QQuickTableView);
5747 qCDebug(lcTableViewDelegateLifecycle);
5751qreal QQuickTableView::minXExtent()
const
5753 return QQuickFlickable::minXExtent() - d_func()->origin.x();
5756qreal QQuickTableView::maxXExtent()
const
5758 return QQuickFlickable::maxXExtent() - d_func()->endExtent.width();
5761qreal QQuickTableView::minYExtent()
const
5763 return QQuickFlickable::minYExtent() - d_func()->origin.y();
5766qreal QQuickTableView::maxYExtent()
const
5768 return QQuickFlickable::maxYExtent() - d_func()->endExtent.height();
5771int QQuickTableView::rows()
const
5773 return d_func()->tableSize.height();
5776int QQuickTableView::columns()
const
5778 return d_func()->tableSize.width();
5781qreal QQuickTableView::rowSpacing()
const
5783 return d_func()->cellSpacing.height();
5786void QQuickTableView::setRowSpacing(qreal spacing)
5788 Q_D(QQuickTableView);
5789 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5791 if (qFuzzyCompare(d->cellSpacing.height(), spacing))
5794 d->cellSpacing.setHeight(spacing);
5795 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5796 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5797 emit rowSpacingChanged();
5800qreal QQuickTableView::columnSpacing()
const
5802 return d_func()->cellSpacing.width();
5805void QQuickTableView::setColumnSpacing(qreal spacing)
5807 Q_D(QQuickTableView);
5808 if (qt_is_nan(spacing) || !qt_is_finite(spacing))
5810 if (qFuzzyCompare(d->cellSpacing.width(), spacing))
5813 d->cellSpacing.setWidth(spacing);
5814 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::LayoutOnly
5815 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5816 emit columnSpacingChanged();
5819QJSValue QQuickTableView::rowHeightProvider()
const
5821 return d_func()->rowHeightProvider;
5824void QQuickTableView::setRowHeightProvider(
const QJSValue &provider)
5826 Q_D(QQuickTableView);
5827 if (provider.strictlyEquals(d->rowHeightProvider))
5830 d->rowHeightProvider = provider;
5831 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5832 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentHeight);
5833 emit rowHeightProviderChanged();
5836QJSValue QQuickTableView::columnWidthProvider()
const
5838 return d_func()->columnWidthProvider;
5841void QQuickTableView::setColumnWidthProvider(
const QJSValue &provider)
5843 Q_D(QQuickTableView);
5844 if (provider.strictlyEquals(d->columnWidthProvider))
5847 d->columnWidthProvider = provider;
5848 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly
5849 | QQuickTableViewPrivate::RebuildOption::CalculateNewContentWidth);
5850 emit columnWidthProviderChanged();
5853QVariant QQuickTableView::model()
const
5855 return d_func()->modelImpl();
5858void QQuickTableView::setModel(
const QVariant &newModel)
5860 Q_D(QQuickTableView);
5862 QVariant model = newModel;
5863 if (model.userType() == qMetaTypeId<QJSValue>())
5864 model = model.value<QJSValue>().toVariant();
5866 if (model == d->assignedModel)
5870 d->setModelImpl(model);
5871 if (d->selectionModel)
5872 d->selectionModel->setModel(d->selectionSourceModel());
5875QQmlComponent *QQuickTableView::delegate()
const
5877 return d_func()->assignedDelegate;
5880void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
5882 Q_D(QQuickTableView);
5883 if (newDelegate == d->assignedDelegate)
5886 d->assignedDelegate = newDelegate;
5887 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5889 emit delegateChanged();
5892QQuickTableView::EditTriggers QQuickTableView::editTriggers()
const
5894 return d_func()->editTriggers;
5897void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers)
5899 Q_D(QQuickTableView);
5900 if (editTriggers == d->editTriggers)
5903 d->editTriggers = editTriggers;
5905 emit editTriggersChanged();
5909
5910
5911
5912
5913
5914QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess()
const
5916 Q_D(
const QQuickTableView);
5917 return d->assignedDelegateModelAccess;
5920void QQuickTableView::setDelegateModelAccess(
5921 QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
5923 Q_D(QQuickTableView);
5924 if (delegateModelAccess == d->assignedDelegateModelAccess)
5927 d->assignedDelegateModelAccess = delegateModelAccess;
5928 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
5930 emit delegateModelAccessChanged();
5933bool QQuickTableView::reuseItems()
const
5935 return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
5938void QQuickTableView::setReuseItems(
bool reuse)
5940 Q_D(QQuickTableView);
5941 if (reuseItems() == reuse)
5944 d->reusableFlag = reuse ? QQmlTableInstanceModel::Reusable : QQmlTableInstanceModel::NotReusable;
5946 if (!reuse && d->tableModel) {
5949 d->tableModel->drainReusableItemsPool(0);
5952 emit reuseItemsChanged();
5955void QQuickTableView::setContentWidth(qreal width)
5957 Q_D(QQuickTableView);
5958 d->explicitContentWidth = width;
5959 QQuickFlickable::setContentWidth(width);
5962void QQuickTableView::setContentHeight(qreal height)
5964 Q_D(QQuickTableView);
5965 d->explicitContentHeight = height;
5966 QQuickFlickable::setContentHeight(height);
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986QQuickTableView *QQuickTableView::syncView()
const
5988 return d_func()->assignedSyncView;
5991void QQuickTableView::setSyncView(QQuickTableView *view)
5993 Q_D(QQuickTableView);
5994 if (d->assignedSyncView == view)
5999 d->clearIndexMapping();
6001 d->assignedSyncView = view;
6002 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6004 emit syncViewChanged();
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025Qt::Orientations QQuickTableView::syncDirection()
const
6027 return d_func()->assignedSyncDirection;
6030void QQuickTableView::setSyncDirection(Qt::Orientations direction)
6032 Q_D(QQuickTableView);
6033 if (d->assignedSyncDirection == direction)
6036 d->assignedSyncDirection = direction;
6037 if (d->assignedSyncView)
6038 d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
6040 emit syncDirectionChanged();
6043QItemSelectionModel *QQuickTableView::selectionModel()
const
6045 return d_func()->selectionModel;
6048void QQuickTableView::setSelectionModel(QItemSelectionModel *selectionModel)
6050 Q_D(QQuickTableView);
6051 if (d->selectionModel == selectionModel)
6058 if (d->selectionModel) {
6059 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6060 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6061 QQuickTableViewPrivate::disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
6062 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6065 d->selectionModel = selectionModel;
6067 if (d->selectionModel) {
6068 d->selectionModel->setModel(d->selectionSourceModel());
6069 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
6070 d, &QQuickTableViewPrivate::selectionChangedInSelectionModel);
6071 QQuickTableViewPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
6072 d, &QQuickTableViewPrivate::currentChangedInSelectionModel);
6075 d->updateSelectedOnAllDelegateItems();
6077 emit selectionModelChanged();
6080bool QQuickTableView::animate()
const
6082 return d_func()->animate;
6085void QQuickTableView::setAnimate(
bool animate)
6087 Q_D(QQuickTableView);
6088 if (d->animate == animate)
6091 d->animate = animate;
6093 d->positionXAnimation.stop();
6094 d->positionYAnimation.stop();
6097 emit animateChanged();
6100bool QQuickTableView::keyNavigationEnabled()
const
6102 return d_func()->keyNavigationEnabled;
6105void QQuickTableView::setKeyNavigationEnabled(
bool enabled)
6107 Q_D(QQuickTableView);
6108 if (d->keyNavigationEnabled == enabled)
6111 d->keyNavigationEnabled = enabled;
6113 emit keyNavigationEnabledChanged();
6116bool QQuickTableView::pointerNavigationEnabled()
const
6118 return d_func()->pointerNavigationEnabled;
6121void QQuickTableView::setPointerNavigationEnabled(
bool enabled)
6123 Q_D(QQuickTableView);
6124 if (d->pointerNavigationEnabled == enabled)
6127 d->pointerNavigationEnabled = enabled;
6129 emit pointerNavigationEnabledChanged();
6132int QQuickTableView::leftColumn()
const
6134 Q_D(
const QQuickTableView);
6135 return d->loadedItems.isEmpty() ? -1 : d_func()->leftColumn();
6138int QQuickTableView::rightColumn()
const
6140 Q_D(
const QQuickTableView);
6141 return d->loadedItems.isEmpty() ? -1 : d_func()->rightColumn();
6144int QQuickTableView::topRow()
const
6146 Q_D(
const QQuickTableView);
6147 return d->loadedItems.isEmpty() ? -1 : d_func()->topRow();
6150int QQuickTableView::bottomRow()
const
6152 Q_D(
const QQuickTableView);
6153 return d->loadedItems.isEmpty() ? -1 : d_func()->bottomRow();
6156int QQuickTableView::currentRow()
const
6158 return d_func()->currentRow;
6161int QQuickTableView::currentColumn()
const
6163 return d_func()->currentColumn;
6166void QQuickTableView::positionViewAtRow(
int row, PositionMode mode, qreal offset,
const QRectF &subRect)
6168 Q_D(QQuickTableView);
6169 if (row < 0 || row >= rows() || d->loadedRows.isEmpty())
6176 if (mode & (AlignTop | AlignBottom | AlignVCenter)) {
6177 mode &= AlignTop | AlignBottom | AlignVCenter;
6178 d->positionViewAtRow(row, Qt::Alignment(
int(mode)), offset, subRect);
6179 }
else if (mode == Contain) {
6180 if (row < topRow()) {
6181 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6182 }
else if (row > bottomRow()) {
6183 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6184 }
else if (row == topRow()) {
6185 if (!subRect.isValid()) {
6186 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6188 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6189 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6190 if (subRectTop < d->viewportRect.y())
6191 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6192 else if (subRectBottom > d->viewportRect.bottom())
6193 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6195 }
else if (row == bottomRow()) {
6196 if (!subRect.isValid()) {
6197 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6201 const qreal subRectBottom = d->loadedTableInnerRect.bottom() + subRect.bottom();
6202 if (subRectBottom > d->viewportRect.bottom())
6203 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6206 }
else if (mode == Visible) {
6207 if (row < topRow()) {
6208 d->positionViewAtRow(row, Qt::AlignTop, -offset, subRect);
6209 }
else if (row > bottomRow()) {
6210 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6211 }
else if (subRect.isValid()) {
6212 if (row == topRow()) {
6213 const qreal subRectTop = d->loadedTableOuterRect.top() + subRect.top();
6214 const qreal subRectBottom = d->loadedTableOuterRect.top() + subRect.bottom();
6215 if (subRectBottom < d->viewportRect.top())
6216 d->positionViewAtRow(row, Qt::AlignTop, offset, subRect);
6217 else if (subRectTop > d->viewportRect.bottom())
6218 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6219 }
else if (row == bottomRow()) {
6222 const qreal subRectTop = d->loadedTableInnerRect.bottom() + subRect.top();
6223 if (subRectTop > d->viewportRect.bottom())
6224 d->positionViewAtRow(row, Qt::AlignTop | Qt::AlignBottom, offset, subRect);
6228 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6232void QQuickTableView::positionViewAtColumn(
int column, PositionMode mode, qreal offset,
const QRectF &subRect)
6234 Q_D(QQuickTableView);
6235 if (column < 0 || column >= columns() || d->loadedColumns.isEmpty())
6242 if (mode & (AlignLeft | AlignRight | AlignHCenter)) {
6243 mode &= AlignLeft | AlignRight | AlignHCenter;
6244 d->positionViewAtColumn(column, Qt::Alignment(
int(mode)), offset, subRect);
6245 }
else if (mode == Contain) {
6246 if (column < leftColumn()) {
6247 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6248 }
else if (column > rightColumn()) {
6249 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6250 }
else if (column == leftColumn()) {
6251 if (!subRect.isValid()) {
6252 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6254 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6255 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6256 if (subRectLeft < d->viewportRect.left())
6257 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6258 else if (subRectRight > d->viewportRect.right())
6259 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6261 }
else if (column == rightColumn()) {
6262 if (!subRect.isValid()) {
6263 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6267 const qreal subRectRight = d->loadedTableInnerRect.right() + subRect.right();
6268 if (subRectRight > d->viewportRect.right())
6269 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6272 }
else if (mode == Visible) {
6273 if (column < leftColumn()) {
6274 d->positionViewAtColumn(column, Qt::AlignLeft, -offset, subRect);
6275 }
else if (column > rightColumn()) {
6276 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6277 }
else if (subRect.isValid()) {
6278 if (column == leftColumn()) {
6279 const qreal subRectLeft = d->loadedTableOuterRect.left() + subRect.left();
6280 const qreal subRectRight = d->loadedTableOuterRect.left() + subRect.right();
6281 if (subRectRight < d->viewportRect.left())
6282 d->positionViewAtColumn(column, Qt::AlignLeft, offset, subRect);
6283 else if (subRectLeft > d->viewportRect.right())
6284 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6285 }
else if (column == rightColumn()) {
6288 const qreal subRectLeft = d->loadedTableInnerRect.right() + subRect.left();
6289 if (subRectLeft > d->viewportRect.right())
6290 d->positionViewAtColumn(column, Qt::AlignLeft | Qt::AlignRight, offset, subRect);
6294 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6298void QQuickTableView::positionViewAtCell(
const QPoint &cell, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6300 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6301 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6302 if (!horizontalMode && !verticalMode) {
6303 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6308 positionViewAtColumn(cell.x(), horizontalMode, offset.x(), subRect);
6310 positionViewAtRow(cell.y(), verticalMode, offset.y(), subRect);
6313void QQuickTableView::positionViewAtIndex(
const QModelIndex &index, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6315 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6316 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6317 if (!horizontalMode && !verticalMode) {
6318 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6323 positionViewAtColumn(columnAtIndex(index), horizontalMode, offset.x(), subRect);
6325 positionViewAtRow(rowAtIndex(index), verticalMode, offset.y(), subRect);
6328#if QT_DEPRECATED_SINCE(6
, 5
)
6329void QQuickTableView::positionViewAtCell(
int column,
int row, PositionMode mode,
const QPointF &offset,
const QRectF &subRect)
6331 PositionMode horizontalMode = mode & ~(AlignTop | AlignBottom | AlignVCenter);
6332 PositionMode verticalMode = mode & ~(AlignLeft | AlignRight | AlignHCenter);
6333 if (!horizontalMode && !verticalMode) {
6334 qmlWarning(
this) <<
"Unsupported mode:" <<
int(mode);
6339 positionViewAtColumn(column, horizontalMode, offset.x(), subRect);
6341 positionViewAtRow(row, verticalMode, offset.y(), subRect);
6345void QQuickTableView::moveColumn(
int source,
int destination)
6347 Q_D(QQuickTableView);
6348 d->moveSection(source, destination, Qt::Horizontal);
6351void QQuickTableView::moveRow(
int source,
int destination)
6353 Q_D(QQuickTableView);
6354 d->moveSection(source, destination, Qt::Vertical);
6357void QQuickTableViewPrivate::moveSection(
int source,
int destination, Qt::Orientation orientation)
6359 Q_Q(QQuickTableView);
6361 if (source < 0 || destination < 0 ||
6362 (orientation == Qt::Horizontal &&
6363 (source >= tableSize.width() || destination >= tableSize.width())) ||
6364 (orientation == Qt::Vertical &&
6365 (source >= tableSize.height() || destination >= tableSize.height())))
6368 if (source == destination)
6371 if (m_sectionState != SectionState::Moving) {
6372 m_sectionState = SectionState::Moving;
6374 syncView->d_func()->moveSection(source, destination, orientation);
6377 initializeIndexMapping();
6380 auto &visualIndices = visualIndicesForOrientation(orientation);
6381 auto &logicalIndices = logicalIndicesForOrientation(orientation);
6383 const int logical = logicalIndices.at(source).index;
6384 int visual = source;
6386 if (destination > source) {
6387 while (visual < destination) {
6388 SectionData &visualData = visualIndices[logicalIndices[visual + 1].index];
6389 SectionData &logicalData = logicalIndices[visual];
6390 visualData.prevIndex = visualData.index;
6391 visualData.index = visual;
6392 logicalData.prevIndex = logicalData.index;
6393 logicalData.index = logicalIndices[visual + 1].index;
6397 while (visual > destination) {
6398 SectionData &visualData = visualIndices[logicalIndices[visual - 1].index];
6399 SectionData &logicalData = logicalIndices[visual];
6400 visualData.prevIndex = visualData.index;
6401 visualData.index = visual;
6402 logicalData.prevIndex = logicalData.index;
6403 logicalData.index = logicalIndices[visual - 1].index;
6408 visualIndices[logical].prevIndex = visualIndices[logical].index;
6409 visualIndices[logical].index = destination;
6410 logicalIndices[destination].prevIndex = logicalIndices[destination].index;
6411 logicalIndices[destination].index = logical;
6415 for (
auto syncChild : std::as_const(syncChildren)) {
6416 auto syncChild_d = syncChild->d_func();
6417 if (syncChild_d->m_sectionState != SectionState::Moving &&
6418 ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
6419 (syncChild_d->syncVertically && orientation == Qt::Vertical)))
6420 syncChild_d->moveSection(source, destination, orientation);
6425 scheduleRebuildTable(RebuildOption::ViewportOnly);
6426 m_sectionState = SectionState::Idle;
6429 const int startIndex = (source > destination) ? destination : source;
6430 const int endIndex = (source > destination) ? source : destination;
6431 const auto &logicalDataIndices = syncView
6432 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6433 : logicalIndicesForOrientation(orientation);
6434 const auto &visualDataIndices = syncView
6435 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6436 : visualIndicesForOrientation(orientation);
6437 for (
int index = startIndex; index <= endIndex; index++) {
6438 const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
6439 if (orientation == Qt::Horizontal)
6440 emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6442 emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
6447void QQuickTableView::clearColumnReordering()
6449 Q_D(QQuickTableView);
6450 d->clearSection(Qt::Horizontal);
6453void QQuickTableView::clearRowReordering()
6455 Q_D(QQuickTableView);
6456 d->clearSection(Qt::Vertical);
6459void QQuickTableViewPrivate::clearSection(Qt::Orientation orientation)
6461 Q_Q(QQuickTableView);
6463 const auto &oldLogicalIndices = syncView
6464 ? syncView->d_func()->logicalIndicesForOrientation(orientation)
6465 : logicalIndicesForOrientation(orientation);
6466 const auto &oldVisualIndices = syncView
6467 ? syncView->d_func()->visualIndicesForOrientation(orientation)
6468 : visualIndicesForOrientation(orientation);
6471 syncView->d_func()->clearSection(orientation);
6474 logicalIndicesForOrientation(orientation).clear();
6475 visualIndicesForOrientation(orientation).clear();
6476 scheduleRebuildTable(RebuildOption::ViewportOnly);
6480 for (
int index = 0; index <
int(oldLogicalIndices.size()); index++) {
6481 const auto &logicalDataIndices = oldLogicalIndices;
6482 const auto &visualDataIndices = oldVisualIndices;
6483 if (logicalDataIndices[index].index != index) {
6484 const int currentIndex = logicalDataIndices[index].index;
6485 if (orientation == Qt::Horizontal)
6486 emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6488 emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
6493void QQuickTableViewPrivate::setContainsDragOnDelegateItem(
const QModelIndex &modelIndex,
bool overlay)
6495 if (!modelIndex.isValid())
6498 const int cellIndex = modelIndexToCellIndex(modelIndex);
6499 if (!loadedItems.contains(cellIndex))
6501 const QPoint cell = cellAtModelIndex(cellIndex);
6502 QQuickItem *item = loadedTableItem(cell)->item;
6503 setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item,
false);
6506QQuickItem *QQuickTableView::itemAtCell(
const QPoint &cell)
const
6508 Q_D(
const QQuickTableView);
6509 const int modelIndex = d->modelIndexAtCell(cell);
6510 if (!d->loadedItems.contains(modelIndex))
6512 return d->loadedItems.value(modelIndex)->item;
6515#if QT_DEPRECATED_SINCE(6
, 5
)
6516QQuickItem *QQuickTableView::itemAtCell(
int column,
int row)
const
6518 return itemAtCell(QPoint(column, row));
6522QQuickItem *QQuickTableView::itemAtIndex(
const QModelIndex &index)
const
6524 Q_D(
const QQuickTableView);
6525 const int serializedIndex = d->modelIndexToCellIndex(index);
6526 if (!d->loadedItems.contains(serializedIndex))
6528 return d->loadedItems.value(serializedIndex)->item;
6531#if QT_DEPRECATED_SINCE(6
, 4
)
6532QPoint QQuickTableView::cellAtPos(qreal x, qreal y,
bool includeSpacing)
const
6534 return cellAtPosition(mapToItem(contentItem(), {x, y}), includeSpacing);
6537QPoint QQuickTableView::cellAtPos(
const QPointF &position,
bool includeSpacing)
const
6539 return cellAtPosition(mapToItem(contentItem(), position), includeSpacing);
6543QPoint QQuickTableView::cellAtPosition(qreal x, qreal y,
bool includeSpacing)
const
6545 return cellAtPosition(QPoint(x, y), includeSpacing);
6548QPoint QQuickTableView::cellAtPosition(
const QPointF &position,
bool includeSpacing)
const
6550 Q_D(
const QQuickTableView);
6552 if (!d->loadedTableOuterRect.contains(position))
6553 return QPoint(-1, -1);
6555 const qreal hSpace = d->cellSpacing.width();
6556 const qreal vSpace = d->cellSpacing.height();
6557 qreal currentColumnEnd = d->loadedTableOuterRect.x();
6558 qreal currentRowEnd = d->loadedTableOuterRect.y();
6560 int foundColumn = -1;
6563 for (
const int column : d->loadedColumns) {
6564 currentColumnEnd += d->getEffectiveColumnWidth(column);
6565 if (position.x() < currentColumnEnd) {
6566 foundColumn = column;
6569 currentColumnEnd += hSpace;
6570 if (!includeSpacing && position.x() < currentColumnEnd) {
6572 return QPoint(-1, -1);
6573 }
else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
6574 foundColumn = column;
6579 for (
const int row : d->loadedRows) {
6580 currentRowEnd += d->getEffectiveRowHeight(row);
6581 if (position.y() < currentRowEnd) {
6585 currentRowEnd += vSpace;
6586 if (!includeSpacing && position.y() < currentRowEnd) {
6588 return QPoint(-1, -1);
6590 if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
6596 return QPoint(foundColumn, foundRow);
6599bool QQuickTableView::isColumnLoaded(
int column)
const
6601 Q_D(
const QQuickTableView);
6602 if (!d->loadedColumns.contains(column))
6605 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6608 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6615bool QQuickTableView::isRowLoaded(
int row)
const
6617 Q_D(
const QQuickTableView);
6618 if (!d->loadedRows.contains(row))
6621 if (d->rebuildState != QQuickTableViewPrivate::RebuildState::Done) {
6624 if (d->rebuildState < QQuickTableViewPrivate::RebuildState::LayoutTable)
6631qreal QQuickTableView::columnWidth(
int column)
const
6633 Q_D(
const QQuickTableView);
6634 if (!isColumnLoaded(column))
6637 return d->getEffectiveColumnWidth(column);
6640qreal QQuickTableView::rowHeight(
int row)
const
6642 Q_D(
const QQuickTableView);
6643 if (!isRowLoaded(row))
6646 return d->getEffectiveRowHeight(row);
6649qreal QQuickTableView::implicitColumnWidth(
int column)
const
6651 Q_D(
const QQuickTableView);
6652 if (!isColumnLoaded(column))
6655 return d->sizeHintForColumn(column);
6658qreal QQuickTableView::implicitRowHeight(
int row)
const
6660 Q_D(
const QQuickTableView);
6661 if (!isRowLoaded(row))
6664 return d->sizeHintForRow(row);
6667void QQuickTableView::setColumnWidth(
int column, qreal size)
6669 Q_D(QQuickTableView);
6671 qmlWarning(
this) <<
"column must be greather than, or equal to, zero";
6675 if (d->syncHorizontally) {
6676 d->syncView->setColumnWidth(column, size);
6680 if (qFuzzyCompare(explicitColumnWidth(column), size))
6684 d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
6686 d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
6688 if (d->loadedItems.isEmpty())
6691 const bool allColumnsLoaded = d->atTableEnd(Qt::LeftEdge) && d->atTableEnd(Qt::RightEdge);
6692 if (column >= leftColumn() || column <= rightColumn() || allColumnsLoaded)
6693 d->forceLayout(
false);
6696void QQuickTableView::clearColumnWidths()
6698 Q_D(QQuickTableView);
6700 if (d->syncHorizontally) {
6701 d->syncView->clearColumnWidths();
6705 if (d->explicitColumnWidths.isEmpty())
6708 d->explicitColumnWidths.clear();
6709 d->forceLayout(
false);
6712qreal QQuickTableView::explicitColumnWidth(
int column)
const
6714 Q_D(
const QQuickTableView);
6716 if (d->syncHorizontally)
6717 return d->syncView->explicitColumnWidth(column);
6719 const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
6720 if (it != d->explicitColumnWidths.constEnd())
6725void QQuickTableView::setRowHeight(
int row, qreal size)
6727 Q_D(QQuickTableView);
6729 qmlWarning(
this) <<
"row must be greather than, or equal to, zero";
6733 if (d->syncVertically) {
6734 d->syncView->setRowHeight(row, size);
6738 if (qFuzzyCompare(explicitRowHeight(row), size))
6742 d->explicitRowHeights.remove(d->logicalRowIndex(row));
6744 d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
6746 if (d->loadedItems.isEmpty())
6749 const bool allRowsLoaded = d->atTableEnd(Qt::TopEdge) && d->atTableEnd(Qt::BottomEdge);
6750 if (row >= topRow() || row <= bottomRow() || allRowsLoaded)
6751 d->forceLayout(
false);
6754void QQuickTableView::clearRowHeights()
6756 Q_D(QQuickTableView);
6758 if (d->syncVertically) {
6759 d->syncView->clearRowHeights();
6763 if (d->explicitRowHeights.isEmpty())
6766 d->explicitRowHeights.clear();
6767 d->forceLayout(
false);
6770qreal QQuickTableView::explicitRowHeight(
int row)
const
6772 Q_D(
const QQuickTableView);
6774 if (d->syncVertically)
6775 return d->syncView->explicitRowHeight(row);
6777 const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
6778 if (it != d->explicitRowHeights.constEnd())
6783QModelIndex QQuickTableView::modelIndex(
const QPoint &cell)
const
6785 Q_D(
const QQuickTableView);
6786 if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
6789 auto const qaim = d->model->abstractItemModel();
6793 return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
6796QPoint QQuickTableView::cellAtIndex(
const QModelIndex &index)
const
6798 if (!index.isValid() || index.parent().isValid())
6800 Q_D(
const QQuickTableView);
6801 return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
6804#if QT_DEPRECATED_SINCE(6
, 4
)
6805QModelIndex QQuickTableView::modelIndex(
int row,
int column)
const
6807 static bool compat6_4 = qEnvironmentVariable(
"QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral(
"6.4");
6813 return modelIndex({row, column});
6815 qmlWarning(
this) <<
"modelIndex(row, column) is deprecated. "
6816 "Use index(row, column) instead. For more information, see "
6817 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
6818 return modelIndex({column, row});
6823QModelIndex QQuickTableView::index(
int row,
int column)
const
6825 return modelIndex({column, row});
6828int QQuickTableView::rowAtIndex(
const QModelIndex &index)
const
6830 return cellAtIndex(index).y();
6833int QQuickTableView::columnAtIndex(
const QModelIndex &index)
const
6835 return cellAtIndex(index).x();
6838void QQuickTableView::forceLayout()
6840 d_func()->forceLayout(
true);
6843void QQuickTableView::edit(
const QModelIndex &requestedIndex)
6845 Q_D(QQuickTableView);
6848 if (!d->canEdit(requestedIndex,
true))
6851 const auto *aim = d->qaim(d->modelImpl());
6856 const QModelIndex index = aim->buddy(requestedIndex);
6858 if (d->editIndex == index)
6864 if (!d->editModel) {
6865 d->editModel =
new QQmlTableInstanceModel(qmlContext(
this));
6866 d->editModel->useImportVersion(d->resolveImportVersion());
6867 QObject::connect(d->editModel, &QQmlInstanceModel::initItem,
this,
6868 [
this, d] (
int serializedModelIndex, QObject *object) {
6874 const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
6875 d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
6876 d->editItem = qmlobject_cast<QQuickItem*>(object);
6880 const bool init =
true;
6881 d->updateItemProperties(serializedModelIndex, object, init);
6882 const auto cellItem = itemAtCell(cellAtIndex(d->editIndex));
6884 d->editItem->setParentItem(cellItem);
6891 if (d->selectionModel)
6892 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
6895 d->closeEditorAndCommit();
6897 const auto cellItem = itemAtCell(cellAtIndex(index));
6899 const auto attached = d->getAttachedObject(cellItem);
6902 d->editModel->setModel(d->tableModel->model());
6903 d->editModel->setDelegate(attached->editDelegate());
6905 const int cellIndex = d->getEditCellIndex(index);
6906 QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
6908 d->editIndex = QModelIndex();
6909 d->editItem =
nullptr;
6910 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate could not be instantiated!";
6917 qmlWarning(
this) <<
"cannot edit: TableView.editDelegate is not an Item!";
6918 d->editItem =
nullptr;
6919 d->editIndex = QModelIndex();
6920 d->editModel->release(object, QQmlInstanceModel::NotReusable);
6926 d->model->object(cellIndex, QQmlIncubator::Synchronous);
6929 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
true), cellIndex, cellItem,
false);
6932 d->editItem->forceActiveFocus(Qt::MouseFocusReason);
6933 (
void)d->installEventFilterOnFocusObjectInsideEditItem();
6936void QQuickTableView::closeEditor()
6938 Q_D(QQuickTableView);
6943 QQuickItem *cellItem = d->editItem->parentItem();
6944 d->editModel->release(d->editItem, QQmlInstanceModel::NotReusable);
6945 d->editItem =
nullptr;
6948 const int cellIndex = d->getEditCellIndex(d->editIndex);
6949 d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(
false), cellIndex, cellItem,
false);
6951 d->model->release(cellItem, QQmlInstanceModel::NotReusable);
6953 if (d->editIndex.isValid()) {
6956 d->editIndex = QModelIndex();
6960QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
6962 return new QQuickTableViewAttached(obj);
6965void QQuickTableView::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
6967 Q_D(QQuickTableView);
6968 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
6970 if (d->tableModel) {
6973 d->tableModel->drainReusableItemsPool(0);
6976 d->forceLayout(
false);
6979void QQuickTableView::viewportMoved(Qt::Orientations orientation)
6981 Q_D(QQuickTableView);
6987 QQuickFlickable::viewportMoved(orientation);
6988 if (d->inSetLocalViewportPos)
6995 d->syncViewportPosRecursive();
6997 auto rootView = d->rootSyncView();
6998 auto rootView_d = rootView->d_func();
7000 rootView_d->scheduleRebuildIfFastFlick();
7002 if (!rootView_d->polishScheduled) {
7003 if (rootView_d->scheduledRebuildOptions) {
7010 const bool updated = rootView->d_func()->updateTableRecursive();
7020void QQuickTableView::keyPressEvent(QKeyEvent *e)
7022 Q_D(QQuickTableView);
7024 if (!d->keyNavigationEnabled) {
7025 QQuickFlickable::keyPressEvent(e);
7029 if (d->tableSize.isEmpty())
7032 if (d->editIndex.isValid()) {
7038 if (d->setCurrentIndexFromKeyEvent(e))
7041 if (d->editFromKeyEvent(e))
7044 QQuickFlickable::keyPressEvent(e);
7047bool QQuickTableView::eventFilter(QObject *obj, QEvent *event)
7049 Q_D(QQuickTableView);
7051 if (obj != d->editItem && !d->editItem->isAncestorOf(qobject_cast<QQuickItem *>(obj))) {
7054 return QQuickFlickable::eventFilter(obj, event);
7057 switch (event->type()) {
7058 case QEvent::KeyPress: {
7059 Q_ASSERT(d->editItem);
7060 QKeyEvent *keyEvent =
static_cast<QKeyEvent *>(event);
7061 switch (keyEvent->key()) {
7063 case Qt::Key_Return:
7064 d->closeEditorAndCommit();
7067 case Qt::Key_Backtab:
7068 if (activeFocusOnTab()) {
7069 if (d->setCurrentIndexFromKeyEvent(keyEvent)) {
7070 const QModelIndex currentIndex = d->selectionModel->currentIndex();
7071 if (d->canEdit(currentIndex,
false))
7077 case Qt::Key_Escape:
7082 case QEvent::FocusOut:
7085 if (!d->installEventFilterOnFocusObjectInsideEditItem())
7086 d->closeEditorAndCommit();
7092 return QQuickFlickable::eventFilter(obj, event);
7095bool QQuickTableView::alternatingRows()
const
7097 return d_func()->alternatingRows;
7100void QQuickTableView::setAlternatingRows(
bool alternatingRows)
7102 Q_D(QQuickTableView);
7103 if (d->alternatingRows == alternatingRows)
7106 d->alternatingRows = alternatingRows;
7107 emit alternatingRowsChanged();
7110QQuickTableView::SelectionBehavior QQuickTableView::selectionBehavior()
const
7112 return d_func()->selectionBehavior;
7115void QQuickTableView::setSelectionBehavior(SelectionBehavior selectionBehavior)
7117 Q_D(QQuickTableView);
7118 if (d->selectionBehavior == selectionBehavior)
7121 d->selectionBehavior = selectionBehavior;
7122 emit selectionBehaviorChanged();
7125QQuickTableView::SelectionMode QQuickTableView::selectionMode()
const
7127 return d_func()->selectionMode;
7130void QQuickTableView::setSelectionMode(SelectionMode selectionMode)
7132 Q_D(QQuickTableView);
7133 if (d->selectionMode == selectionMode)
7136 d->selectionMode = selectionMode;
7137 emit selectionModeChanged();
7140bool QQuickTableView::resizableColumns()
const
7142 return d_func()->resizableColumns;
7145void QQuickTableView::setResizableColumns(
bool enabled)
7147 Q_D(QQuickTableView);
7148 if (d->resizableColumns == enabled)
7151 d->resizableColumns = enabled;
7152 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7153 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7155 emit resizableColumnsChanged();
7158bool QQuickTableView::resizableRows()
const
7160 return d_func()->resizableRows;
7163void QQuickTableView::setResizableRows(
bool enabled)
7165 Q_D(QQuickTableView);
7166 if (d->resizableRows == enabled)
7169 d->resizableRows = enabled;
7170 d->resizeHandler->setEnabled(d->resizableRows || d->resizableColumns);
7171 d->hoverHandler->setEnabled(d->resizableRows || d->resizableColumns);
7173 emit resizableRowsChanged();
7178 : QQuickHoverHandler(view->contentItem())
7182 connect(
this, &QQuickHoverHandler::hoveredChanged,
this, [
this] {
7187#if QT_CONFIG(cursor)
7188 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7189 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7190 tableViewPrivate->updateCursor();
7197 QQuickHoverHandler::handleEventPoint(event, point);
7199 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7200#if QT_CONFIG(cursor)
7201 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7204 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7205 const auto item = tableView->itemAtCell(cell);
7209#if QT_CONFIG(cursor)
7210 tableViewPrivate->updateCursor();
7215 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7216 const bool hoveringRow = (itemPos.y() < margin() || itemPos.y() > item->height() - margin());
7217 const bool hoveringColumn = (itemPos.x() < margin() || itemPos.x() > item->width() - margin());
7218 m_row = hoveringRow ? itemPos.y() < margin() ? cell.y() - 1 : cell.y() : -1;
7219 m_column = hoveringColumn ? itemPos.x() < margin() ? cell.x() - 1 : cell.x() : -1;
7220#if QT_CONFIG(cursor)
7221 tableViewPrivate->updateCursor();
7232 setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
7237 if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
7241 if (event->type() == QEvent::Type::Wheel)
7246 const auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7247 return !tableView->isMoving();
7256 setObjectName(
"tableViewResizeHandler");
7260 , QPointingDevice::GrabTransition transition
7262 , QEventPoint &point)
7264 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
7266 switch (transition) {
7267 case QPointingDevice::GrabPassive:
7268 case QPointingDevice::GrabExclusive:
7270 case QPointingDevice::UngrabPassive:
7271 case QPointingDevice::UngrabExclusive:
7272 case QPointingDevice::CancelGrabPassive:
7273 case QPointingDevice::CancelGrabExclusive:
7274 case QPointingDevice::OverrideGrabPassive:
7275 if (m_state == DraggingStarted || m_state == Dragging) {
7276 m_state = DraggingFinished;
7277 updateDrag(ev, point);
7285 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7286 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7287 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7294 updateDrag(event, point);
7299 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7300 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7302 if (m_state == DraggingFinished)
7303 m_state = Listening;
7305 if (point.state() == QEventPoint::Pressed) {
7306 m_row = tableViewPrivate->resizableRows ? tableViewPrivate->hoverHandler->m_row : -1;
7307 m_column = tableViewPrivate->resizableColumns ? tableViewPrivate->hoverHandler->m_column : -1;
7308 if (m_row != -1 || m_column != -1)
7310 }
else if (point.state() == QEventPoint::Released) {
7311 if (m_state == DraggingStarted || m_state == Dragging)
7312 m_state = DraggingFinished;
7314 m_state = Listening;
7315 }
else if (point.state() == QEventPoint::Updated) {
7320 const qreal distX =
m_column != -1 ? point.position().x() - point.pressPosition().x() : 0;
7321 const qreal distY =
m_row != -1 ? point.position().y() - point.pressPosition().y() : 0;
7322 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7323 if (dragDist > qApp->styleHints()->startDragDistance())
7324 m_state = DraggingStarted;
7326 case DraggingStarted:
7331 case DraggingFinished:
7341 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7342#if QT_CONFIG(cursor)
7343 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7350 setPassiveGrab(event, point,
true);
7354 tableView->setFiltersChildMouseEvents(
false);
7355#if QT_CONFIG(cursor)
7356 tableViewPrivate->setActivePointerHandler(
this);
7359 case DraggingStarted:
7360 setExclusiveGrab(event, point,
true);
7361 m_columnStartX = point.position().x();
7362 m_columnStartWidth = tableView->columnWidth(m_column);
7363 m_rowStartY = point.position().y();
7364 m_rowStartHeight = tableView->rowHeight(m_row);
7365#if QT_CONFIG(cursor)
7366 tableViewPrivate->updateCursor();
7370 const qreal distX = point.position().x() - m_columnStartX;
7371 const qreal distY = point.position().y() - m_rowStartY;
7373 tableView->setColumnWidth(
m_column, qMax(0.001, m_columnStartWidth + distX));
7375 tableView->setRowHeight(
m_row, qMax(0.001, m_rowStartHeight + distY));
7377 case DraggingFinished: {
7378 tableView->setFiltersChildMouseEvents(
true);
7379#if QT_CONFIG(cursor)
7380 tableViewPrivate->setActivePointerHandler(
nullptr);
7381 tableViewPrivate->updateCursor();
7388#if QT_CONFIG(quick_draganddrop)
7390QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
7391 : QQuickTableViewPointerHandler(view)
7393 setObjectName(
"tableViewDragHandler");
7396QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
7401void QQuickTableViewSectionDragHandler::resetDragData()
7403 if (m_state != Listening) {
7404 m_state = Listening;
7405 resetSectionOverlay();
7408 if (m_grabResult.data())
7409 m_grabResult.data()->disconnect();
7410 if (!m_drag.isNull()) {
7411 m_drag->disconnect();
7414 if (!m_dropArea.isNull()) {
7415 m_dropArea->disconnect();
7418 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7419 tableView->setFiltersChildMouseEvents(
true);
7423void QQuickTableViewSectionDragHandler::resetSectionOverlay()
7425 if (m_destination != -1) {
7426 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7427 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7428 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
7429 const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
7430 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
false);
7435void QQuickTableViewSectionDragHandler::grabSection()
7438 QPixmap pixmap(m_grabResult->image().size());
7439 pixmap.fill(Qt::transparent);
7440 QPainter painter(&pixmap);
7441 painter.setOpacity(0.6);
7442 painter.drawImage(0, 0, m_grabResult->image());
7446 auto *mimeData =
new QMimeData();
7447 mimeData->setImageData(pixmap);
7448 m_drag->setMimeData(mimeData);
7449 m_drag->setPixmap(pixmap);
7452void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
7456 if (m_state == Dragging) {
7457 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7458 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7459 tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
7460 m_state = DraggingFinished;
7461 resetSectionOverlay();
7462 if (m_scrollTimer.isActive())
7463 m_scrollTimer.stop();
7468void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
7472 if (m_state == Dragging) {
7473 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7474 const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
7475 const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
7476 const QPoint targetCell = tableView->cellAtPosition(dragItemPosition,
true);
7478 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7479 const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
7480 if (newDestination != m_destination) {
7482 resetSectionOverlay();
7484 const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
7485 const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
7486 tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column),
true);
7487 m_destination = newDestination;
7491 const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
7492 QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
7493 const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
7494 QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
7495 const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
7496 const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
7497 if (useStartPos || useEndPos) {
7498 if (!m_scrollTimer.isActive()) {
7499 m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
7500 QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
7501 m_scrollTimer.start(1);
7504 if (m_scrollTimer.isActive())
7505 m_scrollTimer.stop();
7510void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
7514 if (action == Qt::IgnoreAction) {
7515 resetSectionOverlay();
7516 if (m_scrollTimer.isActive())
7517 m_scrollTimer.stop();
7521void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
7523 QQuickSinglePointHandler::handleEventPoint(event, point);
7525 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7526 auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7527 const auto *activeHandler = tableViewPrivate->activePointerHandler();
7528 if (activeHandler && !qobject_cast<
const QQuickTableViewSectionDragHandler *>(activeHandler))
7531 if (m_state == DraggingFinished) {
7532 if (m_scrollTimer.isActive())
7533 m_scrollTimer.stop();
7537 if (point.state() == QEventPoint::Pressed) {
7541 setPassiveGrab(event, point,
true);
7545 auto *tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7546 tableView->setFiltersChildMouseEvents(
false);
7548 }
else if (point.state() == QEventPoint::Released) {
7550 if (m_scrollTimer.isActive())
7551 m_scrollTimer.stop();
7553 }
else if (point.state() == QEventPoint::Updated) {
7555 const qreal distX = point.position().x() - point.pressPosition().x();
7556 const qreal distY = point.position().y() - point.pressPosition().y();
7557 const qreal dragDist = qSqrt(distX * distX + distY * distY);
7558 if (dragDist > qApp->styleHints()->startDragDistance()) {
7562 const QPoint cell = tableView->cellAtPosition(point.position(),
true);
7563 auto *item = tableView->itemAtCell(cell);
7566 if (m_drag.isNull()) {
7567 m_drag =
new QDrag(item);
7568 connect(m_drag.data(), &QDrag::actionChanged,
this,
7569 &QQuickTableViewSectionDragHandler::handleDragDropAction);
7572 QObject::connect(&m_scrollTimer, &QTimer::timeout,
this, [&]{
7573 const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
7574 m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
7575 m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
7576 m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
7579 if (m_dropArea.isNull()) {
7580 m_dropArea =
new QQuickDropArea(tableView);
7581 m_dropArea->setSize(tableView->size());
7582 connect(m_dropArea, &QQuickDropArea::positionChanged,
this,
7583 &QQuickTableViewSectionDragHandler::handleDrag);
7584 connect(m_dropArea, &QQuickDropArea::dropped,
this,
7585 &QQuickTableViewSectionDragHandler::handleDrop);
7588 m_grabResult = item->grabToImage();
7589 connect(m_grabResult.data(), &QQuickItemGrabResult::ready,
this,
7590 &QQuickTableViewSectionDragHandler::grabSection);
7592 m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
7593 m_state = DraggingStarted;
7595 tableViewPrivate->setActivePointerHandler(
this);
7599 case DraggingStarted: {
7600 if (m_drag && m_drag->mimeData()) {
7601 if (
auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
7603 const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
7605 m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
7609 if (m_state == Dragging)
7612 tableViewPrivate->setActivePointerHandler(
nullptr);
7626void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
7628 if (!sectionDragHandler) {
7629 Q_Q(QQuickTableView);
7630 sectionDragHandler =
new QQuickTableViewSectionDragHandler(q);
7631 sectionDragHandler->setSectionOrientation(orientation);
7635void QQuickTableViewPrivate::destroySectionDragHandler()
7637 if (sectionDragHandler) {
7638 delete sectionDragHandler;
7639 sectionDragHandler =
nullptr;
7644void QQuickTableViewPrivate::initializeIndexMapping()
7646 auto initIndices = [](
auto& visualIndex,
auto& logicalIndex,
int size) {
7647 visualIndex.resize(size);
7648 logicalIndex.resize(size);
7649 for (
int index = 0; index < size; ++index)
7650 visualIndex[index].index = logicalIndex[index].index = index;
7653 if (horizontalVisualIndices.size() != size_t(tableSize.width())
7654 || horizontalLogicalIndices.size() != size_t(tableSize.width()))
7655 initIndices(horizontalVisualIndices, horizontalLogicalIndices, tableSize.width());
7657 if (verticalVisualIndices.size() != size_t(tableSize.height())
7658 || verticalLogicalIndices.size() != size_t(tableSize.height()))
7659 initIndices(verticalVisualIndices, verticalLogicalIndices, tableSize.height());
7662void QQuickTableViewPrivate::clearIndexMapping()
7664 horizontalLogicalIndices.clear();
7665 horizontalVisualIndices.clear();
7667 verticalLogicalIndices.clear();
7668 verticalVisualIndices.clear();
7671int QQuickTableViewPrivate::logicalRowIndex(
const int visualIndex)
const
7674 return syncView->d_func()->logicalRowIndex(visualIndex);
7675 if (verticalLogicalIndices.empty() || visualIndex < 0)
7677 return verticalLogicalIndices.at(visualIndex).index;
7680int QQuickTableViewPrivate::logicalColumnIndex(
const int visualIndex)
const
7683 return syncView->d_func()->logicalColumnIndex(visualIndex);
7684 if (horizontalLogicalIndices.empty() || visualIndex < 0)
7686 return horizontalLogicalIndices.at(visualIndex).index;
7689int QQuickTableViewPrivate::visualRowIndex(
const int logicalIndex)
const
7692 return syncView->d_func()->visualRowIndex(logicalIndex);
7693 if (verticalVisualIndices.empty() || logicalIndex < 0)
7694 return logicalIndex;
7695 return verticalVisualIndices.at(logicalIndex).index;
7698int QQuickTableViewPrivate::visualColumnIndex(
const int logicalIndex)
const
7701 return syncView->d_func()->visualColumnIndex(logicalIndex);
7702 if (horizontalVisualIndices.empty() || logicalIndex < 0)
7703 return logicalIndex;
7704 return horizontalVisualIndices.at(logicalIndex).index;
7707int QQuickTableViewPrivate::getEditCellIndex(
const QModelIndex &index)
const
7711 const bool hasProxyModel = (modelImpl() != assignedModel);
7712 return modelIndexToCellIndex(index, hasProxyModel);
7718 : QQuickTapHandler(view->contentItem())
7720 setObjectName(
"tableViewTapHandler");
7725 auto tableView =
static_cast<QQuickTableView *>(parentItem()->parent());
7726 auto tableViewPrivate = QQuickTableViewPrivate::get(tableView);
7727 return tableViewPrivate->pointerNavigationEnabled && QQuickTapHandler::wantsEventPoint(event, point);
7732#include "moc_qquicktableview_p.cpp"
7733#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