Commit 99f4b635 authored by Ulf Hermann's avatar Ulf Hermann Committed by Ulf Hermann
Browse files

QmlProfiler: show a warning if unsaved notes are to be discarded



Change-Id: I5152f0eefd1f0beec2b0f4fc9e27fedeb3bf7a14
Task-number: QTCREATORBUG-13318
Reviewed-by: default avatarEike Ziller <eike.ziller@theqtcompany.com>
Reviewed-by: default avatarKai Koehne <kai.koehne@theqtcompany.com>
parent 55c24db5
......@@ -32,7 +32,7 @@
namespace QmlProfiler {
NotesModel::NotesModel(QObject *parent) : QObject(parent), m_modelManager(0)
NotesModel::NotesModel(QObject *parent) : QObject(parent), m_modelManager(0), m_modified(false)
{
}
......@@ -114,6 +114,7 @@ int NotesModel::add(int timelineModel, int timelineIndex, const QString &text)
int typeId = model->range(timelineIndex).typeId;
Note note = { text, timelineModel, timelineIndex };
m_data << note;
m_modified = true;
emit changed(typeId, timelineModel, timelineIndex);
return m_data.count() - 1;
}
......@@ -123,6 +124,7 @@ void NotesModel::update(int index, const QString &text)
Note &note = m_data[index];
if (text != note.text) {
note.text = text;
m_modified = true;
emit changed(typeId(index), note.timelineModel, note.timelineIndex);
}
}
......@@ -134,9 +136,15 @@ void NotesModel::remove(int index)
int timelineModel = note.timelineModel;
int timelineIndex = note.timelineIndex;
m_data.removeAt(index);
m_modified = true;
emit changed(noteType, timelineModel, timelineIndex);
}
bool NotesModel::isModified() const
{
return m_modified;
}
void NotesModel::removeTimelineModel(QObject *timelineModel)
{
for (auto i = m_timelineModels.begin(); i != m_timelineModels.end();) {
......@@ -176,12 +184,14 @@ int NotesModel::add(int typeId, qint64 start, qint64 duration, const QString &te
Note note = { text, timelineModel, timelineIndex };
m_data << note;
m_modified = true;
return m_data.count() - 1;
}
void NotesModel::clear()
{
m_data.clear();
m_modified = false;
emit changed(-1, -1, -1);
}
......@@ -194,6 +204,7 @@ void NotesModel::loadData()
const QmlProfilerDataModel::QmlEventNoteData &note = notes[i];
add(note.typeIndex, note.startTime, note.duration, note.text);
}
m_modified = false; // reset after loading
emit changed(-1, -1, -1);
}
......@@ -213,5 +224,6 @@ void NotesModel::saveData()
notes.append(save);
}
m_modelManager->qmlModel()->setNoteData(notes);
m_modified = false;
}
}
......@@ -68,9 +68,11 @@ public:
int add(int timelineModel, int timelineIndex, const QString &text);
void update(int index, const QString &text);
void remove(int index);
bool isModified() const;
void loadData();
void saveData();
void clear();
signals:
void changed(int typeId, int timelineModel, int timelineIndex);
......@@ -82,9 +84,9 @@ protected:
QmlProfilerModelManager *m_modelManager;
QList<Note> m_data;
QHash<int, const AbstractTimelineModel *> m_timelineModels;
bool m_modified;
int add(int typeId, qint64 startTime, qint64 duration, const QString &text);
void clear();
};
}
#endif // NOTESMODEL_H
......@@ -38,6 +38,7 @@
#include <QDebug>
#include <QFile>
#include <QMessageBox>
namespace QmlProfiler {
namespace Internal {
......@@ -447,6 +448,7 @@ void QmlProfilerModelManager::clear()
d->model->clear();
d->v8Model->clear();
d->traceTime->clear();
d->notesModel->clear();
setState(QmlProfilerDataState::Empty);
}
......
......@@ -38,6 +38,7 @@
#include "qmlprofilermodelmanager.h"
#include "qmlprofilerdetailsrewriter.h"
#include "timelinerenderer.h"
#include "notesmodel.h"
#include <analyzerbase/analyzermanager.h>
#include <analyzerbase/analyzerruncontrol.h>
......@@ -272,7 +273,10 @@ QWidget *QmlProfilerTool::createWidgets()
d->m_clearButton->setIcon(QIcon(QLatin1String(":/qmlprofiler/clean_pane_small.png")));
d->m_clearButton->setToolTip(tr("Discard data"));
connect(d->m_clearButton,SIGNAL(clicked()), this, SLOT(clearData()));
connect(d->m_clearButton, &QAbstractButton::clicked, [this](){
if (checkForUnsavedNotes())
clearData();
});
layout->addWidget(d->m_clearButton);
......@@ -324,7 +328,16 @@ void QmlProfilerTool::populateFileFinder(QString projectDirectory, QString activ
void QmlProfilerTool::recordingButtonChanged(bool recording)
{
d->m_profilerState->setClientRecording(recording);
if (recording && d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
if (checkForUnsavedNotes()) {
clearData(); // clear right away, before the application starts
d->m_profilerState->setClientRecording(true);
} else {
d->m_recordButton->setChecked(false);
}
} else {
d->m_profilerState->setClientRecording(recording);
}
}
void QmlProfilerTool::setRecording(bool recording)
......@@ -447,6 +460,13 @@ static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
void QmlProfilerTool::startTool(StartMode mode)
{
if (d->m_recordButton->isChecked()) {
if (!checkForUnsavedNotes())
return;
else
clearData(); // clear right away to suppress second warning on server recording change
}
// Make sure mode is shown.
AnalyzerManager::showMode();
......@@ -499,6 +519,9 @@ void QmlProfilerTool::showSaveDialog()
void QmlProfilerTool::showLoadDialog()
{
if (!checkForUnsavedNotes())
return;
if (ModeManager::currentMode()->id() != MODE_ANALYZE)
AnalyzerManager::showMode();
......@@ -514,6 +537,22 @@ void QmlProfilerTool::showLoadDialog()
}
}
/*!
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
want to show a save/discard dialog here because that will often result in a confusing series of
different dialogs: first "save" and then immediately "load" or "connect".
*/
bool QmlProfilerTool::checkForUnsavedNotes()
{
if (!d->m_profilerModelManager->notesModel()->isModified())
return true;
return QMessageBox::warning(QApplication::activeWindow(), tr("QML Profiler"),
tr("You are about to discard the profiling data, including unsaved "
"notes. Do you want to continue?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes;
}
void QmlProfilerTool::clientsDisconnected()
{
// If the application stopped by itself, check if we have all the data
......@@ -646,13 +685,25 @@ void QmlProfilerTool::clientRecordingChanged()
void QmlProfilerTool::serverRecordingChanged()
{
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
setRecording(d->m_profilerState->serverRecording());
// clear the old data each time we start a new profiling session
if (d->m_profilerState->serverRecording()) {
// We cannot stop it here, so we cannot give the usual yes/no dialog. Show a dialog
// offering to immediately save the data instead.
if (d->m_profilerModelManager->notesModel()->isModified() &&
QMessageBox::warning(QApplication::activeWindow(), tr("QML Profiler"),
tr("Starting a new profiling session will discard the "
"previous data, including unsaved notes.\nDo you want "
"to save the data first?"),
QMessageBox::Save, QMessageBox::Discard) ==
QMessageBox::Save)
showSaveDialog();
setRecording(true);
d->m_clearButton->setEnabled(false);
clearData();
d->m_profilerModelManager->prepareForWriting();
} else {
setRecording(false);
d->m_clearButton->setEnabled(true);
}
} else {
......
......@@ -94,6 +94,7 @@ private:
void populateFileFinder(QString projectDirectory = QString(), QString activeSysroot = QString());
template<QmlDebug::ProfileFeature feature>
void updateFeaturesMenu(quint64 features);
bool checkForUnsavedNotes();
class QmlProfilerToolPrivate;
QmlProfilerToolPrivate *d;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment