From 22ab8d5662590a2150d6c4ba6472c201f5914181 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Thu, 8 Oct 2009 17:23:27 +0200
Subject: [PATCH] Debugger: Do configuration error checking early on.

Add a configuration checking method to the Debugger manager,
depending on toolchain, wire it to the engines.
Check that in the debugger run controls.

Add a convenience method to ICore that shows a warning
message with a "Settings" button, pointing the user
to a configuration error on a settings page.

Remove leftovers of the dumper parser.
Acked-by: con <qtc-committer@nokia.com>
---
 src/plugins/coreplugin/coreimpl.cpp           |  11 ++
 src/plugins/coreplugin/coreimpl.h             |   5 +
 src/plugins/coreplugin/icore.cpp              |  16 +-
 src/plugins/coreplugin/icore.h                |   6 +
 src/plugins/coreplugin/mainwindow.cpp         |  26 +++
 src/plugins/coreplugin/mainwindow.h           |   6 +
 src/plugins/debugger/debuggerdialogs.cpp      |  24 ---
 src/plugins/debugger/debuggerdialogs.h        |   8 -
 src/plugins/debugger/debuggermanager.cpp      |  52 +++++-
 src/plugins/debugger/debuggermanager.h        |   5 +
 src/plugins/debugger/debuggerrunner.cpp       |  15 +-
 src/plugins/debugger/gdb/gdbengine.cpp        |  21 ++-
 src/plugins/debugger/gdb/gdbengine.h          |   2 +
 src/plugins/debugger/gdb/trkoptions.cpp       |  20 ++
 src/plugins/debugger/gdb/trkoptions.h         |   2 +
 src/plugins/debugger/idebuggerengine.h        |   1 +
 src/plugins/debugger/watchutils.cpp           | 173 ------------------
 .../qt-s60/s60devicerunconfiguration.cpp      |  41 ++++-
 .../qt-s60/s60devicerunconfiguration.h        |  13 +-
 19 files changed, 225 insertions(+), 222 deletions(-)

diff --git a/src/plugins/coreplugin/coreimpl.cpp b/src/plugins/coreplugin/coreimpl.cpp
index 81db34a2ac8..1cfe46f00fe 100644
--- a/src/plugins/coreplugin/coreimpl.cpp
+++ b/src/plugins/coreplugin/coreimpl.cpp
@@ -69,6 +69,17 @@ bool CoreImpl::showOptionsDialog(const QString &group, const QString &page, QWid
     return m_mainwindow->showOptionsDialog(group, page, parent);
 }
 
+bool CoreImpl::showWarningWithOptions(const QString &title, const QString &text,
+                                      const QString &details,
+                                      const QString &settingsCategory,
+                                      const QString &settingsId,
+                                      QWidget *parent)
+{
+    return m_mainwindow->showWarningWithOptions(title, text,
+                                                details, settingsCategory,
+                                                settingsId, parent);
+}
+
 ActionManager *CoreImpl::actionManager() const
 {
     return m_mainwindow->actionManager();
diff --git a/src/plugins/coreplugin/coreimpl.h b/src/plugins/coreplugin/coreimpl.h
index ca2410d8d08..d591f3efb6f 100644
--- a/src/plugins/coreplugin/coreimpl.h
+++ b/src/plugins/coreplugin/coreimpl.h
@@ -50,6 +50,11 @@ public:
     bool showOptionsDialog(const QString &group = QString(),
                            const QString &page = QString(),
                            QWidget *parent = 0);
+    bool showWarningWithOptions(const QString &title, const QString &text,
+                                const QString &details = QString(),
+                                const QString &settingsCategory = QString(),
+                                const QString &settingsId = QString(),
+                                QWidget *parent = 0);
 
     ActionManager *actionManager() const;
     FileManager *fileManager() const ;
diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp
index 39938d78894..531319a5adc 100644
--- a/src/plugins/coreplugin/icore.cpp
+++ b/src/plugins/coreplugin/icore.cpp
@@ -68,7 +68,7 @@
 */
 
 /*!
-    \fn void ICore::showOptionsDialog(const QString &group = QString(),
+    \fn bool ICore::showOptionsDialog(const QString &group = QString(),
                                const QString &page = QString())
     \brief Opens the application options/preferences dialog with preselected
     \a page in a specified \a group.
@@ -76,6 +76,20 @@
     The arguments refer to the string IDs of the corresponding IOptionsPage.
 */
 
+/*!
+    \fn bool ICore::showWarningWithOptions(const QString &title, const QString &text,
+                                   const QString &details = QString(),
+                                   const QString &settingsCategory = QString(),
+                                   const QString &settingsId = QString(),
+                                   QWidget *parent = 0);
+
+    \brief Show a warning message with a button that opens a settings page.
+
+    Should be used to display configuration errors and point users to the setting.
+    Returns true if the settings dialog was accepted.
+*/
+
+
 /*!
     \fn ActionManager *ICore::actionManager() const
     \brief Returns the application's action manager.
diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h
index 8d0d913992e..eab9b9abf0f 100644
--- a/src/plugins/coreplugin/icore.h
+++ b/src/plugins/coreplugin/icore.h
@@ -75,6 +75,12 @@ public:
                                    const QString &page = QString(),
                                    QWidget *parent = 0) = 0;
 
+    virtual bool showWarningWithOptions(const QString &title, const QString &text,
+                                       const QString &details = QString(),
+                                       const QString &settingsCategory = QString(),
+                                       const QString &settingsId = QString(),
+                                       QWidget *parent = 0) = 0;
+
     virtual ActionManager *actionManager() const = 0;
     virtual FileManager *fileManager() const = 0;
     virtual UniqueIDManager *uniqueIDManager() const = 0;
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index a8434f6fdfb..282b2bf6815 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -87,6 +87,7 @@
 #include <QtGui/QWizard>
 #include <QtGui/QPrinter>
 #include <QtGui/QToolButton>
+#include <QtGui/QMessageBox>
 
 /*
 #ifdef Q_OS_UNIX
@@ -1262,3 +1263,28 @@ void MainWindow::setFullScreen(bool on)
     }
 }
 
+// Display a warning with an additional button to open
+// the debugger settings dialog if settingsId is nonempty.
+
+bool MainWindow::showWarningWithOptions(const QString &title,
+                                        const QString &text,
+                                        const QString &details,
+                                        const QString &settingsCategory,
+                                        const QString &settingsId,
+                                        QWidget *parent)
+{
+    if (parent == 0)
+        parent = this;
+    QMessageBox msgBox(QMessageBox::Warning, title, text,
+                       QMessageBox::Ok, parent);
+    if (details.isEmpty())
+        msgBox.setDetailedText(details);
+    QAbstractButton *settingsButton = 0;
+    if (!settingsId.isEmpty() || !settingsCategory.isEmpty())
+        settingsButton = msgBox.addButton(tr("Settings..."), QMessageBox::AcceptRole);
+    msgBox.exec();
+    if (settingsButton && msgBox.clickedButton() == settingsButton) {
+        return showOptionsDialog(settingsCategory, settingsId);
+    }
+    return false;
+}
diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h
index a85a51dddab..7b8510c5e0f 100644
--- a/src/plugins/coreplugin/mainwindow.h
+++ b/src/plugins/coreplugin/mainwindow.h
@@ -138,6 +138,12 @@ public slots:
                            const QString &page = QString(),
                            QWidget *parent = 0);
 
+    bool showWarningWithOptions(const QString &title, const QString &text,
+                                const QString &details = QString(),
+                                const QString &settingsCategory = QString(),
+                                const QString &settingsId = QString(),
+                                QWidget *parent = 0);
+
 protected:
     virtual void changeEvent(QEvent *e);
     virtual void closeEvent(QCloseEvent *event);
diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp
index ffd63b90bca..204be588455 100644
--- a/src/plugins/debugger/debuggerdialogs.cpp
+++ b/src/plugins/debugger/debuggerdialogs.cpp
@@ -51,7 +51,6 @@
 #include <QtGui/QPushButton>
 #include <QtGui/QProxyModel>
 #include <QtGui/QSortFilterProxyModel>
-#include <QtGui/QMessageBox>
 
 namespace Debugger {
 namespace Internal {
@@ -519,28 +518,5 @@ bool AddressDialog::isValid() const
     return ok;
 }
 
-int warningWithSettings(const QString &title,
-                        const QString &text,
-                        const QString &details,
-                        const QString &settingsId,
-                        QWidget *parent)
-{
-    QMessageBox msgBox(QMessageBox::Warning, title, text,
-                       QMessageBox::Ok, parent);
-    if (details.isEmpty())
-        msgBox.setDetailedText(details);
-    QAbstractButton *settingsButton = 0;
-    if (!settingsId.isEmpty())
-        settingsButton = msgBox.addButton(QCoreApplication::translate("Debugger::MessageBox", "Settings..."),
-                                          QMessageBox::AcceptRole);
-    const int dialogCode = msgBox.exec();
-    if (settingsButton && msgBox.clickedButton() == settingsButton) {
-        Core::ICore::instance()->showOptionsDialog(QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY),
-                                                   settingsId);
-        return 2;
-    }
-    return dialogCode;
-}
-
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h
index d89916edf62..a70fe106b15 100644
--- a/src/plugins/debugger/debuggerdialogs.h
+++ b/src/plugins/debugger/debuggerdialogs.h
@@ -62,14 +62,6 @@ struct ProcData
     QString state;
 };
 
-// Display a warning with an additional button to open
-// the debugger settings dialog if settingsId is nonempty.
-int warningWithSettings(const QString &title,
-                        const QString &text,
-                        const QString &details = QString(),
-                        const QString &settingsId = QString(),
-                        QWidget *parent = 0);
-
 class AttachCoreDialog : public QDialog
 {
     Q_OBJECT
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 8a3a1245813..3b60855518a 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -925,11 +925,8 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable,
 
     // We need the CDB debugger in order to be able to debug VS
     // executables
-    if (!winEngine) {
-        *errorMessage = DebuggerManager::tr("Debugging VS executables is currently not enabled.");
-        *settingsIdHint = QLatin1String("Cdb");
+    if (!DebuggerManager::instance()->checkDebugConfiguration(ProjectExplorer::ToolChain::MSVC, errorMessage, 0 , settingsIdHint))
         return 0;
-    }
     return winEngine;
 #endif
 }
@@ -991,7 +988,9 @@ void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp)
         // Create Message box with possibility to go to settings
         const QString msg = tr("Cannot debug '%1' (tool chain: '%2'): %3").
                             arg(d->m_startParameters->executable, toolChainName, errorMessage);
-        warningWithSettings(tr("Warning"),  msg, QString(), settingsIdHint);
+        Core::ICore::instance()->showWarningWithOptions(tr("Warning"),  msg, QString(),
+                                            QLatin1String(DEBUGGER_SETTINGS_CATEGORY),
+                                            settingsIdHint);
         return;
     }
 
@@ -1713,6 +1712,49 @@ bool DebuggerManager::debuggerActionsEnabled() const
     return false;
 }
 
+bool DebuggerManager::checkDebugConfiguration(int toolChain,
+                                              QString *errorMessage,
+                                              QString *settingsCategory /* = 0 */,
+                                              QString *settingsPage /* = 0 */) const
+{
+    errorMessage->clear();
+    if (settingsCategory)
+        settingsCategory->clear();
+    if (settingsPage)
+        settingsPage->clear();
+    bool success = true;
+    switch(toolChain) {
+    case ProjectExplorer::ToolChain::GCC:
+    case ProjectExplorer::ToolChain::LinuxICC:
+    case ProjectExplorer::ToolChain::MinGW:
+    case ProjectExplorer::ToolChain::WINCE: // S60
+    case ProjectExplorer::ToolChain::WINSCW:
+    case ProjectExplorer::ToolChain::GCCE:
+    case ProjectExplorer::ToolChain::RVCT_ARMV5:
+    case ProjectExplorer::ToolChain::RVCT_ARMV6:
+        if (gdbEngine) {
+            success = gdbEngine->checkConfiguration(toolChain, errorMessage, settingsPage);
+        } else {
+            success = false;
+            *errorMessage = msgEngineNotAvailable("Gdb");
+        }
+        break;
+    case ProjectExplorer::ToolChain::MSVC:
+        if (winEngine) {
+            success = winEngine->checkConfiguration(toolChain, errorMessage, settingsPage);
+        } else {
+            success = false;
+            *errorMessage = msgEngineNotAvailable("Cdb");
+            if (settingsPage)
+                *settingsPage = QLatin1String("Cdb");
+        }
+        break;
+    }
+    if (!success && settingsCategory && settingsPage && !settingsPage->isEmpty())
+        *settingsCategory = QLatin1String(DEBUGGER_SETTINGS_CATEGORY);
+    return success;
+}
+
 QDebug operator<<(QDebug d, DebuggerState state)
 {
     return d << stateName(state) << '(' << int(state) << ')';
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 71b9be64408..30806390ca0 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -173,6 +173,11 @@ public:
 
     bool debuggerActionsEnabled() const;
 
+    bool checkDebugConfiguration(int toolChain,
+                                 QString *errorMessage,
+                                 QString *settingsCategory = 0,
+                                 QString *settingsPage = 0) const;
+
     static DebuggerManager *instance();
 
 public slots:
diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp
index dc622cf2e35..17e11a1e095 100644
--- a/src/plugins/debugger/debuggerrunner.cpp
+++ b/src/plugins/debugger/debuggerrunner.cpp
@@ -36,6 +36,7 @@
 #include <projectexplorer/projectexplorerconstants.h>
 
 #include <utils/qtcassert.h>
+#include <coreplugin/icore.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/QDir>
@@ -174,7 +175,19 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
 void DebuggerRunControl::start()
 {
     m_running = true;
-    m_manager->startNewDebugger(m_startParameters);
+    QString errorMessage;
+    QString settingsCategory;
+    QString settingsPage;
+    if (m_manager->checkDebugConfiguration(startParameters()->toolChainType, &errorMessage,
+                                           &settingsCategory, &settingsPage)) {
+        m_manager->startNewDebugger(m_startParameters);
+    } else {
+        error(this, errorMessage);
+        emit finished();
+        Core::ICore::instance()->showWarningWithOptions(tr("Debugger"), errorMessage,
+                                                        QString(),
+                                                        settingsCategory, settingsPage);
+    }
 }
 
 void DebuggerRunControl::slotAddToOutputWindowInline(const QString &data)
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 21fcd23af55..d2e3db5c9cd 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -1409,6 +1409,24 @@ int GdbEngine::currentFrame() const
     return manager()->stackHandler()->currentIndex();
 }
 
+bool GdbEngine::checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage) const
+{
+    switch (toolChain) {
+    case ProjectExplorer::ToolChain::WINSCW: // S60
+    case ProjectExplorer::ToolChain::GCCE:
+    case ProjectExplorer::ToolChain::RVCT_ARMV5:
+    case ProjectExplorer::ToolChain::RVCT_ARMV6:
+        if (!m_trkOptions->check(errorMessage)) {
+            if (settingsPage)
+                *settingsPage = TrkOptionsPage::settingsId();
+            return false;
+        }
+    default:
+        break;
+    }
+    return true;
+}
+
 AbstractGdbAdapter *GdbEngine::createAdapter(const DebuggerStartParametersPtr &sp)
 {
     switch (sp->toolChainType) {
@@ -3983,7 +4001,8 @@ void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &sett
 {
     setState(AdapterStartFailed);
     debugMessage(_("ADAPTER START FAILED"));
-    warningWithSettings(tr("Adapter start failed"), msg, QString(), settingsIdHint);
+    Core::ICore::instance()->showWarningWithOptions(tr("Adapter start failed"), msg, QString(),
+						    QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
     shutdown();
 }
 
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index e4a3c652b03..3df5bc46fa4 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -151,6 +151,8 @@ private:
     Q_SLOT void setAutoDerefPointers(const QVariant &on);
     virtual bool isGdbEngine() const { return true; }
 
+    virtual bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const;
+
     //
     // Own stuff
     //
diff --git a/src/plugins/debugger/gdb/trkoptions.cpp b/src/plugins/debugger/gdb/trkoptions.cpp
index 4975d619852..0c364a300df 100644
--- a/src/plugins/debugger/gdb/trkoptions.cpp
+++ b/src/plugins/debugger/gdb/trkoptions.cpp
@@ -28,9 +28,11 @@
 **************************************************************************/
 
 #include "trkoptions.h"
+#include <utils/synchronousprocess.h>
 
 #include <QtCore/QSettings>
 #include <QtCore/QFileInfo>
+#include <QtCore/QCoreApplication>
 
 #ifdef Q_OS_WIN
 #    define SERIALPORT_ROOT "COM"
@@ -104,6 +106,24 @@ void TrkOptions::toSettings(QSettings *s) const
     s->endGroup();
 }
 
+bool TrkOptions::check(QString *errorMessage) const
+{
+    if (gdb.isEmpty()) {
+        *errorMessage = QCoreApplication::translate("TrkOptions", "No Symbian gdb executable specified.");
+        return false;
+    }
+    const QString expanded = Utils::SynchronousProcess::locateBinary(gdb);
+    if (expanded.isEmpty()) {
+        *errorMessage = QCoreApplication::translate("TrkOptions", "The Symbian gdb executable '%1' could not be found in the search path.").arg(gdb);
+        return false;
+    }
+    if (!cygwin.isEmpty() && !QFileInfo(cygwin).isDir()) {
+        *errorMessage = QCoreApplication::translate("TrkOptions", "The Cygwin directory '%1' does not exist.").arg(cygwin);
+        return false;
+    }
+    return true;
+}
+
 bool TrkOptions::equals(const  TrkOptions &o) const
 {
     return mode == o.mode
diff --git a/src/plugins/debugger/gdb/trkoptions.h b/src/plugins/debugger/gdb/trkoptions.h
index 9e50796ea7c..c6f8cac0e8a 100644
--- a/src/plugins/debugger/gdb/trkoptions.h
+++ b/src/plugins/debugger/gdb/trkoptions.h
@@ -54,6 +54,8 @@ struct TrkOptions
     void toSettings(QSettings *s) const;
     bool equals(const  TrkOptions &o) const;
 
+    bool check(QString *errorMessage) const;
+
     // Lists of choices for the devices
     static QStringList serialPorts();
     static QStringList blueToothDevices();
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
index c4d7202152d..b1110bda67a 100644
--- a/src/plugins/debugger/idebuggerengine.h
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -117,6 +117,7 @@ public:
 
     virtual void addOptionPages(QList<Core::IOptionsPage*> *) const {}
     virtual bool isGdbEngine() const { return false; }
+    virtual bool checkConfiguration(int /* toolChain */, QString * /* errorMessage */, QString * /* settingsPage */ = 0) const { return true; }
 
 protected:
     void showStatusMessage(const QString &msg, int timeout = -1);
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index a494c0d7000..576f29811e5 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -695,179 +695,6 @@ void QtDumperHelper::parseQueryTypes(const QStringList &l, Debugger debugger)
     }
 }
 
-/*  A parse for dumper output:
- * "iname="local.sl",addr="0x0012BA84",value="<3 items>",valuedisabled="true",
- * numchild="3",childtype="QString",childnumchild="0",children=[{name="0",value="<binhex>",
- * valueencoded="2"},{name="1",value="dAB3AG8A",valueencoded="2"},{name="2",
- * value="dABoAHIAZQBlAA==",valueencoded="2"}]"
- * Default implementation can be used for debugging purposes. */
-
-class DumperParser
-{
-public:
-    explicit DumperParser(const char *s) : m_s(s) {}
-    bool run();
-    virtual ~DumperParser() {}
-
-protected:
-    // handle 'key="value"'
-    virtual bool handleKeyword(const char *k, int size);
-    virtual bool handleListStart();
-    virtual bool handleListEnd();
-    virtual bool handleHashStart();
-    virtual bool handleHashEnd();
-    virtual bool handleValue(const char *k, int size);
-
-private:
-    bool parseHash(int level, const char *&pos);
-    bool parseValue(int level, const char *&pos);
-    bool parseStringValue(const char *&ptr, int &size, const char *&pos) const;
-
-    const char *m_s;
-};
-
-// get a string value with pos at the opening double quote
-bool DumperParser::parseStringValue(const char *&ptr, int &size, const char *&pos) const
-{
-    pos++;
-    const char *endValuePtr = strchr(pos, '"');
-    if (!endValuePtr)
-        return false;
-    size = endValuePtr - pos;
-    ptr = pos;
-    pos = endValuePtr + 1;
-    return true;
-}
-
-bool DumperParser::run()
-{
-    const char *ptr = m_s;
-    const bool rc = parseHash(0, ptr);
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO << '\n' << m_s << rc;
-    return rc;
-}
-
-// Parse a non-empty hash with pos at the first keyword.
-// Curly braces are present at level 0 only.
-// '{a="X", b="X"}'
-bool DumperParser::parseHash(int level, const char *&pos)
-{
-    while (true) {
-        switch (*pos) {
-        case '\0': // EOS is acceptable at level 0 only
-            return level == 0;
-        case '}':
-            pos++;
-            return true;
-        default:
-            break;
-        }
-        const char *equalsPtr = strchr(pos, '=');
-        if (!equalsPtr)
-            return false;
-        const int keywordLen = equalsPtr - pos;
-        if (!handleKeyword(pos, keywordLen))
-            return false;
-        pos = equalsPtr + 1;
-        if (!*pos)
-            return false;
-        if (!parseValue(level + 1, pos))
-            return false;
-        if (*pos == ',')
-            pos++;
-    }
-    return false;
-}
-
-bool DumperParser::parseValue(int level, const char *&pos)
-{
-    // Simple string literal
-    switch (*pos) {
-    case '"': {
-            const char *valuePtr;
-            int valueSize;
-            return parseStringValue(valuePtr, valueSize, pos) && handleValue(valuePtr, valueSize);
-        }
-        // A List. Note that it has a trailing comma '["a",]'
-    case '[': {
-            if (!handleListStart())
-                return false;
-            pos++;
-            while (true) {
-                switch (*pos) {
-                case ']':
-                    pos++;
-                    return handleListEnd();
-                case '\0':
-                    return false;
-                default:
-                    break;
-                }
-                if (!parseValue(level + 1, pos))
-                    return false;
-                if (*pos == ',')
-                    pos++;
-            }
-        }
-        return false;
-        // A hash '{a="b",b="c"}'
-    case '{': {
-            if (!handleHashStart())
-                return false;
-            pos++;
-            if (!parseHash(level + 1, pos))
-                return false;
-            return handleHashEnd();
-        }
-        return false;
-    }
-    return false;
-}
-
-bool DumperParser::handleKeyword(const char *k, int size)
-{
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO << '\n' << QByteArray(k, size);
-    return true;
-}
-
-bool DumperParser::handleListStart()
-{
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO;
-    return true;
-}
-
-bool DumperParser::handleListEnd()
-{
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO;
-    return true;
-}
-
-bool DumperParser::handleHashStart()
-{
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO;
-    return true;
-}
-
-bool DumperParser::handleHashEnd()
-{
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO;
-
-    return true;
-}
-
-bool DumperParser::handleValue(const char *k, int size)
-{
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO << '\n' << QByteArray(k, size);
-    return true;
-}
-
 static inline QString qClassName(const QString &qtNamespace, const char *className)
 {
     if (qtNamespace.isEmpty())
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
index 3ac0d4b39cf..4dde9723ded 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
@@ -558,8 +558,22 @@ void S60DeviceRunControlBase::start()
     emit addToOutputWindow(this, tr("Creating %1.sisx ...").arg(QDir::toNativeSeparators(m_baseFileName)));
     emit addToOutputWindow(this, tr("Executable file: %1").arg(m_executableFileName));
 
-    if (!createPackageFileFromTemplate())
+    QString errorMessage;
+    QString settingsCategory;
+    QString settingsPage;
+    if (!checkConfiguration(&errorMessage, &settingsCategory, &settingsPage)) {
+        error(this, errorMessage);
+        emit finished();
+        Core::ICore::instance()->showWarningWithOptions(tr("S60 Debugger"), errorMessage, QString(),
+                                                        settingsCategory, settingsPage);
+        return;
+    }
+
+    if (!createPackageFileFromTemplate(&errorMessage)) {
+        error(this, errorMessage);
+        emit finished();
         return;
+    }
     m_makesis->setWorkingDirectory(m_workingDirectory);
     emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(m_makesisTool), m_packageFile));
     m_makesis->start(m_makesisTool, QStringList(m_packageFile), QIODevice::ReadOnly);
@@ -592,12 +606,11 @@ void S60DeviceRunControlBase::readStandardOutput()
     emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
 }
 
-bool S60DeviceRunControlBase::createPackageFileFromTemplate()
+bool S60DeviceRunControlBase::createPackageFileFromTemplate(QString *errorMessage)
 {
     QFile packageTemplate(m_packageTemplateFile);
     if (!packageTemplate.open(QIODevice::ReadOnly)) {
-        error(this, tr("Could not read template package file '%1'").arg(QDir::toNativeSeparators(m_packageTemplateFile)));
-        emit finished();
+        *errorMessage = tr("Could not read template package file '%1'").arg(QDir::toNativeSeparators(m_packageTemplateFile));
         return false;
     }
     QString contents = packageTemplate.readAll();
@@ -606,8 +619,7 @@ bool S60DeviceRunControlBase::createPackageFileFromTemplate()
     contents.replace(QLatin1String("$(TARGET)"), m_symbianTarget);
     QFile packageFile(m_packageFilePath);
     if (!packageFile.open(QIODevice::WriteOnly)) {
-        error(this, tr("Could not write package file '%1'").arg(QDir::toNativeSeparators(m_packageFilePath)));
-        emit finished();
+        *errorMessage = tr("Could not write package file '%1'").arg(QDir::toNativeSeparators(m_packageFilePath));
         return false;
     }
     packageFile.write(contents.toLocal8Bit());
@@ -749,6 +761,13 @@ void S60DeviceRunControlBase::printApplicationOutput(const QString &output)
     emit addToOutputWindowInline(this, output);
 }
 
+bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
+                                                 QString * /* settingsCategory */,
+                                                 QString * /* settingsPage */) const
+{
+    return true;
+}
+
 // =============== S60DeviceRunControl
 S60DeviceRunControl::S60DeviceRunControl(const QSharedPointer<ProjectExplorer::RunConfiguration> &runConfiguration) :
     S60DeviceRunControlBase(runConfiguration)
@@ -849,3 +868,13 @@ void S60DeviceDebugRunControl::debuggingFinished()
     emit addToOutputWindow(this, tr("Debugging finished."));
     emit finished();
 }
+
+bool S60DeviceDebugRunControl::checkConfiguration(QString *errorMessage,
+                                                  QString *settingsCategory,
+                                                  QString *settingsPage) const
+{
+    return Debugger::DebuggerManager::instance()->checkDebugConfiguration(m_startParams->toolChainType,
+                                                                          errorMessage,
+                                                                          settingsCategory,
+                                                                          settingsPage);
+}
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
index 5c117d11b14..aa8ce4db869 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
@@ -166,6 +166,10 @@ protected:
     virtual void handleLauncherFinished() = 0;
     void processFailed(const QString &program, QProcess::ProcessError errorCode);
 
+    virtual bool checkConfiguration(QString *errorMessage,
+                                    QString *settingsCategory,
+                                    QString *settingsPage) const;
+
 protected slots:
     void printApplicationOutput(const QString &output);
 
@@ -185,8 +189,8 @@ private slots:
     void printInstallFailed(const QString &filename, const QString &errorMessage);
     void launcherFinished();
 
-private:
-    bool createPackageFileFromTemplate();
+private:    
+    bool createPackageFileFromTemplate(QString *errorMessage);
 
     QString m_serialPortName;
     QString m_serialPortFriendlyName;
@@ -240,9 +244,12 @@ public:
 
     virtual void stop();
 
-protected:
+protected:    
     virtual void initLauncher(const QString &executable, trk::Launcher *);
     virtual void handleLauncherFinished();
+    virtual bool checkConfiguration(QString *errorMessage,
+                                    QString *settingsCategory,
+                                    QString *settingsPage) const;
 
 private slots:
     void debuggingFinished();
-- 
GitLab