Fix TreeModel emitting nested QAbstractItemModel signals

This led to an assert in QSFPM because it got confused by the
nested reset signals.

Detected by adding
new QAbstractItemModelTester(this, QAbstractItemModelTester::FailureReportingMode::Fatal);
to the OutlineModel constructor, and just opening QtCreator on a small
qmake-based project.

Change-Id: I41dbc81b5a2275521ece6b865115e1428e07ecf7
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
David Faure
2023-11-29 10:46:55 +01:00
parent 81098efbe6
commit 9124833a63
3 changed files with 18 additions and 10 deletions

View File

@@ -604,7 +604,7 @@ TreeItem::~TreeItem()
{ {
QTC_CHECK(m_parent == nullptr); QTC_CHECK(m_parent == nullptr);
QTC_CHECK(m_model == nullptr); QTC_CHECK(m_model == nullptr);
removeChildren(); removeChildren(false);
} }
TreeItem *TreeItem::childAt(int pos) const TreeItem *TreeItem::childAt(int pos) const
@@ -700,15 +700,17 @@ void TreeItem::removeChildAt(int pos)
} }
} }
void TreeItem::removeChildren() void TreeItem::removeChildren(bool emitSignals)
{ {
if (childCount() == 0) if (childCount() == 0)
return; return;
if (m_model) { if (m_model) {
QModelIndex idx = index(); QModelIndex idx = index();
m_model->beginRemoveRows(idx, 0, childCount() - 1); if (emitSignals)
m_model->beginRemoveRows(idx, 0, childCount() - 1);
clear(); clear();
m_model->endRemoveRows(); if (emitSignals)
m_model->endRemoveRows();
} else { } else {
clear(); clear();
} }
@@ -1060,6 +1062,13 @@ TreeItem *BaseTreeModel::rootItem() const
} }
void BaseTreeModel::setRootItem(TreeItem *item) void BaseTreeModel::setRootItem(TreeItem *item)
{
beginResetModel();
setRootItemInternal(item);
endResetModel();
}
void BaseTreeModel::setRootItemInternal(TreeItem *item)
{ {
QTC_ASSERT(item, return); QTC_ASSERT(item, return);
QTC_ASSERT(item->m_model == nullptr, return); QTC_ASSERT(item->m_model == nullptr, return);
@@ -1067,19 +1076,17 @@ void BaseTreeModel::setRootItem(TreeItem *item)
QTC_ASSERT(item != m_root, return); QTC_ASSERT(item != m_root, return);
QTC_CHECK(m_root); QTC_CHECK(m_root);
beginResetModel();
if (m_root) { if (m_root) {
QTC_CHECK(m_root->m_parent == nullptr); QTC_CHECK(m_root->m_parent == nullptr);
QTC_CHECK(m_root->m_model == this); QTC_CHECK(m_root->m_model == this);
// needs to be done explicitly before setting the model to 0, otherwise it might lead to a // needs to be done explicitly before setting the model to 0, otherwise it might lead to a
// crash inside a view or proxy model, especially if there are selected items // crash inside a view or proxy model, especially if there are selected items
m_root->removeChildren(); m_root->removeChildren(false);
m_root->m_model = nullptr; m_root->m_model = nullptr;
delete m_root; delete m_root;
} }
m_root = item; m_root = item;
item->propagateModel(this); item->propagateModel(this);
endResetModel();
} }
void BaseTreeModel::setHeader(const QStringList &displays) void BaseTreeModel::setHeader(const QStringList &displays)

View File

@@ -38,7 +38,7 @@ public:
const std::function<bool(const TreeItem *, const TreeItem *)> &cmp); const std::function<bool(const TreeItem *, const TreeItem *)> &cmp);
void removeChildAt(int pos); void removeChildAt(int pos);
void removeChildren(); void removeChildren(bool emitSignals = true);
void sortChildren(const std::function<bool(const TreeItem *, const TreeItem *)> &cmp); void sortChildren(const std::function<bool(const TreeItem *, const TreeItem *)> &cmp);
void update(); void update();
void updateAll(); void updateAll();
@@ -180,7 +180,8 @@ protected:
void clear(); void clear();
TreeItem *rootItem() const; TreeItem *rootItem() const;
void setRootItem(TreeItem *item); void setRootItem(TreeItem *item); // resets the model
void setRootItemInternal(TreeItem *item);
TreeItem *itemForIndex(const QModelIndex &) const; TreeItem *itemForIndex(const QModelIndex &) const;
QModelIndex indexForItem(const TreeItem *needle) const; QModelIndex indexForItem(const TreeItem *needle) const;

View File

@@ -219,7 +219,7 @@ void OutlineModel::rebuild()
auto root = new SymbolItem; auto root = new SymbolItem;
if (m_cppDocument) if (m_cppDocument)
buildTree(root, true); buildTree(root, true);
setRootItem(root); setRootItemInternal(root);
endResetModel(); endResetModel();
} }