Skip to content
Snippets Groups Projects
maemorunconfiguration.cpp 51.8 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"

#include "maemomanager.h"
#include "maemotoolchain.h"
#include "profilereader.h"
#include "qt4project.h"

#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/QProcess>
#include <QtCore/QSharedPointer>

#include <QtGui/QCheckBox>
#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:
    MaemoRunConfigurationWidget(
        MaemoRunConfiguration *runConfiguration, QWidget *parent = 0);

private slots:
    void configNameEdited(const QString &text);
    void argumentsEdited(const QString &args);
    void hostNameEdited(const QString &name);
    void userNameEdited(const QString &name);
    void portEdited(const QString &port);
    void hostTypeChanged();

#if USE_SSL_PASSWORD
    void passwordUseChanged();
    void passwordEdited(const QString &password);
#endif

    void updateTargetInformation();
ck's avatar
ck committed
    void updateVisibleSimulatorParameter();

private:
    QLineEdit *m_configNameLineEdit;
    QLineEdit *m_argsLineEdit;
    QLineEdit *m_hostNameLineEdit;
    QLineEdit *m_userLineEdit;
    QLineEdit *m_passwordLineEdit;
    QLineEdit *m_portLineEdit;
    QLabel *m_executableLabel;
    QLabel *m_debuggerLabel;
    QLabel *m_simParamsValueLabel;
    QLabel *m_chooseSimPathLabel;
    QLabel *m_simParamsNameLabel;
    QCheckBox *m_passwordCheckBox;
    QRadioButton *m_hwButton;
    QRadioButton *m_simButton;
    QToolButton *m_resetButton;
ck's avatar
ck committed
    Utils::PathChooser *m_simPathChooser;
    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);
    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;
    virtual void deploymentFinished(bool success)=0;
    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
ck's avatar
ck committed

private:
    QProcess deployProcess;
    bool deployingExecutable;
    bool deployingDumperLib;
};

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:
    void deploymentFinished(bool success);
    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:
    void deploymentFinished(bool success);

    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


static const QLatin1String RemoteHostIsSimulatorKey("RemoteHostIsSimulator");
static const QLatin1String ArgumentsKeySim("ArgumentsSim");
static const QLatin1String RemoteHostNameKeySim("RemoteHostNameSim");
static const QLatin1String RemoteUserNameKeySim("RemoteUserNameSim");
static const QLatin1String RemotePortKeySim("RemotePortSim");

static const QLatin1String ArgumentsKeyDevice("ArgumentsDevice");
static const QLatin1String RemoteHostNameKeyDevice("RemoteHostNameDevice");
static const QLatin1String RemoteUserNameKeyDevice("RemoteUserNameDevice");
static const QLatin1String RemotePortKeyDevice("RemotePortDevice");

static const QLatin1String LastDeployedKey("LastDeployed");
static const QLatin1String DebuggingHelpersLastDeployedKey(
    "DebuggingHelpersLastDeployed");
static const QLatin1String SimulatorPath("SimulatorPath");
static const QLatin1String IsUserSetSimulator("IsUserSetSimulator");

ck's avatar
ck committed
#if USE_SSL_PASSWORD
static const QLatinString RemoteUserPasswordKey("RemoteUserPassword");
static const QLatinString RemoteHostRequiresPasswordKey(
    "RemoteHostRequiresPassword");
ck's avatar
ck committed
#endif

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

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

    connect(project, SIGNAL(targetInformationChanged()), this,
        SLOT(invalidateCachedSimulatorInformation()));
    connect(project, SIGNAL(activeBuildConfigurationChanged()), this,
        SLOT(invalidateCachedSimulatorInformation()));

    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
{
    Qt4Project *qt4Project = qobject_cast<Qt4Project*>(project());
    QTC_ASSERT(qt4Project, return false);
    ToolChain::ToolChainType type =
        qt4Project->toolChainType(qt4Project->activeBuildConfiguration());
    return type == ToolChain::GCC_MAEMO;
}

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

void MaemoRunConfiguration::save(PersistentSettingsWriter &writer) const
{
    writer.saveValue(RemoteHostIsSimulatorKey, m_remoteHostIsSimulator);
    writer.saveValue(ArgumentsKeySim, m_argumentsSim);
    writer.saveValue(RemoteHostNameKeySim, m_remoteHostNameSim);
    writer.saveValue(RemoteUserNameKeySim, m_remoteUserNameSim);
    writer.saveValue(RemotePortKeySim, m_remotePortSim);

kh1's avatar
kh1 committed
    writer.saveValue(ArgumentsKeyDevice, m_argumentsDevice);
    writer.saveValue(RemoteHostNameKeyDevice, m_remoteHostNameDevice);
    writer.saveValue(RemoteUserNameKeyDevice, m_remoteUserNameDevice);
    writer.saveValue(RemotePortKeyDevice, m_remotePortDevice);

ck's avatar
ck committed
#if USE_SSL_PASSWORD
    writer.saveValue(RemoteUserPasswordKey, m_remoteUserPassword);
    writer.saveValue(RemoteHostRequiresPasswordKey, m_remoteHostRequiresPassword);
#endif
ck's avatar
ck committed
    writer.saveValue(LastDeployedKey, m_lastDeployed);
    writer.saveValue(DebuggingHelpersLastDeployedKey,
        m_debuggingHelpersLastDeployed);

    writer.saveValue(SimulatorPath, m_simulatorPath);
    writer.saveValue(IsUserSetSimulator, m_isUserSetSimulator);

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);

    m_remoteHostIsSimulator = reader.restoreValue(RemoteHostIsSimulatorKey)
        .toBool();
    m_argumentsSim = reader.restoreValue(ArgumentsKeySim).toStringList();
    m_remoteHostNameSim = reader.restoreValue(RemoteHostNameKeySim).toString();
    m_remoteUserNameSim = reader.restoreValue(RemoteUserNameKeySim).toString();
    m_remotePortSim = reader.restoreValue(RemotePortKeySim).toInt();

    m_argumentsDevice = reader.restoreValue(ArgumentsKeyDevice).toStringList();
    m_remoteHostNameDevice = reader.restoreValue(RemoteHostNameKeyDevice)
        .toString();
    m_remoteUserNameDevice = reader.restoreValue(RemoteUserNameKeyDevice)
        .toString();
    m_remotePortDevice = reader.restoreValue(RemotePortKeyDevice).toInt();

ck's avatar
ck committed
#if USE_SSL_PASSWORD
    m_remoteUserPassword = reader.restoreValue(RemoteUserPasswordKey).toString();
    m_remoteHostRequiresPassword =
        reader.restoreValue(RemoteHostRequiresPasswordKey).toBool();
#endif
ck's avatar
ck committed
    m_lastDeployed = reader.restoreValue(LastDeployedKey).toDateTime();
    m_debuggingHelpersLastDeployed =
        reader.restoreValue(DebuggingHelpersLastDeployedKey).toDateTime();

    m_simulatorPath = reader.restoreValue(SimulatorPath).toString();
    m_isUserSetSimulator = reader.restoreValue(IsUserSetSimulator).toBool();

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
{
    return project()->qtVersion(project()->activeBuildConfiguration())
        ->hasDebuggingHelper();
}

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;
}

const QString MaemoRunConfiguration::remoteHostName() const
{
    return m_remoteHostIsSimulator ? m_remoteHostNameSim
        : m_remoteHostNameDevice;
}

const QString MaemoRunConfiguration::remoteUserName() const
{
    return m_remoteHostIsSimulator ? m_remoteUserNameSim
        : m_remoteUserNameDevice;
}

int MaemoRunConfiguration::remotePort() const
{
    int port = m_remoteHostIsSimulator ? m_remotePortSim : m_remotePortDevice;
    return port > 0 ? port : 22;
}

ck's avatar
ck committed
const QString MaemoRunConfiguration::remoteDir() const
{
    return remoteUserName() == QString::fromLocal8Bit("root")
        ? QString::fromLocal8Bit("/root")
        : QString::fromLocal8Bit("/home/") + remoteUserName();
}

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
{
    Qt4Project *qt4Project = qobject_cast<Qt4Project *>(project());
    QTC_ASSERT(qt4Project != 0, return 0);
    MaemoToolChain *tc = dynamic_cast<MaemoToolChain *>(
        qt4Project->toolChain(qt4Project->activeBuildConfiguration()) );
    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())
        return toolchain()->sysrootRoot();
    return QString();
const QStringList MaemoRunConfiguration::arguments() const
{
    return m_remoteHostIsSimulator ? m_argumentsSim : m_argumentsDevice;
}

ck's avatar
ck committed
const QString MaemoRunConfiguration::dumperLib() const
{
    return project()->qtVersion(project()->activeBuildConfiguration())->
        debuggingHelperLibrary();
}

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)
{
    if (m_remoteHostIsSimulator)
        m_argumentsSim = args;
    else
        m_argumentsDevice = args;
ck's avatar
ck committed
}

void MaemoRunConfiguration::setRemoteHostIsSimulator(bool isSimulator)
{
    m_remoteHostIsSimulator = isSimulator;
}

void MaemoRunConfiguration::setRemoteHostName(const QString &hostName)
{
    m_lastDeployed = QDateTime();
    m_debuggingHelpersLastDeployed = QDateTime();

    if (m_remoteHostIsSimulator)
        m_remoteHostNameSim = hostName;
    else
        m_remoteHostNameDevice = hostName;
ck's avatar
ck committed
}

void MaemoRunConfiguration::setRemoteUserName(const QString &userName)
{
    m_lastDeployed = QDateTime();
    m_debuggingHelpersLastDeployed = QDateTime();

    if (m_remoteHostIsSimulator)
        m_remoteUserNameSim = userName;
    else
        m_remoteUserNameDevice = userName;
ck's avatar
ck committed
}

void MaemoRunConfiguration::setRemotePort(int port)
{
    m_lastDeployed = QDateTime();
    m_debuggingHelpersLastDeployed = QDateTime();

    if (m_remoteHostIsSimulator)
        m_remotePortSim = port;
    else
        m_remotePortDevice = port;
ck's avatar
ck committed
}

#if USE_SSL_PASSWORD
void MaemoRunConfiguration::setRemotePassword(const QString &password)
{
    Q_ASSERT(remoteHostRequiresPassword());
    m_remoteUserPassword = password;
}

void MaemoRunConfiguration::setRemoteHostRequiresPassword(bool requiresPassword)
{
    m_remoteHostRequiresPassword = requiresPassword;
}
#endif

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;

    if (Qt4Project *qt4Project = static_cast<Qt4Project *>(project())) {
        Qt4PriFileNode * priFileNode = qt4Project->rootProjectNode()
            ->findProFileFor(m_proFilePath);
        if (!priFileNode) {
            emit targetInformationChanged();
            return;
        }

        QtVersion *qtVersion =
            qt4Project->qtVersion(qt4Project->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
dt's avatar
dt committed
        QtVersion::QmakeBuildConfigs defaultBuildConfiguration =
ck's avatar
ck committed
            qtVersion->defaultBuildConfig();
        QtVersion::QmakeBuildConfig projectBuildConfiguration =
            QtVersion::QmakeBuildConfig(qt4Project->activeBuildConfiguration()
                ->value("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 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 =
            project()->buildDirectory(project()->activeBuildConfiguration());
        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);
        delete reader;
    }

    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());
}


// #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);
    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

    QHBoxLayout *hostTypeLayout = new QHBoxLayout;
    m_hwButton = new QRadioButton(tr("Physical device"));
    hostTypeLayout->addWidget(m_hwButton);
    m_simButton = new QRadioButton(tr("Simulator"));
ck's avatar
ck committed
    hostTypeLayout->addWidget(m_simButton);
    hostTypeLayout->addStretch(1);
    mainLayout->addRow(tr("Remote host type:"), hostTypeLayout);

ck's avatar
ck committed
    m_chooseSimPathLabel = new QLabel(tr("Choose simulator:"));
    m_simPathChooser = new Utils::PathChooser;
    m_simPathChooser->setPath(m_runConfiguration->simulatorPath());

    QHBoxLayout *pathLayout = new QHBoxLayout;
    pathLayout->addWidget(m_simPathChooser);

    m_resetButton = new QToolButton();
    m_resetButton->setToolTip(tr("Reset to default"));
    m_resetButton->setIcon(QIcon(":/core/images/reset.png"));
    pathLayout->addWidget(m_resetButton);

    mainLayout->addRow(m_chooseSimPathLabel, pathLayout);
ck's avatar
ck committed
    m_simParamsNameLabel = new QLabel(tr("Simulator command line:"));
    m_simParamsValueLabel= new QLabel(m_runConfiguration->visibleSimulatorParameter());
    mainLayout->addRow(m_simParamsNameLabel, m_simParamsValueLabel);

    connect(m_simPathChooser, SIGNAL(changed(QString)), m_runConfiguration,
        SLOT(setUserSimulatorPath(QString)));
    connect(m_runConfiguration, SIGNAL(cachedSimulatorInformationChanged()),
        this, SLOT(updateSimulatorPath()));
    connect(m_runConfiguration, SIGNAL(cachedSimulatorInformationChanged()),
        this, SLOT(updateVisibleSimulatorParameter()));
    connect(m_resetButton, SIGNAL(clicked()), m_runConfiguration,
        SLOT(resetCachedSimulatorInformation()));

ck's avatar
ck committed
    m_hostNameLineEdit = new QLineEdit(m_runConfiguration->remoteHostName());
    mainLayout->addRow(tr("Remote host name:"), m_hostNameLineEdit);
    m_userLineEdit = new QLineEdit(m_runConfiguration->remoteUserName());
    mainLayout->addRow(tr("Remote user name:"), m_userLineEdit);
    m_portLineEdit = new QLineEdit(QString::number(m_runConfiguration->remotePort()));
    mainLayout->addRow(tr("Remote SSH port:"), m_portLineEdit);
ck's avatar
ck committed

    // Unlikely to ever work: ssh uses /dev/tty directly instead of stdin/out
#if USE_SSL_PASSWORD
    m_passwordCheckBox = new QCheckBox(tr("Remote password:"));
    m_passwordCheckBox->setToolTip(tr("Uncheck for passwordless login"));
    m_passwordCheckBox->setChecked(m_runConfiguration
        ->remoteHostRequiresPassword());
    m_passwordLineEdit = new QLineEdit(m_runConfiguration->remoteUserPassword());
    m_passwordLineEdit->setEchoMode(QLineEdit::Password);
    m_passwordLineEdit->setEnabled(m_passwordCheckBox->isChecked());
    mainLayout->addRow(m_passwordCheckBox, m_passwordLineEdit);

    connect(m_passwordCheckBox, SIGNAL(stateChanged(int)), this,
        SLOT(passwordUseChanged()));
    connect(m_passwordLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(passwordEdited(QString)));
ck's avatar
ck committed
#endif

    connect(m_configNameLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(configNameEdited(QString)));
    connect(m_argsLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(argumentsEdited(QString)));
    connect(m_runConfiguration, SIGNAL(targetInformationChanged()), this,
        SLOT(updateTargetInformation()));
    connect(m_hwButton, SIGNAL(toggled(bool)), this, SLOT(hostTypeChanged()));
    connect(m_simButton, SIGNAL(toggled(bool)), this, SLOT(hostTypeChanged()));
    connect(m_hostNameLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(hostNameEdited(QString)));
    connect(m_userLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(userNameEdited(QString)));
    connect(m_portLineEdit, SIGNAL(textEdited(QString)), this,
        SLOT(portEdited(QString)));
    if (m_runConfiguration->remoteHostIsSimulator())
        m_simButton->setChecked(true);
    else
        m_hwButton->setChecked(true);
}

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()
{
    m_simPathChooser->setPath(m_runConfiguration->simulatorPath());
}

ck's avatar
ck committed
void MaemoRunConfigurationWidget::updateVisibleSimulatorParameter()
{
    m_simParamsValueLabel->setText(m_runConfiguration->visibleSimulatorParameter());
}

void MaemoRunConfigurationWidget::hostTypeChanged()
{
    const bool isSimulator = m_simButton->isChecked();
ck's avatar
ck committed
    m_chooseSimPathLabel->setVisible(isSimulator);
    m_simPathChooser->setVisible(isSimulator);
    m_simParamsNameLabel->setVisible(isSimulator);
    m_simParamsValueLabel->setVisible(isSimulator);
    m_resetButton->setVisible(isSimulator);
ck's avatar
ck committed
    m_runConfiguration->setRemoteHostIsSimulator(isSimulator);
    m_argsLineEdit->setText(m_runConfiguration->arguments().join(" "));
    m_hostNameLineEdit->setText(m_runConfiguration->remoteHostName());