Add the Qt::ItemNeverHasChildren flag and use it in QTreeView.

It can be used to determine whether expand() should really expand.

Change-Id: If79d8c295a4ca1356e60051682b227524a065126
Reviewed-by: David Faure (KDE) <faure@kde.org>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
This commit is contained in:
Stephen Kelly 2012-11-23 15:24:48 +01:00 committed by The Qt Project
parent d78bd439dc
commit d315e01218
8 changed files with 77 additions and 4 deletions

View File

@ -1395,7 +1395,8 @@ public:
ItemIsDropEnabled = 8, ItemIsDropEnabled = 8,
ItemIsUserCheckable = 16, ItemIsUserCheckable = 16,
ItemIsEnabled = 32, ItemIsEnabled = 32,
ItemIsTristate = 64 ItemIsTristate = 64,
ItemNeverHasChildren = 128
}; };
Q_DECLARE_FLAGS(ItemFlags, ItemFlag) Q_DECLARE_FLAGS(ItemFlags, ItemFlag)

View File

@ -2441,6 +2441,7 @@
\value ItemIsUserCheckable It can be checked or unchecked by the user. \value ItemIsUserCheckable It can be checked or unchecked by the user.
\value ItemIsEnabled The user can interact with the item. \value ItemIsEnabled The user can interact with the item.
\value ItemIsTristate The item is checkable with three separate states. \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 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. and an initial state, indicating whether the item is checked or not.

View File

@ -3271,6 +3271,17 @@ bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const
return false; 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 \class QAbstractListModel
\inmodule QtCore \inmodule QtCore
@ -3391,6 +3402,17 @@ QModelIndex QAbstractListModel::parent(const QModelIndex & /* index */) const
return QModelIndex(); 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 \internal

View File

@ -419,6 +419,7 @@ public:
bool dropMimeData(const QMimeData *data, Qt::DropAction action, bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent); int row, int column, const QModelIndex &parent);
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
protected: protected:
QAbstractTableModel(QAbstractItemModelPrivate &dd, QObject *parent); QAbstractTableModel(QAbstractItemModelPrivate &dd, QObject *parent);
@ -439,6 +440,8 @@ public:
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent); int row, int column, const QModelIndex &parent);
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
protected: protected:
QAbstractListModel(QAbstractItemModelPrivate &dd, QObject *parent); QAbstractListModel(QAbstractItemModelPrivate &dd, QObject *parent);

View File

@ -964,6 +964,8 @@ Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const
flags |= Qt::ItemIsEditable; flags |= Qt::ItemIsEditable;
if (indexNode->isDir()) if (indexNode->isDir())
flags |= Qt::ItemIsDropEnabled; flags |= Qt::ItemIsDropEnabled;
else
flags |= Qt::ItemNeverHasChildren;
} }
return flags; return flags;
} }

View File

@ -749,6 +749,8 @@ void QTreeView::expand(const QModelIndex &index)
Q_D(QTreeView); Q_D(QTreeView);
if (!d->isIndexValid(index)) if (!d->isIndexValid(index))
return; return;
if (index.flags() & Qt::ItemNeverHasChildren)
return;
if (d->delayedPendingLayout) { if (d->delayedPendingLayout) {
//A complete relayout is going to be performed, just store the expanded index, no need to layout. //A complete relayout is going to be performed, just store the expanded index, no need to layout.
if (d->storeExpanded(index)) if (d->storeExpanded(index))
@ -2887,6 +2889,9 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
if (item == -1 || viewItems.at(item).expanded) if (item == -1 || viewItems.at(item).expanded)
return; return;
const QModelIndex index = viewItems.at(item).index;
if (index.flags() & Qt::ItemNeverHasChildren)
return;
#ifndef QT_NO_ANIMATION #ifndef QT_NO_ANIMATION
if (emitSignal && animationsEnabled) if (emitSignal && animationsEnabled)
@ -2896,7 +2901,6 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
if (state != QAbstractItemView::AnimatingState) if (state != QAbstractItemView::AnimatingState)
stateBeforeAnimation = state; stateBeforeAnimation = state;
q->setState(QAbstractItemView::ExpandingState); q->setState(QAbstractItemView::ExpandingState);
const QModelIndex index = viewItems.at(item).index;
storeExpanded(index); storeExpanded(index);
viewItems[item].expanded = true; viewItems[item].expanded = true;
layout(item); layout(item);
@ -3189,7 +3193,7 @@ void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninit
item->expanded = false; item->expanded = false;
item->total = 0; item->total = 0;
item->hasMoreSiblings = false; item->hasMoreSiblings = false;
if (recursiveExpanding || isIndexExpanded(current)) { if ((recursiveExpanding && !(current.flags() & Qt::ItemNeverHasChildren)) || isIndexExpanded(current)) {
if (recursiveExpanding) if (recursiveExpanding)
expandedIndexes.insert(current); expandedIndexes.insert(current);
item->expanded = true; item->expanded = true;

View File

@ -203,7 +203,7 @@ public:
inline bool isIndexExpanded(const QModelIndex &idx) const { inline bool isIndexExpanded(const QModelIndex &idx) const {
//We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow //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 // used when hiding and showing items

View File

@ -177,6 +177,7 @@ private slots:
void emptyModel(); void emptyModel();
void removeRows(); void removeRows();
void removeCols(); void removeCols();
void limitedExpand();
void expandAndCollapse_data(); void expandAndCollapse_data();
void expandAndCollapse(); void expandAndCollapse();
void expandAndCollapseAll(); void expandAndCollapseAll();
@ -1414,6 +1415,45 @@ void tst_QTreeView::removeCols()
QCOMPARE(view.header()->count(), model.cols); 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() void tst_QTreeView::expandAndCollapse_data()
{ {
QTest::addColumn<bool>("animationEnabled"); QTest::addColumn<bool>("animationEnabled");