2013-08-08 13:28:08 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-08-08 13:28:08 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2013-08-08 13:28:08 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2013-08-08 13:28:08 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2014-02-18 17:32:20 +01:00
|
|
|
#include "qmlprofilerdatamodel.h"
|
2014-02-12 17:35:08 +01:00
|
|
|
#include "qmlprofilermodelmanager.h"
|
2014-10-27 17:41:22 +01:00
|
|
|
#include "qmlprofilernotesmodel.h"
|
2015-09-10 16:03:21 +02:00
|
|
|
#include "qmlprofilerdetailsrewriter.h"
|
2016-05-02 12:18:57 +02:00
|
|
|
#include "qmlprofilereventtypes.h"
|
2016-04-28 16:13:16 +02:00
|
|
|
#include "qmltypedevent.h"
|
2015-09-10 16:03:21 +02:00
|
|
|
|
2013-08-08 13:28:08 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <QUrl>
|
|
|
|
|
#include <QDebug>
|
2016-04-28 16:13:16 +02:00
|
|
|
#include <QStack>
|
2016-04-29 18:38:54 +02:00
|
|
|
#include <QTemporaryFile>
|
2014-03-26 17:23:12 +01:00
|
|
|
#include <algorithm>
|
2013-08-08 13:28:08 +02:00
|
|
|
|
|
|
|
|
namespace QmlProfiler {
|
|
|
|
|
|
2015-09-10 16:03:21 +02:00
|
|
|
class QmlProfilerDataModel::QmlProfilerDataModelPrivate
|
2014-02-18 18:25:57 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2016-04-28 16:13:16 +02:00
|
|
|
void rewriteType(int typeIndex);
|
|
|
|
|
int resolveType(const QmlEventType &type);
|
|
|
|
|
int resolveStackTop();
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
QVector<QmlEventType> eventTypes;
|
|
|
|
|
QHash<QmlEventType, int> eventTypeIds;
|
2015-09-10 16:03:21 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
QStack<QmlTypedEvent> rangesInProgress;
|
|
|
|
|
|
2015-09-10 16:03:21 +02:00
|
|
|
QmlProfilerModelManager *modelManager;
|
|
|
|
|
int modelId;
|
|
|
|
|
Internal::QmlProfilerDetailsRewriter *detailsRewriter;
|
2016-04-29 18:38:54 +02:00
|
|
|
|
|
|
|
|
QTemporaryFile file;
|
|
|
|
|
QDataStream eventStream;
|
2014-02-18 18:25:57 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
QString getDisplayName(const QmlEventType &event)
|
2013-08-08 13:28:08 +02:00
|
|
|
{
|
2014-06-23 14:29:40 +02:00
|
|
|
if (event.location.filename.isEmpty()) {
|
|
|
|
|
return QmlProfilerDataModel::tr("<bytecode>");
|
|
|
|
|
} else {
|
|
|
|
|
const QString filePath = QUrl(event.location.filename).path();
|
|
|
|
|
return filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') +
|
|
|
|
|
QString::number(event.location.line);
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
QString getInitialDetails(const QmlEventType &event)
|
2013-08-08 13:28:08 +02:00
|
|
|
{
|
|
|
|
|
QString details;
|
|
|
|
|
// generate details string
|
2014-06-13 19:16:35 +02:00
|
|
|
if (!event.data.isEmpty()) {
|
2014-06-13 16:33:30 +02:00
|
|
|
details = event.data;
|
2014-06-18 11:33:11 +02:00
|
|
|
details = details.replace(QLatin1Char('\n'),QLatin1Char(' ')).simplified();
|
2014-02-19 11:22:25 +01:00
|
|
|
if (details.isEmpty()) {
|
2016-05-02 12:18:57 +02:00
|
|
|
if (event.rangeType == Javascript)
|
2014-06-13 19:16:35 +02:00
|
|
|
details = QmlProfilerDataModel::tr("anonymous function");
|
2014-02-19 11:22:25 +01:00
|
|
|
} else {
|
|
|
|
|
QRegExp rewrite(QLatin1String("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)"));
|
|
|
|
|
bool match = rewrite.exactMatch(details);
|
|
|
|
|
if (match)
|
|
|
|
|
details = rewrite.cap(1) + QLatin1String(": ") + rewrite.cap(3);
|
2014-02-21 12:11:27 +01:00
|
|
|
if (details.startsWith(QLatin1String("file://")) ||
|
|
|
|
|
details.startsWith(QLatin1String("qrc:/")))
|
2014-02-19 11:22:25 +01:00
|
|
|
details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1);
|
|
|
|
|
}
|
2016-05-02 12:18:57 +02:00
|
|
|
} else if (event.rangeType == Painting) {
|
2014-06-23 14:29:40 +02:00
|
|
|
// QtQuick1 animations always run in GUI thread.
|
|
|
|
|
details = QmlProfilerDataModel::tr("GUI Thread");
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return details;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 16:03:21 +02:00
|
|
|
QString QmlProfilerDataModel::formatTime(qint64 timestamp)
|
|
|
|
|
{
|
|
|
|
|
if (timestamp < 1e6)
|
|
|
|
|
return QString::number(timestamp/1e3f,'f',3) + trUtf8(" \xc2\xb5s");
|
|
|
|
|
if (timestamp < 1e9)
|
|
|
|
|
return QString::number(timestamp/1e6f,'f',3) + tr(" ms");
|
|
|
|
|
|
|
|
|
|
return QString::number(timestamp/1e9f,'f',3) + tr(" s");
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-18 17:32:20 +01:00
|
|
|
QmlProfilerDataModel::QmlProfilerDataModel(Utils::FileInProjectFinder *fileFinder,
|
2015-09-10 16:03:21 +02:00
|
|
|
QmlProfilerModelManager *parent) :
|
|
|
|
|
QObject(parent), d_ptr(new QmlProfilerDataModelPrivate)
|
2013-08-08 13:28:08 +02:00
|
|
|
{
|
2014-02-18 18:25:57 +01:00
|
|
|
Q_D(QmlProfilerDataModel);
|
2015-09-10 16:03:21 +02:00
|
|
|
Q_ASSERT(parent);
|
|
|
|
|
d->modelManager = parent;
|
|
|
|
|
d->detailsRewriter = new QmlProfilerDetailsRewriter(this, fileFinder);
|
|
|
|
|
d->modelId = d->modelManager->registerModelProxy();
|
2015-09-10 17:11:21 +02:00
|
|
|
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString,
|
|
|
|
|
this, &QmlProfilerDataModel::detailsChanged);
|
|
|
|
|
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
|
2016-04-28 16:13:16 +02:00
|
|
|
this, &QmlProfilerDataModel::allTypesLoaded);
|
2016-04-29 18:38:54 +02:00
|
|
|
d->file.open();
|
|
|
|
|
d->eventStream.setDevice(&d->file);
|
2014-02-18 17:32:20 +01:00
|
|
|
}
|
2014-02-12 17:50:55 +01:00
|
|
|
|
2015-09-10 16:03:21 +02:00
|
|
|
QmlProfilerDataModel::~QmlProfilerDataModel()
|
|
|
|
|
{
|
|
|
|
|
Q_D(QmlProfilerDataModel);
|
|
|
|
|
delete d->detailsRewriter;
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
const QVector<QmlEventType> &QmlProfilerDataModel::eventTypes() const
|
2014-06-13 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
Q_D(const QmlProfilerDataModel);
|
|
|
|
|
return d->eventTypes;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-14 16:44:45 +02:00
|
|
|
void QmlProfilerDataModel::setData(qint64 traceStart, qint64 traceEnd,
|
2016-04-26 11:50:59 +02:00
|
|
|
const QVector<QmlEventType> &types,
|
|
|
|
|
const QVector<QmlEvent> &events)
|
2014-08-12 13:39:22 +02:00
|
|
|
{
|
|
|
|
|
Q_D(QmlProfilerDataModel);
|
2014-10-14 16:44:45 +02:00
|
|
|
d->modelManager->traceTime()->setTime(traceStart, traceEnd);
|
2014-08-12 13:39:22 +02:00
|
|
|
d->eventTypes = types;
|
|
|
|
|
for (int id = 0; id < types.count(); ++id)
|
|
|
|
|
d->eventTypeIds[types[id]] = id;
|
2016-04-28 16:13:16 +02:00
|
|
|
|
2016-04-29 18:38:54 +02:00
|
|
|
foreach (const QmlEvent &event, events) {
|
2016-04-28 16:13:16 +02:00
|
|
|
d->modelManager->dispatch(event, d->eventTypes[event.typeIndex()]);
|
2016-04-29 18:38:54 +02:00
|
|
|
d->eventStream << event;
|
|
|
|
|
}
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-18 17:32:20 +01:00
|
|
|
void QmlProfilerDataModel::clear()
|
2013-08-08 13:28:08 +02:00
|
|
|
{
|
2014-02-18 18:25:57 +01:00
|
|
|
Q_D(QmlProfilerDataModel);
|
2016-04-29 18:38:54 +02:00
|
|
|
d->file.remove();
|
|
|
|
|
d->file.open();
|
|
|
|
|
d->eventStream.setDevice(&d->file);
|
2014-06-13 16:34:30 +02:00
|
|
|
d->eventTypes.clear();
|
|
|
|
|
d->eventTypeIds.clear();
|
2016-04-28 16:13:16 +02:00
|
|
|
d->rangesInProgress.clear();
|
2015-09-10 16:03:21 +02:00
|
|
|
d->detailsRewriter->clearRequests();
|
2014-02-18 17:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QmlProfilerDataModel::isEmpty() const
|
|
|
|
|
{
|
2014-02-18 18:25:57 +01:00
|
|
|
Q_D(const QmlProfilerDataModel);
|
2016-04-29 18:38:54 +02:00
|
|
|
return d->file.pos() == 0;
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
inline static uint qHash(const QmlEventType &type)
|
2014-06-13 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
return qHash(type.location.filename) ^
|
|
|
|
|
((type.location.line & 0xfff) | // 12 bits of line number
|
|
|
|
|
((type.message << 12) & 0xf000) | // 4 bits of message
|
|
|
|
|
((type.location.column << 16) & 0xff0000) | // 8 bits of column
|
|
|
|
|
((type.rangeType << 24) & 0xf000000) | // 4 bits of rangeType
|
|
|
|
|
((type.detailType << 28) & 0xf0000000)); // 4 bits of detailType
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
inline static bool operator==(const QmlEventType &type1,
|
|
|
|
|
const QmlEventType &type2)
|
2014-06-13 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
return type1.message == type2.message && type1.rangeType == type2.rangeType &&
|
|
|
|
|
type1.detailType == type2.detailType && type1.location.line == type2.location.line &&
|
|
|
|
|
type1.location.column == type2.location.column &&
|
|
|
|
|
// compare filename last as it's expensive.
|
|
|
|
|
type1.location.filename == type2.location.filename;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeIndex)
|
2013-08-08 13:28:08 +02:00
|
|
|
{
|
2016-04-28 16:13:16 +02:00
|
|
|
QmlEventType &type = eventTypes[typeIndex];
|
|
|
|
|
type.displayName = getDisplayName(type);
|
|
|
|
|
type.data = getInitialDetails(type);
|
2013-08-08 13:28:08 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
// Only bindings and signal handlers need rewriting
|
|
|
|
|
if (type.rangeType != Binding && type.rangeType != HandlingSignal)
|
|
|
|
|
return;
|
2013-08-08 13:28:08 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
// There is no point in looking for invalid locations
|
|
|
|
|
if (type.location.filename.isEmpty() || type.location.line < 0 || type.location.column < 0)
|
|
|
|
|
return;
|
2013-08-08 13:28:08 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
detailsRewriter->requestDetailsForLocation(typeIndex, type.location);
|
|
|
|
|
}
|
2013-08-08 13:28:08 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveType(const QmlEventType &type)
|
|
|
|
|
{
|
|
|
|
|
QHash<QmlEventType, int>::ConstIterator it = eventTypeIds.constFind(type);
|
2013-08-08 13:28:08 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
int typeIndex = -1;
|
|
|
|
|
if (it != eventTypeIds.constEnd()) {
|
|
|
|
|
typeIndex = it.value();
|
|
|
|
|
} else {
|
|
|
|
|
typeIndex = eventTypes.size();
|
|
|
|
|
eventTypeIds[type] = typeIndex;
|
|
|
|
|
eventTypes.append(type);
|
|
|
|
|
rewriteType(typeIndex);
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
2016-04-28 16:13:16 +02:00
|
|
|
return typeIndex;
|
|
|
|
|
}
|
2013-08-08 13:28:08 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveStackTop()
|
|
|
|
|
{
|
|
|
|
|
if (rangesInProgress.isEmpty())
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
QmlTypedEvent &typedEvent = rangesInProgress.top();
|
|
|
|
|
int typeIndex = typedEvent.event.typeIndex();
|
|
|
|
|
if (typeIndex >= 0)
|
|
|
|
|
return typeIndex;
|
|
|
|
|
|
|
|
|
|
typeIndex = resolveType(typedEvent.type);
|
|
|
|
|
typedEvent.event.setTypeIndex(typeIndex);
|
2016-04-29 18:38:54 +02:00
|
|
|
eventStream << typedEvent.event;
|
|
|
|
|
modelManager->dispatch(typedEvent.event, eventTypes[typeIndex]);
|
2016-04-28 16:13:16 +02:00
|
|
|
return typeIndex;
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
void QmlProfilerDataModel::addEvent(const QmlEvent &event, const QmlEventType &type)
|
2013-08-08 13:28:08 +02:00
|
|
|
{
|
2014-02-18 18:25:57 +01:00
|
|
|
Q_D(QmlProfilerDataModel);
|
2014-06-13 16:34:30 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
// RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore,
|
|
|
|
|
// all ranges are perfectly nested. This is why we can defer the type resolution until either
|
|
|
|
|
// the range ends or a child range starts. With only the information in RangeStart we wouldn't
|
|
|
|
|
// be able to uniquely identify the event type.
|
|
|
|
|
Message rangeStage = type.rangeType == MaximumRangeType ? type.message : event.rangeStage();
|
|
|
|
|
switch (rangeStage) {
|
|
|
|
|
case RangeStart:
|
|
|
|
|
d->resolveStackTop();
|
|
|
|
|
d->rangesInProgress.push(QmlTypedEvent({event, type}));
|
|
|
|
|
break;
|
|
|
|
|
case RangeEnd: {
|
|
|
|
|
int typeIndex = d->resolveStackTop();
|
|
|
|
|
QTC_ASSERT(typeIndex != -1, break);
|
2016-04-29 18:38:54 +02:00
|
|
|
QmlEvent appended = event;
|
2016-04-28 16:13:16 +02:00
|
|
|
appended.setTypeIndex(typeIndex);
|
2016-04-29 18:38:54 +02:00
|
|
|
d->eventStream << appended;
|
2016-04-28 16:13:16 +02:00
|
|
|
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
|
|
|
|
|
d->rangesInProgress.pop();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case RangeData:
|
|
|
|
|
d->rangesInProgress.top().type.data = type.data;
|
|
|
|
|
break;
|
|
|
|
|
case RangeLocation:
|
|
|
|
|
d->rangesInProgress.top().type.location = type.location;
|
|
|
|
|
break;
|
|
|
|
|
default: {
|
2016-04-29 18:38:54 +02:00
|
|
|
QmlEvent appended = event;
|
2016-04-28 16:13:16 +02:00
|
|
|
int typeIndex = d->resolveType(type);
|
|
|
|
|
appended.setTypeIndex(typeIndex);
|
2016-04-29 18:38:54 +02:00
|
|
|
d->eventStream << appended;
|
2016-04-28 16:13:16 +02:00
|
|
|
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
|
|
|
|
|
break;
|
2014-06-13 16:34:30 +02:00
|
|
|
}
|
2016-04-28 16:13:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
|
|
|
|
|
QmlProfilerModelManager::EventLoader loader) const
|
|
|
|
|
{
|
|
|
|
|
Q_D(const QmlProfilerDataModel);
|
|
|
|
|
QStack<QmlEvent> stack;
|
2016-04-29 18:38:54 +02:00
|
|
|
QmlEvent event;
|
|
|
|
|
QFile file(d->file.fileName());
|
|
|
|
|
file.open(QIODevice::ReadOnly);
|
|
|
|
|
QDataStream stream(&file);
|
|
|
|
|
while (!stream.atEnd()) {
|
|
|
|
|
stream >> event;
|
|
|
|
|
if (stream.status() == QDataStream::ReadPastEnd)
|
|
|
|
|
break;
|
|
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
const QmlEventType &type = d->eventTypes[event.typeIndex()];
|
|
|
|
|
if (rangeStart != -1 && rangeEnd != -1) {
|
|
|
|
|
if (event.timestamp() < rangeStart) {
|
|
|
|
|
if (type.rangeType != MaximumRangeType) {
|
|
|
|
|
if (event.rangeStage() == RangeStart)
|
|
|
|
|
stack.push(event);
|
|
|
|
|
else if (event.rangeStage() == RangeEnd)
|
|
|
|
|
stack.pop();
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
} else if (event.timestamp() > rangeEnd) {
|
|
|
|
|
if (type.rangeType != MaximumRangeType) {
|
|
|
|
|
if (event.rangeStage() == RangeEnd) {
|
|
|
|
|
if (stack.isEmpty()) {
|
|
|
|
|
QmlEvent endEvent(event);
|
|
|
|
|
endEvent.setTimestamp(rangeEnd);
|
|
|
|
|
loader(event, d->eventTypes[event.typeIndex()]);
|
|
|
|
|
} else {
|
|
|
|
|
stack.pop();
|
|
|
|
|
}
|
|
|
|
|
} else if (event.rangeStage() == RangeStart) {
|
|
|
|
|
stack.push(event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
} else if (!stack.isEmpty()) {
|
|
|
|
|
foreach (QmlEvent stashed, stack) {
|
|
|
|
|
stashed.setTimestamp(rangeStart);
|
|
|
|
|
loader(stashed, d->eventTypes[stashed.typeIndex()]);
|
|
|
|
|
}
|
|
|
|
|
stack.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-13 16:34:30 +02:00
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
loader(event, type);
|
|
|
|
|
}
|
2013-08-08 13:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
void QmlProfilerDataModel::finalize()
|
2014-02-18 17:32:20 +01:00
|
|
|
{
|
2014-02-18 18:25:57 +01:00
|
|
|
Q_D(QmlProfilerDataModel);
|
2016-04-29 18:38:54 +02:00
|
|
|
d->file.flush();
|
2016-04-28 16:13:16 +02:00
|
|
|
d->detailsRewriter->reloadDocuments();
|
2014-02-18 17:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:13:16 +02:00
|
|
|
void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString)
|
2015-09-10 16:03:21 +02:00
|
|
|
{
|
|
|
|
|
Q_D(QmlProfilerDataModel);
|
2016-04-28 16:13:16 +02:00
|
|
|
QTC_ASSERT(requestId < d->eventTypes.count(), return);
|
|
|
|
|
d->eventTypes[requestId].data = newString;
|
2015-09-10 16:03:21 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:02:54 +02:00
|
|
|
} // namespace QmlProfiler
|