From a8d7e15a5dd88f2c7f34e03ca8594d584ac15bc0 Mon Sep 17 00:00:00 2001
From: Nikolai Kosjar <nikolai.kosjar@digia.com>
Date: Mon, 9 Sep 2013 14:34:19 +0200
Subject: [PATCH] Valgrind: Add action to load external log file

...for the memcheck and callgrind tool.

Task-number: QTCREATORBUG-10057

Change-Id: I23dd3ad47f0498af37787bf54e76b09852cb327c
Reviewed-by: hjk <hjk121@nokiamail.com>
---
 src/plugins/valgrind/callgrindtool.cpp |  49 ++++++++++-
 src/plugins/valgrind/callgrindtool.h   |   1 +
 src/plugins/valgrind/memchecktool.cpp  | 115 +++++++++++++++++++------
 src/plugins/valgrind/memchecktool.h    |   8 +-
 4 files changed, 147 insertions(+), 26 deletions(-)

diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp
index a55688c7a42..904b7f196fb 100644
--- a/src/plugins/valgrind/callgrindtool.cpp
+++ b/src/plugins/valgrind/callgrindtool.cpp
@@ -41,6 +41,7 @@
 #include <valgrind/callgrind/callgrindfunction.h>
 #include <valgrind/callgrind/callgrindfunctioncall.h>
 #include <valgrind/callgrind/callgrindparsedata.h>
+#include <valgrind/callgrind/callgrindparser.h>
 #include <valgrind/callgrind/callgrindproxymodel.h>
 #include <valgrind/callgrind/callgrindstackbrowser.h>
 #include <valgrind/valgrindplugin.h>
@@ -74,10 +75,12 @@
 #include <QCheckBox>
 #include <QComboBox>
 #include <QDockWidget>
+#include <QFileDialog>
 #include <QGraphicsItem>
 #include <QHBoxLayout>
 #include <QLineEdit>
 #include <QMenu>
+#include <QMessageBox>
 #include <QSortFilterProxyModel>
 #include <QToolBar>
 #include <QToolButton>
@@ -124,6 +127,7 @@ signals:
 public slots:
     void slotClear();
     void slotRequestDump();
+    void loadExternalXmlLogFile();
 
     void selectFunction(const Valgrind::Callgrind::Function *);
     void setCostFormat(Valgrind::Internal::CostDelegate::CostFormat format);
@@ -158,6 +162,7 @@ public slots:
     void showParserResults(const Valgrind::Callgrind::ParseData *data);
 
     void takeParserData(CallgrindRunControl *rc);
+    void takeParserData(ParseData *data);
     void engineStarting(const Analyzer::AnalyzerRunControl *);
     void engineFinished();
 
@@ -198,6 +203,7 @@ public:
 
     QVector<CallgrindTextMark *> m_textMarks;
 
+    QAction *m_loadExternalLogFile;
     QAction *m_dumpAction;
     QAction *m_resetAction;
     QAction *m_pauseAction;
@@ -562,6 +568,11 @@ void CallgrindTool::startTool(StartMode mode)
     d->setBusyCursor(true);
 }
 
+void CallgrindTool::loadExternalXmlLogFile()
+{
+    d->loadExternalXmlLogFile();
+}
+
 void CallgrindTool::handleShowCostsOfFunction()
 {
    d->handleShowCostsOfFunction();
@@ -654,6 +665,14 @@ QWidget *CallgrindToolPrivate::createWidgets()
     layout->setSpacing(0);
     widget->setLayout(layout);
 
+    // load external XML log file
+    action = new QAction(this);
+    action->setIcon(QIcon(QLatin1String(Core::Constants::ICON_OPENFILE)));
+    action->setToolTip(tr("Load External XML Log File."));
+    connect(action, SIGNAL(triggered(bool)), this, SLOT(loadExternalXmlLogFile()));
+    layout->addWidget(createToolButton(action));
+    m_loadExternalLogFile = action;
+
     // dump action
     action = new QAction(this);
     action->setDisabled(true);
@@ -810,6 +829,7 @@ void CallgrindToolPrivate::engineStarting(const Analyzer::AnalyzerRunControl *)
     // enable/disable actions
     m_resetAction->setEnabled(true);
     m_dumpAction->setEnabled(true);
+    m_loadExternalLogFile->setEnabled(false);
     clearTextMarks();
     slotClear();
 }
@@ -819,6 +839,7 @@ void CallgrindToolPrivate::engineFinished()
     // enable/disable actions
     m_resetAction->setEnabled(false);
     m_dumpAction->setEnabled(false);
+    m_loadExternalLogFile->setEnabled(true);
 
     const ParseData *data = m_dataModel->parseData();
     if (data)
@@ -913,9 +934,35 @@ void CallgrindToolPrivate::slotRequestDump()
     dumpRequested();
 }
 
+void CallgrindToolPrivate::loadExternalXmlLogFile()
+{
+    const QString filePath = QFileDialog::getOpenFileName(Core::ICore::mainWindow(),
+                                                          tr("Open Callgrind XML Log File"));
+    if (filePath.isEmpty())
+        return;
+
+    QFile logFile(filePath);
+    if (!logFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        QMessageBox::critical(AnalyzerManager::mainWindow(), tr("Internal Error"),
+            tr("Failed to open file for reading: %1").arg(filePath));
+        return;
+    }
+
+    AnalyzerManager::showStatusMessage(tr("Parsing Profile Data..."));
+    QCoreApplication::processEvents();
+
+    Parser parser;
+    parser.parse(&logFile);
+    takeParserData(parser.takeData());
+}
+
 void CallgrindToolPrivate::takeParserData(CallgrindRunControl *rc)
 {
-    ParseData *data = rc->takeParserData();
+    takeParserData(rc->takeParserData());
+}
+
+void CallgrindToolPrivate::takeParserData(ParseData *data)
+{
     showParserResults(data);
 
     if (!data)
diff --git a/src/plugins/valgrind/callgrindtool.h b/src/plugins/valgrind/callgrindtool.h
index a3d0b1424c4..68a6c54e86d 100644
--- a/src/plugins/valgrind/callgrindtool.h
+++ b/src/plugins/valgrind/callgrindtool.h
@@ -53,6 +53,7 @@ public:
     QWidget *createWidgets();
 
     void startTool(Analyzer::StartMode mode);
+    void loadExternalXmlLogFile();
 
 public slots:
     void handleShowCostsOfFunction();
diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp
index 622b44bfea8..89921aa9d80 100644
--- a/src/plugins/valgrind/memchecktool.cpp
+++ b/src/plugins/valgrind/memchecktool.cpp
@@ -69,6 +69,7 @@
 
 #include <QString>
 #include <QLatin1String>
+#include <QFileDialog>
 #include <QFileInfo>
 #include <QFile>
 #include <QDir>
@@ -223,6 +224,31 @@ void MemcheckTool::settingsDestroyed(QObject *settings)
     m_settings = ValgrindPlugin::globalSettings();
 }
 
+void MemcheckTool::updateFromSettings()
+{
+    foreach (QAction *action, m_errorFilterActions) {
+        bool contained = true;
+        foreach (const QVariant &v, action->data().toList()) {
+            bool ok;
+            int kind = v.toInt(&ok);
+            if (ok && !m_settings->visibleErrorKinds().contains(kind))
+                contained = false;
+        }
+        action->setChecked(contained);
+    }
+
+    m_filterProjectAction->setChecked(!m_settings->filterExternalIssues());
+    m_errorView->settingsChanged(m_settings);
+
+    connect(m_settings, SIGNAL(visibleErrorKindsChanged(QList<int>)),
+            m_errorProxyModel, SLOT(setAcceptedKinds(QList<int>)));
+    m_errorProxyModel->setAcceptedKinds(m_settings->visibleErrorKinds());
+
+    connect(m_settings, SIGNAL(filterExternalIssuesChanged(bool)),
+            m_errorProxyModel, SLOT(setFilterExternalIssues(bool)));
+    m_errorProxyModel->setFilterExternalIssues(m_settings->filterExternalIssues());
+}
+
 void MemcheckTool::maybeActiveRunConfigurationChanged()
 {
     ValgrindBaseSettings *settings = 0;
@@ -249,27 +275,7 @@ void MemcheckTool::maybeActiveRunConfigurationChanged()
     QTC_ASSERT(m_settings, return);
     connect(m_settings, SIGNAL(destroyed(QObject*)), SLOT(settingsDestroyed(QObject*)));
 
-    foreach (QAction *action, m_errorFilterActions) {
-        bool contained = true;
-        foreach (const QVariant &v, action->data().toList()) {
-            bool ok;
-            int kind = v.toInt(&ok);
-            if (ok && !m_settings->visibleErrorKinds().contains(kind))
-                contained = false;
-        }
-        action->setChecked(contained);
-    }
-
-    m_filterProjectAction->setChecked(!m_settings->filterExternalIssues());
-    m_errorView->settingsChanged(m_settings);
-
-    connect(m_settings, SIGNAL(visibleErrorKindsChanged(QList<int>)),
-            m_errorProxyModel, SLOT(setAcceptedKinds(QList<int>)));
-    m_errorProxyModel->setAcceptedKinds(m_settings->visibleErrorKinds());
-
-    connect(m_settings, SIGNAL(filterExternalIssuesChanged(bool)),
-            m_errorProxyModel, SLOT(setFilterExternalIssues(bool)));
-    m_errorProxyModel->setFilterExternalIssues(m_settings->filterExternalIssues());
+    updateFromSettings();
 }
 
 RunMode MemcheckTool::runMode() const
@@ -371,6 +377,16 @@ QWidget *MemcheckTool::createWidgets()
     layout->setMargin(0);
     layout->setSpacing(0);
 
+    // Load external XML log file
+    action = new QAction(this);
+    action->setIcon(QIcon(QLatin1String(Core::Constants::ICON_OPENFILE)));
+    action->setToolTip(tr("Load External XML Log File."));
+    connect(action, SIGNAL(triggered(bool)), this, SLOT(loadExternalXmlLogFile()));
+    button = new QToolButton;
+    button->setDefaultAction(action);
+    layout->addWidget(button);
+    m_loadExternalLogFile = action;
+
     // Go to previous leak.
     action = new QAction(this);
     action->setDisabled(true);
@@ -429,7 +445,7 @@ AnalyzerRunControl *MemcheckTool::createRunControl(const AnalyzerStartParameters
             this, SLOT(parserError(Valgrind::XmlProtocol::Error)));
     connect(engine, SIGNAL(internalParserError(QString)),
             this, SLOT(internalParserError(QString)));
-    connect(engine, SIGNAL(finished()), this, SLOT(finished()));
+    connect(engine, SIGNAL(finished()), this, SLOT(engineFinished()));
     return engine;
 }
 
@@ -437,6 +453,7 @@ void MemcheckTool::engineStarting(const AnalyzerRunControl *engine)
 {
     setBusyCursor(true);
     clearErrorView();
+    m_loadExternalLogFile->setDisabled(true);
 
     QString dir;
     if (RunConfiguration *rc = engine->runConfiguration())
@@ -468,6 +485,42 @@ void MemcheckTool::suppressionActionTriggered()
     Core::EditorManager::openEditorAt(file, 0);
 }
 
+void MemcheckTool::loadExternalXmlLogFile()
+{
+    const QString filePath = QFileDialog::getOpenFileName(Core::ICore::mainWindow(),
+                                                          tr("Open Memcheck XML Log File"));
+    if (filePath.isEmpty())
+        return;
+
+    QFile *logFile = new QFile(filePath);
+    if (!logFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
+        delete logFile;
+        QMessageBox::critical(m_errorView, tr("Internal Error"),
+            tr("Failed to open file for reading: %1").arg(filePath));
+        return;
+    }
+
+    setBusyCursor(true);
+    clearErrorView();
+    m_loadExternalLogFile->setDisabled(true);
+
+    if (!m_settings || m_settings != ValgrindPlugin::globalSettings()) {
+        m_settings = ValgrindPlugin::globalSettings();
+        m_errorView->settingsChanged(m_settings);
+        updateFromSettings();
+    }
+
+    ThreadedParser *parser = new ThreadedParser;
+    connect(parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
+            this, SLOT(parserError(Valgrind::XmlProtocol::Error)));
+    connect(parser, SIGNAL(internalError(QString)),
+            this, SLOT(internalParserError(QString)));
+    connect(parser, SIGNAL(finished()), this, SLOT(loadingExternalXmlLogFileFinished()));
+    connect(parser, SIGNAL(finished()), parser, SLOT(deleteLater()));
+
+    parser->parse(logFile); // ThreadedParser owns the file
+}
+
 void MemcheckTool::parserError(const Valgrind::XmlProtocol::Error &error)
 {
     m_errorModel->addError(error);
@@ -510,16 +563,30 @@ void MemcheckTool::updateErrorFilter()
     m_settings->setVisibleErrorKinds(errorKinds);
 }
 
-void MemcheckTool::finished()
+int MemcheckTool::updateUiAfterFinishedHelper()
 {
     const int issuesFound = m_errorModel->rowCount();
     m_goBack->setEnabled(issuesFound > 1);
     m_goNext->setEnabled(issuesFound > 1);
+    m_loadExternalLogFile->setEnabled(true);
+    setBusyCursor(false);
+    return issuesFound;
+}
+
+void MemcheckTool::engineFinished()
+{
+    const int issuesFound = updateUiAfterFinishedHelper();
     AnalyzerManager::showStatusMessage(issuesFound > 0
         ? AnalyzerManager::tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound)
         : AnalyzerManager::tr("Memory Analyzer Tool finished, no issues were found."));
+}
 
-    setBusyCursor(false);
+void MemcheckTool::loadingExternalXmlLogFileFinished()
+{
+    const int issuesFound = updateUiAfterFinishedHelper();
+    AnalyzerManager::showStatusMessage(issuesFound > 0
+        ? AnalyzerManager::tr("Log file processed, %n issues were found.", 0, issuesFound)
+        : AnalyzerManager::tr("Log file processed, no issues were found."));
 }
 
 void MemcheckTool::setBusyCursor(bool busy)
diff --git a/src/plugins/valgrind/memchecktool.h b/src/plugins/valgrind/memchecktool.h
index e12120077a5..93d913477af 100644
--- a/src/plugins/valgrind/memchecktool.h
+++ b/src/plugins/valgrind/memchecktool.h
@@ -88,13 +88,16 @@ private slots:
     void maybeActiveRunConfigurationChanged();
 
     void engineStarting(const Analyzer::AnalyzerRunControl *engine);
-    void finished();
+    void engineFinished();
+    void loadingExternalXmlLogFileFinished();
 
     void parserError(const Valgrind::XmlProtocol::Error &error);
     void internalParserError(const QString &errorString);
     void updateErrorFilter();
     void suppressionActionTriggered();
 
+    void loadExternalXmlLogFile();
+
 private:
     ToolMode toolMode() const;
     QWidget *createWidgets();
@@ -104,6 +107,8 @@ private:
                                ProjectExplorer::RunConfiguration *runConfiguration = 0);
 
     void clearErrorView();
+    void updateFromSettings();
+    int updateUiAfterFinishedHelper();
 
 private:
     ValgrindBaseSettings *m_settings;
@@ -118,6 +123,7 @@ private:
     QAction *m_filterProjectAction;
     QList<QAction *> m_suppressionActions;
     QAction *m_suppressionSeparator;
+    QAction *m_loadExternalLogFile;
     QAction *m_goBack;
     QAction *m_goNext;
 };
-- 
GitLab