Skip to content
Snippets Groups Projects
maemorunconfiguration.cpp 46.2 KiB
Newer Older
ck's avatar
ck committed
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "maemorunconfiguration.h"

ck's avatar
ck committed
#include "maemodeviceconfigurations.h"
ck's avatar
ck committed
#include "maemomanager.h"
#include "maemotoolchain.h"
#include "profilereader.h"
#include "qt4project.h"
#include "qt4buildconfiguration.h"
ck's avatar
ck committed

#include <coreplugin/progressmanager/progressmanager.h>
ck's avatar
ck committed
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <debugger/debuggermanager.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <projectexplorer/persistentsettings.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>

#include <QtCore/QDebug>
#include <QtCore/QFuture>
kh1's avatar
kh1 committed
#include <QtCore/QPair>
ck's avatar
ck committed
#include <QtCore/QProcess>
#include <QtCore/QSharedPointer>

ck's avatar
ck committed
#include <QtGui/QComboBox>
ck's avatar
ck committed
#include <QtGui/QCheckBox>
#include <QtGui/QDesktopServices>
ck's avatar
ck committed
#include <QtGui/QFormLayout>
#include <QtGui/QFrame>
#include <QtGui/QHBoxLayout>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QRadioButton>
#include <QtGui/QToolButton>
ck's avatar
ck committed

using namespace ProjectExplorer;

dt's avatar
dt committed
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
ck's avatar
ck committed

class MaemoRunConfigurationWidget : public QWidget
{
    Q_OBJECT
public:
ck's avatar
ck committed
    MaemoRunConfigurationWidget(MaemoRunConfiguration *runConfiguration,
                                QWidget *parent = 0);
ck's avatar
ck committed

private slots:
    void configNameEdited(const QString &text);
    void argumentsEdited(const QString &args);
ck's avatar
ck committed
    void deviceConfigurationChanged(const QString &name);
    void resetDeviceConfigurations();
ck's avatar
ck committed

    void updateSimulatorPath();
kh1's avatar
kh1 committed
    void updateTargetInformation();
ck's avatar
ck committed

private:
ck's avatar
ck committed
    void setSimInfoVisible(const MaemoDeviceConfigurations::DeviceConfig &devConf);

ck's avatar
ck committed
    QLineEdit *m_configNameLineEdit;
    QLineEdit *m_argsLineEdit;
    QLabel *m_executableLabel;
    QLabel *m_debuggerLabel;
ck's avatar
ck committed
    QComboBox *m_devConfBox;
    QLabel *m_simPathNameLabel;
    QLabel *m_simPathValueLabel;
ck's avatar
ck committed
    MaemoRunConfiguration *m_runConfiguration;
};

class AbstractMaemoRunControl : public ProjectExplorer::RunControl
{
    Q_OBJECT

public:
    AbstractMaemoRunControl(RunConfiguration *runConfig);
ck's avatar
ck committed
    virtual ~AbstractMaemoRunControl() {}

protected:
    void startDeployment(bool forDebugging);
kh1's avatar
kh1 committed
    void deploy();
ck's avatar
ck committed
    void stopDeployment();
    bool isDeploying() const;
    const QString executableOnHost() const;
    const QString executableOnTarget() const;
    const QString executableFileName() const;
    const QString port() const;
    const QString targetCmdLinePrefix() const;
ck's avatar
ck committed
    const QString remoteDir() const;
    const QStringList options() const;
    void deploymentFinished(bool success);
ck's avatar
ck committed
    virtual bool setProcessEnvironment(QProcess &process);
private slots:
    void readStandardError();
    void readStandardOutput();
    void deployProcessFinished();

protected:
    ErrorDumper dumper;
dt's avatar
dt committed
    MaemoRunConfiguration *runConfig; // TODO this pointer can be invalid
kh1's avatar
kh1 committed
    const MaemoDeviceConfigurations::DeviceConfig devConfig;
ck's avatar
ck committed

private:
    virtual void handleDeploymentFinished(bool success)=0;

    QFutureInterface<void> m_progress;
ck's avatar
ck committed
    QProcess deployProcess;
    struct Deployable
    {
        typedef void (MaemoRunConfiguration::*updateFunc)();
        Deployable(const QString &f, const QString &d, updateFunc u)
            : fileName(f), dir(d), updateTimestamp(u) {}
        QString fileName;
        QString dir;
        updateFunc updateTimestamp;
    };
    QList<Deployable> deployables;
ck's avatar
ck committed
};

class MaemoRunControl : public AbstractMaemoRunControl
{
    Q_OBJECT
public:
    MaemoRunControl(RunConfiguration *runConfiguration);
ck's avatar
ck committed
    ~MaemoRunControl();
    void start();
    void stop();
    bool isRunning() const;

private slots:
    void executionFinished();

private:
    virtual void handleDeploymentFinished(bool success);
ck's avatar
ck committed
    void startExecution();

    QProcess sshProcess;
    QProcess stopProcess;
    bool stoppedByUser;
};

class MaemoDebugRunControl : public AbstractMaemoRunControl
{
    Q_OBJECT
public:
    MaemoDebugRunControl(RunConfiguration *runConfiguration);
ck's avatar
ck committed
    ~MaemoDebugRunControl();
    void start();
    void stop();
    bool isRunning() const;
    Q_SLOT void debuggingFinished();

signals:
    void stopRequested();

private slots:
    void gdbServerStarted();
    void debuggerOutput(const QString &output);

private:
    virtual void handleDeploymentFinished(bool success);
ck's avatar
ck committed

    void startGdbServer();
    void gdbServerStartFailed(const QString &reason);
    void startDebugging();

    QProcess gdbServer;
    QProcess stopProcess;
    const QString gdbServerPort;
    Debugger::DebuggerManager *debuggerManager;
    QSharedPointer<Debugger::DebuggerStartParameters> startParams;
    int inferiorPid;
};

void ErrorDumper::printToStream(QProcess::ProcessError error)
{
    QString reason;
    switch (error) {
        case QProcess::FailedToStart:
            reason = "The process failed to start. Either the invoked program is"
                " missing, or you may have insufficient permissions to invoke "
                "the program.";
            break;

        case QProcess::Crashed:
            reason = "The process crashed some time after starting successfully.";
            break;

        case QProcess::Timedout:
            reason = "The last waitFor...() function timed out. The state of "
                "QProcess is unchanged, and you can try calling waitFor...() "
                "again.";
            break;

        case QProcess::WriteError:
            reason = "An error occurred when attempting to write to the process."
                " For example, the process may not be running, or it may have "
                "closed its input channel.";
            break;

        case QProcess::ReadError:
            reason = "An error occurred when attempting to read from the process."
                " For example, the process may not be running.";
            break;

        default:
            reason = "QProcess::UnknownError";
            break;
    }
    qWarning() << "Failed to run emulator. Reason:" << reason;
}


// #pragma mark -- MaemoRunConfiguration


ck's avatar
ck committed
static const QLatin1String ArgumentsKey("Arguments");
static const QLatin1String SimulatorPathKey("Simulator");
static const QLatin1String DeviceIdKey("DeviceId");
static const QLatin1String LastDeployedKey("LastDeployed");
static const QLatin1String DebuggingHelpersLastDeployedKey(
    "DebuggingHelpersLastDeployed");
ck's avatar
ck committed

MaemoRunConfiguration::MaemoRunConfiguration(Project *project,
        const QString &proFilePath)
    : RunConfiguration(project)
    , m_proFilePath(proFilePath)
    , m_cachedTargetInformationValid(false)
    , m_cachedSimulatorInformationValid(false)
    , qemu(0)
{
    if (!m_proFilePath.isEmpty()) {
        setName(tr("%1 on Maemo device").arg(QFileInfo(m_proFilePath)
            .completeBaseName()));
    } else {
        setName(tr("MaemoRunConfiguration"));
    }

ck's avatar
ck committed
    connect(&MaemoDeviceConfigurations::instance(), SIGNAL(updated()),
            this, SLOT(updateDeviceConfigurations()));

    connect(project, SIGNAL(targetInformationChanged()),
            this, SLOT(invalidateCachedTargetInformation()));

    connect(project, SIGNAL(targetInformationChanged()),
            this, SLOT(enabledStateChanged()));

    connect(project, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)),
            this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*)));
ck's avatar
ck committed

    qemu = new QProcess(this);
    connect(qemu, SIGNAL(error(QProcess::ProcessError)), &dumper,
        SLOT(printToStream(QProcess::ProcessError)));
    connect(qemu, SIGNAL(finished(int, QProcess::ExitStatus)), this,
        SLOT(qemuProcessFinished()));
}

MaemoRunConfiguration::~MaemoRunConfiguration()
{
    if (qemu && qemu->state() != QProcess::NotRunning) {
        qemu->terminate();
        qemu->kill();
    }
    delete qemu;
    qemu = NULL;
}

QString MaemoRunConfiguration::type() const
{
    return QLatin1String("Qt4ProjectManager.MaemoRunConfiguration");
}

Qt4Project *MaemoRunConfiguration::project() const
{
    Qt4Project *pro = qobject_cast<Qt4Project *>(RunConfiguration::project());
    Q_ASSERT(pro != 0);
    return pro;
}

bool MaemoRunConfiguration::isEnabled() const
{
dt's avatar
dt committed
    Qt4BuildConfiguration *qt4bc = project()->activeQt4BuildConfiguration();
    QTC_ASSERT(qt4bc, return false);
    ToolChain::ToolChainType type = qt4bc->toolChainType();
ck's avatar
ck committed
    return type == ToolChain::GCC_MAEMO;
}

QWidget *MaemoRunConfiguration::configurationWidget()
{
    return new MaemoRunConfigurationWidget(this);
}

void MaemoRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro)
{
    if (m_proFilePath == pro->path())
        invalidateCachedTargetInformation();
}


ck's avatar
ck committed
void MaemoRunConfiguration::save(PersistentSettingsWriter &writer) const
{
ck's avatar
ck committed
    writer.saveValue(DeviceIdKey, m_devConfig.internalId);
    writer.saveValue(ArgumentsKey, m_arguments);
ck's avatar
ck committed
    writer.saveValue(LastDeployedKey, m_lastDeployed);
    writer.saveValue(DebuggingHelpersLastDeployedKey,
        m_debuggingHelpersLastDeployed);

ck's avatar
ck committed
    writer.saveValue(SimulatorPathKey, m_simulatorPath);
ck's avatar
ck committed
    const QDir &dir = QFileInfo(project()->file()->fileName()).absoluteDir();
    writer.saveValue("ProFile", dir.relativeFilePath(m_proFilePath));

    RunConfiguration::save(writer);
}

void MaemoRunConfiguration::restore(const PersistentSettingsReader &reader)
{
    RunConfiguration::restore(reader);

ck's avatar
ck committed
    setDeviceConfig(MaemoDeviceConfigurations::instance().
        find(reader.restoreValue(DeviceIdKey).toInt()));
    m_arguments = reader.restoreValue(ArgumentsKey).toStringList();
ck's avatar
ck committed
    m_lastDeployed = reader.restoreValue(LastDeployedKey).toDateTime();
    m_debuggingHelpersLastDeployed =
        reader.restoreValue(DebuggingHelpersLastDeployedKey).toDateTime();

ck's avatar
ck committed
    m_simulatorPath = reader.restoreValue(SimulatorPathKey).toString();
ck's avatar
ck committed
    const QDir &dir = QFileInfo(project()->file()->fileName()).absoluteDir();
    m_proFilePath = dir.filePath(reader.restoreValue("ProFile").toString());
}

bool MaemoRunConfiguration::currentlyNeedsDeployment() const
{
    return fileNeedsDeployment(executable(), m_lastDeployed);
}

void MaemoRunConfiguration::wasDeployed()
{
    m_lastDeployed = QDateTime::currentDateTime();
}

bool MaemoRunConfiguration::hasDebuggingHelpers() const
{
dt's avatar
dt committed
    Qt4BuildConfiguration *qt4bc = project()->activeQt4BuildConfiguration();
    return qt4bc->qtVersion()->hasDebuggingHelper();
ck's avatar
ck committed
}

bool MaemoRunConfiguration::debuggingHelpersNeedDeployment() const
{
    if (hasDebuggingHelpers())
        return fileNeedsDeployment(dumperLib(), m_debuggingHelpersLastDeployed);
    return false;
}

void MaemoRunConfiguration::debuggingHelpersDeployed()
{
    m_debuggingHelpersLastDeployed = QDateTime::currentDateTime();
}

bool MaemoRunConfiguration::fileNeedsDeployment(const QString &path,
    const QDateTime &lastDeployed) const
{
    return !lastDeployed.isValid()
        || QFileInfo(path).lastModified() > lastDeployed;
}

ck's avatar
ck committed
void MaemoRunConfiguration::setDeviceConfig(
    const MaemoDeviceConfigurations::DeviceConfig &devConf)
ck's avatar
ck committed
    m_devConfig = devConf;
ck's avatar
ck committed
MaemoDeviceConfigurations::DeviceConfig MaemoRunConfiguration::deviceConfig() const
ck's avatar
ck committed
    return m_devConfig;
ck's avatar
ck committed
}

const QString MaemoRunConfiguration::sshCmd() const
{
    return cmd(QString::fromLocal8Bit("ssh"));
}

const QString MaemoRunConfiguration::scpCmd() const
{
    return cmd(QString::fromLocal8Bit("scp"));
}

const QString MaemoRunConfiguration::cmd(const QString &cmdName) const
{
    QString command(cmdName);
#ifdef Q_OS_WIN
    command = maddeRoot() + QLatin1String("/bin/") + command
          + QLatin1String(".exe");
#endif
    return command;
}

const MaemoToolChain *MaemoRunConfiguration::toolchain() const
{
kh1's avatar
kh1 committed
    Qt4BuildConfiguration *qt4bc = qobject_cast<Qt4BuildConfiguration *>
        (project()->activeBuildConfiguration());
    QTC_ASSERT(qt4bc, return 0);
ck's avatar
ck committed
    MaemoToolChain *tc = dynamic_cast<MaemoToolChain *>(
        qt4bc->toolChain() );
ck's avatar
ck committed
    QTC_ASSERT(tc != 0, return 0);
    return tc;
}

const QString MaemoRunConfiguration::gdbCmd() const
{
    if (const MaemoToolChain *tc = toolchain())
        return tc->targetRoot() + "/bin/gdb";
    return QString();
ck's avatar
ck committed
}

QString MaemoRunConfiguration::maddeRoot() const
{
    if (const MaemoToolChain *tc = toolchain())
kh1's avatar
kh1 committed
        return tc->maddeRoot();
    return QString();
ck's avatar
ck committed
}

const QString MaemoRunConfiguration::sysRoot() const
{
    if (const MaemoToolChain *tc = toolchain())
ck's avatar
ck committed
        return tc->sysrootRoot();
    return QString();
const QStringList MaemoRunConfiguration::arguments() const
{
ck's avatar
ck committed
    return m_arguments;
ck's avatar
ck committed
const QString MaemoRunConfiguration::dumperLib() const
{
dt's avatar
dt committed
    Qt4BuildConfiguration *qt4bc = project()->activeQt4BuildConfiguration();
    return qt4bc->qtVersion()->debuggingHelperLibrary();
ck's avatar
ck committed
}

QString MaemoRunConfiguration::executable() const
{
    const_cast<MaemoRunConfiguration*> (this)->updateTarget();
    return m_executable;
}

QString MaemoRunConfiguration::simulatorPath() const
{
    qDebug("MaemoRunConfiguration::simulatorPath() called, %s",
        qPrintable(m_simulatorPath));

    const_cast<MaemoRunConfiguration*> (this)->updateSimulatorInformation();
    return m_simulatorPath;
}

QString MaemoRunConfiguration::visibleSimulatorParameter() const
{
    qDebug("MaemoRunConfiguration::visibleSimulatorParameter() called");

    const_cast<MaemoRunConfiguration*> (this)->updateSimulatorInformation();
    return m_visibleSimulatorParameter;
}

QString MaemoRunConfiguration::simulator() const
{
    const_cast<MaemoRunConfiguration*> (this)->updateSimulatorInformation();
    return m_simulator;
}

QString MaemoRunConfiguration::simulatorArgs() const
{
    const_cast<MaemoRunConfiguration*> (this)->updateSimulatorInformation();
    return m_simulatorArgs;
}

void MaemoRunConfiguration::setArguments(const QStringList &args)
{
ck's avatar
ck committed
    m_arguments = args;
ck's avatar
ck committed
}


bool MaemoRunConfiguration::isQemuRunning() const
{
    return (qemu && qemu->state() != QProcess::NotRunning);
}

void MaemoRunConfiguration::invalidateCachedTargetInformation()
{
    m_cachedTargetInformationValid = false;
    emit targetInformationChanged();
}

void MaemoRunConfiguration::setUserSimulatorPath(const QString &path)
ck's avatar
ck committed
{
    qDebug("MaemoRunConfiguration::setUserSimulatorPath() called, "
ck's avatar
ck committed
        "m_simulatorPath: %s, new path: %s", qPrintable(m_simulatorPath),
        qPrintable(path));

    m_isUserSetSimulator = true;
    if (m_userSimulatorPath != path)
ck's avatar
ck committed
        m_cachedSimulatorInformationValid = false;

    m_userSimulatorPath = path;
ck's avatar
ck committed
    emit cachedSimulatorInformationChanged();
}

void MaemoRunConfiguration::invalidateCachedSimulatorInformation()
{
    qDebug("MaemoRunConfiguration::invalidateCachedSimulatorInformation() "
        "called");

    m_cachedSimulatorInformationValid = false;
    emit cachedSimulatorInformationChanged();
}

void MaemoRunConfiguration::resetCachedSimulatorInformation()
{
    m_userSimulatorPath.clear();
    m_isUserSetSimulator = false;

    m_cachedSimulatorInformationValid = false;
    emit cachedSimulatorInformationChanged();
}

ck's avatar
ck committed
void MaemoRunConfiguration::updateTarget()
{
    if (m_cachedTargetInformationValid)
        return;

    m_executable = QString::null;
    m_cachedTargetInformationValid = true;

dt's avatar
dt committed
    if (Qt4Project *qt4Project = project()) {
        Qt4BuildConfiguration *qt4bc = qt4Project->activeQt4BuildConfiguration();
        Qt4ProFileNode *proFileNode = qt4Project->rootProjectNode()->findProFileFor(m_proFilePath);
        if (!proFileNode) {
ck's avatar
ck committed
            emit targetInformationChanged();
            return;
        }

        ProFileReader *reader = qt4Project->createProFileReader(proFileNode);
ck's avatar
ck committed
        reader->setCumulative(false);

        // Find out what flags we pass on to qmake
ck's avatar
ck committed
        QStringList addedUserConfigArguments;
        QStringList removedUserConfigArguments;
        qt4bc->getConfigCommandLineArguments(&addedUserConfigArguments, &removedUserConfigArguments);
        reader->setConfigCommandLineArguments(addedUserConfigArguments, removedUserConfigArguments);
ck's avatar
ck committed

        if (!reader->readProFile(m_proFilePath)) {
            qt4Project->destroyProFileReader(reader);
ck's avatar
ck committed
            Core::ICore::instance()->messageManager()->printToOutputPane(tr(
                "Could not parse %1. The Maemo run configuration %2 "
                "can not be started.").arg(m_proFilePath).arg(name()));
            emit targetInformationChanged();
            return;
        }

        // Extract data
        QDir baseProjectDirectory =
            QFileInfo(project()->file()->fileName()).absoluteDir();
        QString relSubDir =
            baseProjectDirectory.relativeFilePath(QFileInfo(m_proFilePath).path());
        QDir baseBuildDirectory = qt4bc->buildDirectory();
ck's avatar
ck committed
        QString baseDir = baseBuildDirectory.absoluteFilePath(relSubDir);

        if (!reader->contains("DESTDIR")) {
#if 0   // TODO: fix this, seems to be wrong on windows
            if (reader->values("CONFIG").contains("debug_and_release_target")) {
                QString qmakeBuildConfig = "release";
                if (projectBuildConfiguration & QtVersion::DebugBuild)
                    qmakeBuildConfig = "debug";
                baseDir += QLatin1Char('/') + qmakeBuildConfig;
            }
#endif
        } else {
            const QString &destDir = reader->value("DESTDIR");
            if (QDir::isRelativePath(destDir))
                baseDir += QLatin1Char('/') + destDir;
            else
                baseDir = destDir;
        }

        QString target = reader->value("TARGET");
        if (target.isEmpty())
            target = QFileInfo(m_proFilePath).baseName();

        m_executable = QDir::cleanPath(baseDir + QLatin1Char('/') + target);
        qt4Project->destroyProFileReader(reader);
ck's avatar
ck committed
    }

    emit targetInformationChanged();
}

void MaemoRunConfiguration::updateSimulatorInformation()
{
    if (m_cachedSimulatorInformationValid)
        return;

    m_simulator = QString::null;
    m_simulatorArgs == QString::null;
    m_cachedSimulatorInformationValid = true;
    m_simulatorPath = QDir::toNativeSeparators(m_userSimulatorPath);
    m_visibleSimulatorParameter = tr("Could not autodetect target simulator, "
        "please choose one on your own.");

    if (!m_isUserSetSimulator) {
        if (const MaemoToolChain *tc = toolchain())
            m_simulatorPath = QDir::toNativeSeparators(tc->simulatorRoot());
    }
ck's avatar
ck committed

    if (!m_simulatorPath.isEmpty()) {
        m_visibleSimulatorParameter = tr("'%1' is not a valid Maemo simulator.")
            .arg(m_simulatorPath);
    }

    QDir dir(m_simulatorPath);
    if (dir.exists(m_simulatorPath)) {
        const QStringList &files = dir.entryList(QDir::Files | QDir::NoSymLinks
            | QDir::NoDotAndDotDot);
        if (files.count() >= 2) {
            const QLatin1String info("information");
            if (files.contains(info)) {
                QFile file(m_simulatorPath + QLatin1Char('/') + info);
                if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                    QMap<QString, QString> map;
                    QTextStream stream(&file);
                    while (!stream.atEnd()) {
                        const QString &line = stream.readLine().trimmed();
                        const int index = line.indexOf(QLatin1Char('='));
                        map.insert(line.mid(0, index).remove(QLatin1Char('\'')),
                            line.mid(index + 1).remove(QLatin1Char('\'')));
                    }

                    m_simulator = map.value(QLatin1String("runcommand"));
                    m_simulatorArgs = map.value(QLatin1String("runcommand_args"));

                    m_visibleSimulatorParameter = m_simulator
ck's avatar
ck committed
#ifdef Q_OS_WIN
ck's avatar
ck committed
#endif
                        + QLatin1Char(' ') + m_simulatorArgs;
                }
    } else {
        m_visibleSimulatorParameter = tr("'%1' could not be found. Please "
            "choose a simulator on your own.").arg(m_simulatorPath);
ck's avatar
ck committed
    }

    emit cachedSimulatorInformationChanged();
}

void MaemoRunConfiguration::startStopQemu()
{
    if (qemu->state() != QProcess::NotRunning) {
        if (qemu->state() == QProcess::Running) {
            qemu->terminate();
            qemu->kill();
            emit qemuProcessStatus(false);
        }
        return;
    }

    QString root = maddeRoot();
    if (root.isEmpty() || simulator().isEmpty())
        return;

    const QLatin1Char colon(';');
    const QString path = QDir::toNativeSeparators(root + QLatin1Char('/'));

    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("PATH", env.value("Path") + colon + path + QLatin1String("bin"));
    env.insert("PATH", env.value("Path") + colon + path + QLatin1String("madlib"));

    qemu->setProcessEnvironment(env);
    qemu->setWorkingDirectory(simulatorPath());

    QString app = root + QLatin1String("/madlib/") + simulator()
#ifdef Q_OS_WIN
        + QLatin1String(".exe")
#endif
    ;   // keep

    qemu->start(app + QLatin1Char(' ') + simulatorArgs(), QIODevice::ReadWrite);
    emit qemuProcessStatus(qemu->waitForStarted());
}

void MaemoRunConfiguration::qemuProcessFinished()
{
    emit qemuProcessStatus(false);
}

void MaemoRunConfiguration::enabledStateChanged()
{
    MaemoManager::instance()->setQemuSimulatorStarterEnabled(isEnabled());
}

ck's avatar
ck committed
void MaemoRunConfiguration::updateDeviceConfigurations()
{
    qDebug("%s: Current devid = %llu", Q_FUNC_INFO, m_devConfig.internalId);
    m_devConfig =
        MaemoDeviceConfigurations::instance().find(m_devConfig.internalId);
    qDebug("%s: new devid = %llu", Q_FUNC_INFO, m_devConfig.internalId);
    emit deviceConfigurationsUpdated();
}

ck's avatar
ck committed

// #pragma mark -- MaemoRunConfigurationWidget

MaemoRunConfigurationWidget::MaemoRunConfigurationWidget(
        MaemoRunConfiguration *runConfiguration, QWidget *parent)
    : QWidget(parent)
    , m_runConfiguration(runConfiguration)
{
    QFormLayout *mainLayout = new QFormLayout;
    setLayout(mainLayout);
dt's avatar
dt committed

ck's avatar
ck committed
    mainLayout->setFormAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    m_configNameLineEdit = new QLineEdit(m_runConfiguration->name());
    mainLayout->addRow(tr("Run configuration name:"), m_configNameLineEdit);
ck's avatar
ck committed
    m_devConfBox = new QComboBox;
    m_devConfBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
ck's avatar
ck committed
    mainLayout->addRow(new QLabel(tr("Device Configuration:")), m_devConfBox);
ck's avatar
ck committed
    m_executableLabel = new QLabel(m_runConfiguration->executable());
    mainLayout->addRow(tr("Executable:"), m_executableLabel);
    m_argsLineEdit = new QLineEdit(m_runConfiguration->arguments().join(" "));
    mainLayout->addRow(tr("Arguments:"), m_argsLineEdit);
    m_debuggerLabel = new QLabel(m_runConfiguration->gdbCmd());
    mainLayout->addRow(tr("Debugger:"), m_debuggerLabel);
    mainLayout->addItem(new QSpacerItem(10, 10));
ck's avatar
ck committed
    m_simPathNameLabel = new QLabel(tr("Simulator Path:"));
    m_simPathValueLabel = new QLabel(m_runConfiguration->simulatorPath());
    mainLayout->addRow(m_simPathNameLabel, m_simPathValueLabel);
    resetDeviceConfigurations();
    connect(m_runConfiguration, SIGNAL(cachedSimulatorInformationChanged()),
        this, SLOT(updateSimulatorPath()));
ck's avatar
ck committed
    connect(m_runConfiguration, SIGNAL(deviceConfigurationsUpdated()),
            this, SLOT(resetDeviceConfigurations()));
ck's avatar
ck committed

    connect(m_configNameLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(configNameEdited(QString)));
    connect(m_argsLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(argumentsEdited(QString)));
ck's avatar
ck committed
    connect(m_devConfBox, SIGNAL(activated(QString)), this,
            SLOT(deviceConfigurationChanged(QString)));
ck's avatar
ck committed
    connect(m_runConfiguration, SIGNAL(targetInformationChanged()), this,
        SLOT(updateTargetInformation()));
}

void MaemoRunConfigurationWidget::configNameEdited(const QString &text)
{
    m_runConfiguration->setName(text);
}

void MaemoRunConfigurationWidget::argumentsEdited(const QString &text)
{
    m_runConfiguration->setArguments(text.split(' ', QString::SkipEmptyParts));
}

void MaemoRunConfigurationWidget::updateTargetInformation()
{
    m_executableLabel->setText(m_runConfiguration->executable());
}

void MaemoRunConfigurationWidget::updateSimulatorPath()
{
ck's avatar
ck committed
    m_simPathValueLabel->setText(m_runConfiguration->simulatorPath());
ck's avatar
ck committed
void MaemoRunConfigurationWidget::deviceConfigurationChanged(const QString &name)
ck's avatar
ck committed
{
ck's avatar
ck committed
    const MaemoDeviceConfigurations::DeviceConfig &devConfig =
            MaemoDeviceConfigurations::instance().find(name);
    setSimInfoVisible(devConfig);
    m_runConfiguration->setDeviceConfig(devConfig);
ck's avatar
ck committed
void MaemoRunConfigurationWidget::setSimInfoVisible(
    const MaemoDeviceConfigurations::DeviceConfig &devConf)
ck's avatar
ck committed
{
ck's avatar
ck committed
    const bool isSimulator =
        devConf.type == MaemoDeviceConfigurations::DeviceConfig::Simulator;
    m_simPathNameLabel->setVisible(isSimulator);
    m_simPathValueLabel->setVisible(isSimulator);
ck's avatar
ck committed
void MaemoRunConfigurationWidget::resetDeviceConfigurations()
ck's avatar
ck committed
{
ck's avatar
ck committed
    m_devConfBox->clear();
    const QList<MaemoDeviceConfigurations::DeviceConfig> &devConfs =
        MaemoDeviceConfigurations::instance().devConfigs();
    foreach (const MaemoDeviceConfigurations::DeviceConfig &devConf, devConfs)
        m_devConfBox->addItem(devConf.name);
    m_devConfBox->addItem(MaemoDeviceConfigurations::DeviceConfig().name);
    const MaemoDeviceConfigurations::DeviceConfig &devConf =
        m_runConfiguration->deviceConfig();
    m_devConfBox->setCurrentIndex(m_devConfBox->findText(devConf.name));
    setSimInfoVisible(devConf);
ck's avatar
ck committed
}

// #pragma mark -- MaemoRunConfigurationFactory


MaemoRunConfigurationFactory::MaemoRunConfigurationFactory(QObject* parent)
    : IRunConfigurationFactory(parent)
{
}

MaemoRunConfigurationFactory::~MaemoRunConfigurationFactory()
{
}

bool MaemoRunConfigurationFactory::canRestore(const QString &type) const
{
    return type == "Qt4ProjectManager.MaemoRunConfiguration";
}

QStringList MaemoRunConfigurationFactory::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("MaemoRunConfiguration." + node->path());
        }
        return applicationProFiles;
    }
    return QStringList();
}

QString MaemoRunConfigurationFactory::displayNameForType(
    const QString &type) const
{
    const int size = QString::fromLocal8Bit("MaemoRunConfiguration.").size();
    return tr("%1 on Maemo Device").arg(QFileInfo(type.mid(size))
ck's avatar
ck committed
        .completeBaseName());
}

RunConfiguration *MaemoRunConfigurationFactory::create(Project *project,
ck's avatar
ck committed
    const QString &type)
{
    Qt4Project *qt4project = qobject_cast<Qt4Project *>(project);
    Q_ASSERT(qt4project);

    connect(project, SIGNAL(addedRunConfiguration(ProjectExplorer::Project*,
        QString)), this, SLOT(addedRunConfiguration(ProjectExplorer::Project*)));
    connect(project, SIGNAL(removedRunConfiguration(ProjectExplorer::Project*,
        QString)), this, SLOT(removedRunConfiguration(ProjectExplorer::Project*)));

    RunConfiguration *rc = 0;
ck's avatar
ck committed
    const QLatin1String prefix("MaemoRunConfiguration.");
    if (type.startsWith(prefix)) {
        rc = new MaemoRunConfiguration(qt4project, type.mid(QString(prefix).size()));
ck's avatar
ck committed
    } else {
        Q_ASSERT(type == "Qt4ProjectManager.MaemoRunConfiguration");
        rc = new MaemoRunConfiguration(qt4project, QString::null);
    if (rc) {
ck's avatar
ck committed
        connect(project, SIGNAL(runConfigurationsEnabledStateChanged()),
            rc, SLOT(enabledStateChanged()));
        connect(MaemoManager::instance(), SIGNAL(startStopQemu()), rc,
ck's avatar
ck committed
            SLOT(startStopQemu()));
        connect(rc, SIGNAL(qemuProcessStatus(bool)),
ck's avatar
ck committed
            MaemoManager::instance(), SLOT(updateQemuSimulatorStarter(bool)));
    }

    ProjectExplorerPlugin *explorer = ProjectExplorerPlugin::instance();
    connect(explorer->session(), SIGNAL(projectAdded(ProjectExplorer::Project*)),
        this, SLOT(projectAdded(ProjectExplorer::Project*)));
    connect(explorer->session(), SIGNAL(projectRemoved(ProjectExplorer::Project*)),
        this, SLOT(projectRemoved(ProjectExplorer::Project*)));
    connect(explorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
        this, SLOT(currentProjectChanged(ProjectExplorer::Project*)));

    return rc;
}

bool hasMaemoRunConfig(ProjectExplorer::Project* project)
{
    if (Qt4Project *qt4Project = qobject_cast<Qt4Project *>(project)) {
        QList<RunConfiguration *> list = qt4Project->runConfigurations();
        foreach (RunConfiguration *rc, list) {
            if (qobject_cast<MaemoRunConfiguration *>(rc))
ck's avatar
ck committed
                return true;
        }
    }
    return false;
}

void MaemoRunConfigurationFactory::addedRunConfiguration(
    ProjectExplorer::Project* project)
{
    if (hasMaemoRunConfig(project))
        MaemoManager::instance()->addQemuSimulatorStarter(project);
}

void MaemoRunConfigurationFactory::removedRunConfiguration(
    ProjectExplorer::Project* project)
{
    if (!hasMaemoRunConfig(project))
        MaemoManager::instance()->removeQemuSimulatorStarter(project);
}

void MaemoRunConfigurationFactory::projectAdded(
    ProjectExplorer::Project* project)
{
    if (hasMaemoRunConfig(project))
        MaemoManager::instance()->addQemuSimulatorStarter(project);
}

void MaemoRunConfigurationFactory::projectRemoved(
    ProjectExplorer::Project* project)
{
    if (hasMaemoRunConfig(project))
        MaemoManager::instance()->removeQemuSimulatorStarter(project);
}

void MaemoRunConfigurationFactory::currentProjectChanged(
    ProjectExplorer::Project* project)
{
    bool hasRunConfig = hasMaemoRunConfig(project);
    MaemoManager::instance()->setQemuSimulatorStarterEnabled(hasRunConfig);

    bool isRunning = false;
    if (Qt4Project *qt4Project = qobject_cast<Qt4Project *>(project)) {
        RunConfiguration *rc = qt4Project->activeRunConfiguration();
        if (MaemoRunConfiguration *mrc = qobject_cast<MaemoRunConfiguration *>(rc))
            isRunning = mrc->isQemuRunning();
ck's avatar
ck committed
    }
    MaemoManager::instance()->updateQemuSimulatorStarter(isRunning);
}


// #pragma mark -- MaemoRunControlFactory


MaemoRunControlFactory::MaemoRunControlFactory(QObject *parent)
    : IRunControlFactory(parent)
{
}

bool MaemoRunControlFactory::canRun(RunConfiguration *runConfiguration,
ck's avatar
ck committed
    const QString &mode) const
{
    return qobject_cast<MaemoRunConfiguration *>(runConfiguration)
ck's avatar
ck committed
        && (mode == ProjectExplorer::Constants::RUNMODE
        || mode == ProjectExplorer::Constants::DEBUGMODE);
}

RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig,
ck's avatar
ck committed
    const QString &mode)
{
dt's avatar
dt committed
    MaemoRunConfiguration *rc = qobject_cast<MaemoRunConfiguration *>(runConfig);
    Q_ASSERT(rc);
ck's avatar
ck committed
    Q_ASSERT(mode == ProjectExplorer::Constants::RUNMODE
        || mode == ProjectExplorer::Constants::DEBUGMODE);
    if (mode == ProjectExplorer::Constants::RUNMODE)
        return new MaemoRunControl(rc);
    return new MaemoDebugRunControl(rc);
}

QString MaemoRunControlFactory::displayName() const