Skip to content

Commit f0e8581

Browse files
committed
add Favourites to TimeLineWidget
this allows the user to group important timelines together so that he can compare them better
1 parent 7d91243 commit f0e8581

File tree

6 files changed

+210
-61
lines changed

6 files changed

+210
-61
lines changed

src/models/eventmodel.cpp

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,19 @@ enum class Tag : quint8
2424
Processes,
2525
Threads,
2626
Tracepoints,
27+
Favorites,
2728
};
2829

2930
enum OverviewRow : quint8
3031
{
3132
CpuRow,
3233
ProcessRow,
3334
TracepointRow,
35+
FavoriteRow,
3436
};
35-
constexpr auto numRows = TracepointRow + 1;
37+
constexpr auto numRows = FavoriteRow + 1;
3638

37-
constexpr auto LAST_TAG = Tag::Tracepoints;
39+
constexpr auto LAST_TAG = Tag::Favorites;
3840

3941
const auto DATATAG_SHIFT = sizeof(Tag) * 8;
4042
const auto DATATAG_UNSHIFT = (sizeof(quintptr) - sizeof(Tag)) * 8;
@@ -88,6 +90,7 @@ int EventModel::rowCount(const QModelIndex& parent) const
8890
case Tag::Cpus:
8991
case Tag::Threads:
9092
case Tag::Tracepoints:
93+
case Tag::Favorites:
9194
return 0;
9295
break;
9396
case Tag::Processes:
@@ -100,6 +103,8 @@ int EventModel::rowCount(const QModelIndex& parent) const
100103
return m_processes.size();
101104
case OverviewRow::TracepointRow:
102105
return m_data.tracepoints.size();
106+
case OverviewRow::FavoriteRow:
107+
return m_favourites.size();
103108
}
104109
Q_UNREACHABLE();
105110
case Tag::Root:
@@ -167,6 +172,8 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
167172
return tr("Processes");
168173
case OverviewRow::TracepointRow:
169174
return tr("Tracepoints");
175+
case OverviewRow::FavoriteRow:
176+
return tr("Favorites");
170177
}
171178
} else if (role == Qt::ToolTipRole) {
172179
switch (static_cast<OverviewRow>(index.row())) {
@@ -177,6 +184,8 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
177184
return tr("Event timelines for the individual threads and processes.");
178185
case OverviewRow::TracepointRow:
179186
return tr("Event timelines for tracepoints");
187+
case OverviewRow::FavoriteRow:
188+
return tr("A list of favourites to group important events");
180189
}
181190
} else if (role == SortRole) {
182191
return index.row();
@@ -244,6 +253,13 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
244253
Q_ASSERT(thread);
245254
} else if (tag == Tag::Tracepoints) {
246255
tracepoint = &m_data.tracepoints[index.row()];
256+
} else if (tag == Tag::Favorites) {
257+
if (role == IsFavoriteRole) {
258+
return true;
259+
}
260+
261+
const auto& favourite = m_favourites[index.row()];
262+
return data(favourite.siblingAtColumn(index.column()), role);
247263
}
248264

249265
if (role == ThreadStartRole) {
@@ -257,6 +273,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
257273
case Tag::Processes:
258274
case Tag::Tracepoints:
259275
return m_time.start;
276+
case Tag::Favorites:
277+
// they are handled elsewhere
278+
Q_UNREACHABLE();
260279
}
261280
} else if (role == ThreadEndRole) {
262281
switch (tag) {
@@ -269,6 +288,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
269288
case Tag::Processes:
270289
case Tag::Tracepoints:
271290
return m_time.end;
291+
case Tag::Favorites:
292+
// they are handled elsewhere
293+
Q_UNREACHABLE();
272294
}
273295
} else if (role == ThreadNameRole) {
274296
switch (tag) {
@@ -282,6 +304,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
282304
case Tag::Processes:
283305
case Tag::Tracepoints:
284306
return {};
307+
case Tag::Favorites:
308+
// they are handled elsewhere
309+
Q_UNREACHABLE();
285310
}
286311
} else if (role == ThreadIdRole) {
287312
switch (tag) {
@@ -294,6 +319,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
294319
case Tag::Processes:
295320
case Tag::Tracepoints:
296321
return Data::INVALID_TID;
322+
case Tag::Favorites:
323+
// they are handled elsewhere
324+
Q_UNREACHABLE();
297325
}
298326
} else if (role == ProcessIdRole) {
299327
switch (tag) {
@@ -306,6 +334,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
306334
case Tag::Processes:
307335
case Tag::Tracepoints:
308336
return Data::INVALID_PID;
337+
case Tag::Favorites:
338+
// they are handled elsewhere
339+
Q_UNREACHABLE();
309340
}
310341
} else if (role == CpuIdRole) {
311342
switch (tag) {
@@ -318,6 +349,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
318349
case Tag::Threads:
319350
case Tag::Tracepoints:
320351
return Data::INVALID_CPU_ID;
352+
case Tag::Favorites:
353+
// they are handled elsewhere
354+
Q_UNREACHABLE();
321355
}
322356
} else if (role == EventsRole) {
323357
switch (tag) {
@@ -332,6 +366,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
332366
case Tag::Overview:
333367
case Tag::Processes:
334368
return QVariant::fromValue(Data::Events());
369+
case Tag::Favorites:
370+
// they are handled elsewhere
371+
Q_UNREACHABLE();
335372
}
336373
} else if (role == SortRole) {
337374
if (index.column() == ThreadColumn) {
@@ -347,6 +384,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
347384
case Tag::Overview:
348385
case Tag::Processes:
349386
return {};
387+
case Tag::Favorites:
388+
// they are handled elsewhere
389+
Q_UNREACHABLE();
350390
}
351391
} else {
352392
switch (tag) {
@@ -361,8 +401,13 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
361401
case Tag::Overview:
362402
case Tag::Processes:
363403
return {};
404+
case Tag::Favorites:
405+
// they are handled elsewhere
406+
Q_UNREACHABLE();
364407
}
365408
}
409+
} else if (role == IsFavoriteRole) {
410+
return false;
366411
}
367412

368413
switch (static_cast<Columns>(index.column())) {
@@ -380,6 +425,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
380425
case Tag::Overview:
381426
case Tag::Processes:
382427
return {};
428+
case Tag::Favorites:
429+
// they are handled elsewhere
430+
Q_UNREACHABLE();
383431
}
384432
} else if (role == Qt::ToolTipRole) {
385433
QString tooltip;
@@ -420,6 +468,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
420468
case Tag::Overview:
421469
case Tag::Processes:
422470
break;
471+
case Tag::Favorites:
472+
// they are handled elsewhere
473+
Q_UNREACHABLE();
423474
}
424475

425476
tooltip += tr("Number of Events: %1 (%2% of the total)")
@@ -441,6 +492,9 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
441492
case Tag::Overview:
442493
case Tag::Processes:
443494
return {};
495+
case Tag::Favorites:
496+
// they are handled elsewhere
497+
Q_UNREACHABLE();
444498
}
445499
}
446500
break;
@@ -455,6 +509,8 @@ QVariant EventModel::data(const QModelIndex& index, int role) const
455509
void EventModel::setData(const Data::EventResults& data)
456510
{
457511
beginResetModel();
512+
m_favourites.clear();
513+
458514
m_data = data;
459515
m_totalEvents = 0;
460516
m_maxCost = 0;
@@ -515,6 +571,7 @@ QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) co
515571
case Tag::Cpus:
516572
case Tag::Tracepoints:
517573
case Tag::Threads:
574+
case Tag::Favorites:
518575
break;
519576
case Tag::Root: // root has the 1st level children: Overview
520577
return createIndex(row, column, static_cast<quintptr>(Tag::Overview));
@@ -526,6 +583,8 @@ QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) co
526583
return createIndex(row, column, static_cast<quintptr>(Tag::Processes));
527584
case OverviewRow::TracepointRow:
528585
return createIndex(row, column, static_cast<quintptr>(Tag::Tracepoints));
586+
case OverviewRow::FavoriteRow:
587+
return createIndex(row, column, static_cast<quintptr>(Tag::Favorites));
529588
}
530589
Q_UNREACHABLE();
531590
case Tag::Processes: // 3rd level children: Threads
@@ -547,12 +606,44 @@ QModelIndex EventModel::parent(const QModelIndex& child) const
547606
case Tag::Processes:
548607
return createIndex(OverviewRow::ProcessRow, 0, static_cast<quintptr>(Tag::Overview));
549608
case Tag::Tracepoints:
550-
return createIndex(OverviewRow::TracepointRow, 0, static_cast<qintptr>(Tag::Overview));
551-
case Tag::Threads: {
609+
return createIndex(OverviewRow::TracepointRow, 0, static_cast<quintptr>(Tag::Overview));
610+
case Tag::Favorites:
611+
return createIndex(OverviewRow::FavoriteRow, 0, static_cast<quintptr>(Tag::Overview));
612+
case Tag::Threads:
552613
const auto parentRow = tagData(child.internalId());
553614
return createIndex(parentRow, 0, static_cast<quintptr>(Tag::Processes));
554615
}
555-
}
556616

557617
return {};
558618
}
619+
620+
void EventModel::addToFavorites(const QModelIndex& _index)
621+
{
622+
Q_ASSERT(_index.model() == this);
623+
624+
// we only want one index per row, so we force it to be column zero
625+
// this way we can easily check if we have duplicate rows
626+
const auto& index = _index.siblingAtColumn(0);
627+
628+
if (m_favourites.contains(index)) {
629+
return;
630+
}
631+
632+
const int position = m_favourites.size();
633+
beginInsertRows(createIndex(FavoriteRow, 0, static_cast<quintptr>(Tag::Overview)), position, position);
634+
m_favourites.push_back(index);
635+
endInsertRows();
636+
}
637+
638+
void EventModel::removeFromFavorites(const QModelIndex& index)
639+
{
640+
Q_ASSERT(index.model() == this);
641+
642+
auto row = index.row();
643+
644+
if (row >= 0 && row < m_favourites.size()) {
645+
beginRemoveRows(createIndex(FavoriteRow, 0, static_cast<quintptr>(Tag::Overview)), row, row);
646+
m_favourites.remove(row);
647+
endRemoveRows();
648+
}
649+
}

src/models/eventmodel.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class EventModel : public QAbstractItemModel
4242
SortRole,
4343
TotalCostsRole,
4444
EventResultsRole,
45+
IsFavoriteRole,
4546
};
4647

4748
int rowCount(const QModelIndex& parent = {}) const override;
@@ -71,9 +72,14 @@ class EventModel : public QAbstractItemModel
7172
QString name;
7273
};
7374

75+
public:
76+
void addToFavorites(const QModelIndex& index);
77+
void removeFromFavorites(const QModelIndex& index);
78+
7479
private:
7580
Data::EventResults m_data;
7681
QVector<Process> m_processes;
82+
QVector<QModelIndex> m_favourites;
7783
Data::TimeRange m_time;
7884
quint64 m_totalOnCpuTime = 0;
7985
quint64 m_totalOffCpuTime = 0;

src/models/timelinedelegate.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <QHelpEvent>
1414
#include <QMenu>
1515
#include <QPainter>
16+
#include <QSortFilterProxyModel>
1617
#include <QToolTip>
1718

1819
#include "../util.h"
@@ -459,6 +460,20 @@ bool TimeLineDelegate::eventFilter(QObject* watched, QEvent* event)
459460
const auto isMainThread = threadStartTime == minTime && threadEndTime == maxTime;
460461
const auto cpuId = index.data(EventModel::CpuIdRole).value<quint32>();
461462
const auto numCpus = index.data(EventModel::NumCpusRole).value<uint>();
463+
const auto isFavourite = index.data(EventModel::IsFavoriteRole).value<bool>();
464+
465+
contextMenu->addAction(QIcon::fromTheme(QStringLiteral("favorite")),
466+
isFavourite ? tr("Remove from favorites") : tr("Add to favorites"), this,
467+
[this, index, isFavourite] {
468+
auto model = qobject_cast<const QSortFilterProxyModel*>(index.model());
469+
Q_ASSERT(model);
470+
if (isFavourite) {
471+
emit removeFromFavorites(model->mapToSource(index));
472+
} else {
473+
emit addToFavorites(model->mapToSource(index));
474+
}
475+
});
476+
462477
if (isTimeSpanSelected && (minTime != timeSlice.start || maxTime != timeSlice.end)) {
463478
contextMenu->addAction(QIcon::fromTheme(QStringLiteral("zoom-in")), tr("Zoom In On Selection"), this,
464479
[this, timeSlice]() { m_filterAndZoomStack->zoomIn(timeSlice); });

src/models/timelinedelegate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class TimeLineDelegate : public QStyledItemDelegate
6464

6565
signals:
6666
void stacksHovered(const QSet<qint32>& stacks);
67+
void addToFavorites(const QModelIndex& index);
68+
void removeFromFavorites(const QModelIndex& index);
6769

6870
protected:
6971
bool eventFilter(QObject* watched, QEvent* event) override;

src/timelinewidget.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ TimeLineWidget::TimeLineWidget(PerfParser* parser, QMenu* filterMenu, FilterAndZ
110110
m_timeLineDelegate->setEventType(typeId);
111111
});
112112

113+
connect(m_timeLineDelegate, &TimeLineDelegate::addToFavorites, this,
114+
[eventModel](const QModelIndex& index) { eventModel->addToFavorites(index); });
115+
connect(m_timeLineDelegate, &TimeLineDelegate::removeFromFavorites, this,
116+
[eventModel](const QModelIndex& index) { eventModel->removeFromFavorites(index); });
117+
113118
connect(m_timeLineDelegate, &TimeLineDelegate::stacksHovered, this, [this](const QSet<qint32>& stackIds) {
114119
if (stackIds.isEmpty()) {
115120
++m_currentHoverStacksJobId;

0 commit comments

Comments
 (0)