diff --git a/src/models/CMakeLists.txt b/src/models/CMakeLists.txt index b1754778..16846410 100644 --- a/src/models/CMakeLists.txt +++ b/src/models/CMakeLists.txt @@ -11,6 +11,7 @@ add_library( disassemblymodel.cpp disassemblyoutput.cpp eventmodel.cpp + eventmodelproxy.cpp filterandzoomstack.cpp formattingutils.cpp frequencymodel.cpp diff --git a/src/models/eventmodelproxy.cpp b/src/models/eventmodelproxy.cpp new file mode 100644 index 00000000..12a547ba --- /dev/null +++ b/src/models/eventmodelproxy.cpp @@ -0,0 +1,43 @@ +/* + SPDX-FileCopyrightText: Lieven Hey + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "eventmodelproxy.h" +#include "eventmodel.h" + +EventModelProxy::EventModelProxy(QObject* parent) + : QSortFilterProxyModel(parent) +{ + setDynamicSortFilter(true); + setRecursiveFilteringEnabled(true); + setSortRole(EventModel::SortRole); + setFilterKeyColumn(EventModel::ThreadColumn); + setFilterRole(Qt::DisplayRole); +} + +EventModelProxy::~EventModelProxy() = default; + +bool EventModelProxy::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const +{ + // index is invalid -> we are at the root node + // hide categories that have no children (e.g. favorites, tracepoints) + if (!source_parent.isValid()) { + const auto model = sourceModel(); + if (!model->hasChildren(model->index(source_row, 0))) + return false; + } + + auto data = sourceModel() + ->index(source_row, EventModel::EventsColumn, source_parent) + .data(EventModel::EventsRole) + .value(); + + if (data.empty()) { + return false; + } + + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); +} diff --git a/src/models/eventmodelproxy.h b/src/models/eventmodelproxy.h new file mode 100644 index 00000000..a720fd58 --- /dev/null +++ b/src/models/eventmodelproxy.h @@ -0,0 +1,21 @@ +/* + SPDX-FileCopyrightText: Lieven Hey + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +class EventModelProxy : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit EventModelProxy(QObject* parent = nullptr); + ~EventModelProxy() override; + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; +}; diff --git a/src/timelinewidget.cpp b/src/timelinewidget.cpp index e38458bc..8f6cc1b5 100644 --- a/src/timelinewidget.cpp +++ b/src/timelinewidget.cpp @@ -9,6 +9,7 @@ #include "filterandzoomstack.h" #include "models/eventmodel.h" +#include "models/eventmodelproxy.h" #include "resultsutil.h" #include "timelinedelegate.h" @@ -61,12 +62,8 @@ TimeLineWidget::TimeLineWidget(PerfParser* parser, QMenu* filterMenu, FilterAndZ ui->setupUi(this); auto* eventModel = new EventModel(this); - auto* timeLineProxy = new QSortFilterProxyModel(this); - timeLineProxy->setRecursiveFilteringEnabled(true); + auto* timeLineProxy = new EventModelProxy(this); timeLineProxy->setSourceModel(eventModel); - timeLineProxy->setSortRole(EventModel::SortRole); - timeLineProxy->setFilterKeyColumn(EventModel::ThreadColumn); - timeLineProxy->setFilterRole(Qt::DisplayRole); ResultsUtil::connectFilter(ui->timeLineSearch, timeLineProxy, ui->regexCheckBox); ui->timeLineView->setModel(timeLineProxy); ui->timeLineView->setSortingEnabled(true); diff --git a/tests/modeltests/tst_models.cpp b/tests/modeltests/tst_models.cpp index c8f4e74e..48358956 100644 --- a/tests/modeltests/tst_models.cpp +++ b/tests/modeltests/tst_models.cpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace { @@ -672,6 +673,38 @@ private slots: QCOMPARE(model.rowCount(favoritesIndex), 0); } + void testEventModelProxy() + { + const auto events = createEventModelTestData(); + EventModel model; + QAbstractItemModelTester tester(&model); + model.setData(events); + + EventModelProxy proxy; + proxy.setSourceModel(&model); + + const auto favoritesIndex = model.index(3, 0); + const auto processesIndex = model.index(1, 0); + + QCOMPARE(model.rowCount(), 4); + QCOMPARE(proxy.rowCount(), 2); + + proxy.setFilterRegularExpression(QStringLiteral("this does not match")); + QCOMPARE(proxy.rowCount(), 0); + proxy.setFilterRegularExpression(QString()); + QCOMPARE(proxy.rowCount(), 2); + + // add the first data trace to favourites + // adding the whole process doesn't work currently + auto firstProcess = model.index(0, 0, processesIndex); + model.addToFavorites(model.index(0, 0, firstProcess)); + + QCOMPARE(proxy.rowCount(), 3); + + model.removeFromFavorites(model.index(0, 0, favoritesIndex)); + QCOMPARE(proxy.rowCount(), 2); + } + void testPrettySymbol_data() { QTest::addColumn("prettySymbol");