From a8cf4cb1bc879f252d8a6b962185419894543bb8 Mon Sep 17 00:00:00 2001
From: con <qtc-committer@nokia.com>
Date: Tue, 16 Jun 2009 15:11:47 +0200
Subject: [PATCH] Add a run configuration for winscw emulator.

The runner uses the applicationlauncher internally, which is now
exported from the projectexplorer plugin for that reason.
---
 .../projectexplorer/applicationlauncher.h     |  12 +-
 .../applicationlauncher_win.cpp               |   1 +
 .../applicationlauncher_x11.cpp               |   2 +-
 .../applicationrunconfiguration.cpp           |   2 +-
 .../applicationrunconfiguration.h             |   2 +-
 .../projectexplorer/runconfiguration.cpp      |   6 +-
 .../projectexplorer/runconfiguration.h        |   4 +-
 .../qt4projectmanager/qt-s60/qt-s60-todo.txt  |   8 +-
 .../qt4projectmanager/qt-s60/qt-s60.pri       |   8 +-
 .../qt-s60/s60emulatorrunconfiguration.cpp    | 309 ++++++++++++++++++
 .../qt-s60/s60emulatorrunconfiguration.h      | 107 ++++++
 .../qt4projectmanager/qt-s60/s60manager.cpp   |  23 +-
 .../qt4projectmanager/qt-s60/s60manager.h     |   8 +-
 13 files changed, 472 insertions(+), 20 deletions(-)
 create mode 100644 src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp
 create mode 100644 src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h

diff --git a/src/plugins/projectexplorer/applicationlauncher.h b/src/plugins/projectexplorer/applicationlauncher.h
index 47840c547a7..2eea8988841 100644
--- a/src/plugins/projectexplorer/applicationlauncher.h
+++ b/src/plugins/projectexplorer/applicationlauncher.h
@@ -30,6 +30,8 @@
 #ifndef APPLICATIONLAUNCHER_H
 #define APPLICATIONLAUNCHER_H
 
+#include "projectexplorer_export.h"
+
 #include <QtCore/QObject>
 #include <QtCore/QStringList>
 #include <QtCore/QProcess>
@@ -44,11 +46,12 @@ class ConsoleProcess;
 }
 
 namespace ProjectExplorer {
-namespace Internal {
 
-class WinGuiProcess;
+namespace Internal {
+    class WinGuiProcess;
+}
 
-class ApplicationLauncher : public QObject
+class PROJECTEXPLORER_EXPORT ApplicationLauncher : public QObject
 {
     Q_OBJECT
 
@@ -93,14 +96,13 @@ private:
     Mode m_currentMode;
 
 #ifdef Q_OS_WIN
-    WinGuiProcess *m_winGuiProcess;
+    Internal::WinGuiProcess *m_winGuiProcess;
 #else
     QTextCodec *m_outputCodec;
     QTextCodec::ConverterState m_outputCodecState;
 #endif
 };
 
-} // namespace Internal
 } // namespace ProjectExplorer
 
 #endif // APPLICATIONLAUNCHER_H
diff --git a/src/plugins/projectexplorer/applicationlauncher_win.cpp b/src/plugins/projectexplorer/applicationlauncher_win.cpp
index 66163298000..92cf13fafad 100644
--- a/src/plugins/projectexplorer/applicationlauncher_win.cpp
+++ b/src/plugins/projectexplorer/applicationlauncher_win.cpp
@@ -33,6 +33,7 @@
 
 #include <QDebug>
 
+using namespace ProjectExplorer;
 using namespace ProjectExplorer::Internal;
 using namespace Core::Utils;
 
diff --git a/src/plugins/projectexplorer/applicationlauncher_x11.cpp b/src/plugins/projectexplorer/applicationlauncher_x11.cpp
index e5c61a59109..3dd189bfe81 100644
--- a/src/plugins/projectexplorer/applicationlauncher_x11.cpp
+++ b/src/plugins/projectexplorer/applicationlauncher_x11.cpp
@@ -34,7 +34,7 @@
 
 #include <QtCore/QTimer>
 
-using namespace ProjectExplorer::Internal;
+using namespace ProjectExplorer;
 using namespace Core::Utils;
 
 ApplicationLauncher::ApplicationLauncher(QObject *parent)
diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.cpp b/src/plugins/projectexplorer/applicationrunconfiguration.cpp
index c1dee4a0562..b881b944f73 100644
--- a/src/plugins/projectexplorer/applicationrunconfiguration.cpp
+++ b/src/plugins/projectexplorer/applicationrunconfiguration.cpp
@@ -134,7 +134,7 @@ void ApplicationRunControl::start()
 
     m_executable = rc->executable();
 
-    m_applicationLauncher.start(static_cast<Internal::ApplicationLauncher::Mode>(rc->runMode()),
+    m_applicationLauncher.start(static_cast<ApplicationLauncher::Mode>(rc->runMode()),
                                 m_executable, rc->commandLineArguments());
     emit started();
 
diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.h b/src/plugins/projectexplorer/applicationrunconfiguration.h
index d9f5b543af0..6d347c0ab62 100644
--- a/src/plugins/projectexplorer/applicationrunconfiguration.h
+++ b/src/plugins/projectexplorer/applicationrunconfiguration.h
@@ -44,7 +44,7 @@ class PROJECTEXPLORER_EXPORT ApplicationRunConfiguration : public RunConfigurati
     Q_OBJECT
 public:
     enum RunMode {
-        Console = Internal::ApplicationLauncher::Console,
+        Console = ApplicationLauncher::Console,
         Gui
     };
 
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
index e89a03cab8b..98aad4ca9be 100644
--- a/src/plugins/projectexplorer/runconfiguration.cpp
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -79,7 +79,8 @@ void RunConfiguration::restore(const PersistentSettingsReader &reader)
 }
 
 
-IRunConfigurationFactory::IRunConfigurationFactory()
+IRunConfigurationFactory::IRunConfigurationFactory(QObject *parent)
+    : QObject(parent)
 {
 }
 
@@ -87,7 +88,8 @@ IRunConfigurationFactory::~IRunConfigurationFactory()
 {
 }
 
-IRunConfigurationRunner::IRunConfigurationRunner()
+IRunConfigurationRunner::IRunConfigurationRunner(QObject *parent)
+    : QObject(parent)
 {
 }
 
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index 2c3e264058d..b45a996c20e 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -102,7 +102,7 @@ class PROJECTEXPLORER_EXPORT IRunConfigurationFactory : public QObject
 {
     Q_OBJECT
 public:
-    IRunConfigurationFactory();
+    IRunConfigurationFactory(QObject *parent = 0);
     virtual ~IRunConfigurationFactory();
     // used to recreate the runConfigurations when restoring settings
     virtual bool canRestore(const QString &type) const = 0;
@@ -118,7 +118,7 @@ class PROJECTEXPLORER_EXPORT IRunConfigurationRunner : public QObject
 {
     Q_OBJECT
 public:
-    IRunConfigurationRunner();
+    IRunConfigurationRunner(QObject *parent = 0);
     virtual ~IRunConfigurationRunner();
     virtual bool canRun(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode) = 0;
     virtual RunControl* run(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode) = 0;
diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt b/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt
index 846f57c86dd..984c00ae082 100644
--- a/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt
+++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt
@@ -17,9 +17,15 @@
 * Debugging helpers
     * must probably be compiled for different toolchains
 
+* Run Configurations
+    * enabled property doesn't update correctly
+        * missing signals qtVersionChanged + toolChainChanged
+    * handling of active run config getting disabled
+
+* Add compile output parser winscw at least!
+
 * WINSCW tool chain:
     * predefined macros
 
-* Run WINSCW executables
 * Deploy gcce executables
 
diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri
index af319a68ae6..bec391fdcbc 100644
--- a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri
+++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri
@@ -6,12 +6,14 @@ SUPPORT_QT_S60 = $$(QTCREATOR_WITH_S60)
         $$PWD/s60devicespreferencepane.cpp \
         $$PWD/s60manager.cpp \
         $$PWD/winscwtoolchain.cpp \
-        $$PWD/gccetoolchain.cpp
+        $$PWD/gccetoolchain.cpp \
+        $$PWD/s60emulatorrunconfiguration.cpp
     HEADERS += $$PWD/s60devices.h \
         $$PWD/s60devicespreferencepane.h \
         $$PWD/s60manager.h \
         $$PWD/winscwtoolchain.h \
-        $$PWD/gccetoolchain.h
+        $$PWD/gccetoolchain.h \
+        $$PWD/s60emulatorrunconfiguration.h
     FORMS += $$PWD/s60devicespreferencepane.ui
-    OTHER_FILES += qt-s60-todo.txt
+    OTHER_FILES += $$PWD/qt-s60-todo.txt
 }
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp
new file mode 100644
index 00000000000..29081da0f40
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp
@@ -0,0 +1,309 @@
+#include "s60emulatorrunconfiguration.h"
+
+#include "qt4project.h"
+#include "qtversionmanager.h"
+#include "profilereader.h"
+#include "s60manager.h"
+#include "s60devices.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+#include <utils/qtcassert.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/project.h>
+
+using namespace ProjectExplorer;
+using namespace Qt4ProjectManager::Internal;
+
+// ======== S60EmulatorRunConfiguration
+S60EmulatorRunConfiguration::S60EmulatorRunConfiguration(Project *project, const QString &proFilePath)
+    : RunConfiguration(project),
+    m_proFilePath(proFilePath),
+    m_cachedTargetInformationValid(false)
+{
+    if (!m_proFilePath.isEmpty())
+        setName(tr("%1 in Emulator").arg(QFileInfo(m_proFilePath).completeBaseName()));
+    else
+        setName(tr("QtS60EmulatorRunConfiguration"));
+
+    connect(project, SIGNAL(activeBuildConfigurationChanged()),
+            this, SLOT(invalidateCachedTargetInformation()));
+}
+
+S60EmulatorRunConfiguration::~S60EmulatorRunConfiguration()
+{
+}
+
+QString S60EmulatorRunConfiguration::type() const
+{
+    return "Qt4ProjectManager.EmulatorRunConfiguration";
+}
+
+bool S60EmulatorRunConfiguration::isEnabled() const
+{
+    Qt4Project *pro = qobject_cast<Qt4Project*>(project());
+    QTC_ASSERT(pro, return false);
+    ToolChain::ToolChainType type = pro->toolChainType(pro->activeBuildConfiguration());
+    return type == ToolChain::WINSCW;
+}
+
+QWidget *S60EmulatorRunConfiguration::configurationWidget()
+{
+    return new S60EmulatorRunConfigurationWidget(this);
+}
+
+void S60EmulatorRunConfiguration::save(PersistentSettingsWriter &writer) const
+{
+    const QDir projectDir = QFileInfo(project()->file()->fileName()).absoluteDir();
+    writer.saveValue("ProFile", projectDir.relativeFilePath(m_proFilePath));
+    RunConfiguration::save(writer);
+}
+
+void S60EmulatorRunConfiguration::restore(const PersistentSettingsReader &reader)
+{
+    RunConfiguration::restore(reader);
+    const QDir projectDir = QFileInfo(project()->file()->fileName()).absoluteDir();
+    m_proFilePath = projectDir.filePath(reader.restoreValue("ProFile").toString());
+}
+
+QString S60EmulatorRunConfiguration::executable() const
+{
+    const_cast<S60EmulatorRunConfiguration *>(this)->updateTarget();
+    return m_executable;
+}
+
+void S60EmulatorRunConfiguration::updateTarget()
+{
+    if (m_cachedTargetInformationValid)
+        return;
+    Qt4Project *pro = static_cast<Qt4Project *>(project());
+    Qt4PriFileNode * priFileNode = static_cast<Qt4Project *>(project())->rootProjectNode()->findProFileFor(m_proFilePath);
+    if (!priFileNode) {
+        m_executable = QString::null;
+        m_cachedTargetInformationValid = true;
+        emit targetInformationChanged();
+        return;
+    }
+    QtVersion *qtVersion = pro->qtVersion(pro->activeBuildConfiguration());
+    ProFileReader *reader = priFileNode->createProFileReader();
+    reader->setCumulative(false);
+    reader->setQtVersion(qtVersion);
+
+    // Find out what flags we pass on to qmake, this code is duplicated in the qmake step
+    QtVersion::QmakeBuildConfig defaultBuildConfiguration = qtVersion->defaultBuildConfig();
+    QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(pro->qmakeStep()->value(pro->activeBuildConfiguration(), "buildConfiguration").toInt());
+    QStringList addedUserConfigArguments;
+    QStringList removedUserConfigArguments;
+    if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll))
+        removedUserConfigArguments << "debug_and_release";
+    if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll))
+        addedUserConfigArguments << "debug_and_release";
+    if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild))
+        addedUserConfigArguments << "release";
+    if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild))
+        addedUserConfigArguments << "debug";
+
+    reader->setUserConfigCmdArgs(addedUserConfigArguments, removedUserConfigArguments);
+
+    if (!reader->readProFile(m_proFilePath)) {
+        delete reader;
+        Core::ICore::instance()->messageManager()->printToOutputPane(tr("Could not parse %1. The QtS60 emulator run configuration %2 can not be started.").arg(m_proFilePath).arg(name()));
+        return;
+    }
+
+    QString baseDir = S60Manager::instance()->devices()->deviceForId(
+            S60Manager::instance()->deviceIdFromDetectionSource(qtVersion->autodetectionSource())).epocRoot;
+    QString qmakeBuildConfig = "urel";
+    if (projectBuildConfiguration & QtVersion::DebugBuild)
+        qmakeBuildConfig = "udeb";
+    baseDir += "/epoc32/release/winscw/" + qmakeBuildConfig;
+
+    m_executable = QDir::toNativeSeparators(
+            QDir::cleanPath(baseDir + QLatin1Char('/') + reader->value("TARGET")));
+    m_executable += QLatin1String(".exe");
+
+    delete reader;
+    m_cachedTargetInformationValid = true;
+    emit targetInformationChanged();
+}
+
+void S60EmulatorRunConfiguration::invalidateCachedTargetInformation()
+{
+    m_cachedTargetInformationValid = false;
+    emit targetInformationChanged();
+}
+
+// ======== S60EmulatorRunConfigurationWidget
+
+S60EmulatorRunConfigurationWidget::S60EmulatorRunConfigurationWidget(S60EmulatorRunConfiguration *runConfiguration,
+                                                                     QWidget *parent)
+    : QWidget(parent),
+    m_runConfiguration(runConfiguration)
+{
+    QFormLayout *toplayout = new QFormLayout();
+    toplayout->setMargin(0);
+    setLayout(toplayout);
+
+    QLabel *nameLabel = new QLabel(tr("Name:"));
+    m_nameLineEdit = new QLineEdit(m_runConfiguration->name());
+    nameLabel->setBuddy(m_nameLineEdit);
+    toplayout->addRow(nameLabel, m_nameLineEdit);
+
+    m_executableLabel = new QLabel(m_runConfiguration->executable());
+    toplayout->addRow(tr("Executable:"), m_executableLabel);
+
+    connect(m_nameLineEdit, SIGNAL(textEdited(QString)),
+        this, SLOT(nameEdited(QString)));
+    connect(m_runConfiguration, SIGNAL(targetInformationChanged()),
+            this, SLOT(updateTargetInformation()));
+}
+
+void S60EmulatorRunConfigurationWidget::nameEdited(const QString &text)
+{
+    m_runConfiguration->setName(text);
+}
+
+void S60EmulatorRunConfigurationWidget::updateTargetInformation()
+{
+    m_executableLabel->setText(m_runConfiguration->executable());
+}
+
+// ======== S60EmulatorRunConfigurationFactory
+
+S60EmulatorRunConfigurationFactory::S60EmulatorRunConfigurationFactory(QObject *parent)
+    : IRunConfigurationFactory(parent)
+{
+}
+
+S60EmulatorRunConfigurationFactory::~S60EmulatorRunConfigurationFactory()
+{
+}
+
+bool S60EmulatorRunConfigurationFactory::canRestore(const QString &type) const
+{
+    return type == "Qt4ProjectManager.EmulatorRunConfiguration";
+}
+
+QStringList S60EmulatorRunConfigurationFactory::availableCreationTypes(Project *pro) const
+{
+    Qt4Project *qt4project = qobject_cast<Qt4Project *>(pro);
+    if (qt4project) {
+        QStringList applicationProFiles;
+        QList<Qt4ProFileNode *> list = qt4project->applicationProFiles();
+        foreach (Qt4ProFileNode * node, list) {
+            applicationProFiles.append("QtS60EmulatorRunConfiguration." + node->path());
+        }
+        return applicationProFiles;
+    } else {
+        return QStringList();
+    }
+}
+
+QString S60EmulatorRunConfigurationFactory::displayNameForType(const QString &type) const
+{
+    QString fileName = type.mid(QString("QtS60EmulatorRunConfiguration.").size());
+    return tr("%1 in Emulator").arg(QFileInfo(fileName).completeBaseName());
+}
+
+QSharedPointer<RunConfiguration> S60EmulatorRunConfigurationFactory::create(Project *project, const QString &type)
+{
+    Qt4Project *p = qobject_cast<Qt4Project *>(project);
+    Q_ASSERT(p);
+    if (type.startsWith("QtS60EmulatorRunConfiguration.")) {
+        QString fileName = type.mid(QString("QtS60EmulatorRunConfiguration.").size());
+        return QSharedPointer<RunConfiguration>(new S60EmulatorRunConfiguration(p, fileName));
+    }
+    Q_ASSERT(type == "Qt4ProjectManager.EmulatorRunConfiguration");
+    // The right path is set in restoreSettings
+    QSharedPointer<RunConfiguration> rc(new S60EmulatorRunConfiguration(p, QString::null));
+    return rc;
+}
+
+// ======== S60EmulatorRunConfigurationRunner
+
+S60EmulatorRunConfigurationRunner::S60EmulatorRunConfigurationRunner(QObject *parent)
+    : IRunConfigurationRunner(parent)
+{
+}
+
+bool S60EmulatorRunConfigurationRunner::canRun(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode)
+{
+    return (mode == ProjectExplorer::Constants::RUNMODE)
+            && (!runConfiguration.dynamicCast<S60EmulatorRunConfiguration>().isNull());
+}
+
+RunControl* S60EmulatorRunConfigurationRunner::run(QSharedPointer<RunConfiguration> runConfiguration, const QString &mode)
+{
+    QSharedPointer<S60EmulatorRunConfiguration> rc = runConfiguration.dynamicCast<S60EmulatorRunConfiguration>();
+    Q_ASSERT(!rc.isNull());
+    Q_ASSERT(mode == ProjectExplorer::Constants::RUNMODE);
+
+    S60EmulatorRunControl *runControl = new S60EmulatorRunControl(rc);
+    return runControl;
+}
+
+// ======== S60EmulatorRunControl
+
+S60EmulatorRunControl::S60EmulatorRunControl(QSharedPointer<RunConfiguration> runConfiguration)
+    : RunControl(runConfiguration)
+{
+    connect(&m_applicationLauncher, SIGNAL(applicationError(QString)),
+            this, SLOT(slotError(QString)));
+    connect(&m_applicationLauncher, SIGNAL(appendOutput(QString)),
+            this, SLOT(slotAddToOutputWindow(QString)));
+    connect(&m_applicationLauncher, SIGNAL(processExited(int)),
+            this, SLOT(processExited(int)));
+    connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
+            this, SLOT(bringApplicationToForeground(qint64)));
+}
+
+void S60EmulatorRunControl::start()
+{
+    QSharedPointer<S60EmulatorRunConfiguration> rc = runConfiguration().dynamicCast<S60EmulatorRunConfiguration>();
+    Q_ASSERT(!rc.isNull());
+
+    // stuff like the EPOCROOT and EPOCDEVICE env variable
+    Environment env = Environment::systemEnvironment();
+    static_cast<Qt4Project *>(rc->project())->toolChain(rc->project()->activeBuildConfiguration())->addToEnvironment(env);
+    m_applicationLauncher.setEnvironment(env.toStringList());
+
+    m_executable = rc->executable();
+
+    m_applicationLauncher.start(ApplicationLauncher::Gui,
+                                m_executable, QStringList());
+    emit started();
+
+    emit addToOutputWindow(this, tr("Starting %1...").arg(QDir::toNativeSeparators(m_executable)));
+}
+
+void S60EmulatorRunControl::stop()
+{
+    m_applicationLauncher.stop();
+}
+
+bool S60EmulatorRunControl::isRunning() const
+{
+    return m_applicationLauncher.isRunning();
+}
+
+void S60EmulatorRunControl::slotError(const QString & err)
+{
+    emit error(this, err);
+    emit finished();
+}
+
+void S60EmulatorRunControl::slotAddToOutputWindow(const QString &line)
+{
+    static QString prefix = tr("[Qt Message]");
+    static int prefixLength = prefix.length();
+    int index = line.indexOf(prefix);
+    if (index != -1) {
+        emit addToOutputWindowInline(this, line.mid(index + prefixLength + 1));
+    }
+}
+
+void S60EmulatorRunControl::processExited(int exitCode)
+{
+    emit addToOutputWindow(this, tr("%1 exited with code %2").arg(QDir::toNativeSeparators(m_executable)).arg(exitCode));
+    emit finished();
+}
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h
new file mode 100644
index 00000000000..55ef013dc8c
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h
@@ -0,0 +1,107 @@
+#ifndef S60EMULATORRUNCONFIGURATION_H
+#define S60EMULATORRUNCONFIGURATION_H
+
+#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/applicationlauncher.h>
+
+#include <QtGui/QWidget>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class S60EmulatorRunConfiguration : public ProjectExplorer::RunConfiguration
+{
+    Q_OBJECT
+public:
+    S60EmulatorRunConfiguration(ProjectExplorer::Project *project, const QString &proFilePath);
+    ~S60EmulatorRunConfiguration();
+
+    QString type() const;
+    bool isEnabled() const;
+    QWidget *configurationWidget();
+    void save(ProjectExplorer::PersistentSettingsWriter &writer) const;
+    void restore(const ProjectExplorer::PersistentSettingsReader &reader);
+
+    QString executable() const;
+
+signals:
+    void targetInformationChanged();
+
+private slots:
+    void invalidateCachedTargetInformation();
+
+private:
+    void updateTarget();
+
+    QString m_proFilePath;
+    QString m_executable;
+    bool m_cachedTargetInformationValid;
+};
+
+class S60EmulatorRunConfigurationWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    S60EmulatorRunConfigurationWidget(S60EmulatorRunConfiguration *runConfiguration,
+                                      QWidget *parent = 0);
+
+private slots:
+    void nameEdited(const QString &text);
+    void updateTargetInformation();
+
+private:
+    S60EmulatorRunConfiguration *m_runConfiguration;
+    QLineEdit *m_nameLineEdit;
+    QLabel *m_executableLabel;
+};
+
+class S60EmulatorRunConfigurationFactory : public ProjectExplorer::IRunConfigurationFactory
+{
+    Q_OBJECT
+public:
+    S60EmulatorRunConfigurationFactory(QObject *parent);
+    ~S60EmulatorRunConfigurationFactory();
+    bool canRestore(const QString &type) const;
+    QStringList availableCreationTypes(ProjectExplorer::Project *pro) const;
+    // used to translate the types to names to display to the user
+    QString displayNameForType(const QString &type) const;
+    QSharedPointer<ProjectExplorer::RunConfiguration> create(ProjectExplorer::Project *project, const QString &type);
+};
+
+class S60EmulatorRunConfigurationRunner : public ProjectExplorer::IRunConfigurationRunner
+{
+    Q_OBJECT
+public:
+    S60EmulatorRunConfigurationRunner(QObject *parent = 0);
+    bool canRun(QSharedPointer<ProjectExplorer::RunConfiguration> runConfiguration, const QString &mode);
+    ProjectExplorer::RunControl* run(QSharedPointer<ProjectExplorer::RunConfiguration> runConfiguration, const QString &mode);
+    QString displayName() const { return "Run in Emulator"; }
+    QWidget *configurationWidget(QSharedPointer<ProjectExplorer::RunConfiguration> runConfiguration) { return 0; }
+};
+
+class S60EmulatorRunControl : public ProjectExplorer::RunControl
+{
+    Q_OBJECT
+public:
+    S60EmulatorRunControl(QSharedPointer<ProjectExplorer::RunConfiguration> runConfiguration);
+    ~S60EmulatorRunControl() {}
+    void start();
+    void stop();
+    bool isRunning() const;
+
+private slots:
+    void processExited(int exitCode);
+    void slotAddToOutputWindow(const QString &line);
+    void slotError(const QString & error);
+
+private:
+    ProjectExplorer::ApplicationLauncher m_applicationLauncher;
+    QString m_executable;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // S60EMULATORRUNCONFIGURATION_H
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp
index 139df343581..fb1276b0577 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp
@@ -33,6 +33,7 @@
 #include "s60devicespreferencepane.h"
 #include "winscwtoolchain.h"
 #include "gccetoolchain.h"
+#include "s60emulatorrunconfiguration.h"
 
 #include <extensionsystem/pluginmanager.h>
 
@@ -49,12 +50,18 @@ S60Manager *S60Manager::instance() { return m_instance; }
 S60Manager::S60Manager(QObject *parent)
         : QObject(parent),
         m_devices(new S60Devices(this)),
-        m_devicesPreferencePane(new S60DevicesPreferencePane(m_devices, this))
+        m_devicesPreferencePane(new S60DevicesPreferencePane(m_devices, this)),
+        m_s60EmulatorRunConfigurationFactory(new S60EmulatorRunConfigurationFactory(this)),
+        m_s60EmulatorRunConfigurationRunner(new S60EmulatorRunConfigurationRunner(this))
 {
     m_instance = this;
     m_devices->detectQtForDevices();
     ExtensionSystem::PluginManager::instance()
             ->addObject(m_devicesPreferencePane);
+    ExtensionSystem::PluginManager::instance()
+            ->addObject(m_s60EmulatorRunConfigurationFactory);
+    ExtensionSystem::PluginManager::instance()
+            ->addObject(m_s60EmulatorRunConfigurationRunner);
     updateQtVersions();
     connect(m_devices, SIGNAL(qtVersionsChanged()),
             this, SLOT(updateQtVersions()));
@@ -62,10 +69,21 @@ S60Manager::S60Manager(QObject *parent)
 
 S60Manager::~S60Manager()
 {
+    ExtensionSystem::PluginManager::instance()
+            ->removeObject(m_s60EmulatorRunConfigurationRunner);
+    ExtensionSystem::PluginManager::instance()
+            ->removeObject(m_s60EmulatorRunConfigurationFactory);
     ExtensionSystem::PluginManager::instance()
             ->removeObject(m_devicesPreferencePane);
 }
 
+QString S60Manager::deviceIdFromDetectionSource(const QString &autoDetectionSource) const
+{
+    if (autoDetectionSource.startsWith(S60_AUTODETECTION_SOURCE))
+        return autoDetectionSource.mid(QString(S60_AUTODETECTION_SOURCE).length()+1);
+    return "";
+}
+
 void S60Manager::updateQtVersions()
 {
     // This assumes that the QtVersionManager has already read
@@ -81,8 +99,7 @@ void S60Manager::updateQtVersions()
         // look if we have a respective Qt version already
         foreach (QtVersion *version, versions) {
             if (version->isAutodetected()
-                    && version->autodetectionSource().startsWith(S60_AUTODETECTION_SOURCE)
-                    && version->autodetectionSource().mid(QString(S60_AUTODETECTION_SOURCE).length()+1) == device.id) {
+                    && deviceIdFromDetectionSource(version->autodetectionSource()) == device.id) {
                 deviceVersion = version;
                 break;
             }
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.h b/src/plugins/qt4projectmanager/qt-s60/s60manager.h
index bed940a903c..3f1df4cb0a6 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60manager.h
+++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.h
@@ -38,11 +38,12 @@
 #include <QtCore/QObject>
 
 namespace Qt4ProjectManager {
-
 namespace Internal {
 
 class S60Devices;
 class S60DevicesPreferencePane;
+class S60EmulatorRunConfigurationFactory;
+class S60EmulatorRunConfigurationRunner;
 
 class S60Manager : public QObject
 {
@@ -55,6 +56,9 @@ public:
     ProjectExplorer::ToolChain *createWINSCWToolChain(const Qt4ProjectManager::QtVersion *version) const;
     ProjectExplorer::ToolChain *createGCCEToolChain(const Qt4ProjectManager::QtVersion *version) const;
 
+    S60Devices *devices() const { return m_devices; }
+    QString deviceIdFromDetectionSource(const QString &autoDetectionSource) const;
+
 private slots:
     void updateQtVersions();
 
@@ -62,6 +66,8 @@ private:
     static S60Manager *m_instance;
     S60Devices *m_devices;
     S60DevicesPreferencePane *m_devicesPreferencePane;
+    S60EmulatorRunConfigurationFactory *m_s60EmulatorRunConfigurationFactory;
+    S60EmulatorRunConfigurationRunner *m_s60EmulatorRunConfigurationRunner;
 };
 
 } // namespace Internal
-- 
GitLab