From d315e012184a2b71b7b5e41869d166c05093d13d Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Fri, 23 Nov 2012 15:24:48 +0100 Subject: [PATCH] Add the Qt::ItemNeverHasChildren flag and use it in QTreeView. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can be used to determine whether expand() should really expand. Change-Id: If79d8c295a4ca1356e60051682b227524a065126 Reviewed-by: David Faure (KDE) Reviewed-by: Olivier Goffart Reviewed-by: Thorbjørn Lund Martsum --- src/corelib/global/qnamespace.h | 3 +- src/corelib/global/qnamespace.qdoc | 1 + src/corelib/itemmodels/qabstractitemmodel.cpp | 22 ++++++++++ src/corelib/itemmodels/qabstractitemmodel.h | 3 ++ src/widgets/dialogs/qfilesystemmodel.cpp | 2 + src/widgets/itemviews/qtreeview.cpp | 8 +++- src/widgets/itemviews/qtreeview_p.h | 2 +- .../itemviews/qtreeview/tst_qtreeview.cpp | 40 +++++++++++++++++++ 8 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index ebbfc9ca83..a60743d3df 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1395,7 +1395,8 @@ public: ItemIsDropEnabled = 8, ItemIsUserCheckable = 16, ItemIsEnabled = 32, - ItemIsTristate = 64 + ItemIsTristate = 64, + ItemNeverHasChildren = 128 }; Q_DECLARE_FLAGS(ItemFlags, ItemFlag) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index f157190591..b271620ee0 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2441,6 +2441,7 @@ \value ItemIsUserCheckable It can be checked or unchecked by the user. \value ItemIsEnabled The user can interact with the item. \value ItemIsTristate The item is checkable with three separate states. + \value ItemNeverHasChildren The item never has child items. Note that checkable items need to be given both a suitable set of flags and an initial state, indicating whether the item is checked or not. diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index ebe38a97cd..ad9be5419b 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -3271,6 +3271,17 @@ bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const return false; } +/*! + \reimp + */ +Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags f = QAbstractItemModel::flags(index); + if (index.isValid()) + f |= Qt::ItemNeverHasChildren; + return f; +} + /*! \class QAbstractListModel \inmodule QtCore @@ -3391,6 +3402,17 @@ QModelIndex QAbstractListModel::parent(const QModelIndex & /* index */) const return QModelIndex(); } +/*! + \reimp + */ +Qt::ItemFlags QAbstractListModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags f = QAbstractItemModel::flags(index); + if (index.isValid()) + f |= Qt::ItemNeverHasChildren; + return f; +} + /*! \internal diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h index f138f53487..8e4f12e9ea 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.h +++ b/src/corelib/itemmodels/qabstractitemmodel.h @@ -419,6 +419,7 @@ public: bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; protected: QAbstractTableModel(QAbstractItemModelPrivate &dd, QObject *parent); @@ -439,6 +440,8 @@ public: QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; protected: QAbstractListModel(QAbstractItemModelPrivate &dd, QObject *parent); diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 4d3c7a24ec..251af273b9 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -964,6 +964,8 @@ Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const flags |= Qt::ItemIsEditable; if (indexNode->isDir()) flags |= Qt::ItemIsDropEnabled; + else + flags |= Qt::ItemNeverHasChildren; } return flags; } diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 1f922dd6e3..cee47faab4 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -749,6 +749,8 @@ void QTreeView::expand(const QModelIndex &index) Q_D(QTreeView); if (!d->isIndexValid(index)) return; + if (index.flags() & Qt::ItemNeverHasChildren) + return; if (d->delayedPendingLayout) { //A complete relayout is going to be performed, just store the expanded index, no need to layout. if (d->storeExpanded(index)) @@ -2887,6 +2889,9 @@ void QTreeViewPrivate::expand(int item, bool emitSignal) if (item == -1 || viewItems.at(item).expanded) return; + const QModelIndex index = viewItems.at(item).index; + if (index.flags() & Qt::ItemNeverHasChildren) + return; #ifndef QT_NO_ANIMATION if (emitSignal && animationsEnabled) @@ -2896,7 +2901,6 @@ void QTreeViewPrivate::expand(int item, bool emitSignal) if (state != QAbstractItemView::AnimatingState) stateBeforeAnimation = state; q->setState(QAbstractItemView::ExpandingState); - const QModelIndex index = viewItems.at(item).index; storeExpanded(index); viewItems[item].expanded = true; layout(item); @@ -3189,7 +3193,7 @@ void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninit item->expanded = false; item->total = 0; item->hasMoreSiblings = false; - if (recursiveExpanding || isIndexExpanded(current)) { + if ((recursiveExpanding && !(current.flags() & Qt::ItemNeverHasChildren)) || isIndexExpanded(current)) { if (recursiveExpanding) expandedIndexes.insert(current); item->expanded = true; diff --git a/src/widgets/itemviews/qtreeview_p.h b/src/widgets/itemviews/qtreeview_p.h index 5a0821c9cf..6778446ed3 100644 --- a/src/widgets/itemviews/qtreeview_p.h +++ b/src/widgets/itemviews/qtreeview_p.h @@ -203,7 +203,7 @@ public: inline bool isIndexExpanded(const QModelIndex &idx) const { //We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow - return isPersistent(idx) && expandedIndexes.contains(idx); + return !(idx.flags() & Qt::ItemNeverHasChildren) && isPersistent(idx) && expandedIndexes.contains(idx); } // used when hiding and showing items diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 0f69e951bf..a1de5f190c 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -177,6 +177,7 @@ private slots: void emptyModel(); void removeRows(); void removeCols(); + void limitedExpand(); void expandAndCollapse_data(); void expandAndCollapse(); void expandAndCollapseAll(); @@ -1414,6 +1415,45 @@ void tst_QTreeView::removeCols() QCOMPARE(view.header()->count(), model.cols); } +void tst_QTreeView::limitedExpand() +{ + { + QStandardItemModel model; + QStandardItem *parentItem = model.invisibleRootItem(); + parentItem->appendRow(new QStandardItem); + parentItem->appendRow(new QStandardItem); + parentItem->appendRow(new QStandardItem); + + QStandardItem *firstItem = model.item(0, 0); + firstItem->setFlags(firstItem->flags() | Qt::ItemNeverHasChildren); + + QTreeView view; + view.setModel(&model); + + QSignalSpy spy(&view, SIGNAL(expanded(QModelIndex))); + QVERIFY(spy.isValid()); + + view.expand(model.index(0, 0)); + QCOMPARE(spy.count(), 0); + + view.expand(model.index(1, 0)); + QCOMPARE(spy.count(), 1); + } + { + QStringListModel model(QStringList() << "one" << "two"); + QTreeView view; + view.setModel(&model); + + QSignalSpy spy(&view, SIGNAL(expanded(QModelIndex))); + QVERIFY(spy.isValid()); + + view.expand(model.index(0, 0)); + QCOMPARE(spy.count(), 0); + view.expandAll(); + QCOMPARE(spy.count(), 0); + } +} + void tst_QTreeView::expandAndCollapse_data() { QTest::addColumn("animationEnabled");