forked from qt-creator/qt-creator
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:
@@ -105,11 +105,13 @@ void QmlProfilerStatisticsModel::restrictToFeatures(quint64 features)
|
||||
return;
|
||||
|
||||
clear();
|
||||
beginResetModel();
|
||||
if (!m_modelManager->replayEvents(m_modelManager->traceTime()->startTime(),
|
||||
m_modelManager->traceTime()->endTime(),
|
||||
std::bind(&QmlProfilerStatisticsModel::loadEvent,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2))) {
|
||||
endResetModel();
|
||||
emit m_modelManager->error(tr("Could not re-read events from temporary trace file."));
|
||||
clear();
|
||||
} else {
|
||||
@@ -195,6 +197,7 @@ QString QmlProfilerStatisticsModel::summary(const QVector<int> &typeIds) const
|
||||
|
||||
void QmlProfilerStatisticsModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_rootDuration = 0;
|
||||
m_data.clear();
|
||||
m_notes.clear();
|
||||
@@ -204,6 +207,7 @@ void QmlProfilerStatisticsModel::clear()
|
||||
m_calleesModel->clear();
|
||||
if (!m_callersModel.isNull())
|
||||
m_callersModel->clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative,
|
||||
@@ -400,12 +404,21 @@ QVariant QmlProfilerStatisticsModel::headerData(int section, Qt::Orientation ori
|
||||
|
||||
void QmlProfilerStatisticsModel::modelManagerStateChanged()
|
||||
{
|
||||
if (m_modelManager->state() == QmlProfilerModelManager::ClearingData)
|
||||
switch (m_modelManager->state()) {
|
||||
case QmlProfilerModelManager::ClearingData:
|
||||
clear();
|
||||
break;
|
||||
case QmlProfilerModelManager::AcquiringData:
|
||||
beginResetModel();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
|
||||
{
|
||||
static const QVector<int> noteRoles({Qt::ToolTipRole, Qt::TextColorRole});
|
||||
const QmlProfilerNotesModel *notesModel = m_modelManager->notesModel();
|
||||
if (typeIndex == -1) {
|
||||
m_notes.clear();
|
||||
@@ -418,6 +431,7 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
|
||||
} else {
|
||||
note.append(QStringLiteral("\n")).append(notesModel->text(noteId));
|
||||
}
|
||||
emit dataChanged(index(noteType, 0), index(noteType, MainDetails), noteRoles);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -430,6 +444,7 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
|
||||
newNotes << notesModel->text(it->toInt());
|
||||
}
|
||||
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)
|
||||
stats.finalize();
|
||||
endResetModel();
|
||||
|
||||
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
|
||||
{
|
||||
return m_data.count();
|
||||
@@ -718,10 +749,12 @@ int QmlProfilerStatisticsRelativesModel::count() const
|
||||
|
||||
void QmlProfilerStatisticsRelativesModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_relativeTypeIndex = std::numeric_limits<int>::max();
|
||||
m_data.clear();
|
||||
m_callStack.clear();
|
||||
m_compileStack.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
} // namespace QmlProfiler
|
||||
|
@@ -218,6 +218,9 @@ public:
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, 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:
|
||||
void dataAvailable();
|
||||
|
||||
|
@@ -33,7 +33,6 @@
|
||||
|
||||
#include <QUrl>
|
||||
#include <QHash>
|
||||
#include <QStandardItem>
|
||||
#include <QHeaderView>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
@@ -41,6 +40,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMenu>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <functional>
|
||||
|
||||
@@ -49,64 +49,6 @@ namespace Internal {
|
||||
|
||||
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)
|
||||
{
|
||||
view->setFrameStyle(QFrame::NoFrame);
|
||||
@@ -116,68 +58,12 @@ static void setViewDefaults(Utils::TreeView *view)
|
||||
header->setMinimumSectionSize(50);
|
||||
}
|
||||
|
||||
static QString displayHeader(MainField header)
|
||||
{
|
||||
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,
|
||||
static void getSourceLocation(const QModelIndex &index,
|
||||
std::function<void (const QString &, int, int)> receiver)
|
||||
{
|
||||
int line = infoItem->data(LineRole).toInt();
|
||||
int column = infoItem->data(ColumnRole).toInt();
|
||||
QString fileName = infoItem->data(FilenameRole).toString();
|
||||
const int line = index.data(LineRole).toInt();
|
||||
const int column = index.data(ColumnRole).toInt();
|
||||
const QString fileName = index.data(FilenameRole).toString();
|
||||
if (line != -1 && !fileName.isEmpty())
|
||||
receiver(fileName, line, column);
|
||||
}
|
||||
@@ -234,13 +120,6 @@ QmlProfilerStatisticsView::QmlProfilerStatisticsView(QmlProfilerModelManager *pr
|
||||
setLayout(groupLayout);
|
||||
}
|
||||
|
||||
void QmlProfilerStatisticsView::clear()
|
||||
{
|
||||
m_mainView->clear();
|
||||
m_calleesView->clear();
|
||||
m_callersView->clear();
|
||||
}
|
||||
|
||||
QString QmlProfilerStatisticsView::summary(const QVector<int> &typeIds) const
|
||||
{
|
||||
return m_mainView->summary(typeIds);
|
||||
@@ -344,33 +223,30 @@ QmlProfilerStatisticsMainView::QmlProfilerStatisticsMainView(QmlProfilerStatisti
|
||||
setViewDefaults(this);
|
||||
setObjectName(QLatin1String("QmlProfilerEventsTable"));
|
||||
|
||||
m_standardItemModel.reset(new QStandardItemModel);
|
||||
m_standardItemModel->setSortRole(SortRole);
|
||||
setModel(m_standardItemModel.get());
|
||||
connect(this, &QAbstractItemView::activated, this, &QmlProfilerStatisticsMainView::jumpToItem);
|
||||
auto sortModel = new QSortFilterProxyModel(this);
|
||||
sortModel->setSourceModel(model);
|
||||
sortModel->setSortRole(SortRole);
|
||||
sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
sortModel->setFilterRole(FilterRole);
|
||||
sortModel->setFilterKeyColumn(MainType);
|
||||
sortModel->setFilterFixedString("+");
|
||||
|
||||
connect(m_model.get(), &QmlProfilerStatisticsModel::dataAvailable,
|
||||
this, &QmlProfilerStatisticsMainView::buildModel);
|
||||
connect(m_model.get(), &QmlProfilerStatisticsModel::notesAvailable,
|
||||
this, &QmlProfilerStatisticsMainView::updateNotes);
|
||||
setModel(sortModel);
|
||||
|
||||
connect(this, &QAbstractItemView::activated, this, &QmlProfilerStatisticsMainView::jumpToItem);
|
||||
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(DEFAULT_SORT_COLUMN, Qt::DescendingOrder);
|
||||
|
||||
buildModel();
|
||||
setShowExtendedStatistics(m_showExtendedStatistics);
|
||||
setRootIsDecorated(false);
|
||||
|
||||
resizeColumnToContents(MainLocation);
|
||||
resizeColumnToContents(MainType);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -393,59 +269,6 @@ bool QmlProfilerStatisticsMainView::showExtendedStatistics() const
|
||||
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> ¬eList = 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)
|
||||
{
|
||||
m_model->restrictToFeatures(features);
|
||||
@@ -466,132 +289,40 @@ QStringList QmlProfilerStatisticsMainView::details(int typeId) const
|
||||
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
|
||||
{
|
||||
QModelIndex index = selectedModelIndex();
|
||||
if (!index.isValid())
|
||||
return -1;
|
||||
QStandardItem *item = m_standardItemModel->item(index.row());
|
||||
return item->data(TypeIdRole).toInt();
|
||||
return model()->data(selectedModelIndex(), TypeIdRole).toInt();
|
||||
}
|
||||
|
||||
void QmlProfilerStatisticsMainView::jumpToItem(const QModelIndex &index)
|
||||
{
|
||||
QStandardItem *infoItem = itemFromIndex(index);
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
// 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.
|
||||
QModelIndex index = m_standardItemModel->indexFromItem(item);
|
||||
if (index != currentIndex()) {
|
||||
setCurrentIndex(index);
|
||||
|
||||
// show in callers/callees subwindow
|
||||
emit typeSelected(itemFromIndex(index)->data(TypeIdRole).toInt());
|
||||
emit typeSelected(index.data(TypeIdRole).toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerStatisticsMainView::selectType(int typeIndex)
|
||||
{
|
||||
for (int i = 0; i < m_standardItemModel->rowCount(); i++) {
|
||||
QStandardItem *infoItem = m_standardItemModel->item(i);
|
||||
if (infoItem->data(TypeIdRole).toInt() == typeIndex) {
|
||||
selectItem(infoItem);
|
||||
QAbstractItemModel *itemModel = model();
|
||||
for (int i = 0; i < itemModel->rowCount(); i++) {
|
||||
QModelIndex index = itemModel->index(i, MainLocation);
|
||||
if (itemModel->data(index, TypeIdRole).toInt() == typeIndex) {
|
||||
selectItem(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -606,16 +337,15 @@ QModelIndex QmlProfilerStatisticsMainView::selectedModelIndex() const
|
||||
return sel.first();
|
||||
}
|
||||
|
||||
QString QmlProfilerStatisticsMainView::textForItem(QStandardItem *item) const
|
||||
QString QmlProfilerStatisticsMainView::textForItem(const QModelIndex &index) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
// item's data
|
||||
int colCount = m_standardItemModel->columnCount();
|
||||
const int colCount = model()->columnCount();
|
||||
for (int j = 0; j < colCount; ++j) {
|
||||
QStandardItem *colItem = item->parent() ? item->parent()->child(item->row(),j) :
|
||||
m_standardItemModel->item(item->row(),j);
|
||||
str += colItem->data(Qt::DisplayRole).toString();
|
||||
const QModelIndex cellIndex = model()->index(index.row(), j);
|
||||
str += cellIndex.data(Qt::DisplayRole).toString();
|
||||
if (j < colCount-1) str += QLatin1Char('\t');
|
||||
}
|
||||
str += QLatin1Char('\n');
|
||||
@@ -626,20 +356,24 @@ QString QmlProfilerStatisticsMainView::textForItem(QStandardItem *item) const
|
||||
void QmlProfilerStatisticsMainView::copyTableToClipboard() const
|
||||
{
|
||||
QString str;
|
||||
|
||||
const QAbstractItemModel *itemModel = model();
|
||||
|
||||
// headers
|
||||
int columnCount = m_standardItemModel->columnCount();
|
||||
const int columnCount = itemModel->columnCount();
|
||||
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)
|
||||
str += QLatin1Char('\t');
|
||||
else
|
||||
str += QLatin1Char('\n');
|
||||
}
|
||||
|
||||
// data
|
||||
int rowCount = m_standardItemModel->rowCount();
|
||||
for (int i = 0; i != rowCount; ++i) {
|
||||
str += textForItem(m_standardItemModel->item(i));
|
||||
}
|
||||
const int rowCount = itemModel->rowCount();
|
||||
for (int i = 0; i != rowCount; ++i)
|
||||
str += textForItem(itemModel->index(i, 0));
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(str, QClipboard::Selection);
|
||||
clipboard->setText(str, QClipboard::Clipboard);
|
||||
@@ -647,7 +381,7 @@ void QmlProfilerStatisticsMainView::copyTableToClipboard() const
|
||||
|
||||
void QmlProfilerStatisticsMainView::copyRowToClipboard() const
|
||||
{
|
||||
QString str = textForItem(m_standardItemModel->itemFromIndex(selectedModelIndex()));
|
||||
QString str = textForItem(selectedModelIndex());
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(str, QClipboard::Selection);
|
||||
clipboard->setText(str, QClipboard::Clipboard);
|
||||
@@ -658,21 +392,18 @@ QmlProfilerStatisticsRelativesView::QmlProfilerStatisticsRelativesView(
|
||||
m_model(model)
|
||||
{
|
||||
setViewDefaults(this);
|
||||
QStandardItemModel *itemModel = new QStandardItemModel(this);
|
||||
itemModel->setSortRole(SortRole);
|
||||
setModel(itemModel);
|
||||
auto sortModel = new QSortFilterProxyModel(this);
|
||||
sortModel->setSourceModel(model);
|
||||
sortModel->setSortRole(SortRole);
|
||||
sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
setModel(sortModel);
|
||||
setRootIsDecorated(false);
|
||||
updateHeader();
|
||||
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(DEFAULT_SORT_COLUMN, Qt::DescendingOrder);
|
||||
|
||||
connect(this, &QAbstractItemView::activated,
|
||||
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()
|
||||
@@ -681,100 +412,18 @@ QmlProfilerStatisticsRelativesView::~QmlProfilerStatisticsRelativesView()
|
||||
|
||||
void QmlProfilerStatisticsRelativesView::displayType(int typeIndex)
|
||||
{
|
||||
SortPreserver sorter(this);
|
||||
rebuildTree(m_model->getData(typeIndex));
|
||||
|
||||
updateHeader();
|
||||
model()->setData(QModelIndex(), typeIndex, TypeIdRole);
|
||||
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)
|
||||
{
|
||||
if (treeModel()) {
|
||||
QStandardItem *infoItem = treeModel()->item(index.row());
|
||||
// show in editor
|
||||
getSourceLocation(infoItem, [this](const QString &fileName, int line, int column) {
|
||||
emit gotoSourceLocation(fileName, line, column);
|
||||
});
|
||||
// show in editor
|
||||
getSourceLocation(index, [this](const QString &fileName, int line, int column) {
|
||||
emit gotoSourceLocation(fileName, line, column);
|
||||
});
|
||||
|
||||
emit typeClicked(infoItem->data(TypeIdRole).toInt());
|
||||
}
|
||||
emit typeClicked(index.data(TypeIdRole).toInt());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include <utils/itemviews.h>
|
||||
|
||||
#include <QPointer>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
@@ -49,7 +48,6 @@ public:
|
||||
explicit QmlProfilerStatisticsView(QmlProfilerModelManager *profilerModelManager,
|
||||
QWidget *parent = nullptr);
|
||||
~QmlProfilerStatisticsView() override = default;
|
||||
void clear() override;
|
||||
|
||||
QString summary(const QVector<int> &typeIds) const;
|
||||
QStringList details(int typeId) const;
|
||||
@@ -89,11 +87,8 @@ public:
|
||||
void setShowExtendedStatistics(bool);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
void clear();
|
||||
void jumpToItem(const QModelIndex &index);
|
||||
void selectType(int typeIndex);
|
||||
void buildModel();
|
||||
void updateNotes(int typeIndex);
|
||||
|
||||
void restrictToFeatures(quint64 features);
|
||||
bool isRestrictedToRange() const;
|
||||
@@ -106,14 +101,10 @@ signals:
|
||||
void typeSelected(int typeIndex);
|
||||
|
||||
private:
|
||||
void selectItem(const QStandardItem *item);
|
||||
void setHeaderLabels();
|
||||
void parseModel();
|
||||
QStandardItem *itemFromIndex(const QModelIndex &index) const;
|
||||
QString textForItem(QStandardItem *item) const;
|
||||
void selectItem(const QModelIndex &index);
|
||||
QString textForItem(const QModelIndex &index) const;
|
||||
|
||||
std::unique_ptr<QmlProfilerStatisticsModel> m_model;
|
||||
std::unique_ptr<QStandardItemModel> m_standardItemModel;
|
||||
bool m_showExtendedStatistics = false;
|
||||
};
|
||||
|
||||
@@ -126,17 +117,12 @@ public:
|
||||
|
||||
void displayType(int typeIndex);
|
||||
void jumpToItem(const QModelIndex &);
|
||||
void clear();
|
||||
|
||||
signals:
|
||||
void typeClicked(int typeIndex);
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
|
||||
private:
|
||||
void rebuildTree(
|
||||
const QVector<QmlProfilerStatisticsRelativesModel::QmlStatisticsRelativesData> &data);
|
||||
void updateHeader();
|
||||
QStandardItemModel *treeModel();
|
||||
|
||||
std::unique_ptr<QmlProfilerStatisticsRelativesModel> m_model;
|
||||
};
|
||||
|
Reference in New Issue
Block a user