Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquicktreeview.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qobject.h>
8#include <QtQml/qqmlcontext.h>
9#include <QtQuick/private/qquicktaphandler_p.h>
10
11#include <QtQmlModels/private/qqmltreemodeltotablemodel_p_p.h>
12
13/*!
14 \qmltype TreeView
15 \inqmlmodule QtQuick
16 \ingroup qtquick-views
17 \since 6.3
18 \inherits TableView
19 \brief Provides a tree view to display data from a QAbstractItemModel.
20
21 A TreeView has a \l model that defines the data to be displayed, and a
22 \l delegate that defines how the data should be displayed.
23
24 TreeView inherits \l TableView. This means that, despite the model
25 has a parent-child tree structure, TreeView is internally using a
26 proxy model that converts that structure into a flat table
27 model that can be rendered by TableView. Each node in the tree ends up
28 occupying one row in the table, where the first column renders the tree
29 itself. By indenting each delegate item in that column according to its
30 parent-child depth in the model, it will end up looking like a tree, even
31 if it's technically still just a flat list of items.
32
33 \section2 Declare a TreeView
34
35 TreeView is a data bound control, so it cannot show anything without a
36 data model. You cannot declare tree nodes in QML.
37
38 When you declare a TreeView, you need to specify:
39
40 \list
41 \li \b{A data model}. TreeView can work with data models that derive from
42 \l QAbstractItemModel.
43 \li \b{A delegate}. A delegate is a template that specifies how the tree
44 nodes are displayed in the UI.
45 \endlist
46
47 \qml
48 TreeView {
49 // The model needs to be a QAbstractItemModel
50 model: myTreeModel
51 // You can set a custom delegate or use a built-in TreeViewDelegate
52 delegate: TreeViewDelegate {}
53 }
54 \endqml
55
56 \section2 Creating a data model
57
58 A TreeView only accepts a model that inherits \l QAbstractItemModel.
59
60 For information on how to create and use a custom tree model, see the
61 example: \l {Qt Quick Controls - Table of Contents}.
62
63 \section2 Customize tree nodes
64
65 For better flexibility, TreeView itself doesn't position the delegate items
66 into a tree structure. This burden is placed on the delegate.
67 \l {Qt Quick Controls} offers a ready-made \l TreeViewDelegate that can be
68 used for this, which has the advantage that it works out-of-the-box and
69 renders a tree which follows the style of the platform where the application
70 runs.
71
72 Even though \l TreeViewDelegate is customizable, there might be situations
73 where you want to render the tree in a different way, or ensure that
74 the delegate ends up as minimal as possible, perhaps for performance reasons.
75 Creating your own delegate from scratch is easy, since TreeView offers
76 a set of properties that can be used to position and render each node
77 in the tree correctly.
78
79 An example of a custom delegate with an animating indicator is shown below:
80
81 \snippet qml/treeview/qml-customdelegate.qml 0
82
83
84 The properties that are marked as \c required will be filled in by
85 TreeView, and are similar to attached properties. By marking them as
86 required, the delegate indirectly informs TreeView that it should take
87 responsibility for assigning them values. The following required properties
88 can be added to a delegate:
89
90 \list
91 \li \c {required property TreeView treeView}
92 - Points to the TreeView that contains the delegate item.
93 \li \c {required property bool isTreeNode}
94 - Is \c true if the delegate item represents a node in
95 the tree. Only one column in the view will be used to draw the tree, and
96 therefore, only delegate items in that column will have this
97 property set to \c true.
98 A node in the tree should typically be indented according to its
99 \c depth, and show an indicator if \c hasChildren is \c true.
100 Delegate items in other columns will have this property set to
101 \c false, and will show data from the remaining columns
102 in the model (and typically not be indented).
103 \li \c {required property bool expanded}
104 - Is \c true if the model item drawn by the delegate is expanded
105 in the view.
106 \li \c {required property bool hasChildren}
107 - Is \c true if the model item drawn by the delegate has children
108 in the model.
109 \li \c {required property int depth}
110 - Contains the depth of the model item drawn by the delegate.
111 The depth of a model item is the same as the number of ancestors
112 it has in the model.
113 \endlist
114
115 See also \l {Required Properties}.
116
117 \section2 End-user interaction
118
119 By default, TreeView \l {toggleExpanded()}{toggles} the expanded state
120 of a row when you double tap on it. Since this is in conflict with
121 double tapping to edit a cell, TreeView sets \l {TableView::}{editTriggers} to
122 \c TableView.EditKeyPressed by default (which is different from TableView,
123 which uses \c {TableView.EditKeyPressed | TableView.DoubleTapped}.
124 If you change \l {TableView::}{editTriggers} to also contain \c TableView.DoubleTapped,
125 toggling the expanded state with a double tap will be disabled.
126
127*/
128
129/*!
130 \qmlproperty QModelIndex QtQuick::TreeView::rootIndex
131 \since 6.6
132
133 This property holds the model index of the root item in the tree.
134 By default, this is the same as the root index in the model, but you can
135 set it to be a child index instead, to show only a branch of the tree.
136 Set it to \c undefined to show the whole model.
137*/
138
139/*!
140 \qmlmethod int QtQuick::TreeView::depth(row)
141
142 Returns the depth (the number of parents up to the root) of the given \a row.
143
144 \a row should be the row in the view (table row), and not a row in the model.
145 If \a row is not between \c 0 and \l {TableView::}{rows}, the return value will
146 be \c -1.
147
148 \sa {TableView::}{modelIndex()}
149*/
150
151/*!
152 \qmlmethod bool QtQuick::TreeView::isExpanded(row)
153
154 Returns if the given \a row in the view is shown as expanded.
155
156 \a row should be the row in the view (table row), and not a row in the model.
157 If \a row is not between \c 0 and \l {TableView::}{rows}, the return value will
158 be \c false.
159*/
160
161/*!
162 \qmlmethod void QtQuick::TreeView::expand(row)
163
164 Expands the tree node at the given \a row in the view.
165
166 \a row should be the row in the view (table row), and not a row in the model.
167
168 \note this function will not affect the model, only
169 the visual representation in the view.
170
171 \sa collapse(), isExpanded(), expandRecursively()
172*/
173
174/*!
175 \qmlmethod void QtQuick::TreeView::expandRecursively(row = -1, depth = -1)
176 \since 6.4
177
178 Expands the tree node at the given \a row in the view recursively down to
179 \a depth. \a depth should be relative to the depth of \a row. If
180 \a depth is \c -1, the tree will be expanded all the way down to all leaves.
181
182 For a model that has more than one root, you can also call this function
183 with \a row equal to \c -1. This will expand all roots. Hence, calling
184 expandRecursively(-1, -1), or simply expandRecursively(), will expand
185 all nodes in the model.
186
187 \a row should be the row in the view (table row), and not a row in the model.
188
189 \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more} data.
190 \note This function will not affect the model, only the visual representation in the view.
191 \warning If the model contains a large number of items, this function will
192 take some time to execute.
193
194 \sa collapseRecursively(), expand(), collapse(), isExpanded(), depth()
195*/
196
197/*!
198 \qmlmethod void QtQuick::TreeView::expandToIndex(QModelIndex index)
199 \since 6.4
200
201 Expands the tree from the given model \a index, and recursively all the way up
202 to the root. The result will be that the delegate item that represents \a index
203 becomes visible in the view (unless it ends up outside the viewport). To
204 ensure that the row ends up visible in the viewport, you can do:
205
206 \code
207 expandToIndex(index)
208 forceLayout()
209 positionViewAtRow(rowAtIndex(index), Qt.AlignVCenter)
210 \endcode
211
212 \sa expand(), expandRecursively()
213*/
214
215/*!
216 \qmlmethod void QtQuick::TreeView::collapse(row)
217
218 Collapses the tree node at the given \a row in the view.
219
220 \a row should be the row in the view (table row), and not a row in the model.
221
222 \note this function will not affect the model, only
223 the visual representation in the view.
224
225 \sa expand(), isExpanded()
226*/
227
228/*!
229 \qmlmethod void QtQuick::TreeView::collapseRecursively(row = -1)
230 \since 6.4
231
232 Collapses the tree node at the given \a row in the view recursively down to
233 all leaves.
234
235 For a model has more than one root, you can also call this function
236 with \a row equal to \c -1. This will collapse all roots. Hence, calling
237 collapseRecursively(-1), or simply collapseRecursively(), will collapse
238 all nodes in the model.
239
240 \a row should be the row in the view (table row), and not a row in the model.
241
242 \note this function will not affect the model, only
243 the visual representation in the view.
244
245 \sa expandRecursively(), expand(), collapse(), isExpanded(), depth()
246*/
247
248/*!
249 \qmlmethod void QtQuick::TreeView::toggleExpanded(row)
250
251 Toggles if the tree node at the given \a row should be expanded.
252 This is a convenience for doing:
253
254 \code
255 if (isExpanded(row))
256 collapse(row)
257 else
258 expand(row)
259 \endcode
260
261 \a row should be the row in the view (table row), and not a row in the model.
262*/
263
264/*!
265 \qmlsignal QtQuick::TreeView::expanded(row, depth)
266
267 This signal is emitted when a \a row is expanded in the view.
268 \a row and \a depth will be equal to the arguments given to the call
269 that caused the expansion to happen (\l expand() or \l expandRecursively()).
270 In case of \l expand(), \a depth will always be \c 1.
271 In case of \l expandToIndex(), \a depth will be the depth of the
272 target index.
273
274 \note when a row is expanded recursively, the expanded signal will
275 only be emitted for that one row, and not for its descendants.
276
277 \sa collapsed(), expand(), collapse(), toggleExpanded()
278*/
279
280/*!
281 \qmlsignal QtQuick::TreeView::collapsed(row, recursively)
282
283 This signal is emitted when a \a row is collapsed in the view.
284 \a row will be equal to the argument given to the call that caused
285 the collapse to happen (\l collapse() or \l collapseRecursively()).
286 If the row was collapsed recursively, \a recursively will be \c true.
287
288 \note when a row is collapsed recursively, the collapsed signal will
289 only be emitted for that one row, and not for its descendants.
290
291 \sa expanded(), expand(), collapse(), toggleExpanded()
292*/
293
294// Hard-code the tree column to be 0 for now
295static const int kTreeColumn = 0;
296
297QT_BEGIN_NAMESPACE
298
299QQuickTreeViewPrivate::QQuickTreeViewPrivate()
300 : QQuickTableViewPrivate()
301{
302}
303
304QQuickTreeViewPrivate::~QQuickTreeViewPrivate()
305{
306}
307
308QVariant QQuickTreeViewPrivate::modelImpl() const
309{
310 return m_assignedModel;
311}
312
313void QQuickTreeViewPrivate::setModelImpl(const QVariant &newModel)
314{
315 Q_Q(QQuickTreeView);
316
317 m_assignedModel = newModel;
318 if (m_assignedModel.isNull())
319 m_treeModelToTableModel.setModel(nullptr);
320 else if (const auto qaim = qvariant_cast<QAbstractItemModel *>(m_assignedModel))
321 m_treeModelToTableModel.setModel(qaim);
322 else
323 qmlWarning(q) << "TreeView only accepts a model of type QAbstractItemModel";
324
325
326 scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
327 emit q->modelChanged();
328}
329
330void QQuickTreeViewPrivate::dataChangedCallback(
331 const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles)
332{
333 Q_Q(QQuickTreeView);
334 Q_UNUSED(roles);
335
336 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
337 for (int column = topLeft.column(); column <= bottomRight.column(); ++column) {
338 const QPoint cell(column, row);
339 auto item = q->itemAtCell(cell);
340 if (!item)
341 continue;
342
343 const int flatIndex = column * m_treeModelToTableModel.rowCount() + row;
344 updateItemProperties(flatIndex, item, false);
345 }
346 }
347}
348
349void QQuickTreeViewPrivate::updateItemProperties(int flatIndex, QObject *object, bool init)
350{
351 Q_Q(QQuickTreeView);
352 QQuickTableViewPrivate::updateItemProperties(flatIndex, object, init);
353
354 // Use the model's row count rather than cellAtModelIndex(), since a pending rebuild
355 // can leave the table size in TableView stale relative to m_treeModelToTableModel.
356 const int availableRows = m_treeModelToTableModel.rowCount();
357 const int column = flatIndex / availableRows;
358 const int row = flatIndex % availableRows;
359
360 setRequiredProperty("treeView", QVariant::fromValue(q), flatIndex, object, init);
361 setRequiredProperty("isTreeNode", column == kTreeColumn, flatIndex, object, init);
362 setRequiredProperty("hasChildren", m_treeModelToTableModel.hasChildren(row), flatIndex, object, init);
363 setRequiredProperty("expanded", q->isExpanded(row), flatIndex, object, init);
364 setRequiredProperty("depth", m_treeModelToTableModel.depthAtRow(row), flatIndex, object, init);
365}
366
367void QQuickTreeViewPrivate::updateSelection(const QRect &oldSelection, const QRect &newSelection)
368{
369 Q_Q(QQuickTreeView);
370
371 if (oldSelection == newSelection)
372 return;
373
374 QItemSelection select;
375 QItemSelection deselect;
376
377 // Because each row can have a different parent, we need to create separate QItemSelections
378 // per row. But all the cells in a given row have the same parent, so they can be combined.
379 // As a result, the final QItemSelection can end up more fragmented compared to a selection
380 // in QQuickTableView, where all cells have the same parent. In the end, if TreeView has
381 // a lot of columns and the selection mode is "SelectCells", using the mouse to adjust
382 // a selection containing a _large_ number of columns can be slow.
383 const QRect cells = newSelection.normalized();
384 for (int row = cells.y(); row <= cells.y() + cells.height(); ++row) {
385 const QModelIndex startIndex = q->index(row, cells.x());
386 const QModelIndex endIndex = q->index(row, cells.x() + cells.width());
387 select.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
388 }
389
390 const QModelIndexList indexes = selectionModel->selection().indexes();
391 for (const QModelIndex &index : indexes) {
392 if (!select.contains(index) && !existingSelection.contains(index))
393 deselect.merge(QItemSelection(index, index), QItemSelectionModel::Select);
394 }
395
396 if (selectionFlag == QItemSelectionModel::Select) {
397 selectionModel->select(deselect, QItemSelectionModel::Deselect);
398 selectionModel->select(select, QItemSelectionModel::Select);
399 } else {
400 QItemSelection oldSelection = existingSelection;
401 oldSelection.merge(select, QItemSelectionModel::Deselect);
402 selectionModel->select(oldSelection, QItemSelectionModel::Select);
403 selectionModel->select(select, QItemSelectionModel::Deselect);
404 }
405}
406
407QQuickTreeView::QQuickTreeView(QQuickItem *parent)
408 : QQuickTableView(*(new QQuickTreeViewPrivate), parent)
409{
410 Q_D(QQuickTreeView);
411
412 setSelectionBehavior(SelectRows);
413 setEditTriggers(EditKeyPressed);
414
415 // Note: QQuickTableView will only ever see the table model m_treeModelToTableModel, and
416 // never the actual tree model that is assigned to us by the application.
417 const auto modelAsVariant = QVariant::fromValue(std::addressof(d->m_treeModelToTableModel));
418 d->QQuickTableViewPrivate::setModelImpl(modelAsVariant);
419 QObjectPrivate::connect(&d->m_treeModelToTableModel, &QAbstractItemModel::dataChanged,
420 d, &QQuickTreeViewPrivate::dataChangedCallback);
421 QObject::connect(&d->m_treeModelToTableModel, &QQmlTreeModelToTableModel::rootIndexChanged,
422 this, &QQuickTreeView::rootIndexChanged);
423
424 auto tapHandler = new QQuickTapHandler(this);
425 tapHandler->setAcceptedModifiers(Qt::NoModifier);
426 connect(tapHandler, &QQuickTapHandler::doubleTapped, this, [this, tapHandler] {
427 if (!pointerNavigationEnabled())
428 return;
429 if (editTriggers() & DoubleTapped)
430 return;
431
432 const int row = cellAtPosition(tapHandler->point().pressPosition()).y();
433 toggleExpanded(row);
434 });
435}
436
437QQuickTreeView::~QQuickTreeView()
438{
439}
440
441QModelIndex QQuickTreeView::rootIndex() const
442{
443 return d_func()->m_treeModelToTableModel.rootIndex();
444}
445
446void QQuickTreeView::setRootIndex(const QModelIndex &index)
447{
448 Q_D(QQuickTreeView);
449 d->m_treeModelToTableModel.setRootIndex(index);
450 positionViewAtCell({0, 0}, QQuickTableView::AlignTop | QQuickTableView::AlignLeft);
451}
452
453void QQuickTreeView::resetRootIndex()
454{
455 Q_D(QQuickTreeView);
456 d->m_treeModelToTableModel.resetRootIndex();
457 positionViewAtCell({0, 0}, QQuickTableView::AlignTop | QQuickTableView::AlignLeft);
458}
459
460int QQuickTreeView::depth(int row) const
461{
462 Q_D(const QQuickTreeView);
463 if (row < 0 || row >= d->m_treeModelToTableModel.rowCount())
464 return -1;
465
466 return d->m_treeModelToTableModel.depthAtRow(row);
467}
468
469bool QQuickTreeView::isExpanded(int row) const
470{
471 Q_D(const QQuickTreeView);
472 if (row < 0 || row >= d->m_treeModelToTableModel.rowCount())
473 return false;
474
475 return d->m_treeModelToTableModel.isExpanded(row);
476}
477
478void QQuickTreeView::expand(int row)
479{
480 if (row >= 0)
481 expandRecursively(row, 1);
482}
483
484void QQuickTreeView::expandRecursively(int row, int depth)
485{
486 Q_D(QQuickTreeView);
487 if (row >= d->m_treeModelToTableModel.rowCount())
488 return;
489 if (row < 0 && row != -1)
490 return;
491 if (depth == 0 || depth < -1)
492 return;
493
494 auto expandRowRecursively = [this, d, depth](int startRow) {
495 d->m_treeModelToTableModel.expandRecursively(startRow, depth);
496 // Update the expanded state of the startRow. The descendant rows that gets
497 // expanded will get the correct state set from initItem/itemReused instead.
498 for (int c = leftColumn(); c <= rightColumn(); ++c) {
499 const QPoint treeNodeCell(c, startRow);
500 if (const auto item = itemAtCell(treeNodeCell))
501 d->setRequiredProperty("expanded", true, d->modelIndexAtCell(treeNodeCell), item, false);
502 }
503 };
504
505 if (row >= 0) {
506 // Expand only one row recursively
507 const bool isExpanded = d->m_treeModelToTableModel.isExpanded(row);
508 if (isExpanded && depth == 1)
509 return;
510 expandRowRecursively(row);
511 } else if (const auto model = d->m_treeModelToTableModel.model()) {
512 // Expand all root nodes recursively
513 for (int r = 0; r < model->rowCount(); ++r) {
514 const int rootRow = d->m_treeModelToTableModel.itemIndex(model->index(r, 0));
515 if (rootRow != -1)
516 expandRowRecursively(rootRow);
517 }
518 }
519
520 emit expanded(row, depth);
521}
522
523void QQuickTreeView::expandToIndex(const QModelIndex &index)
524{
525 Q_D(QQuickTreeView);
526
527 if (!index.isValid()) {
528 qmlWarning(this) << "index is not valid: " << index;
529 return;
530 }
531
532 if (index.model() != d->m_treeModelToTableModel.model()) {
533 qmlWarning(this) << "index doesn't belong to correct model: " << index;
534 return;
535 }
536
537 if (rowAtIndex(index) != -1) {
538 // index is already visible
539 return;
540 }
541
542 int depth = 1;
543 QModelIndex parent = index.parent();
544 int row = rowAtIndex(parent);
545
546 while (parent.isValid()) {
547 if (row != -1) {
548 // The node is already visible, since it maps to a row in the table!
549 d->m_treeModelToTableModel.expandRow(row);
550
551 // Update the state of the already existing delegate item
552 for (int c = leftColumn(); c <= rightColumn(); ++c) {
553 const QPoint treeNodeCell(c, row);
554 if (const auto item = itemAtCell(treeNodeCell))
555 d->setRequiredProperty("expanded", true, d->modelIndexAtCell(treeNodeCell), item, false);
556 }
557
558 // When we hit a node that is visible, we know that all other nodes
559 // up to the parent have to be visible as well, so we can stop.
560 break;
561 } else {
562 d->m_treeModelToTableModel.expand(parent);
563 parent = parent.parent();
564 row = rowAtIndex(parent);
565 depth++;
566 }
567 }
568
569 emit expanded(row, depth);
570}
571
572void QQuickTreeView::collapse(int row)
573{
574 Q_D(QQuickTreeView);
575 if (row < 0 || row >= d->m_treeModelToTableModel.rowCount())
576 return;
577
578 if (!d->m_treeModelToTableModel.isExpanded(row))
579 return;
580
581 d_func()->m_treeModelToTableModel.collapseRow(row);
582
583 for (int c = leftColumn(); c <= rightColumn(); ++c) {
584 const QPoint treeNodeCell(c, row);
585 if (const auto item = itemAtCell(treeNodeCell))
586 d->setRequiredProperty("expanded", false, d->modelIndexAtCell(treeNodeCell), item, false);
587 }
588
589 emit collapsed(row, false);
590}
591
592void QQuickTreeView::collapseRecursively(int row)
593{
594 Q_D(QQuickTreeView);
595 if (row >= d->m_treeModelToTableModel.rowCount())
596 return;
597 if (row < 0 && row != -1)
598 return;
599
600 auto collapseRowRecursive = [this, d](int startRow) {
601 // Always collapse descendants recursively,
602 // even if the top row itself is already collapsed.
603 d->m_treeModelToTableModel.collapseRecursively(startRow);
604 // Update the expanded state of the (still visible) startRow
605 for (int c = leftColumn(); c <= rightColumn(); ++c) {
606 const QPoint treeNodeCell(c, startRow);
607 if (const auto item = itemAtCell(treeNodeCell))
608 d->setRequiredProperty("expanded", false, d->modelIndexAtCell(treeNodeCell), item, false);
609 }
610 };
611
612 if (row >= 0) {
613 collapseRowRecursive(row);
614 } else if (const auto model = d->m_treeModelToTableModel.model()) {
615 // Collapse all root nodes recursively
616 for (int r = 0; r < model->rowCount(); ++r) {
617 const int rootRow = d->m_treeModelToTableModel.itemIndex(model->index(r, 0));
618 if (rootRow != -1)
619 collapseRowRecursive(rootRow);
620 }
621 }
622
623 emit collapsed(row, true);
624}
625
626void QQuickTreeView::toggleExpanded(int row)
627{
628 if (isExpanded(row))
629 collapse(row);
630 else
631 expand(row);
632}
633
634QModelIndex QQuickTreeView::modelIndex(const QPoint &cell) const
635{
636 Q_D(const QQuickTreeView);
637 const QModelIndex tableIndex = d->m_treeModelToTableModel.index(cell.y(), cell.x());
638 return d->m_treeModelToTableModel.mapToModel(tableIndex);
639}
640
641QPoint QQuickTreeView::cellAtIndex(const QModelIndex &index) const
642{
643 const QModelIndex tableIndex = d_func()->m_treeModelToTableModel.mapFromModel(index);
644 return QPoint(tableIndex.column(), tableIndex.row());
645}
646
647#if QT_DEPRECATED_SINCE(6, 4)
648QModelIndex QQuickTreeView::modelIndex(int row, int column) const
649{
650 static const bool compat6_4 = qEnvironmentVariable("QT_QUICK_TABLEVIEW_COMPAT_VERSION") == QStringLiteral("6.4");
651 if (compat6_4) {
652 // XXX Qt 7: Remove this compatibility path here and in QQuickTableView.
653 // In Qt 6.4.0 and 6.4.1, a source incompatible change led to row and column
654 // being documented to be specified in the opposite order.
655 // QT_QUICK_TABLEVIEW_COMPAT_VERSION can therefore be set to force tableview
656 // to continue accepting calls to modelIndex(column, row).
657 return modelIndex({row, column});
658 } else {
659 qmlWarning(this) << "modelIndex(row, column) is deprecated. "
660 "Use index(row, column) instead. For more information, see "
661 "https://doc.qt.io/qt-6/qml-qtquick-tableview-obsolete.html";
662 return modelIndex({column, row});
663 }
664}
665#endif
666
667void QQuickTreeView::keyPressEvent(QKeyEvent *event)
668{
669 event->ignore();
670
671 if (!keyNavigationEnabled())
672 return;
673 if (!selectionModel())
674 return;
675
676 const int row = cellAtIndex(selectionModel()->currentIndex()).y();
677 switch (event->key()) {
678 case Qt::Key_Left:
679 collapse(row);
680 event->accept();
681 break;
682 case Qt::Key_Right:
683 expand(row);
684 event->accept();
685 break;
686 default:
687 break;
688 }
689
690 if (!event->isAccepted()) {
691 event->accept();
692 QQuickTableView::keyPressEvent(event);
693 }
694}
695
696QT_END_NAMESPACE
697
698#include "moc_qquicktreeview_p.cpp"
static const int kTreeColumn
\qmlproperty QModelIndex QtQuick::TreeView::rootIndex