Skip to content

Commit

Permalink
Add tooltips for each of the models.
Browse files Browse the repository at this point in the history
Tooltips include one for each column header and one for each row of
data.

Fixes: KDAB#29
  • Loading branch information
nwrogers committed Apr 3, 2017
1 parent 3b8b013 commit 6cdaea7
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/models/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_library(models STATIC
data.cpp
callercalleemodel.cpp
costdelegate.cpp
../util.cpp
)

target_link_libraries(models
Expand Down
54 changes: 37 additions & 17 deletions src/models/callercalleemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/

#include "callercalleemodel.h"
#include "../util.h"

CallerCalleeModel::CallerCalleeModel(QObject* parent)
: HashModel(parent)
Expand All @@ -42,30 +43,45 @@ QVariant CallerCalleeModel::headerCell(Columns column, int role)
return Qt::DescendingOrder;
}
}
if (role != Qt::DisplayRole) {
if (role != Qt::DisplayRole && role != Qt::ToolTipRole) {
return {};
}

switch (column) {
case Symbol:
return tr("Symbol");
case Binary:
return tr("Binary");
case SelfCost:
return tr("Self Cost");
case InclusiveCost:
return tr("Inclusive Cost");
case Callers:
return tr("Callers");
case Callees:
return tr("Callees");
if (role == Qt::DisplayRole) {
switch (column) {
case Symbol:
return tr("Symbol");
case Binary:
return tr("Binary");
case SelfCost:
return tr("Self Cost");
case InclusiveCost:
return tr("Inclusive Cost");
case Callers:
return tr("Callers");
case Callees:
return tr("Callees");
}
} else if (role == Qt::ToolTipRole) {
switch (column) {
case Symbol:
return tr("The symbol's function name. May be empty when debug information is missing.");
case Binary:
return tr("The name of the executable the symbol resides in. May be empty when debug information is missing.");
case SelfCost:
return tr("The number of samples directly attributed to this symbol.");
case InclusiveCost:
return tr("The number of samples attributed to this symbol, both directly and indirectly. This includes the costs of all functions called by this symbol plus its self cost.");
default:
break;
}
}

return {};
}

QVariant CallerCalleeModel::cell(Columns column, int role, const Data::Symbol& symbol,
const Data::CallerCalleeEntry& entry)
const Data::CallerCalleeEntry& entry, quint64 sampleCount)
{
if (role == SortRole) {
switch (column) {
Expand Down Expand Up @@ -107,10 +123,14 @@ QVariant CallerCalleeModel::cell(Columns column, int role, const Data::Symbol& s
return QVariant::fromValue(entry.callers);
} else if (role == SourceMapRole) {
return QVariant::fromValue(entry.sourceMap);
} else if (role == Qt::ToolTipRole) {
QString toolTip = tr("%1 in %2\nself cost: %3 out of %4 total samples (%5%)\ninclusive cost: %6 out of %7 total samples (%8%)").arg(
Util::formatString(symbol.symbol), Util::formatString(symbol.binary),
Util::formatCost(entry.selfCost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(entry.selfCost.samples, sampleCount),
Util::formatCost(entry.inclusiveCost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(entry.inclusiveCost.samples, sampleCount));
return toolTip;
}

// TODO: tooltips

return {};
}

Expand Down
68 changes: 47 additions & 21 deletions src/models/callercalleemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class CallerCalleeModel : public HashModel<Data::CallerCalleeEntryMap, CallerCal

static QVariant headerCell(Columns column, int role);
static QVariant cell(Columns column, int role, const Data::Symbol& symbol,
const Data::CallerCalleeEntry& entry);
const Data::CallerCalleeEntry& entry, quint64 sampleCount);
QModelIndex indexForSymbol(const Data::Symbol& symbol) const;
};

Expand Down Expand Up @@ -99,24 +99,35 @@ class SymbolCostModelImpl : public HashModel<Data::SymbolCostMap, ModelImpl>
if (role == Qt::InitialSortOrderRole && column == Cost) {
return Qt::DescendingOrder;
}
if (role != Qt::DisplayRole) {
if (role != Qt::DisplayRole && role != Qt::ToolTipRole) {
return {};
}

switch (column) {
case Symbol:
return ModelImpl::symbolHeader();
case Binary:
return QObject::tr("Binary");
case Cost:
return QObject::tr("Cost");
if (role == Qt::DisplayRole) {
switch (column) {
case Symbol:
return ModelImpl::symbolHeader();
case Binary:
return QObject::tr("Binary");
case Cost:
return QObject::tr("Cost");
}
} else if (role == Qt::ToolTipRole) {
switch (column) {
case Symbol:
return QObject::tr("The function name of the %1. May be empty when debug information is missing.").arg(ModelImpl::symbolHeader());
case Binary:
return QObject::tr("The name of the executable the symbol resides in. May be empty when debug information is missing.");
case Cost:
return QObject::tr("The number of CPU samples used by this symbol.");
}
}

return {};
}

static QVariant cell(Columns column, int role, const Data::Symbol& symbol,
const Data::Cost& cost)
const Data::Cost& cost, quint64 sampleCount)
{
if (role == SortRole) {
switch (column) {
Expand All @@ -142,10 +153,13 @@ class SymbolCostModelImpl : public HashModel<Data::SymbolCostMap, ModelImpl>
}
} else if (role == SymbolRole) {
return QVariant::fromValue(symbol);
} else if (role == Qt::ToolTipRole) {
QString toolTip = QObject::tr("%1 in %2\ncost: %3 out of %4 total samples (%5%)").arg(
Util::formatString(symbol.symbol), Util::formatString(symbol.binary),
Util::formatCost(cost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(cost.samples, sampleCount));
return toolTip;
}

// TODO: tooltips

return {};
}
};
Expand Down Expand Up @@ -201,22 +215,32 @@ class LocationCostModelImpl : public HashModel<Data::LocationCostMap, ModelImpl>
if (role == Qt::InitialSortOrderRole && column == Cost) {
return Qt::DescendingOrder;
}
if (role != Qt::DisplayRole) {

if (role != Qt::DisplayRole && role != Qt::ToolTipRole) {
return {};
}

switch (column) {
case Location:
return QObject::tr("Location");
case Cost:
return QObject::tr("Cost");
if (role == Qt::DisplayRole) {
switch (column) {
case Location:
return QObject::tr("Location");
case Cost:
return QObject::tr("Cost");
}
} else if (role == Qt::ToolTipRole) {
switch (column) {
case Location:
return QObject::tr("The source file name and line number where the cost was measured. May be empty when debug information is missing.");
case Cost:
return QObject::tr("The number of samples attributed to this code location.");
}
}

return {};
}

static QVariant cell(Columns column, int role, const QString& location,
const Data::Cost& cost)
const Data::Cost& cost, quint64 sampleCount)
{
if (role == SortRole) {
switch (column) {
Expand All @@ -237,10 +261,12 @@ class LocationCostModelImpl : public HashModel<Data::LocationCostMap, ModelImpl>
}
} else if (role == LocationRole) {
return QVariant::fromValue(location);
} else if (role == Qt::ToolTipRole) {
QString toolTip = QObject::tr("%1\ncost: %2 out of %3 total samples (%4%)").arg(
Util::formatString(location), Util::formatCost(cost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(cost.samples, sampleCount));
return toolTip;
}

// TODO: tooltips

return {};
}
};
Expand Down
19 changes: 18 additions & 1 deletion src/models/hashmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class HashModel : public QAbstractTableModel
std::advance(it, index.row());

const auto column = static_cast<typename ModelImpl::Columns>(index.column());
return ModelImpl::cell(column, role, it.key(), it.value());
return ModelImpl::cell(column, role, it.key(), it.value(), m_sampleCount);
}

using QAbstractTableModel::setData;
Expand Down Expand Up @@ -104,6 +104,23 @@ class HashModel : public QAbstractTableModel
return index(row, column);
}

static QString formatSymbolBinaryString(const QString& symbol, const QString& binary)
{
auto blankString = tr("??");
auto symbolName = symbol.isEmpty() ? blankString : symbol;
auto binaryName = binary.isEmpty() ? blankString : binary;

return symbolName + tr(" in ") + binaryName;
}

static QString formatCostString(const QString& name, quint32 cost, quint64 sampleCount)
{
const auto fraction = QString::number(double(cost) * 100. / sampleCount, 'g', 3);

return name + QLatin1String(": ") + QString::number(cost) + tr(" out of ") +
QString::number(sampleCount) + tr(" samples (") + fraction + QLatin1String("%)");
}

protected:
Rows m_rows;

Expand Down
48 changes: 48 additions & 0 deletions src/models/treemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/

#include "treemodel.h"
#include "../util.h"

AbstractTreeModel::AbstractTreeModel(QObject* parent)
: QAbstractItemModel(parent)
Expand Down Expand Up @@ -55,6 +56,20 @@ QString BottomUpModel::headerTitle(Columns column)
return {};
}

QString BottomUpModel::headerToolTip(Columns column)
{
switch (column) {
case Symbol:
return tr("The symbol's function name. May be empty when debug information is missing.");
case Binary:
return tr("The name of the executable the symbol resides in. May be empty when debug information is missing.");
case Cost:
return tr("The number of CPU samples used by this symbol.");
}
Q_UNREACHABLE();
return {};
}

QVariant BottomUpModel::displayData(const Data::BottomUp* row, Columns column)
{
switch (column) {
Expand All @@ -69,6 +84,14 @@ QVariant BottomUpModel::displayData(const Data::BottomUp* row, Columns column)
return {};
}

QVariant BottomUpModel::displayToolTip(const Data::BottomUp* row, quint64 sampleCount)
{
QString toolTip = tr("%1 in %2\ncost: %3 out of %4 total samples (%5%)").arg(
Util::formatString(row->symbol.symbol), Util::formatString(row->symbol.binary),
Util::formatCost(row->cost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(row->cost.samples, sampleCount));
return toolTip;
}

TopDownModel::TopDownModel(QObject* parent)
: TreeModel(parent)
{
Expand All @@ -92,6 +115,22 @@ QString TopDownModel::headerTitle(Columns column)
return {};
}

QString TopDownModel::headerToolTip(Columns column)
{
switch (column) {
case Symbol:
return tr("The symbol's function name. May be empty when debug information is missing.");
case Binary:
return tr("The name of the executable the symbol resides in. May be empty when debug information is missing.");
case InclusiveCost:
return tr("The number of samples attributed to this symbol, both directly and indirectly. This includes the costs of all functions called by this symbol plus its self cost.");
case SelfCost:
return tr("The number of samples directly attributed to this symbol.");
}
Q_UNREACHABLE();
return {};
}

QVariant TopDownModel::displayData(const Data::TopDown* row, Columns column)
{
switch (column) {
Expand All @@ -107,3 +146,12 @@ QVariant TopDownModel::displayData(const Data::TopDown* row, Columns column)
Q_UNREACHABLE();
return {};
}

QVariant TopDownModel::displayToolTip(const Data::TopDown* row, quint64 sampleCount)
{
QString toolTip = tr("%1 in %2\nself cost: %3 out of %4 total samples (%5%)\ninclusive cost: %6 out of %7 total samples (%8%)").arg(
Util::formatString(row->symbol.symbol), Util::formatString(row->symbol.binary),
Util::formatCost(row->selfCost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(row->selfCost.samples, sampleCount),
Util::formatCost(row->inclusiveCost.samples), Util::formatCost(sampleCount), Util::formatCostRelative(row->inclusiveCost.samples, sampleCount));
return toolTip;
}
14 changes: 12 additions & 2 deletions src/models/treemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,17 @@ class TreeModel : public AbstractTreeModel

QVariant headerData(int section, Qt::Orientation orientation, int role) const final override
{
if (role != Qt::DisplayRole || orientation != Qt::Horizontal
if ((role != Qt::DisplayRole && role != Qt::ToolTipRole) || orientation != Qt::Horizontal
|| section < 0 || section > ModelImpl::NUM_COLUMNS)
{
return {};
}

return ModelImpl::headerTitle(static_cast<typename ModelImpl::Columns>(section));
if (role == Qt::ToolTipRole) {
return ModelImpl::headerToolTip(static_cast<typename ModelImpl::Columns>(section));
} else {
return ModelImpl::headerTitle(static_cast<typename ModelImpl::Columns>(section));
}
}

QVariant data(const QModelIndex& index, int role) const final override
Expand All @@ -146,6 +150,8 @@ class TreeModel : public AbstractTreeModel
return m_sampleCount;
} else if (role == SymbolRole) {
return QVariant::fromValue(item->symbol);
} else if (role == Qt::ToolTipRole) {
return ModelImpl::displayToolTip(item, m_sampleCount);
}

// TODO: tooltips
Expand Down Expand Up @@ -205,7 +211,9 @@ class BottomUpModel : public TreeModel<Data::BottomUp, BottomUpModel>
};

static QString headerTitle(Columns column);
static QString headerToolTip(Columns column);
static QVariant displayData(const Data::BottomUp* row, Columns column);
static QVariant displayToolTip(const Data::BottomUp* row, quint64 sampleCount);
};

class TopDownModel : public TreeModel<Data::TopDown, TopDownModel>
Expand All @@ -227,5 +235,7 @@ class TopDownModel : public TreeModel<Data::TopDown, TopDownModel>
};

static QString headerTitle(Columns column);
static QString headerToolTip(Columns column);
static QVariant displayData(const Data::TopDown* row, Columns column);
static QVariant displayToolTip(const Data::TopDown* row, quint64 sampleCount);
};
15 changes: 15 additions & 0 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,18 @@ QString Util::findLibexecBinary(const QString& name)
}
return info.absoluteFilePath();
}

QString Util::formatString(const QString& input)
{
return input.isEmpty() ? QObject::tr("??") : input;
}

QString Util::formatCost(quint32 cost)
{
return QString::number(cost);
}

QString Util::formatCostRelative(quint32 selfCost, quint64 totalCost)
{
return QString::number(double(selfCost) * 100. / totalCost, 'g', 3);
}
Loading

0 comments on commit 6cdaea7

Please sign in to comment.