From 2b0381655133a8b244b20b78c40c3ae91f135637 Mon Sep 17 00:00:00 2001 From: Lieven Hey Date: Thu, 21 Sep 2023 11:32:58 +0200 Subject: [PATCH] add Favourites to TimeLineWidget this allows the user to group important timelines together so that he can compare them better --- src/models/eventmodel.cpp | 68 +++++++++++++++++++++++++++++++-- src/models/eventmodel.h | 4 ++ src/models/timelinedelegate.cpp | 9 +++++ src/models/timelinedelegate.h | 1 + src/timelinewidget.cpp | 3 ++ tests/modeltests/tst_models.cpp | 2 +- 6 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/models/eventmodel.cpp b/src/models/eventmodel.cpp index dfd51052f..8ecae1cec 100644 --- a/src/models/eventmodel.cpp +++ b/src/models/eventmodel.cpp @@ -29,6 +29,7 @@ enum class Tag : quint8 Processes, Threads, Tracepoints, + Favorites, }; enum OverViewRow : quint8 @@ -36,10 +37,11 @@ enum OverViewRow : quint8 Cpu_Row, Process_Row, Tracepoint_Row, + Favorite_Row, }; -constexpr auto numRows = Tracepoint_Row + 1; +constexpr auto numRows = Favorite_Row + 1; -constexpr auto LAST_TAG = Tag::Tracepoints; +constexpr auto LAST_TAG = Tag::Favorites; const auto DATATAG_SHIFT = sizeof(Tag) * 8; const auto DATATAG_UNSHIFT = (sizeof(quintptr) - sizeof(Tag)) * 8; @@ -93,6 +95,7 @@ int EventModel::rowCount(const QModelIndex& parent) const case Tag::Cpus: case Tag::Threads: case Tag::Tracepoints: + case Tag::Favorites: return 0; break; case Tag::Processes: @@ -105,6 +108,8 @@ int EventModel::rowCount(const QModelIndex& parent) const return m_processes.size(); case OverViewRow::Tracepoint_Row: return m_data.tracepoints.size(); + case OverViewRow::Favorite_Row: + return m_favourites.size(); default: Q_UNREACHABLE(); } @@ -173,6 +178,8 @@ QVariant EventModel::data(const QModelIndex& index, int role) const return tr("Processes"); case OverViewRow::Tracepoint_Row: return tr("Tracepoints"); + case 3: + return tr("Favorites"); } } else if (role == Qt::ToolTipRole) { switch (static_cast(index.row())) { @@ -183,6 +190,8 @@ QVariant EventModel::data(const QModelIndex& index, int role) const return tr("Event timelines for the individual threads and processes."); case OverViewRow::Tracepoint_Row: return tr("Event timelines for tracepoints"); + case OverViewRow::Favorite_Row: + return tr("A list of favourites to group important events"); } } else if (role == SortRole) { return index.row(); @@ -250,6 +259,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const Q_ASSERT(thread); } else if (tag == Tag::Tracepoints) { tracepoint = &m_data.tracepoints[index.row()]; + } else if (tag == Tag::Favorites) { + auto& favourite = m_favourites[index.row()]; + return data(favourite, role); } if (role == ThreadStartRole) { @@ -263,6 +275,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Processes: case Tag::Tracepoints: return m_time.start; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == ThreadEndRole) { switch (tag) { @@ -275,6 +290,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Processes: case Tag::Tracepoints: return m_time.end; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == ThreadNameRole) { switch (tag) { @@ -288,6 +306,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Processes: case Tag::Tracepoints: return {}; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == ThreadIdRole) { switch (tag) { @@ -300,6 +321,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Processes: case Tag::Tracepoints: return Data::INVALID_TID; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == ProcessIdRole) { switch (tag) { @@ -312,6 +336,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Processes: case Tag::Tracepoints: return Data::INVALID_PID; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == CpuIdRole) { switch (tag) { @@ -324,6 +351,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Threads: case Tag::Tracepoints: return Data::INVALID_CPU_ID; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == EventsRole) { switch (tag) { @@ -338,6 +368,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Overview: case Tag::Processes: return QVariant::fromValue(Data::Events()); + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == SortRole) { if (index.column() == ThreadColumn) { @@ -353,6 +386,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Overview: case Tag::Processes: return {}; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else { switch (tag) { @@ -367,6 +403,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Overview: case Tag::Processes: return {}; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } } @@ -386,6 +425,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Overview: case Tag::Processes: return {}; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } else if (role == Qt::ToolTipRole) { QString tooltip; @@ -426,6 +468,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Overview: case Tag::Processes: break; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } tooltip += tr("Number of Events: %1 (%2% of the total)") @@ -447,6 +492,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const case Tag::Overview: case Tag::Processes: return {}; + case Tag::Favorites: + // there are handled elsewhere + Q_UNREACHABLE(); } } break; @@ -521,6 +569,7 @@ QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) co case Tag::Cpus: case Tag::Tracepoints: case Tag::Threads: + case Tag::Favorites: break; case Tag::Root: // root has the 1st level children: Overview return createIndex(row, column, static_cast(Tag::Overview)); @@ -532,6 +581,8 @@ QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) co return createIndex(row, column, static_cast(Tag::Processes)); case OverViewRow::Tracepoint_Row: return createIndex(row, column, static_cast(Tag::Tracepoints)); + case OverViewRow::Favorite_Row: + return createIndex(row, column, static_cast(Tag::Favorites)); } Q_UNREACHABLE(); case Tag::Processes: // 3rd level children: Threads @@ -554,11 +605,20 @@ QModelIndex EventModel::parent(const QModelIndex& child) const return createIndex(OverViewRow::Process_Row, 0, static_cast(Tag::Overview)); case Tag::Tracepoints: return createIndex(OverViewRow::Tracepoint_Row, 0, static_cast(Tag::Overview)); - case Tag::Threads: { + case Tag::Favorites: + return createIndex(OverViewRow::Favorite_Row, 0, static_cast(Tag::Overview)); + case Tag::Threads: const auto parentRow = tagData(child.internalId()); return createIndex(parentRow, 0, static_cast(Tag::Processes)); } - } return {}; } + +void EventModel::addToFavourites(const QModelIndex& index) +{ + const int position = m_favourites.size(); + beginInsertRows(createIndex(Favorite_Row, 0, static_cast(Tag::Overview)), position, position); + m_favourites.push_back(index); + endInsertRows(); +} diff --git a/src/models/eventmodel.h b/src/models/eventmodel.h index 53fc03949..c5cbf7900 100644 --- a/src/models/eventmodel.h +++ b/src/models/eventmodel.h @@ -71,9 +71,13 @@ class EventModel : public QAbstractItemModel QString name; }; +public: + void addToFavourites(const QModelIndex& index); + private: Data::EventResults m_data; QVector m_processes; + QVector m_favourites; Data::TimeRange m_time; quint64 m_totalOnCpuTime = 0; quint64 m_totalOffCpuTime = 0; diff --git a/src/models/timelinedelegate.cpp b/src/models/timelinedelegate.cpp index bbab5dba5..3cbd398e9 100644 --- a/src/models/timelinedelegate.cpp +++ b/src/models/timelinedelegate.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "../util.h" @@ -460,6 +461,14 @@ bool TimeLineDelegate::eventFilter(QObject* watched, QEvent* event) const auto isMainThread = threadStartTime == minTime && threadEndTime == maxTime; const auto cpuId = index.data(EventModel::CpuIdRole).value(); const auto numCpus = index.data(EventModel::NumCpusRole).value(); + + contextMenu->addAction(QIcon::fromTheme(QStringLiteral("favorite")), tr("Add to favorites"), this, + [this, index] { + auto model = qobject_cast(index.model()); + Q_ASSERT(model); + emit addToFavourites(model->mapToSource(index)); + }); + if (isTimeSpanSelected && (minTime != timeSlice.start || maxTime != timeSlice.end)) { contextMenu->addAction(QIcon::fromTheme(QStringLiteral("zoom-in")), tr("Zoom In On Selection"), this, [this, timeSlice]() { m_filterAndZoomStack->zoomIn(timeSlice); }); diff --git a/src/models/timelinedelegate.h b/src/models/timelinedelegate.h index 3019b41b8..9cae9308b 100644 --- a/src/models/timelinedelegate.h +++ b/src/models/timelinedelegate.h @@ -64,6 +64,7 @@ class TimeLineDelegate : public QStyledItemDelegate signals: void stacksHovered(const QSet& stacks); + void addToFavourites(const QModelIndex& index); protected: bool eventFilter(QObject* watched, QEvent* event) override; diff --git a/src/timelinewidget.cpp b/src/timelinewidget.cpp index 8acea5ae5..9bc40aefe 100644 --- a/src/timelinewidget.cpp +++ b/src/timelinewidget.cpp @@ -110,6 +110,9 @@ TimeLineWidget::TimeLineWidget(PerfParser* parser, QMenu* filterMenu, FilterAndZ m_timeLineDelegate->setEventType(typeId); }); + connect(m_timeLineDelegate, &TimeLineDelegate::addToFavourites, this, + [eventModel](const QModelIndex& index) { eventModel->addToFavourites(index); }); + connect(m_timeLineDelegate, &TimeLineDelegate::stacksHovered, this, [this](const QSet& stackIds) { if (stackIds.isEmpty()) { ++m_currentHoverStacksJobId; diff --git a/tests/modeltests/tst_models.cpp b/tests/modeltests/tst_models.cpp index 482e6615b..a0e57b823 100644 --- a/tests/modeltests/tst_models.cpp +++ b/tests/modeltests/tst_models.cpp @@ -537,7 +537,7 @@ private slots: model.setData(events); QCOMPARE(model.columnCount(), static_cast(EventModel::NUM_COLUMNS)); - QCOMPARE(model.rowCount(), 2); + QCOMPARE(model.rowCount(), 4); auto simplifiedEvents = events; simplifiedEvents.cpus.remove(1);