From 539b1df87b6edb0441240c78df3c7aa5e059e3dc Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 15 Mar 2016 20:18:00 +0100 Subject: [PATCH] Colorize model cost cells background based on relative cost to total. Maniphest Task: https://phabricator.kde.org/T1709 --- gui/CMakeLists.txt | 1 + gui/costdelegate.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ gui/costdelegate.h | 36 +++++++++++++++++++++++++ gui/mainwindow.cpp | 21 ++++++++++++++- gui/parser.h | 15 ----------- gui/treemodel.cpp | 23 ++++++++++++---- gui/treemodel.h | 20 +++++++++++++- 7 files changed, 170 insertions(+), 22 deletions(-) create mode 100644 gui/costdelegate.cpp create mode 100644 gui/costdelegate.h diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 18cb20b..37c336f 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(heaptrack_gui mainwindow.cpp treemodel.cpp treeproxy.cpp + costdelegate.cpp chartwidget.cpp chartmodel.cpp chartproxy.cpp diff --git a/gui/costdelegate.cpp b/gui/costdelegate.cpp new file mode 100644 index 0000000..eb68f7e --- /dev/null +++ b/gui/costdelegate.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2016 Milian Wolff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "costdelegate.h" + +#include "treemodel.h" + +#include +#include + +CostDelegate::CostDelegate(QObject* parent) + : QStyledItemDelegate(parent) +{ +} + +CostDelegate::~CostDelegate() = default; + +void CostDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + const uint64_t cost = index.data(TreeModel::SortRole).toULongLong(); + if (cost == 0) { + QStyledItemDelegate::paint(painter, option, index); + return; + } + + const uint64_t maxCost = index.data(TreeModel::MaxCostRole).toULongLong(); + // top-down can miscalculate the peak cost + const auto fraction = std::min(1.f, float(cost) / maxCost); + auto rect = option.rect; + rect.setWidth(rect.width() * fraction); + + const auto& brush = painter->brush(); + const auto& pen = painter->pen(); + + painter->setPen(Qt::NoPen); + + if (option.features & QStyleOptionViewItem::Alternate) { + // we must handle this ourselves as otherwise the custom background + // would get painted over with the alternate background color + painter->setBrush(option.palette.alternateBase()); + painter->drawRect(option.rect); + } + + auto color = QColor::fromHsv(120 - fraction * 120, 255, 255, + (-((fraction-1) * (fraction-1))) * 120 + 120); + painter->setBrush(color); + painter->drawRect(rect); + + painter->setBrush(brush); + painter->setPen(pen); + + if (option.features & QStyleOptionViewItem::Alternate) { + auto o = option; + o.features &= ~QStyleOptionViewItem::Alternate; + QStyledItemDelegate::paint(painter, o, index); + } else { + QStyledItemDelegate::paint(painter, option, index); + } +} + diff --git a/gui/costdelegate.h b/gui/costdelegate.h new file mode 100644 index 0000000..b305ebb --- /dev/null +++ b/gui/costdelegate.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Milian Wolff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COSTDELEGATE_H +#define COSTDELEGATE_H + +#include + +class CostDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit CostDelegate(QObject *parent = nullptr); + ~CostDelegate(); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; +}; + +#endif // COSTDELEGATE_H diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 530c411..c6b5c52 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -33,6 +33,7 @@ #include "treemodel.h" #include "treeproxy.h" #include "topproxy.h" +#include "costdelegate.h" #include "parser.h" #include "chartmodel.h" #include "chartproxy.h" @@ -147,7 +148,9 @@ MainWindow::MainWindow(QWidget* parent) m_ui->tabWidget->setTabEnabled(m_ui->tabWidget->indexOf(m_ui->sizesTab), true); }); connect(m_parser, &Parser::summaryAvailable, - this, [this] (const SummaryData& data) { + this, [this, bottomUpModel, topDownModel] (const SummaryData& data) { + bottomUpModel->setSummary(data); + topDownModel->setSummary(data); KFormat format; QString textLeft; QString textCenter; @@ -209,6 +212,12 @@ MainWindow::MainWindow(QWidget* parent) bottomUpProxy->setSourceModel(bottomUpModel); bottomUpProxy->setSortRole(TreeModel::SortRole); m_ui->bottomUpResults->setModel(bottomUpProxy); + auto costDelegate = new CostDelegate(this); + m_ui->bottomUpResults->setItemDelegateForColumn(TreeModel::PeakColumn, costDelegate); + m_ui->bottomUpResults->setItemDelegateForColumn(TreeModel::AllocatedColumn, costDelegate); + m_ui->bottomUpResults->setItemDelegateForColumn(TreeModel::LeakedColumn, costDelegate); + m_ui->bottomUpResults->setItemDelegateForColumn(TreeModel::AllocationsColumn, costDelegate); + m_ui->bottomUpResults->setItemDelegateForColumn(TreeModel::TemporaryColumn, costDelegate); m_ui->bottomUpResults->hideColumn(TreeModel::FunctionColumn); m_ui->bottomUpResults->hideColumn(TreeModel::FileColumn); m_ui->bottomUpResults->hideColumn(TreeModel::LineColumn); @@ -224,6 +233,11 @@ MainWindow::MainWindow(QWidget* parent) topDownProxy->setSourceModel(topDownModel); topDownProxy->setSortRole(TreeModel::SortRole); m_ui->topDownResults->setModel(topDownProxy); + m_ui->topDownResults->setItemDelegateForColumn(TreeModel::PeakColumn, costDelegate); + m_ui->topDownResults->setItemDelegateForColumn(TreeModel::AllocatedColumn, costDelegate); + m_ui->topDownResults->setItemDelegateForColumn(TreeModel::LeakedColumn, costDelegate); + m_ui->topDownResults->setItemDelegateForColumn(TreeModel::AllocationsColumn, costDelegate); + m_ui->topDownResults->setItemDelegateForColumn(TreeModel::TemporaryColumn, costDelegate); m_ui->topDownResults->hideColumn(TreeModel::FunctionColumn); m_ui->topDownResults->hideColumn(TreeModel::FileColumn); m_ui->topDownResults->hideColumn(TreeModel::LineColumn); @@ -241,10 +255,15 @@ MainWindow::MainWindow(QWidget* parent) setupStacks(); setupTopView(bottomUpModel, m_ui->topPeak, TopProxy::Peak); + m_ui->topPeak->setItemDelegate(costDelegate); setupTopView(bottomUpModel, m_ui->topLeaked, TopProxy::Leaked); + m_ui->topLeaked->setItemDelegate(costDelegate); setupTopView(bottomUpModel, m_ui->topAllocations, TopProxy::Allocations); + m_ui->topAllocations->setItemDelegate(costDelegate); setupTopView(bottomUpModel, m_ui->topTemporary, TopProxy::Temporary); + m_ui->topTemporary->setItemDelegate(costDelegate); setupTopView(bottomUpModel, m_ui->topAllocated, TopProxy::Allocated); + m_ui->topAllocated->setItemDelegate(costDelegate); setWindowTitle(i18n("Heaptrack")); } diff --git a/gui/parser.h b/gui/parser.h index 33f33ad..113eadf 100644 --- a/gui/parser.h +++ b/gui/parser.h @@ -26,21 +26,6 @@ #include "chartmodel.h" #include "histogrammodel.h" -struct SummaryData -{ - QString debuggee; - uint64_t totalTime; - uint64_t peakTime; - uint64_t peak; - uint64_t leaked; - uint64_t allocations; - uint64_t temporary; - uint64_t allocated; - uint64_t peakRSS; - uint64_t totalSystemMemory; -}; -Q_DECLARE_METATYPE(SummaryData); - class Parser : public QObject { Q_OBJECT diff --git a/gui/treemodel.cpp b/gui/treemodel.cpp index 1569153..e9bcc57 100644 --- a/gui/treemodel.cpp +++ b/gui/treemodel.cpp @@ -143,11 +143,13 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const if (index.row() < 0 || index.column() < 0 || index.column() > NUM_COLUMNS) { return {}; } - const auto row = toRow(index); - if (role == Qt::DisplayRole || role == SortRole) { + + const auto row = (role == MaxCostRole) ? &m_maxCost : toRow(index); + + if (role == Qt::DisplayRole || role == SortRole || role == MaxCostRole) { switch (static_cast(index.column())) { case AllocatedColumn: - if (role == SortRole) { + if (role == SortRole || role == MaxCostRole) { return row->allocated; } else { return m_format.formatByteSize(row->allocated); @@ -157,13 +159,13 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const case TemporaryColumn: return row->temporary; case PeakColumn: - if (role == SortRole) { + if (role == SortRole || role == MaxCostRole) { return row->peak; } else { return m_format.formatByteSize(row->peak); } case LeakedColumn: - if (role == SortRole) { + if (role == SortRole || role == MaxCostRole) { return row->leaked; } else { return m_format.formatByteSize(row->leaked); @@ -269,6 +271,17 @@ void TreeModel::resetData(const TreeData& data) endResetModel(); } +void TreeModel::setSummary(const SummaryData& data) +{ + beginResetModel(); + m_maxCost.allocated = data.allocated; + m_maxCost.leaked = data.leaked; + m_maxCost.peak = data.peak; + m_maxCost.allocations = data.allocations; + m_maxCost.temporary = data.temporary; + endResetModel(); +} + const RowData* TreeModel::toRow(const QModelIndex& index) const { if (!index.isValid()) { diff --git a/gui/treemodel.h b/gui/treemodel.h index 220346d..f90873b 100644 --- a/gui/treemodel.h +++ b/gui/treemodel.h @@ -29,6 +29,21 @@ #include +struct SummaryData +{ + QString debuggee; + uint64_t totalTime; + uint64_t peakTime; + uint64_t peak; + uint64_t leaked; + uint64_t allocations; + uint64_t temporary; + uint64_t allocated; + uint64_t peakRSS; + uint64_t totalSystemMemory; +}; +Q_DECLARE_METATYPE(SummaryData); + struct LocationData { QString function; @@ -108,7 +123,8 @@ public: }; enum Roles { - SortRole = Qt::UserRole + SortRole = Qt::UserRole, + MaxCostRole = Qt::UserRole + 1 }; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; @@ -120,6 +136,7 @@ public: public slots: void resetData(const TreeData& data); + void setSummary(const SummaryData& data); private: /// @return the row resembled by @p index @@ -128,6 +145,7 @@ private: int rowOf(const RowData* row) const; TreeData m_data; + RowData m_maxCost; // TODO: update via global event filter when the locale changes (changeEvent) KFormat m_format; }; -- 2.7.4