QmlProfiler: Eliminate QStandardItemModel from statistics

This resolves the data duplication between model manager and statistics
models, that gets in the way of updating the details strings on the fly.

Task-number: QTCREATORBUG-20106
Change-Id: I1c4881f903402dff936267de03b84d05ab7c39ca
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ulf Hermann
2018-03-23 13:37:37 +01:00
parent 495b9aa9c2
commit 4aa432bb9a
4 changed files with 95 additions and 424 deletions

View File

@@ -105,11 +105,13 @@ void QmlProfilerStatisticsModel::restrictToFeatures(quint64 features)
return; return;
clear(); clear();
beginResetModel();
if (!m_modelManager->replayEvents(m_modelManager->traceTime()->startTime(), if (!m_modelManager->replayEvents(m_modelManager->traceTime()->startTime(),
m_modelManager->traceTime()->endTime(), m_modelManager->traceTime()->endTime(),
std::bind(&QmlProfilerStatisticsModel::loadEvent, std::bind(&QmlProfilerStatisticsModel::loadEvent,
this, std::placeholders::_1, this, std::placeholders::_1,
std::placeholders::_2))) { std::placeholders::_2))) {
endResetModel();
emit m_modelManager->error(tr("Could not re-read events from temporary trace file.")); emit m_modelManager->error(tr("Could not re-read events from temporary trace file."));
clear(); clear();
} else { } else {
@@ -195,6 +197,7 @@ QString QmlProfilerStatisticsModel::summary(const QVector<int> &typeIds) const
void QmlProfilerStatisticsModel::clear() void QmlProfilerStatisticsModel::clear()
{ {
beginResetModel();
m_rootDuration = 0; m_rootDuration = 0;
m_data.clear(); m_data.clear();
m_notes.clear(); m_notes.clear();
@@ -204,6 +207,7 @@ void QmlProfilerStatisticsModel::clear()
m_calleesModel->clear(); m_calleesModel->clear();
if (!m_callersModel.isNull()) if (!m_callersModel.isNull())
m_callersModel->clear(); m_callersModel->clear();
endResetModel();
} }
void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative, void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative,
@@ -400,12 +404,21 @@ QVariant QmlProfilerStatisticsModel::headerData(int section, Qt::Orientation ori
void QmlProfilerStatisticsModel::modelManagerStateChanged() void QmlProfilerStatisticsModel::modelManagerStateChanged()
{ {
if (m_modelManager->state() == QmlProfilerModelManager::ClearingData) switch (m_modelManager->state()) {
case QmlProfilerModelManager::ClearingData:
clear(); clear();
break;
case QmlProfilerModelManager::AcquiringData:
beginResetModel();
break;
default:
break;
}
} }
void QmlProfilerStatisticsModel::notesChanged(int typeIndex) void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
{ {
static const QVector<int> noteRoles({Qt::ToolTipRole, Qt::TextColorRole});
const QmlProfilerNotesModel *notesModel = m_modelManager->notesModel(); const QmlProfilerNotesModel *notesModel = m_modelManager->notesModel();
if (typeIndex == -1) { if (typeIndex == -1) {
m_notes.clear(); m_notes.clear();
@@ -418,6 +431,7 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
} else { } else {
note.append(QStringLiteral("\n")).append(notesModel->text(noteId)); note.append(QStringLiteral("\n")).append(notesModel->text(noteId));
} }
emit dataChanged(index(noteType, 0), index(noteType, MainDetails), noteRoles);
} }
} }
} else { } else {
@@ -430,6 +444,7 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
newNotes << notesModel->text(it->toInt()); newNotes << notesModel->text(it->toInt());
} }
m_notes[typeIndex] = newNotes.join(QStringLiteral("\n")); m_notes[typeIndex] = newNotes.join(QStringLiteral("\n"));
emit dataChanged(index(typeIndex, 0), index(typeIndex, MainDetails), noteRoles);
} }
} }
@@ -492,6 +507,7 @@ void QmlProfilerStatisticsModel::finalize()
{ {
for (QmlEventStats &stats : m_data) for (QmlEventStats &stats : m_data)
stats.finalize(); stats.finalize();
endResetModel();
emit dataAvailable(); emit dataAvailable();
} }
@@ -711,6 +727,21 @@ QVariant QmlProfilerStatisticsRelativesModel::headerData(int section, Qt::Orient
} }
} }
bool QmlProfilerStatisticsRelativesModel::setData(const QModelIndex &index, const QVariant &value,
int role)
{
bool ok = false;
const int typeIndex = value.toInt(&ok);
if (index.isValid() || !ok || role != TypeIdRole) {
return QAbstractTableModel::setData(index, value, role);
} else {
beginResetModel();
m_relativeTypeIndex = typeIndex;
endResetModel();
return true;
}
}
int QmlProfilerStatisticsRelativesModel::count() const int QmlProfilerStatisticsRelativesModel::count() const
{ {
return m_data.count(); return m_data.count();
@@ -718,10 +749,12 @@ int QmlProfilerStatisticsRelativesModel::count() const
void QmlProfilerStatisticsRelativesModel::clear() void QmlProfilerStatisticsRelativesModel::clear()
{ {
beginResetModel();
m_relativeTypeIndex = std::numeric_limits<int>::max(); m_relativeTypeIndex = std::numeric_limits<int>::max();
m_data.clear(); m_data.clear();
m_callStack.clear(); m_callStack.clear();
m_compileStack.clear(); m_compileStack.clear();
endResetModel();
} }
} // namespace QmlProfiler } // namespace QmlProfiler

View File

@@ -218,6 +218,9 @@ public:
int columnCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
signals: signals:
void dataAvailable(); void dataAvailable();

View File

@@ -33,7 +33,6 @@
#include <QUrl> #include <QUrl>
#include <QHash> #include <QHash>
#include <QStandardItem>
#include <QHeaderView> #include <QHeaderView>
#include <QApplication> #include <QApplication>
#include <QClipboard> #include <QClipboard>
@@ -41,6 +40,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QMenu> #include <QMenu>
#include <QSortFilterProxyModel>
#include <functional> #include <functional>
@@ -49,64 +49,6 @@ namespace Internal {
const int DEFAULT_SORT_COLUMN = MainTimeInPercent; const int DEFAULT_SORT_COLUMN = MainTimeInPercent;
struct SortPreserver {
SortPreserver(Utils::TreeView *view) : view(view)
{
const QHeaderView *header = view->header();
column = header->sortIndicatorSection();
order = header->sortIndicatorOrder();
view->setSortingEnabled(false);
}
~SortPreserver()
{
view->setSortingEnabled(true);
view->sortByColumn(column, order);
}
int column = DEFAULT_SORT_COLUMN;
Qt::SortOrder order = Qt::DescendingOrder;
Utils::TreeView *view = nullptr;
};
struct Colors {
QColor noteBackground = QColor("orange");
QColor defaultBackground = QColor("white");
};
struct RootEventType : public QmlEventType {
RootEventType() : QmlEventType(MaximumMessage, MaximumRangeType, -1,
QmlEventLocation("<program>", 1, 1),
QmlProfilerStatisticsMainView::tr("Main Program"),
QmlProfilerStatisticsMainView::tr("<program>"))
{
}
};
Q_GLOBAL_STATIC(Colors, colors)
Q_GLOBAL_STATIC(RootEventType, rootEventType)
class StatisticsViewItem : public QStandardItem
{
public:
StatisticsViewItem(const QString &text, const QVariant &sort) : QStandardItem(text)
{
setData(sort, SortRole);
}
virtual bool operator<(const QStandardItem &other) const
{
if (data(SortRole).type() == QVariant::String) {
// Strings should be case-insensitive compared
return data(SortRole).toString().compare(other.data(SortRole).toString(),
Qt::CaseInsensitive) < 0;
} else {
// For everything else the standard comparison should be OK
return QStandardItem::operator<(other);
}
}
};
static void setViewDefaults(Utils::TreeView *view) static void setViewDefaults(Utils::TreeView *view)
{ {
view->setFrameStyle(QFrame::NoFrame); view->setFrameStyle(QFrame::NoFrame);
@@ -116,68 +58,12 @@ static void setViewDefaults(Utils::TreeView *view)
header->setMinimumSectionSize(50); header->setMinimumSectionSize(50);
} }
static QString displayHeader(MainField header) static void getSourceLocation(const QModelIndex &index,
{
switch (header) {
case MainCallCount:
return QmlProfilerStatisticsMainView::tr("Calls");
case MainDetails:
return QmlProfilerStatisticsMainView::tr("Details");
case MainLocation:
return QmlProfilerStatisticsMainView::tr("Location");
case MainMaxTime:
return QmlProfilerStatisticsMainView::tr("Longest Time");
case MainTimePerCall:
return QmlProfilerStatisticsMainView::tr("Mean Time");
case MainSelfTime:
return QmlProfilerStatisticsMainView::tr("Self Time");
case MainSelfTimeInPercent:
return QmlProfilerStatisticsMainView::tr("Self Time in Percent");
case MainMinTime:
return QmlProfilerStatisticsMainView::tr("Shortest Time");
case MainTimeInPercent:
return QmlProfilerStatisticsMainView::tr("Time in Percent");
case MainTotalTime:
return QmlProfilerStatisticsMainView::tr("Total Time");
case MainType:
return QmlProfilerStatisticsMainView::tr("Type");
case MainMedianTime:
return QmlProfilerStatisticsMainView::tr("Median Time");
case MaxMainField:
QTC_ASSERT(false, break);
}
return QString();
}
static QString displayHeader(RelativeField header, QmlProfilerStatisticsRelation relation)
{
switch (header) {
case RelativeLocation:
return relation == QmlProfilerStatisticsCallees
? QmlProfilerStatisticsMainView::tr("Callee")
: QmlProfilerStatisticsMainView::tr("Caller");
case RelativeType:
return displayHeader(MainType);
case RelativeTotalTime:
return displayHeader(MainTotalTime);
case RelativeCallCount:
return displayHeader(MainCallCount);
case RelativeDetails:
return relation == QmlProfilerStatisticsCallees
? QmlProfilerStatisticsMainView::tr("Callee Description")
: QmlProfilerStatisticsMainView::tr("Caller Description");
case MaxRelativeField:
QTC_ASSERT(false, break);
}
return QString();
}
static void getSourceLocation(QStandardItem *infoItem,
std::function<void (const QString &, int, int)> receiver) std::function<void (const QString &, int, int)> receiver)
{ {
int line = infoItem->data(LineRole).toInt(); const int line = index.data(LineRole).toInt();
int column = infoItem->data(ColumnRole).toInt(); const int column = index.data(ColumnRole).toInt();
QString fileName = infoItem->data(FilenameRole).toString(); const QString fileName = index.data(FilenameRole).toString();
if (line != -1 && !fileName.isEmpty()) if (line != -1 && !fileName.isEmpty())
receiver(fileName, line, column); receiver(fileName, line, column);
} }
@@ -234,13 +120,6 @@ QmlProfilerStatisticsView::QmlProfilerStatisticsView(QmlProfilerModelManager *pr
setLayout(groupLayout); setLayout(groupLayout);
} }
void QmlProfilerStatisticsView::clear()
{
m_mainView->clear();
m_calleesView->clear();
m_callersView->clear();
}
QString QmlProfilerStatisticsView::summary(const QVector<int> &typeIds) const QString QmlProfilerStatisticsView::summary(const QVector<int> &typeIds) const
{ {
return m_mainView->summary(typeIds); return m_mainView->summary(typeIds);
@@ -344,33 +223,30 @@ QmlProfilerStatisticsMainView::QmlProfilerStatisticsMainView(QmlProfilerStatisti
setViewDefaults(this); setViewDefaults(this);
setObjectName(QLatin1String("QmlProfilerEventsTable")); setObjectName(QLatin1String("QmlProfilerEventsTable"));
m_standardItemModel.reset(new QStandardItemModel); auto sortModel = new QSortFilterProxyModel(this);
m_standardItemModel->setSortRole(SortRole); sortModel->setSourceModel(model);
setModel(m_standardItemModel.get()); sortModel->setSortRole(SortRole);
connect(this, &QAbstractItemView::activated, this, &QmlProfilerStatisticsMainView::jumpToItem); sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
sortModel->setFilterRole(FilterRole);
sortModel->setFilterKeyColumn(MainType);
sortModel->setFilterFixedString("+");
connect(m_model.get(), &QmlProfilerStatisticsModel::dataAvailable, setModel(sortModel);
this, &QmlProfilerStatisticsMainView::buildModel);
connect(m_model.get(), &QmlProfilerStatisticsModel::notesAvailable, connect(this, &QAbstractItemView::activated, this, &QmlProfilerStatisticsMainView::jumpToItem);
this, &QmlProfilerStatisticsMainView::updateNotes);
setSortingEnabled(true); setSortingEnabled(true);
sortByColumn(DEFAULT_SORT_COLUMN, Qt::DescendingOrder); sortByColumn(DEFAULT_SORT_COLUMN, Qt::DescendingOrder);
buildModel(); setShowExtendedStatistics(m_showExtendedStatistics);
setRootIsDecorated(false);
resizeColumnToContents(MainLocation);
resizeColumnToContents(MainType);
} }
QmlProfilerStatisticsMainView::~QmlProfilerStatisticsMainView() QmlProfilerStatisticsMainView::~QmlProfilerStatisticsMainView()
{ {
clear();
}
void QmlProfilerStatisticsMainView::setHeaderLabels()
{
for (int i = 0; i < MaxMainField; ++i) {
m_standardItemModel->setHeaderData(i, Qt::Horizontal,
displayHeader(static_cast<MainField>(i)));
}
} }
void QmlProfilerStatisticsMainView::setShowExtendedStatistics(bool show) void QmlProfilerStatisticsMainView::setShowExtendedStatistics(bool show)
@@ -393,59 +269,6 @@ bool QmlProfilerStatisticsMainView::showExtendedStatistics() const
return m_showExtendedStatistics; return m_showExtendedStatistics;
} }
void QmlProfilerStatisticsMainView::clear()
{
SortPreserver sorter(this);
m_standardItemModel->clear();
m_standardItemModel->setColumnCount(MaxMainField);
setHeaderLabels();
}
void QmlProfilerStatisticsMainView::buildModel()
{
clear();
{
SortPreserver sorter(this);
parseModel();
setShowExtendedStatistics(m_showExtendedStatistics);
setRootIsDecorated(false);
}
resizeColumnToContents(MainLocation);
resizeColumnToContents(MainType);
}
void QmlProfilerStatisticsMainView::updateNotes(int typeIndex)
{
const QVector<QmlProfilerStatisticsModel::QmlEventStats> &eventList = m_model->getData();
const QHash<int, QString> &noteList = m_model->getNotes();
QStandardItem *rootItem = m_standardItemModel->invisibleRootItem();
for (int rowIndex = 0; rowIndex < rootItem->rowCount(); ++rowIndex) {
int rowType = rootItem->child(rowIndex)->data(TypeIdRole).toInt();
if (rowType == -1 || (rowType != typeIndex && typeIndex != -1))
continue;
const QmlProfilerStatisticsModel::QmlEventStats &stats = eventList[rowType];
for (int columnIndex = 0; columnIndex < rootItem->columnCount(); ++columnIndex) {
QStandardItem *item = rootItem->child(rowIndex, columnIndex);
QHash<int, QString>::ConstIterator it = noteList.find(rowType);
if (it != noteList.end()) {
item->setBackground(colors()->noteBackground);
item->setToolTip(it.value());
} else if (stats.recursive > 0) {
item->setBackground(colors()->noteBackground);
item->setToolTip(tr("+%1 in recursive calls")
.arg(Timeline::formatTime(stats.recursive)));
} else if (!item->toolTip().isEmpty()){
item->setBackground(colors()->defaultBackground);
item->setToolTip(QString());
}
}
}
}
void QmlProfilerStatisticsMainView::restrictToFeatures(quint64 features) void QmlProfilerStatisticsMainView::restrictToFeatures(quint64 features)
{ {
m_model->restrictToFeatures(features); m_model->restrictToFeatures(features);
@@ -466,132 +289,40 @@ QStringList QmlProfilerStatisticsMainView::details(int typeId) const
return m_model->details(typeId); return m_model->details(typeId);
} }
void QmlProfilerStatisticsMainView::parseModel()
{
const QVector<QmlProfilerStatisticsModel::QmlEventStats> &eventList = m_model->getData();
const QVector<QmlEventType> &typeList = m_model->getTypes();
QmlProfilerStatisticsModel::QmlEventStats rootEventStats;
rootEventStats.total = rootEventStats.maximum = rootEventStats.minimum = rootEventStats.median
= m_model->rootDuration();
rootEventStats.calls = rootEventStats.total > 0 ? 1 : 0;
for (int typeIndex = -1; typeIndex < eventList.size(); ++typeIndex) {
const QmlProfilerStatisticsModel::QmlEventStats &stats = typeIndex >= 0
? eventList[typeIndex] : rootEventStats;
if (stats.calls == 0)
continue;
const QmlEventType &type = typeIndex >= 0 ? typeList[typeIndex] : *rootEventType();
QStandardItem *rootItem = m_standardItemModel->invisibleRootItem();
QList<QStandardItem *> newRow;
newRow << new StatisticsViewItem(
type.displayName().isEmpty() ? tr("<bytecode>") : type.displayName(),
type.displayName());
QString typeString = QmlProfilerStatisticsModel::nameForType(type.rangeType());
newRow << new StatisticsViewItem(typeString, typeString);
const double percent = m_model->durationPercent(typeIndex);
newRow << new StatisticsViewItem(QString::number(percent, 'f', 2)
+ QLatin1String(" %"), percent);
newRow << new StatisticsViewItem(
Timeline::formatTime(stats.totalNonRecursive()),
stats.totalNonRecursive());
const double percentSelf = m_model->durationSelfPercent(typeIndex);
newRow << new StatisticsViewItem(QString::number(percentSelf, 'f', 2)
+ QLatin1String(" %"), percentSelf);
newRow << new StatisticsViewItem(Timeline::formatTime(stats.self),
stats.self);
newRow << new StatisticsViewItem(QString::number(stats.calls), stats.calls);
const qint64 timePerCall = stats.average();
newRow << new StatisticsViewItem(Timeline::formatTime(timePerCall),
timePerCall);
newRow << new StatisticsViewItem(Timeline::formatTime(stats.median),
stats.median);
newRow << new StatisticsViewItem(Timeline::formatTime(stats.maximum),
stats.maximum);
newRow << new StatisticsViewItem(Timeline::formatTime(stats.minimum),
stats.minimum);
newRow << new StatisticsViewItem(type.data().isEmpty() ? tr("Source code not available")
: type.data(), type.data());
// no edit
foreach (QStandardItem *item, newRow)
item->setEditable(false);
// metadata
QStandardItem *first = newRow.at(MainLocation);
first->setData(typeIndex, TypeIdRole);
const QmlEventLocation location(type.location());
first->setData(location.filename(), FilenameRole);
first->setData(location.line(), LineRole);
first->setData(location.column(), ColumnRole);
// append
rootItem->appendRow(newRow);
}
}
QStandardItem *QmlProfilerStatisticsMainView::itemFromIndex(const QModelIndex &index) const
{
QStandardItem *indexItem = m_standardItemModel->itemFromIndex(index);
if (indexItem->parent())
return indexItem->parent()->child(indexItem->row());
else
return m_standardItemModel->item(index.row());
}
int QmlProfilerStatisticsMainView::selectedTypeId() const int QmlProfilerStatisticsMainView::selectedTypeId() const
{ {
QModelIndex index = selectedModelIndex(); return model()->data(selectedModelIndex(), TypeIdRole).toInt();
if (!index.isValid())
return -1;
QStandardItem *item = m_standardItemModel->item(index.row());
return item->data(TypeIdRole).toInt();
} }
void QmlProfilerStatisticsMainView::jumpToItem(const QModelIndex &index) void QmlProfilerStatisticsMainView::jumpToItem(const QModelIndex &index)
{ {
QStandardItem *infoItem = itemFromIndex(index);
// show in editor // show in editor
getSourceLocation(infoItem, [this](const QString &fileName, int line, int column) { getSourceLocation(index, [this](const QString &fileName, int line, int column) {
emit gotoSourceLocation(fileName, line, column); emit gotoSourceLocation(fileName, line, column);
}); });
// show in callers/callees subwindow // show in callers/callees subwindow
emit typeSelected(infoItem->data(TypeIdRole).toInt()); emit typeSelected(model()->data(index, TypeIdRole).toInt());
} }
void QmlProfilerStatisticsMainView::selectItem(const QStandardItem *item) void QmlProfilerStatisticsMainView::selectItem(const QModelIndex &index)
{ {
// If the same item is already selected, don't reselect it. // If the same item is already selected, don't reselect it.
QModelIndex index = m_standardItemModel->indexFromItem(item);
if (index != currentIndex()) { if (index != currentIndex()) {
setCurrentIndex(index); setCurrentIndex(index);
// show in callers/callees subwindow // show in callers/callees subwindow
emit typeSelected(itemFromIndex(index)->data(TypeIdRole).toInt()); emit typeSelected(index.data(TypeIdRole).toInt());
} }
} }
void QmlProfilerStatisticsMainView::selectType(int typeIndex) void QmlProfilerStatisticsMainView::selectType(int typeIndex)
{ {
for (int i = 0; i < m_standardItemModel->rowCount(); i++) { QAbstractItemModel *itemModel = model();
QStandardItem *infoItem = m_standardItemModel->item(i); for (int i = 0; i < itemModel->rowCount(); i++) {
if (infoItem->data(TypeIdRole).toInt() == typeIndex) { QModelIndex index = itemModel->index(i, MainLocation);
selectItem(infoItem); if (itemModel->data(index, TypeIdRole).toInt() == typeIndex) {
selectItem(index);
return; return;
} }
} }
@@ -606,16 +337,15 @@ QModelIndex QmlProfilerStatisticsMainView::selectedModelIndex() const
return sel.first(); return sel.first();
} }
QString QmlProfilerStatisticsMainView::textForItem(QStandardItem *item) const QString QmlProfilerStatisticsMainView::textForItem(const QModelIndex &index) const
{ {
QString str; QString str;
// item's data // item's data
int colCount = m_standardItemModel->columnCount(); const int colCount = model()->columnCount();
for (int j = 0; j < colCount; ++j) { for (int j = 0; j < colCount; ++j) {
QStandardItem *colItem = item->parent() ? item->parent()->child(item->row(),j) : const QModelIndex cellIndex = model()->index(index.row(), j);
m_standardItemModel->item(item->row(),j); str += cellIndex.data(Qt::DisplayRole).toString();
str += colItem->data(Qt::DisplayRole).toString();
if (j < colCount-1) str += QLatin1Char('\t'); if (j < colCount-1) str += QLatin1Char('\t');
} }
str += QLatin1Char('\n'); str += QLatin1Char('\n');
@@ -626,20 +356,24 @@ QString QmlProfilerStatisticsMainView::textForItem(QStandardItem *item) const
void QmlProfilerStatisticsMainView::copyTableToClipboard() const void QmlProfilerStatisticsMainView::copyTableToClipboard() const
{ {
QString str; QString str;
const QAbstractItemModel *itemModel = model();
// headers // headers
int columnCount = m_standardItemModel->columnCount(); const int columnCount = itemModel->columnCount();
for (int i = 0; i < columnCount; ++i) { for (int i = 0; i < columnCount; ++i) {
str += m_standardItemModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); str += itemModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
if (i < columnCount - 1) if (i < columnCount - 1)
str += QLatin1Char('\t'); str += QLatin1Char('\t');
else else
str += QLatin1Char('\n'); str += QLatin1Char('\n');
} }
// data // data
int rowCount = m_standardItemModel->rowCount(); const int rowCount = itemModel->rowCount();
for (int i = 0; i != rowCount; ++i) { for (int i = 0; i != rowCount; ++i)
str += textForItem(m_standardItemModel->item(i)); str += textForItem(itemModel->index(i, 0));
}
QClipboard *clipboard = QApplication::clipboard(); QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(str, QClipboard::Selection); clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard); clipboard->setText(str, QClipboard::Clipboard);
@@ -647,7 +381,7 @@ void QmlProfilerStatisticsMainView::copyTableToClipboard() const
void QmlProfilerStatisticsMainView::copyRowToClipboard() const void QmlProfilerStatisticsMainView::copyRowToClipboard() const
{ {
QString str = textForItem(m_standardItemModel->itemFromIndex(selectedModelIndex())); QString str = textForItem(selectedModelIndex());
QClipboard *clipboard = QApplication::clipboard(); QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(str, QClipboard::Selection); clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard); clipboard->setText(str, QClipboard::Clipboard);
@@ -658,21 +392,18 @@ QmlProfilerStatisticsRelativesView::QmlProfilerStatisticsRelativesView(
m_model(model) m_model(model)
{ {
setViewDefaults(this); setViewDefaults(this);
QStandardItemModel *itemModel = new QStandardItemModel(this); auto sortModel = new QSortFilterProxyModel(this);
itemModel->setSortRole(SortRole); sortModel->setSourceModel(model);
setModel(itemModel); sortModel->setSortRole(SortRole);
sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
setModel(sortModel);
setRootIsDecorated(false); setRootIsDecorated(false);
updateHeader();
setSortingEnabled(true); setSortingEnabled(true);
sortByColumn(DEFAULT_SORT_COLUMN, Qt::DescendingOrder); sortByColumn(DEFAULT_SORT_COLUMN, Qt::DescendingOrder);
connect(this, &QAbstractItemView::activated, connect(this, &QAbstractItemView::activated,
this, &QmlProfilerStatisticsRelativesView::jumpToItem); this, &QmlProfilerStatisticsRelativesView::jumpToItem);
// Clear when new data available as the selection may be invalid now.
connect(m_model.get(), &QmlProfilerStatisticsRelativesModel::dataAvailable,
this, &QmlProfilerStatisticsRelativesView::clear);
} }
QmlProfilerStatisticsRelativesView::~QmlProfilerStatisticsRelativesView() QmlProfilerStatisticsRelativesView::~QmlProfilerStatisticsRelativesView()
@@ -681,100 +412,18 @@ QmlProfilerStatisticsRelativesView::~QmlProfilerStatisticsRelativesView()
void QmlProfilerStatisticsRelativesView::displayType(int typeIndex) void QmlProfilerStatisticsRelativesView::displayType(int typeIndex)
{ {
SortPreserver sorter(this); model()->setData(QModelIndex(), typeIndex, TypeIdRole);
rebuildTree(m_model->getData(typeIndex));
updateHeader();
resizeColumnToContents(RelativeLocation); resizeColumnToContents(RelativeLocation);
} }
void QmlProfilerStatisticsRelativesView::rebuildTree(
const QVector<QmlProfilerStatisticsRelativesModel::QmlStatisticsRelativesData> &data)
{
Q_ASSERT(treeModel());
treeModel()->clear();
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
const QVector<QmlEventType> &typeList = m_model->getTypes();
for (auto it = data.constBegin(); it != data.constEnd(); ++it) {
const QmlProfilerStatisticsRelativesModel::QmlStatisticsRelativesData &stats = *it;
const QmlEventType &type = stats.typeIndex != -1 ? typeList[stats.typeIndex]
: *rootEventType();
QList<QStandardItem *> newRow;
// ToDo: here we were going to search for the data in the other model
// maybe we should store the data in this model and get it here
// no indirections at this level of abstraction!
newRow << new StatisticsViewItem(
type.displayName().isEmpty() ? tr("<bytecode>") : type.displayName(),
type.displayName());
const QString typeName = QmlProfilerStatisticsModel::nameForType(type.rangeType());
newRow << new StatisticsViewItem(typeName, typeName);
newRow << new StatisticsViewItem(Timeline::formatTime(stats.duration),
stats.duration);
newRow << new StatisticsViewItem(QString::number(stats.calls), stats.calls);
newRow << new StatisticsViewItem(type.data().isEmpty() ? tr("Source code not available") :
type.data(), type.data());
QStandardItem *first = newRow.at(RelativeLocation);
first->setData(stats.typeIndex, TypeIdRole);
const QmlEventLocation location(type.location());
first->setData(location.filename(), FilenameRole);
first->setData(location.line(), LineRole);
first->setData(location.column(), ColumnRole);
if (stats.isRecursive) {
foreach (QStandardItem *item, newRow) {
item->setBackground(colors()->noteBackground);
item->setToolTip(tr("called recursively"));
}
}
foreach (QStandardItem *item, newRow)
item->setEditable(false);
topLevelItem->appendRow(newRow);
}
}
void QmlProfilerStatisticsRelativesView::clear()
{
if (treeModel()) {
SortPreserver sorter(this);
treeModel()->clear();
updateHeader();
}
}
void QmlProfilerStatisticsRelativesView::updateHeader()
{
const QmlProfilerStatisticsRelation relation = m_model->relation();
if (QStandardItemModel *model = treeModel()) {
model->setColumnCount(MaxRelativeField);
for (int i = 0; i < MaxRelativeField; ++i) {
model->setHeaderData(i, Qt::Horizontal,
displayHeader(static_cast<RelativeField>(i), relation));
}
}
}
QStandardItemModel *QmlProfilerStatisticsRelativesView::treeModel()
{
return qobject_cast<QStandardItemModel *>(model());
}
void QmlProfilerStatisticsRelativesView::jumpToItem(const QModelIndex &index) void QmlProfilerStatisticsRelativesView::jumpToItem(const QModelIndex &index)
{ {
if (treeModel()) {
QStandardItem *infoItem = treeModel()->item(index.row());
// show in editor // show in editor
getSourceLocation(infoItem, [this](const QString &fileName, int line, int column) { getSourceLocation(index, [this](const QString &fileName, int line, int column) {
emit gotoSourceLocation(fileName, line, column); emit gotoSourceLocation(fileName, line, column);
}); });
emit typeClicked(infoItem->data(TypeIdRole).toInt()); emit typeClicked(index.data(TypeIdRole).toInt());
}
} }
} // namespace Internal } // namespace Internal

View File

@@ -34,7 +34,6 @@
#include <utils/itemviews.h> #include <utils/itemviews.h>
#include <QPointer> #include <QPointer>
#include <QStandardItemModel>
namespace QmlProfiler { namespace QmlProfiler {
namespace Internal { namespace Internal {
@@ -49,7 +48,6 @@ public:
explicit QmlProfilerStatisticsView(QmlProfilerModelManager *profilerModelManager, explicit QmlProfilerStatisticsView(QmlProfilerModelManager *profilerModelManager,
QWidget *parent = nullptr); QWidget *parent = nullptr);
~QmlProfilerStatisticsView() override = default; ~QmlProfilerStatisticsView() override = default;
void clear() override;
QString summary(const QVector<int> &typeIds) const; QString summary(const QVector<int> &typeIds) const;
QStringList details(int typeId) const; QStringList details(int typeId) const;
@@ -89,11 +87,8 @@ public:
void setShowExtendedStatistics(bool); void setShowExtendedStatistics(bool);
bool showExtendedStatistics() const; bool showExtendedStatistics() const;
void clear();
void jumpToItem(const QModelIndex &index); void jumpToItem(const QModelIndex &index);
void selectType(int typeIndex); void selectType(int typeIndex);
void buildModel();
void updateNotes(int typeIndex);
void restrictToFeatures(quint64 features); void restrictToFeatures(quint64 features);
bool isRestrictedToRange() const; bool isRestrictedToRange() const;
@@ -106,14 +101,10 @@ signals:
void typeSelected(int typeIndex); void typeSelected(int typeIndex);
private: private:
void selectItem(const QStandardItem *item); void selectItem(const QModelIndex &index);
void setHeaderLabels(); QString textForItem(const QModelIndex &index) const;
void parseModel();
QStandardItem *itemFromIndex(const QModelIndex &index) const;
QString textForItem(QStandardItem *item) const;
std::unique_ptr<QmlProfilerStatisticsModel> m_model; std::unique_ptr<QmlProfilerStatisticsModel> m_model;
std::unique_ptr<QStandardItemModel> m_standardItemModel;
bool m_showExtendedStatistics = false; bool m_showExtendedStatistics = false;
}; };
@@ -126,17 +117,12 @@ public:
void displayType(int typeIndex); void displayType(int typeIndex);
void jumpToItem(const QModelIndex &); void jumpToItem(const QModelIndex &);
void clear();
signals: signals:
void typeClicked(int typeIndex); void typeClicked(int typeIndex);
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber); void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
private: private:
void rebuildTree(
const QVector<QmlProfilerStatisticsRelativesModel::QmlStatisticsRelativesData> &data);
void updateHeader();
QStandardItemModel *treeModel();
std::unique_ptr<QmlProfilerStatisticsRelativesModel> m_model; std::unique_ptr<QmlProfilerStatisticsRelativesModel> m_model;
}; };