diff --git a/src/plugins/qmlprofiler/qmlprofilerconstants.h b/src/plugins/qmlprofiler/qmlprofilerconstants.h index ca7a466198f..8addadce456 100644 --- a/src/plugins/qmlprofiler/qmlprofilerconstants.h +++ b/src/plugins/qmlprofiler/qmlprofilerconstants.h @@ -36,6 +36,7 @@ namespace Constants { const char ATTACH[] = "Menu.Analyzer.Attach"; const char TraceFileExtension[] = ".qtd"; +const char TASK_LOAD[] = "QmlProfiler.TaskLoad"; const char TASK_SAVE[] = "QmlProfiler.TaskSave"; } // namespace Constants diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index fdd7825cf46..f9262036536 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -406,27 +406,33 @@ void QmlProfilerModelManager::setFilename(const QString &filename) void QmlProfilerModelManager::load() { - QString filename = d->fileName; - - QFile file(filename); - - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - emit error(tr("Could not open %1 for reading.").arg(filename)); + QFile *file = new QFile(d->fileName, this); + if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) { + emit error(tr("Could not open %1 for reading.").arg(d->fileName)); + delete file; + emit loadFinished(); return; } - // erase current clear(); - setState(QmlProfilerDataState::AcquiringData); - QmlProfilerFileReader reader; - connect(&reader, SIGNAL(error(QString)), this, SIGNAL(error(QString))); - reader.setV8DataModel(d->v8Model); - reader.setQmlDataModel(d->model); - reader.load(&file); + QFuture result = QtConcurrent::run([this, file] (QFutureInterface &future) { + QmlProfilerFileReader reader; + reader.setFuture(&future); + connect(&reader, &QmlProfilerFileReader::error, this, &QmlProfilerModelManager::error); + 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); } diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h index 2050f844790..3729df5b73e 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h @@ -137,6 +137,7 @@ signals: void stateChanged(); void progressChanged(); void dataAvailable(); + void loadFinished(); void saveFinished(); void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location); @@ -162,6 +163,7 @@ public slots: void load(); void newTimeEstimation(qint64 estimation); + private: void setState(QmlProfilerDataState::State state); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 74a0d479529..cf14fd9af76 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -151,7 +151,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) connect(d->m_profilerModelManager, SIGNAL(availableFeaturesChanged(quint64)), this, SLOT(setAvailableFeatures(quint64))); 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); Command *command = 0; @@ -597,11 +599,6 @@ void QmlProfilerTool::showSaveDialog() } } -void QmlProfilerTool::onSaveFinished() -{ - AnalyzerManager::mainWindow()->setEnabled(true); -} - void QmlProfilerTool::showLoadDialog() { if (!checkForUnsavedNotes()) @@ -616,12 +613,16 @@ void QmlProfilerTool::showLoadDialog() tr("QML traces (*%1)").arg(QLatin1String(TraceFileExtension))); if (!filename.isEmpty()) { - // delayed load (prevent graphical artifacts due to long load time) - d->m_profilerModelManager->setFilename(filename); - QTimer::singleShot(100, d->m_profilerModelManager, SLOT(load())); + AnalyzerManager::mainWindow()->setEnabled(false); + d->m_profilerModelManager->load(filename); } } +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 with a potentially destructive operation and discard the warnings, or false if not. We don't diff --git a/src/plugins/qmlprofiler/qmlprofilertool.h b/src/plugins/qmlprofiler/qmlprofilertool.h index 165cdfabd79..981c0f3467c 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.h +++ b/src/plugins/qmlprofiler/qmlprofilertool.h @@ -95,8 +95,8 @@ private slots: void showSaveOption(); void showLoadOption(); void showSaveDialog(); - void onSaveFinished(); void showLoadDialog(); + void onLoadSaveFinished(); void toggleRecordingFeature(QAction *action); diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp index 8b85d23da41..d92bb738d65 100644 --- a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp @@ -122,7 +122,8 @@ static QString qmlTypeAsString(Message message, RangeType rangeType) QmlProfilerFileReader::QmlProfilerFileReader(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; } +void QmlProfilerFileReader::setFuture(QFutureInterface *future) +{ + m_future = future; +} + 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); bool validVersion = true; @@ -145,6 +156,8 @@ bool QmlProfilerFileReader::load(QIODevice *device) qint64 traceEnd = -1; while (validVersion && !stream.atEnd() && !stream.hasError()) { + if (isCanceled()) + return false; QXmlStreamReader::TokenType token = stream.readNext(); const QStringRef elementName = stream.name(); switch (token) { @@ -179,7 +192,7 @@ bool QmlProfilerFileReader::load(QIODevice *device) if (elementName == _("v8profile")) { if (m_v8Model) - m_v8Model->load(stream); + m_v8Model->load(stream, m_future); break; } @@ -217,12 +230,16 @@ void QmlProfilerFileReader::loadEventData(QXmlStreamReader &stream) const QmlProfilerDataModel::QmlEventTypeData defaultEvent = event; while (!stream.atEnd() && !stream.hasError()) { + if (isCanceled()) + return; + QXmlStreamReader::TokenType token = stream.readNext(); const QStringRef elementName = stream.name(); switch (token) { case QXmlStreamReader::StartElement: { if (elementName == _("event")) { + progress(stream.device()); event = defaultEvent; const QXmlStreamAttributes attributes = stream.attributes(); @@ -322,12 +339,16 @@ void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream) QTC_ASSERT(stream.name() == _("profilerDataModel"), return); while (!stream.atEnd() && !stream.hasError()) { + if (isCanceled()) + return; + QXmlStreamReader::TokenType token = stream.readNext(); const QStringRef elementName = stream.name(); switch (token) { case QXmlStreamReader::StartElement: { if (elementName == _("range")) { + progress(stream.device()); QmlProfilerDataModel::QmlEventData range = { -1, 0, 0, 0, 0, 0, 0, 0 }; const QXmlStreamAttributes attributes = stream.attributes(); @@ -389,12 +410,16 @@ void QmlProfilerFileReader::loadNoteData(QXmlStreamReader &stream) { QmlProfilerDataModel::QmlEventNoteData currentNote; while (!stream.atEnd() && !stream.hasError()) { + if (isCanceled()) + return; + QXmlStreamReader::TokenType token = stream.readNext(); const QStringRef elementName = stream.name(); switch (token) { case QXmlStreamReader::StartElement: { if (elementName == _("note")) { + progress(stream.device()); QXmlStreamAttributes attrs = stream.attributes(); currentNote.startTime = attrs.value(_("startTime")).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) : QObject(parent), m_startTime(0), diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.h b/src/plugins/qmlprofiler/qmlprofilertracefile.h index 992b2632785..e87cd15c47f 100644 --- a/src/plugins/qmlprofiler/qmlprofilertracefile.h +++ b/src/plugins/qmlprofiler/qmlprofilertracefile.h @@ -58,6 +58,7 @@ public: void setV8DataModel(QV8ProfilerDataModel *dataModel); void setQmlDataModel(QmlProfilerDataModel *dataModel); + void setFuture(QFutureInterface *future); bool load(QIODevice *device); @@ -68,9 +69,12 @@ private: void loadEventData(QXmlStreamReader &reader); void loadProfilerDataModel(QXmlStreamReader &reader); void loadNoteData(QXmlStreamReader &reader); + void progress(QIODevice *device); + bool isCanceled() const; QV8ProfilerDataModel *m_v8Model; QmlProfilerDataModel *m_qmlModel; + QFutureInterface *m_future; QVector m_qmlEvents; QVector m_ranges; QVector m_notes; diff --git a/src/plugins/qmlprofiler/qv8profilerdatamodel.cpp b/src/plugins/qmlprofiler/qv8profilerdatamodel.cpp index 66c7cd7aee2..264c5d8f79e 100644 --- a/src/plugins/qmlprofiler/qv8profilerdatamodel.cpp +++ b/src/plugins/qmlprofiler/qv8profilerdatamodel.cpp @@ -372,7 +372,7 @@ void QV8ProfilerDataModel::save(QXmlStreamWriter &stream, QFutureInterface stream.writeEndElement(); // v8 profiler output } -void QV8ProfilerDataModel::load(QXmlStreamReader &stream) +void QV8ProfilerDataModel::load(QXmlStreamReader &stream, QFutureInterface *future) { Q_D(QV8ProfilerDataModel); QHash v8eventBuffer; @@ -392,12 +392,17 @@ void QV8ProfilerDataModel::load(QXmlStreamReader &stream) bool finishedReading = false; while (!stream.atEnd() && !stream.hasError() && !finishedReading) { + if (future && future->isCanceled()) + return; + QXmlStreamReader::TokenType token = stream.readNext(); const QStringRef elementName = stream.name(); switch (token) { case QXmlStreamReader::StartDocument : continue; case QXmlStreamReader::StartElement : { if (elementName == QLatin1String("event")) { + if (future) + future->setProgressValue(qMin(stream.device()->pos(), qint64(INT_MAX))); QXmlStreamAttributes attributes = stream.attributes(); if (attributes.hasAttribute(QLatin1String("index"))) { int ndx = attributes.value(QLatin1String("index")).toString().toInt(); diff --git a/src/plugins/qmlprofiler/qv8profilerdatamodel.h b/src/plugins/qmlprofiler/qv8profilerdatamodel.h index af650896772..90708212563 100644 --- a/src/plugins/qmlprofiler/qv8profilerdatamodel.h +++ b/src/plugins/qmlprofiler/qv8profilerdatamodel.h @@ -89,7 +89,7 @@ public: qint64 v8MeasuredTime() const; void save(QXmlStreamWriter &stream, QFutureInterface *future = 0); - void load(QXmlStreamReader &stream); + void load(QXmlStreamReader &stream, QFutureInterface *future = 0); void complete();