diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp index 6f969b7d3c2..315a6ca2680 100644 --- a/src/libs/extensionsystem/pluginview.cpp +++ b/src/libs/extensionsystem/pluginview.cpp @@ -315,8 +315,8 @@ PluginView::PluginView(QWidget *parent) m_categoryView->setSelectionMode(QAbstractItemView::SingleSelection); m_categoryView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_model = new TreeModel(this); - m_model->setHeader(QStringList() << tr("Name") << tr("Load") << tr("Version") << tr("Vendor")); + m_model = new LeveledTreeModel(this); + m_model->setHeader({ tr("Name"), tr("Load"), tr("Version"), tr("Vendor") }); m_sortModel = new CategorySortFilterModel(this); m_sortModel->setSourceModel(m_model); @@ -369,7 +369,7 @@ void PluginView::setFilter(const QString &filter) PluginSpec *PluginView::pluginForIndex(const QModelIndex &index) const { const QModelIndex &sourceIndex = m_sortModel->mapToSource(index); - auto item = dynamic_cast(m_model->itemForIndex(sourceIndex)); + PluginItem *item = m_model->secondLevelItemForIndex(sourceIndex); return item ? item->m_spec: 0; } @@ -456,7 +456,7 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl QSet affectedPlugins = plugins + additionalPlugins; foreach (PluginSpec *spec, affectedPlugins) { - PluginItem *item = m_model->findItemAtLevel(2, [spec](PluginItem *item) { + PluginItem *item = m_model->findSecondLevelItem([spec](PluginItem *item) { return item->m_spec == spec; }); QTC_ASSERT(item, continue); diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h index 3b4da885fe0..01e3dc45241 100644 --- a/src/libs/extensionsystem/pluginview.h +++ b/src/libs/extensionsystem/pluginview.h @@ -27,6 +27,8 @@ #include "extensionsystem_global.h" +#include + #include #include #include @@ -35,11 +37,7 @@ QT_BEGIN_NAMESPACE class QSortFilterProxyModel; QT_END_NAMESPACE -namespace Utils { -class TreeItem; -class TreeModel; -class TreeView; -} // namespace Utils +namespace Utils { class TreeView; } namespace ExtensionSystem { @@ -73,7 +71,7 @@ private: bool setPluginsEnabled(const QSet &plugins, bool enable); Utils::TreeView *m_categoryView; - Utils::TreeModel *m_model; + Utils::LeveledTreeModel *m_model; QSortFilterProxyModel *m_sortModel; friend class Internal::CollectionItem; diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h index 15aa5a9a5b0..cb171f080d0 100644 --- a/src/libs/utils/treemodel.h +++ b/src/libs/utils/treemodel.h @@ -94,11 +94,73 @@ public: void walkTree(TreeItemVisitor *visitor); void walkTree(std::function f); + template + void forSelectedChildren(const Predicate &pred) const { + foreach (TreeItem *item, m_children) { + if (pred(static_cast(item))) + item->forSelectedChildren(pred); + } + } + + template + void forAllChildren(const Predicate &pred) const { + foreach (TreeItem *item, m_children) { + pred(static_cast(item)); + item->forAllChildren(pred); + } + } // Levels are 1-based: Child at Level 1 is an immediate child. + template + void forFirstLevelChildren(Predicate pred) { + foreach (TreeItem *item, m_children) + pred(static_cast(item)); + } + + template + void forSecondLevelChildren(Predicate pred) { + foreach (TreeItem *item1, m_children) + foreach (TreeItem *item2, item1->m_children) + pred(static_cast(item2)); + } + + template + T findFirstLevelChild(Predicate pred) const { + foreach (TreeItem *item, m_children) + if (pred(static_cast(item))) + return static_cast(item); + return 0; + } + + template + T findSecondLevelChild(Predicate pred) const { + foreach (TreeItem *item1, m_children) + foreach (TreeItem *item2, item1->children()) + if (pred(static_cast(item2))) + return static_cast(item2); + return 0; + } + + // FIXME: Remove. Should only be present in LevelModels + template + T findChildAtLevel(int n, Predicate func) const { + if (n == 1) { + foreach (TreeItem *item, m_children) + if (func(static_cast(item))) + return static_cast(item); + } else { + foreach (TreeItem *item, m_children) + if (T found = item->findChildAtLevel(n - 1, func)) + return found; + } + return 0; + } + + // Levels are 1-based: Child at Level 1 is an immediate child. + // FIXME: Remove. Should only be present in LevelModels template void forEachChildAtLevel(int n, Function func) { - foreach (auto item, m_children) { + foreach (TreeItem *item, m_children) { if (n == 1) func(static_cast(item)); else @@ -106,21 +168,13 @@ public: } } - template - void forEachChild(Function func) const { - forEachChildAtLevel(1, func); - } - template - T findChildAtLevel(int n, Predicate func) const { - if (n == 1) { - foreach (auto item, m_children) - if (func(static_cast(item))) - return static_cast(item); - } else { - foreach (auto item, m_children) - if (T found = item->findChildAtLevel(n - 1, func)) - return found; + T findAnyChild(Predicate pred) const { + foreach (TreeItem *item, m_children) { + if (pred(static_cast(item))) + return static_cast(item); + if (T found = item->findAnyChild(pred)) + return found; } return 0; } @@ -141,6 +195,8 @@ private: friend class TreeModel; }; +// A general purpose multi-level model where each item can have its +// own (TreeItem-derived) type. class QTCREATOR_UTILS_EXPORT TreeModel : public QAbstractItemModel { Q_OBJECT @@ -174,22 +230,24 @@ public: bool canFetchMore(const QModelIndex &idx) const override; void fetchMore(const QModelIndex &idx) override; + TreeItem *takeItem(TreeItem *item); // item is not destroyed. + + // FIXME: Remove. Should only be uses in LeveledTreeModel + template + T findItemAtLevel(int n, Predicate func) const { + return m_root->findChildAtLevel(n, func); + } + // FIXME: Remove. Should only be uses in LeveledTreeModel template void forEachItemAtLevel(int n, Function func) const { m_root->forEachChildAtLevel(n, func); } - template - T findItemAtLevel(int n, Predicate func) const { - return m_root->findChildAtLevel(n, func); - } - - TreeItem *takeItem(TreeItem *item); // item is not destroyed. signals: void requestExpansion(QModelIndex); -private: +protected: friend class TreeItem; TreeItem *m_root; // Owned. @@ -198,4 +256,102 @@ private: int m_columnCount; }; +// A multi-level model with uniform types per level. +// All items below second level have to have identitical types. +template +class LeveledTreeModel : public TreeModel +{ +public: + explicit LeveledTreeModel(QObject *parent = 0) : TreeModel(parent) {} + explicit LeveledTreeModel(RootItem *root, QObject *parent = 0) : TreeModel(root, parent) {} + + template + void forFirstLevelItems(const Predicate &pred) const { + m_root->forFirstLevelChildren(pred); + } + + template + void forSecondLevelItems(const Predicate &pred) const { + m_root->forSecondLevelChildren(pred); + } + + template + FirstLevelItem *findFirstLevelItem(const Predicate &pred) const { + return m_root->findFirstLevelChild(pred); + } + + template + SecondLevelItem *findSecondLevelItem(const Predicate &pred) const { + return m_root->findSecondLevelChild(pred); + } + + RootItem *rootItem() const { + return static_cast(TreeModel::rootItem()); + } + + + FirstLevelItem *firstLevelItemForIndex(const QModelIndex &idx) const { + TreeItem *item = TreeModel::itemForIndex(idx); + return item && item->level() == 1 ? static_cast(item) : 0; + } + + SecondLevelItem *secondLevelItemForIndex(const QModelIndex &idx) const { + TreeItem *item = TreeModel::itemForIndex(idx); + return item && item->level() == 2 ? static_cast(item) : 0; + } +}; + +// A two-level model with a first level of static headers and a uniform second level. +template +class TwoLevelTreeModel : public LeveledTreeModel +{ +public: + using FirstLevelItem = TreeItem; + using SecondLevelItem = SecondLevelItemType; + using BaseType = LeveledTreeModel; + + explicit TwoLevelTreeModel(QObject *parent = 0) : BaseType(parent) {} + + FirstLevelItem *appendFirstLevelItem(const QStringList &display) { + auto item = new FirstLevelItem(display); + this->rootItem()->appendChild(item); + return item; + } +}; + +// A model where all non-root nodes are the same. +template +class UniformTreeModel : public LeveledTreeModel +{ +public: + using BaseType = LeveledTreeModel; + + explicit UniformTreeModel(QObject *parent = 0) : BaseType(parent) {} + + ItemType *nonRootItemForIndex(const QModelIndex &idx) const { + TreeItem *item = TreeModel::itemForIndex(idx); + return item && item->parent() ? static_cast(item) : 0; + } + + template + ItemType *findNonRooItem(const Predicate &pred) const { + TreeItem *root = this->rootItem(); + return root->findAnyChild(pred); + } + + template + void forSelectedItems(const Predicate &pred) const { + TreeItem *root = this->rootItem(); + root->forSelectedChildren(pred); + } + + template + void forAllItems(const Predicate &pred) const { + TreeItem *root = this->rootItem(); + root->forAllChildren(pred); + } +}; + } // namespace Utils diff --git a/src/plugins/debugger/debuggeroptionspage.cpp b/src/plugins/debugger/debuggeroptionspage.cpp index f071ac5ef97..4c0702071ea 100644 --- a/src/plugins/debugger/debuggeroptionspage.cpp +++ b/src/plugins/debugger/debuggeroptionspage.cpp @@ -99,7 +99,7 @@ public: // DebuggerItemModel // -------------------------------------------------------------------------- -class DebuggerItemModel : public TreeModel +class DebuggerItemModel : public TwoLevelTreeModel { Q_DECLARE_TR_FUNCTIONS(Debugger::DebuggerOptionsPage) @@ -124,10 +124,9 @@ private: DebuggerItemModel::DebuggerItemModel() : m_currentTreeItem(0) { - setHeader(QStringList() << tr("Name") << tr("Location") << tr("Type")); - rootItem()->appendChild(new TreeItem(QStringList() << tr("Auto-detected") << QString() << QString())); - rootItem()->appendChild(new TreeItem(QStringList() << tr("Manual") << QString() << QString())); - + setHeader({ tr("Name"), tr("Location"), tr("Type") }); + appendFirstLevelItem({ tr("Auto-detected") }); + appendFirstLevelItem({ tr("Manual") }); foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) addDebugger(item, false); } @@ -141,7 +140,7 @@ void DebuggerItemModel::addDebugger(const DebuggerItem &item, bool changed) void DebuggerItemModel::updateDebugger(const DebuggerItem &item) { auto matcher = [item](DebuggerTreeItem *n) { return n->m_item.m_id == item.id(); }; - DebuggerTreeItem *treeItem = findItemAtLevel(2, matcher); + DebuggerTreeItem *treeItem = findSecondLevelItem(matcher); QTC_ASSERT(treeItem, return); TreeItem *parent = treeItem->parent(); @@ -180,7 +179,7 @@ void DebuggerItemModel::apply() foreach (const QVariant &id, m_removedItems) DebuggerItemManager::deregisterDebugger(id); - forEachItemAtLevel(2, [](DebuggerTreeItem *item) { + forSecondLevelItems([](DebuggerTreeItem *item) { item->m_changed = false; DebuggerItemManager::updateOrAddDebugger(item->m_item); }); diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 0ce5b3fe50b..bfcf0be1e3b 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -231,16 +231,14 @@ ToolTipWatchItem::ToolTipWatchItem(TreeItem *item) // ///////////////////////////////////////////////////////////////////////// -class ToolTipModel : public TreeModel +class ToolTipModel : public UniformTreeModel { public: ToolTipModel() { - QStringList headers; - headers.append(DebuggerToolTipManager::tr("Name")); - headers.append(DebuggerToolTipManager::tr("Value")); - headers.append(DebuggerToolTipManager::tr("Type")); - setHeader(headers); + setHeader({ DebuggerToolTipManager::tr("Name"), + DebuggerToolTipManager::tr("Value"), + DebuggerToolTipManager::tr("Type") }); m_enabled = true; auto item = new ToolTipWatchItem; item->expandable = true; @@ -538,10 +536,9 @@ DebuggerToolTipWidget::DebuggerToolTipWidget() connect(copyButton, &QAbstractButton::clicked, [this] { QString text; QTextStream str(&text); - model.rootItem()->walkTree([&str](TreeItem *item) { - auto titem = static_cast(item); + model.forAllItems([&str](ToolTipWatchItem *item) { str << QString(item->level(), QLatin1Char('\t')) - << titem->name << '\t' << titem->value << '\t' << titem->type << '\n'; + << item->name << '\t' << item->value << '\t' << item->type << '\n'; }); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(text, QClipboard::Selection); @@ -926,7 +923,7 @@ void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const w.writeAttributes(attributes); w.writeStartElement(QLatin1String(treeElementC)); - widget->model.rootItem()->walkTree([&w](TreeItem *item) { + widget->model.forAllItems([&w](ToolTipWatchItem *item) { const QString modelItemElement = QLatin1String(modelItemElementC); for (int i = 0; i < 3; ++i) { const QString value = item->data(i, Qt::DisplayRole).toString(); diff --git a/src/plugins/debugger/threadshandler.cpp b/src/plugins/debugger/threadshandler.cpp index 78f2250a8ba..e9ba1f87676 100644 --- a/src/plugins/debugger/threadshandler.cpp +++ b/src/plugins/debugger/threadshandler.cpp @@ -240,7 +240,6 @@ ThreadsHandler::ThreadsHandler() { m_resetLocationScheduled = false; setObjectName(QLatin1String("ThreadsModel")); - setRootItem(new ThreadItem(this)); setHeader({ QLatin1String(" ") + tr("ID") + QLatin1String(" "), tr("Address"), tr("Function"), tr("File"), tr("Line"), tr("State"), @@ -251,7 +250,7 @@ ThreadsHandler::ThreadsHandler() static ThreadItem *itemForThreadId(const ThreadsHandler *handler, ThreadId threadId) { const auto matcher = [threadId](ThreadItem *item) { return item->threadData.id == threadId; }; - return handler->findItemAtLevel(1, matcher); + return handler->findFirstLevelItem(matcher); } static int indexForThreadId(const ThreadsHandler *handler, ThreadId threadId) @@ -321,11 +320,6 @@ void ThreadsHandler::notifyGroupCreated(const QByteArray &groupId, const QByteAr m_pidForGroupId[groupId] = pid; } -void ThreadsHandler::foreachThread(const std::function &func) -{ - forEachItemAtLevel(1, func); -} - void ThreadsHandler::updateThread(const ThreadData &threadData) { if (ThreadItem *item = itemForThreadId(this, threadData.id)) @@ -354,7 +348,7 @@ void ThreadsHandler::setThreads(const Threads &threads) void ThreadsHandler::updateThreadBox() { QStringList list; - foreachThread([&list](ThreadItem *item) { + forFirstLevelItems([&list](ThreadItem *item) { list.append(QString::fromLatin1("#%1 %2").arg(item->threadData.id.raw()).arg(item->threadData.name)); }); Internal::setThreadBoxContents(list, indexForThreadId(this, m_currentId)); @@ -375,7 +369,7 @@ void ThreadsHandler::removeAll() bool ThreadsHandler::notifyGroupExited(const QByteArray &groupId) { QList list; - foreachThread([&list, groupId](ThreadItem *item) { + forFirstLevelItems([&list, groupId](ThreadItem *item) { if (item->threadData.groupId == groupId) list.append(item); }); @@ -402,7 +396,7 @@ void ThreadsHandler::notifyRunning(const QByteArray &data) void ThreadsHandler::notifyAllRunning() { - foreachThread([](ThreadItem *item) { item->notifyRunning(); }); + forFirstLevelItems([](ThreadItem *item) { item->notifyRunning(); }); } void ThreadsHandler::notifyRunning(ThreadId threadId) @@ -427,7 +421,7 @@ void ThreadsHandler::notifyStopped(const QByteArray &data) void ThreadsHandler::notifyAllStopped() { - foreachThread([](ThreadItem *item) { item->notifyStopped(); }); + forFirstLevelItems([](ThreadItem *item) { item->notifyStopped(); }); } void ThreadsHandler::notifyStopped(ThreadId threadId) diff --git a/src/plugins/debugger/threadshandler.h b/src/plugins/debugger/threadshandler.h index b32f59cd379..9ef6f14cc74 100644 --- a/src/plugins/debugger/threadshandler.h +++ b/src/plugins/debugger/threadshandler.h @@ -41,7 +41,7 @@ namespace Internal { class GdbMi; class ThreadItem; -class ThreadsHandler : public Utils::TreeModel +class ThreadsHandler : public Utils::LeveledTreeModel { Q_OBJECT @@ -78,8 +78,6 @@ public: void resetLocation(); void scheduleResetLocation(); - void foreachThread(const std::function &func); - private: void updateThreadBox(); diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index b74921e5549..badcf601c3b 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -657,18 +657,6 @@ QString WatchItem::expression() const return name; } -WatchItem *WatchItem::findItem(const QByteArray &iname) -{ - if (internalName() == iname) - return this; - foreach (TreeItem *child, children()) { - auto witem = static_cast(child); - if (WatchItem *result = witem->findItem(iname)) - return result; - } - return 0; -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index 98053b67765..17d23dadf45 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -59,7 +59,6 @@ public: QVariant editValue() const; int editType() const; - WatchItem *findItem(const QByteArray &iname); WatchItem *parentItem() const; enum State diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 5a5154d4522..aff998af27c 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -351,7 +351,6 @@ public: void reinitialize(bool includeInspectData = false); WatchItem *findItem(const QByteArray &iname) const; - const WatchItem *watchItem(const QModelIndex &idx) const; void reexpandItems(); @@ -368,7 +367,6 @@ public: bool m_contentsValid; bool m_resetLocationScheduled; - WatchItem *root() const { return static_cast(rootItem()); } WatchItem *m_localsRoot; // Not owned. WatchItem *m_inspectorRoot; // Not owned. WatchItem *m_watchRoot; // Not owned. @@ -394,8 +392,7 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine) m_contentsValid = true; // FIXME m_resetLocationScheduled = false; - setHeader(QStringList() << tr("Name") << tr("Value") << tr("Type")); - auto root = new WatchItem; + setHeader({ tr("Name"), tr("Value"), tr("Type") }); m_localsRoot = new WatchItem; m_localsRoot->iname = "local"; m_localsRoot->name = tr("Locals"); @@ -411,12 +408,12 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine) m_tooltipRoot = new WatchItem; m_tooltipRoot->iname = "tooltip"; m_tooltipRoot->name = tr("Tooltip"); + auto root = rootItem(); root->appendChild(m_localsRoot); root->appendChild(m_inspectorRoot); root->appendChild(m_watchRoot); root->appendChild(m_returnRoot); root->appendChild(m_tooltipRoot); - setRootItem(root); m_requestUpdateTimer.setSingleShot(true); connect(&m_requestUpdateTimer, &QTimer::timeout, @@ -444,12 +441,7 @@ void WatchModel::reinitialize(bool includeInspectData) WatchItem *WatchModel::findItem(const QByteArray &iname) const { - return root()->findItem(iname); -} - -const WatchItem *WatchModel::watchItem(const QModelIndex &idx) const -{ - return static_cast(itemForIndex(idx)); + return findNonRooItem([iname](WatchItem *item) { return item->iname == iname; }); } static QByteArray parentName(const QByteArray &iname) @@ -912,7 +904,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const l.append(indexForItem(item)); return QVariant::fromValue(l); } - const WatchItem *item = watchItem(idx); + const WatchItem *item = nonRootItemForIndex(idx); if (!item) return QVariant(); @@ -1074,7 +1066,7 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const if (!idx.isValid()) return 0; - const WatchItem *item = watchItem(idx); + const WatchItem *item = nonRootItemForIndex(idx); if (!item) return Qt::ItemIsEnabled|Qt::ItemIsSelectable; @@ -1140,7 +1132,7 @@ bool WatchModel::canFetchMore(const QModelIndex &idx) const return false; // See "hasChildren" below. - const WatchItem *item = watchItem(idx); + const WatchItem *item = nonRootItemForIndex(idx); if (!item) return false; if (!item->wantsChildren) @@ -1155,7 +1147,7 @@ void WatchModel::fetchMore(const QModelIndex &idx) if (!idx.isValid()) return; - WatchItem *item = static_cast(itemForIndex(idx)); + WatchItem *item = nonRootItemForIndex(idx); if (item) { m_expandedINames.insert(item->iname); if (item->children().isEmpty()) { @@ -1167,7 +1159,7 @@ void WatchModel::fetchMore(const QModelIndex &idx) bool WatchModel::hasChildren(const QModelIndex &idx) const { - const WatchItem *item = watchItem(idx); + const WatchItem *item = nonRootItemForIndex(idx); if (!item) return true; if (item->rowCount() > 0) @@ -1310,7 +1302,7 @@ bool WatchHandler::insertItem(WatchItem *item) item->update(); - item->walkTree([this](TreeItem *sub) { m_model->showEditValue(static_cast(sub)); }); + item->forAllChildren([this](WatchItem *sub) { m_model->showEditValue(sub); }); return !found; } @@ -1344,10 +1336,8 @@ void WatchHandler::removeAllData(bool includeInspectData) void WatchHandler::resetValueCache() { m_model->m_valueCache.clear(); - TreeItem *root = m_model->rootItem(); - root->walkTree([this, root](TreeItem *item) { - auto watchItem = static_cast(item); - m_model->m_valueCache[watchItem->iname] = watchItem->value; + m_model->forAllItems([this](WatchItem *item) { + m_model->m_valueCache[item->iname] = item->value; }); } @@ -1361,13 +1351,13 @@ void WatchHandler::notifyUpdateStarted(const QList &inames) auto marker = [](TreeItem *it) { static_cast(it)->outdated = true; }; if (inames.isEmpty()) { - m_model->forEachItemAtLevel(2, [marker](WatchItem *item) { - item->walkTree(marker); + m_model->forSecondLevelItems([marker](WatchItem *item) { + item->forAllChildren(marker); }); } else { - foreach (auto iname, inames) { + for (auto iname : inames) { if (WatchItem *item = m_model->findItem(iname)) - item->walkTree(marker); + item->forAllChildren(marker); } } @@ -1378,23 +1368,16 @@ void WatchHandler::notifyUpdateStarted(const QList &inames) void WatchHandler::notifyUpdateFinished() { - struct OutDatedItemsFinder : public TreeItemVisitor - { - bool preVisit(TreeItem *item) - { - auto watchItem = static_cast(item); - if (level() <= 1 || !watchItem->outdated) - return true; - toRemove.append(watchItem); + QList toRemove; + m_model->forSelectedItems([this, &toRemove](WatchItem *item) { + if (item->outdated) { + toRemove.append(item); return false; } + return true; + }); - QList toRemove; - } finder; - - m_model->root()->walkTree(&finder); - - foreach (auto item, finder.toRemove) + foreach (auto item, toRemove) delete m_model->takeItem(item); m_model->m_contentsValid = true; @@ -1840,21 +1823,16 @@ void WatchHandler::addTypeFormats(const QByteArray &type, const DisplayFormats & m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats); } -static void showInEditorHelper(const WatchItem *item, QTextStream &ts, int depth) -{ - const QChar tab = QLatin1Char('\t'); - const QChar nl = QLatin1Char('\n'); - ts << QString(depth, tab) << item->name << tab << displayValue(item) << tab - << item->type << nl; - foreach (const TreeItem *child, item->children()) - showInEditorHelper(static_cast(child), ts, depth + 1); -} - QString WatchHandler::editorContents() { QString contents; QTextStream ts(&contents); - showInEditorHelper(m_model->root(), ts, 0); + m_model->forAllItems([&ts](WatchItem *item) { + const QChar tab = QLatin1Char('\t'); + const QChar nl = QLatin1Char('\n'); + ts << QString(item->level(), tab) << item->name << tab << displayValue(item) << tab + << item->type << nl; + }); return contents; } diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index b64533904dd..d6afbf661d5 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -38,7 +38,7 @@ class WatchModel; typedef QVector DisplayFormats; -class WatchModelBase : public Utils::TreeModel +class WatchModelBase : public Utils::UniformTreeModel { Q_OBJECT diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index b6b1524a1ea..e36c1ab4598 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1448,7 +1448,10 @@ void tst_Dumpers::dumper() //qDebug() << "NUM CHECKS" << data.checks.size(); Check check = data.checks.at(i); QByteArray iname = "local." + check.iname; - if (const WatchItem *item = local.findItem(iname)) { + WatchItem *item = local.findAnyChild([iname](WatchItem *item) { + return item->iname == iname; + }); + if (item) { seenINames.insert(iname); //qDebug() << "CHECKS" << i << check.iname; data.checks.removeAt(i); diff --git a/tests/auto/utils/treemodel/tst_treemodel.cpp b/tests/auto/utils/treemodel/tst_treemodel.cpp index 0d387050a7e..ba536338378 100644 --- a/tests/auto/utils/treemodel/tst_treemodel.cpp +++ b/tests/auto/utils/treemodel/tst_treemodel.cpp @@ -37,18 +37,23 @@ class tst_TreeModel : public QObject private slots: void testIteration(); + void testMixed(); }; static int countLevelItems(TreeItem *base, int level) { int n = 0; - base->forEachChildAtLevel(level, [&n](TreeItem *) { ++n; }); + int bl = base->level(); + base->forAllChildren([level, bl, &n](TreeItem *item) { + if (item->level() == bl + level) + ++n; + }); return n; } static TreeItem *createItem(const char *name) { - return new TreeItem(QStringList(QString::fromLatin1(name))); + return new TreeItem({ QString::fromLatin1(name) }); } void tst_TreeModel::testIteration() @@ -85,6 +90,28 @@ void tst_TreeModel::testIteration() QCOMPARE(countLevelItems(group2, 2), 0); } +struct ItemA : public TreeItem {}; +struct ItemB : public TreeItem {}; + +void tst_TreeModel::testMixed() +{ + LeveledTreeModel m; + TreeItem *r = m.rootItem(); + TreeItem *ra; + r->appendChild(new ItemA); + r->appendChild(ra = new ItemA); + ra->appendChild(new ItemB); + ra->appendChild(new ItemB); + + int n = 0; + m.forFirstLevelItems([&n](ItemA *) { ++n; }); + QCOMPARE(n, 2); + + n = 0; + m.forSecondLevelItems([&n](ItemB *) { ++n; }); + QCOMPARE(n, 2); +} + QTEST_MAIN(tst_TreeModel)