forked from qt-creator/qt-creator
QmlProfiler: fix progress bar visibilty for loading traces
Move the main part of the loading work into a background thread and show the standard progress indicator for the "reading file" part of the load operation. The load operation can be canceled now. Change-Id: I4cb3b762072ab4a0665dcf9d4a39d6d6630d22e8 Task-number: QTCREATORBUG-11822 Reviewed-by: Ulf Hermann <ulf.hermann@theqtcompany.com>
This commit is contained in:
@@ -36,6 +36,7 @@ namespace Constants {
|
|||||||
|
|
||||||
const char ATTACH[] = "Menu.Analyzer.Attach";
|
const char ATTACH[] = "Menu.Analyzer.Attach";
|
||||||
const char TraceFileExtension[] = ".qtd";
|
const char TraceFileExtension[] = ".qtd";
|
||||||
|
const char TASK_LOAD[] = "QmlProfiler.TaskLoad";
|
||||||
const char TASK_SAVE[] = "QmlProfiler.TaskSave";
|
const char TASK_SAVE[] = "QmlProfiler.TaskSave";
|
||||||
|
|
||||||
} // namespace Constants
|
} // namespace Constants
|
||||||
|
|||||||
@@ -406,27 +406,33 @@ void QmlProfilerModelManager::setFilename(const QString &filename)
|
|||||||
|
|
||||||
void QmlProfilerModelManager::load()
|
void QmlProfilerModelManager::load()
|
||||||
{
|
{
|
||||||
QString filename = d->fileName;
|
QFile *file = new QFile(d->fileName, this);
|
||||||
|
if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
QFile file(filename);
|
emit error(tr("Could not open %1 for reading.").arg(d->fileName));
|
||||||
|
delete file;
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
emit loadFinished();
|
||||||
emit error(tr("Could not open %1 for reading.").arg(filename));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// erase current
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
setState(QmlProfilerDataState::AcquiringData);
|
setState(QmlProfilerDataState::AcquiringData);
|
||||||
|
|
||||||
QmlProfilerFileReader reader;
|
QFuture<void> result = QtConcurrent::run<void>([this, file] (QFutureInterface<void> &future) {
|
||||||
connect(&reader, SIGNAL(error(QString)), this, SIGNAL(error(QString)));
|
QmlProfilerFileReader reader;
|
||||||
reader.setV8DataModel(d->v8Model);
|
reader.setFuture(&future);
|
||||||
reader.setQmlDataModel(d->model);
|
connect(&reader, &QmlProfilerFileReader::error, this, &QmlProfilerModelManager::error);
|
||||||
reader.load(&file);
|
reader.setV8DataModel(d->v8Model);
|
||||||
|
reader.setQmlDataModel(d->model);
|
||||||
|
reader.load(file);
|
||||||
|
file->close();
|
||||||
|
file->deleteLater();
|
||||||
|
|
||||||
complete();
|
// The completion step uses the old progress display widget for now.
|
||||||
|
complete();
|
||||||
|
QMetaObject::invokeMethod(this, "loadFinished", Qt::QueuedConnection);
|
||||||
|
});
|
||||||
|
|
||||||
|
Core::ProgressManager::addTask(result, tr("Loading Trace Data"), Constants::TASK_LOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ signals:
|
|||||||
void stateChanged();
|
void stateChanged();
|
||||||
void progressChanged();
|
void progressChanged();
|
||||||
void dataAvailable();
|
void dataAvailable();
|
||||||
|
void loadFinished();
|
||||||
void saveFinished();
|
void saveFinished();
|
||||||
|
|
||||||
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
|
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
|
||||||
@@ -162,6 +163,7 @@ public slots:
|
|||||||
void load();
|
void load();
|
||||||
|
|
||||||
void newTimeEstimation(qint64 estimation);
|
void newTimeEstimation(qint64 estimation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setState(QmlProfilerDataState::State state);
|
void setState(QmlProfilerDataState::State state);
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
|||||||
connect(d->m_profilerModelManager, SIGNAL(availableFeaturesChanged(quint64)),
|
connect(d->m_profilerModelManager, SIGNAL(availableFeaturesChanged(quint64)),
|
||||||
this, SLOT(setAvailableFeatures(quint64)));
|
this, SLOT(setAvailableFeatures(quint64)));
|
||||||
connect(d->m_profilerModelManager, &QmlProfilerModelManager::saveFinished,
|
connect(d->m_profilerModelManager, &QmlProfilerModelManager::saveFinished,
|
||||||
this, &QmlProfilerTool::onSaveFinished);
|
this, &QmlProfilerTool::onLoadSaveFinished);
|
||||||
|
connect(d->m_profilerModelManager, &QmlProfilerModelManager::loadFinished,
|
||||||
|
this, &QmlProfilerTool::onLoadSaveFinished);
|
||||||
|
|
||||||
d->m_profilerConnections->setModelManager(d->m_profilerModelManager);
|
d->m_profilerConnections->setModelManager(d->m_profilerModelManager);
|
||||||
Command *command = 0;
|
Command *command = 0;
|
||||||
@@ -597,11 +599,6 @@ void QmlProfilerTool::showSaveDialog()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerTool::onSaveFinished()
|
|
||||||
{
|
|
||||||
AnalyzerManager::mainWindow()->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlProfilerTool::showLoadDialog()
|
void QmlProfilerTool::showLoadDialog()
|
||||||
{
|
{
|
||||||
if (!checkForUnsavedNotes())
|
if (!checkForUnsavedNotes())
|
||||||
@@ -616,12 +613,16 @@ void QmlProfilerTool::showLoadDialog()
|
|||||||
tr("QML traces (*%1)").arg(QLatin1String(TraceFileExtension)));
|
tr("QML traces (*%1)").arg(QLatin1String(TraceFileExtension)));
|
||||||
|
|
||||||
if (!filename.isEmpty()) {
|
if (!filename.isEmpty()) {
|
||||||
// delayed load (prevent graphical artifacts due to long load time)
|
AnalyzerManager::mainWindow()->setEnabled(false);
|
||||||
d->m_profilerModelManager->setFilename(filename);
|
d->m_profilerModelManager->load(filename);
|
||||||
QTimer::singleShot(100, d->m_profilerModelManager, SLOT(load()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerTool::onLoadSaveFinished()
|
||||||
|
{
|
||||||
|
AnalyzerManager::mainWindow()->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Checks if we have unsaved notes. If so, shows a warning dialog. Returns true if we can continue
|
Checks if we have unsaved notes. If so, shows a warning dialog. Returns true if we can continue
|
||||||
with a potentially destructive operation and discard the warnings, or false if not. We don't
|
with a potentially destructive operation and discard the warnings, or false if not. We don't
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ private slots:
|
|||||||
void showSaveOption();
|
void showSaveOption();
|
||||||
void showLoadOption();
|
void showLoadOption();
|
||||||
void showSaveDialog();
|
void showSaveDialog();
|
||||||
void onSaveFinished();
|
|
||||||
void showLoadDialog();
|
void showLoadDialog();
|
||||||
|
void onLoadSaveFinished();
|
||||||
|
|
||||||
void toggleRecordingFeature(QAction *action);
|
void toggleRecordingFeature(QAction *action);
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ static QString qmlTypeAsString(Message message, RangeType rangeType)
|
|||||||
|
|
||||||
QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
|
QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_v8Model(0)
|
m_v8Model(0),
|
||||||
|
m_future(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +137,18 @@ void QmlProfilerFileReader::setQmlDataModel(QmlProfilerDataModel *dataModel)
|
|||||||
m_qmlModel = dataModel;
|
m_qmlModel = dataModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerFileReader::setFuture(QFutureInterface<void> *future)
|
||||||
|
{
|
||||||
|
m_future = future;
|
||||||
|
}
|
||||||
|
|
||||||
bool QmlProfilerFileReader::load(QIODevice *device)
|
bool QmlProfilerFileReader::load(QIODevice *device)
|
||||||
{
|
{
|
||||||
|
if (m_future) {
|
||||||
|
m_future->setProgressRange(0, qMin(device->size(), qint64(INT_MAX)));
|
||||||
|
m_future->setProgressValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
QXmlStreamReader stream(device);
|
QXmlStreamReader stream(device);
|
||||||
|
|
||||||
bool validVersion = true;
|
bool validVersion = true;
|
||||||
@@ -145,6 +156,8 @@ bool QmlProfilerFileReader::load(QIODevice *device)
|
|||||||
qint64 traceEnd = -1;
|
qint64 traceEnd = -1;
|
||||||
|
|
||||||
while (validVersion && !stream.atEnd() && !stream.hasError()) {
|
while (validVersion && !stream.atEnd() && !stream.hasError()) {
|
||||||
|
if (isCanceled())
|
||||||
|
return false;
|
||||||
QXmlStreamReader::TokenType token = stream.readNext();
|
QXmlStreamReader::TokenType token = stream.readNext();
|
||||||
const QStringRef elementName = stream.name();
|
const QStringRef elementName = stream.name();
|
||||||
switch (token) {
|
switch (token) {
|
||||||
@@ -179,7 +192,7 @@ bool QmlProfilerFileReader::load(QIODevice *device)
|
|||||||
|
|
||||||
if (elementName == _("v8profile")) {
|
if (elementName == _("v8profile")) {
|
||||||
if (m_v8Model)
|
if (m_v8Model)
|
||||||
m_v8Model->load(stream);
|
m_v8Model->load(stream, m_future);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +230,16 @@ void QmlProfilerFileReader::loadEventData(QXmlStreamReader &stream)
|
|||||||
const QmlProfilerDataModel::QmlEventTypeData defaultEvent = event;
|
const QmlProfilerDataModel::QmlEventTypeData defaultEvent = event;
|
||||||
|
|
||||||
while (!stream.atEnd() && !stream.hasError()) {
|
while (!stream.atEnd() && !stream.hasError()) {
|
||||||
|
if (isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
QXmlStreamReader::TokenType token = stream.readNext();
|
QXmlStreamReader::TokenType token = stream.readNext();
|
||||||
const QStringRef elementName = stream.name();
|
const QStringRef elementName = stream.name();
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case QXmlStreamReader::StartElement: {
|
case QXmlStreamReader::StartElement: {
|
||||||
if (elementName == _("event")) {
|
if (elementName == _("event")) {
|
||||||
|
progress(stream.device());
|
||||||
event = defaultEvent;
|
event = defaultEvent;
|
||||||
|
|
||||||
const QXmlStreamAttributes attributes = stream.attributes();
|
const QXmlStreamAttributes attributes = stream.attributes();
|
||||||
@@ -322,12 +339,16 @@ void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream)
|
|||||||
QTC_ASSERT(stream.name() == _("profilerDataModel"), return);
|
QTC_ASSERT(stream.name() == _("profilerDataModel"), return);
|
||||||
|
|
||||||
while (!stream.atEnd() && !stream.hasError()) {
|
while (!stream.atEnd() && !stream.hasError()) {
|
||||||
|
if (isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
QXmlStreamReader::TokenType token = stream.readNext();
|
QXmlStreamReader::TokenType token = stream.readNext();
|
||||||
const QStringRef elementName = stream.name();
|
const QStringRef elementName = stream.name();
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case QXmlStreamReader::StartElement: {
|
case QXmlStreamReader::StartElement: {
|
||||||
if (elementName == _("range")) {
|
if (elementName == _("range")) {
|
||||||
|
progress(stream.device());
|
||||||
QmlProfilerDataModel::QmlEventData range = { -1, 0, 0, 0, 0, 0, 0, 0 };
|
QmlProfilerDataModel::QmlEventData range = { -1, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
const QXmlStreamAttributes attributes = stream.attributes();
|
const QXmlStreamAttributes attributes = stream.attributes();
|
||||||
@@ -389,12 +410,16 @@ void QmlProfilerFileReader::loadNoteData(QXmlStreamReader &stream)
|
|||||||
{
|
{
|
||||||
QmlProfilerDataModel::QmlEventNoteData currentNote;
|
QmlProfilerDataModel::QmlEventNoteData currentNote;
|
||||||
while (!stream.atEnd() && !stream.hasError()) {
|
while (!stream.atEnd() && !stream.hasError()) {
|
||||||
|
if (isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
QXmlStreamReader::TokenType token = stream.readNext();
|
QXmlStreamReader::TokenType token = stream.readNext();
|
||||||
const QStringRef elementName = stream.name();
|
const QStringRef elementName = stream.name();
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case QXmlStreamReader::StartElement: {
|
case QXmlStreamReader::StartElement: {
|
||||||
if (elementName == _("note")) {
|
if (elementName == _("note")) {
|
||||||
|
progress(stream.device());
|
||||||
QXmlStreamAttributes attrs = stream.attributes();
|
QXmlStreamAttributes attrs = stream.attributes();
|
||||||
currentNote.startTime = attrs.value(_("startTime")).toString().toLongLong();
|
currentNote.startTime = attrs.value(_("startTime")).toString().toLongLong();
|
||||||
currentNote.duration = attrs.value(_("duration")).toString().toLongLong();
|
currentNote.duration = attrs.value(_("duration")).toString().toLongLong();
|
||||||
@@ -420,6 +445,19 @@ void QmlProfilerFileReader::loadNoteData(QXmlStreamReader &stream)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerFileReader::progress(QIODevice *device)
|
||||||
|
{
|
||||||
|
if (!m_future)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_future->setProgressValue(qMin(device->pos(), qint64(INT_MAX)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QmlProfilerFileReader::isCanceled() const
|
||||||
|
{
|
||||||
|
return m_future && m_future->isCanceled();
|
||||||
|
}
|
||||||
|
|
||||||
QmlProfilerFileWriter::QmlProfilerFileWriter(QObject *parent) :
|
QmlProfilerFileWriter::QmlProfilerFileWriter(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_startTime(0),
|
m_startTime(0),
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public:
|
|||||||
|
|
||||||
void setV8DataModel(QV8ProfilerDataModel *dataModel);
|
void setV8DataModel(QV8ProfilerDataModel *dataModel);
|
||||||
void setQmlDataModel(QmlProfilerDataModel *dataModel);
|
void setQmlDataModel(QmlProfilerDataModel *dataModel);
|
||||||
|
void setFuture(QFutureInterface<void> *future);
|
||||||
|
|
||||||
bool load(QIODevice *device);
|
bool load(QIODevice *device);
|
||||||
|
|
||||||
@@ -68,9 +69,12 @@ private:
|
|||||||
void loadEventData(QXmlStreamReader &reader);
|
void loadEventData(QXmlStreamReader &reader);
|
||||||
void loadProfilerDataModel(QXmlStreamReader &reader);
|
void loadProfilerDataModel(QXmlStreamReader &reader);
|
||||||
void loadNoteData(QXmlStreamReader &reader);
|
void loadNoteData(QXmlStreamReader &reader);
|
||||||
|
void progress(QIODevice *device);
|
||||||
|
bool isCanceled() const;
|
||||||
|
|
||||||
QV8ProfilerDataModel *m_v8Model;
|
QV8ProfilerDataModel *m_v8Model;
|
||||||
QmlProfilerDataModel *m_qmlModel;
|
QmlProfilerDataModel *m_qmlModel;
|
||||||
|
QFutureInterface<void> *m_future;
|
||||||
QVector<QmlProfilerDataModel::QmlEventTypeData> m_qmlEvents;
|
QVector<QmlProfilerDataModel::QmlEventTypeData> m_qmlEvents;
|
||||||
QVector<QmlProfilerDataModel::QmlEventData> m_ranges;
|
QVector<QmlProfilerDataModel::QmlEventData> m_ranges;
|
||||||
QVector<QmlProfilerDataModel::QmlEventNoteData> m_notes;
|
QVector<QmlProfilerDataModel::QmlEventNoteData> m_notes;
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ void QV8ProfilerDataModel::save(QXmlStreamWriter &stream, QFutureInterface<void>
|
|||||||
stream.writeEndElement(); // v8 profiler output
|
stream.writeEndElement(); // v8 profiler output
|
||||||
}
|
}
|
||||||
|
|
||||||
void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
|
void QV8ProfilerDataModel::load(QXmlStreamReader &stream, QFutureInterface<void> *future)
|
||||||
{
|
{
|
||||||
Q_D(QV8ProfilerDataModel);
|
Q_D(QV8ProfilerDataModel);
|
||||||
QHash <int, QV8EventData *> v8eventBuffer;
|
QHash <int, QV8EventData *> v8eventBuffer;
|
||||||
@@ -392,12 +392,17 @@ void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
|
|||||||
|
|
||||||
bool finishedReading = false;
|
bool finishedReading = false;
|
||||||
while (!stream.atEnd() && !stream.hasError() && !finishedReading) {
|
while (!stream.atEnd() && !stream.hasError() && !finishedReading) {
|
||||||
|
if (future && future->isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
QXmlStreamReader::TokenType token = stream.readNext();
|
QXmlStreamReader::TokenType token = stream.readNext();
|
||||||
const QStringRef elementName = stream.name();
|
const QStringRef elementName = stream.name();
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case QXmlStreamReader::StartDocument : continue;
|
case QXmlStreamReader::StartDocument : continue;
|
||||||
case QXmlStreamReader::StartElement : {
|
case QXmlStreamReader::StartElement : {
|
||||||
if (elementName == QLatin1String("event")) {
|
if (elementName == QLatin1String("event")) {
|
||||||
|
if (future)
|
||||||
|
future->setProgressValue(qMin(stream.device()->pos(), qint64(INT_MAX)));
|
||||||
QXmlStreamAttributes attributes = stream.attributes();
|
QXmlStreamAttributes attributes = stream.attributes();
|
||||||
if (attributes.hasAttribute(QLatin1String("index"))) {
|
if (attributes.hasAttribute(QLatin1String("index"))) {
|
||||||
int ndx = attributes.value(QLatin1String("index")).toString().toInt();
|
int ndx = attributes.value(QLatin1String("index")).toString().toInt();
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public:
|
|||||||
qint64 v8MeasuredTime() const;
|
qint64 v8MeasuredTime() const;
|
||||||
|
|
||||||
void save(QXmlStreamWriter &stream, QFutureInterface<void> *future = 0);
|
void save(QXmlStreamWriter &stream, QFutureInterface<void> *future = 0);
|
||||||
void load(QXmlStreamReader &stream);
|
void load(QXmlStreamReader &stream, QFutureInterface<void> *future = 0);
|
||||||
|
|
||||||
void complete();
|
void complete();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user