/************************************************************************** ** ** 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 "maemodeviceconfigurations.h" #include "maemomanager.h" #include "maemorunconfigurationwidget.h" #include "maemoruncontrol.h" #include "maemotoolchain.h" #include "profilereader.h" #include "qt4project.h" #include "qt4target.h" #include "qt4buildconfiguration.h" #include #include #include #include #include #include #include #include #include #include #include namespace { const char * const MAEMO_RC_ID("Qt4ProjectManager.MaemoRunConfiguration"); const char * const MAEMO_RC_ID_PREFIX("Qt4ProjectManager.MaemoRunConfiguration."); QString targetFromId(const QString &id) { QString prefix(MAEMO_RC_ID_PREFIX); if (!id.startsWith(prefix)) return QString(); return id.mid(prefix.size()); } QString targetToId(const QString &target) { return QString::fromLatin1(MAEMO_RC_ID_PREFIX) + target; } } // namespace static const QLatin1String ArgumentsKey("Qt4ProjectManager.MaemoRunConfiguration.Arguments"); static const QLatin1String SimulatorPathKey("Qt4ProjectManager.MaemoRunConfiguration.Simulator"); static const QLatin1String DeviceIdKey("Qt4ProjectManager.MaemoRunConfiguration.DeviceId"); static const QLatin1String LastDeployedKey("Qt4ProjectManager.MaemoRunConfiguration.LastDeployed"); static const QLatin1String DebuggingHelpersLastDeployedKey( "Qt4ProjectManager.MaemoRunConfiguration.DebuggingHelpersLastDeployed"); static const QLatin1String ProFileKey("Qt4ProjectManager.MaemoRunConfiguration.ProFile"); namespace Qt4ProjectManager { namespace Internal { using namespace ProjectExplorer; 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 MaemoRunConfiguration::MaemoRunConfiguration(Qt4Target *parent, const QString &proFilePath) : RunConfiguration(parent, QLatin1String(MAEMO_RC_ID)) , m_proFilePath(proFilePath) , m_cachedTargetInformationValid(false) , m_cachedSimulatorInformationValid(false) , qemu(0) { init(); } MaemoRunConfiguration::MaemoRunConfiguration(Qt4Target *parent, MaemoRunConfiguration *source) : RunConfiguration(parent, source) , m_executable(source->m_executable) , m_proFilePath(source->m_proFilePath) , m_cachedTargetInformationValid(false) , m_simulator(source->m_simulator) , m_simulatorArgs(source->m_simulatorArgs) , m_simulatorPath(source->m_simulatorPath) , m_visibleSimulatorParameter(source->m_visibleSimulatorParameter) , m_simulatorLibPath(source->m_simulatorLibPath) , m_simulatorSshPort(source->m_simulatorSshPort) , m_simulatorGdbServerPort(source->m_simulatorGdbServerPort) , m_cachedSimulatorInformationValid(false) , m_gdbPath(source->m_gdbPath) , m_devConfig(source->m_devConfig) , m_arguments(source->m_arguments) , m_lastDeployed(source->m_lastDeployed) , m_debuggingHelpersLastDeployed(source->m_debuggingHelpersLastDeployed) , qemu(0) { init(); } void MaemoRunConfiguration::init() { if (!m_proFilePath.isEmpty()) { setDisplayName(tr("%1 on Maemo device").arg(QFileInfo(m_proFilePath) .completeBaseName())); } else { setDisplayName(tr("MaemoRunConfiguration")); } connect(&MaemoDeviceConfigurations::instance(), SIGNAL(updated()), this, SLOT(updateDeviceConfigurations())); connect(qt4Target(), SIGNAL(targetInformationChanged()), this, SLOT(invalidateCachedTargetInformation())); connect(qt4Target(), SIGNAL(targetInformationChanged()), this, SLOT(enabledStateChanged())); connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)), this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*))); 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; } Qt4Target *MaemoRunConfiguration::qt4Target() const { return static_cast(target()); } Qt4BuildConfiguration *MaemoRunConfiguration::activeQt4BuildConfiguration() const { return static_cast(activeBuildConfiguration()); } bool MaemoRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *config) const { Qt4BuildConfiguration *qt4bc = qobject_cast(config); QTC_ASSERT(qt4bc, return false); ToolChain::ToolChainType type = qt4bc->toolChainType(); 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(); } QVariantMap MaemoRunConfiguration::toMap() const { QVariantMap map(RunConfiguration::toMap()); map.insert(DeviceIdKey, m_devConfig.internalId); map.insert(ArgumentsKey, m_arguments); map.insert(LastDeployedKey, m_lastDeployed); map.insert(DebuggingHelpersLastDeployedKey, m_debuggingHelpersLastDeployed); map.insert(SimulatorPathKey, m_simulatorPath); const QDir &dir = QFileInfo(qt4Target()->qt4Project()->file()->fileName()).absoluteDir(); map.insert(ProFileKey, dir.relativeFilePath(m_proFilePath)); return map; } bool MaemoRunConfiguration::fromMap(const QVariantMap &map) { if (!RunConfiguration::fromMap(map)) return false; setDeviceConfig(MaemoDeviceConfigurations::instance(). find(map.value(DeviceIdKey, 0).toInt())); m_arguments = map.value(ArgumentsKey).toStringList(); m_lastDeployed = map.value(LastDeployedKey).toDateTime(); m_debuggingHelpersLastDeployed = map.value(DebuggingHelpersLastDeployedKey).toDateTime(); m_simulatorPath = map.value(SimulatorPathKey).toString(); const QDir &dir = QFileInfo(qt4Target()->qt4Project()->file()->fileName()).absoluteDir(); m_proFilePath = dir.filePath(map.value(ProFileKey).toString()); return true; } bool MaemoRunConfiguration::currentlyNeedsDeployment() const { return fileNeedsDeployment(executable(), m_lastDeployed); } void MaemoRunConfiguration::wasDeployed() { m_lastDeployed = QDateTime::currentDateTime(); } bool MaemoRunConfiguration::hasDebuggingHelpers() const { Qt4BuildConfiguration *qt4bc = activeQt4BuildConfiguration(); return qt4bc->qtVersion()->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; } void MaemoRunConfiguration::setDeviceConfig(const MaemoDeviceConfig &devConf) { m_devConfig = devConf; } MaemoDeviceConfig MaemoRunConfiguration::deviceConfig() const { return m_devConfig; } 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 { Qt4BuildConfiguration *qt4bc(activeQt4BuildConfiguration()); QTC_ASSERT(qt4bc, return 0); MaemoToolChain *tc = dynamic_cast(qt4bc->toolChain()); 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(); } QString MaemoRunConfiguration::maddeRoot() const { if (const MaemoToolChain *tc = toolchain()) return tc->maddeRoot(); return QString(); } const QString MaemoRunConfiguration::sysRoot() const { if (const MaemoToolChain *tc = toolchain()) return tc->sysrootRoot(); return QString(); } const QStringList MaemoRunConfiguration::arguments() const { return m_arguments; } const QString MaemoRunConfiguration::dumperLib() const { Qt4BuildConfiguration *qt4bc(activeQt4BuildConfiguration()); return qt4bc->qtVersion()->debuggingHelperLibrary(); } QString MaemoRunConfiguration::executable() const { updateTarget(); return m_executable; } QString MaemoRunConfiguration::simulatorSshPort() const { updateSimulatorInformation(); return m_simulatorSshPort; } QString MaemoRunConfiguration::simulatorGdbServerPort() const { updateSimulatorInformation();; return m_simulatorGdbServerPort; } QString MaemoRunConfiguration::simulatorPath() const { updateSimulatorInformation(); return m_simulatorPath; } QString MaemoRunConfiguration::visibleSimulatorParameter() const { updateSimulatorInformation(); return m_visibleSimulatorParameter; } QString MaemoRunConfiguration::simulator() const { updateSimulatorInformation(); return m_simulator; } QString MaemoRunConfiguration::simulatorArgs() const { updateSimulatorInformation(); return m_simulatorArgs; } void MaemoRunConfiguration::setArguments(const QStringList &args) { m_arguments = args; } bool MaemoRunConfiguration::isQemuRunning() const { return (qemu && qemu->state() != QProcess::NotRunning); } void MaemoRunConfiguration::invalidateCachedTargetInformation() { m_cachedTargetInformationValid = false; emit targetInformationChanged(); } void MaemoRunConfiguration::updateTarget() const { if (m_cachedTargetInformationValid) return; m_executable.clear(); m_cachedTargetInformationValid = true; Qt4TargetInformation info = qt4Target()->targetInformation(activeQt4BuildConfiguration(), m_proFilePath); if (info.error != Qt4TargetInformation::NoError) { if (info.error == Qt4TargetInformation::ProParserError) { Core::ICore::instance()->messageManager()->printToOutputPane(tr( "Could not parse %1. The Maemo run configuration %2 " "can not be started.").arg(m_proFilePath).arg(displayName())); } emit targetInformationChanged(); return; } m_executable = QDir::cleanPath(info.workingDir % QLatin1Char('/') % info.target); emit targetInformationChanged(); } void MaemoRunConfiguration::updateSimulatorInformation() const { if (m_cachedSimulatorInformationValid) return; m_simulator.clear(); m_simulatorPath.clear(); m_simulatorArgs.clear(); m_visibleSimulatorParameter.clear(); m_simulatorLibPath.clear(); m_simulatorSshPort.clear(); m_simulatorGdbServerPort.clear(); m_cachedSimulatorInformationValid = true; if (const MaemoToolChain *tc = toolchain()) m_simulatorPath = QDir::toNativeSeparators(tc->simulatorRoot()); if (!m_simulatorPath.isEmpty()) { m_visibleSimulatorParameter = tr("'%1' does not contain a valid Maemo " "simulator image.").arg(m_simulatorPath); } QDir dir(m_simulatorPath); if (!m_simulatorPath.isEmpty() && 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 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("qemu")); m_simulatorArgs = map.value(QLatin1String("qemu_args")); const QString &libPathSpec = map.value(QLatin1String("libpath")); m_simulatorLibPath = libPathSpec.mid(libPathSpec.indexOf(QLatin1Char('=')) + 1); m_simulatorSshPort = map.value(QLatin1String("sshport")); m_simulatorGdbServerPort = map.value(QLatin1String("redirport2")); m_visibleSimulatorParameter = m_simulator #ifdef Q_OS_WIN + QLatin1String(".exe") #endif + QLatin1Char(' ') + m_simulatorArgs; } } } } else { m_visibleSimulatorParameter = tr("Simulator could not be found. Please " "check the Qt Version you are using and that a simulator image is " "already installed."); } 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; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); #ifdef Q_OS_WIN const QLatin1Char colon(';'); const QString path = QDir::toNativeSeparators(root + QLatin1Char('/')); const QLatin1String key("PATH"); env.insert(key, env.value(key) % colon % path % QLatin1String("bin")); env.insert(key, env.value(key) % colon % path % QLatin1String("madlib")); #elif defined(Q_OS_UNIX) const QLatin1String key("LD_LIBRARY_PATH"); env.insert(key, env.value(key) % QLatin1Char(':') % m_simulatorLibPath); #endif qemu->setProcessEnvironment(env); qemu->setWorkingDirectory(simulatorPath()); const 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()); } 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(); } // #pragma mark -- MaemoRunConfigurationFactory MaemoRunConfigurationFactory::MaemoRunConfigurationFactory(QObject *parent) : IRunConfigurationFactory(parent) { 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*))); } MaemoRunConfigurationFactory::~MaemoRunConfigurationFactory() { } bool MaemoRunConfigurationFactory::canCreate(Target *parent, const QString &id) const { Qt4Target * t = qobject_cast(parent); if (!t || (t->id() != QLatin1String(MAEMO_DEVICE_TARGET_ID) && t->id() != QLatin1String(MAEMO_EMULATOR_TARGET_ID))) return false; return id == QLatin1String(MAEMO_RC_ID); } bool MaemoRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const { QString id(ProjectExplorer::idFromMap(map)); return canCreate(parent, id); } bool MaemoRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const { QString id(source->id()); return canCreate(parent, id); } QStringList MaemoRunConfigurationFactory::availableCreationIds(Target *parent) const { Qt4Target *t = qobject_cast(parent); if (!t || (t->id() != QLatin1String(MAEMO_DEVICE_TARGET_ID) && t->id() != QLatin1String(MAEMO_EMULATOR_TARGET_ID))) return QStringList(); return t->qt4Project()->applicationProFilePathes(QLatin1String(MAEMO_RC_ID_PREFIX)); } QString MaemoRunConfigurationFactory::displayNameForId(const QString &id) const { QString target(targetFromId(id)); if (target.isEmpty()) return QString(); return tr("%1 on Maemo Device").arg(QFileInfo(target).completeBaseName()); } RunConfiguration *MaemoRunConfigurationFactory::create(Target *parent, const QString &id) { if (!canCreate(parent, id)) return 0; Qt4Target *pqt4parent = static_cast(parent); MaemoRunConfiguration *rc = new MaemoRunConfiguration(pqt4parent, targetFromId(id)); setupRunConfiguration(rc); return rc; } RunConfiguration *MaemoRunConfigurationFactory::restore(Target *parent, const QVariantMap &map) { if (!canRestore(parent, map)) return 0; Qt4Target *t = static_cast(parent); MaemoRunConfiguration *rc = new MaemoRunConfiguration(t, QString()); if (!rc->fromMap(map)) { delete rc; return 0; } setupRunConfiguration(rc); return rc; } RunConfiguration *MaemoRunConfigurationFactory::clone(Target *parent, RunConfiguration *source) { if (!canClone(parent, source)) return 0; Qt4Target *t = static_cast(parent); MaemoRunConfiguration *old = static_cast(source); MaemoRunConfiguration *rc = new MaemoRunConfiguration(t, old); setupRunConfiguration(rc); return rc; } void MaemoRunConfigurationFactory::setupRunConfiguration(MaemoRunConfiguration *rc) { if (!rc) return; connect(MaemoManager::instance(), SIGNAL(startStopQemu()), rc, SLOT(startStopQemu())); connect(rc, SIGNAL(qemuProcessStatus(bool)), MaemoManager::instance(), SLOT(updateQemuSimulatorStarter(bool))); } void MaemoRunConfigurationFactory::projectAdded( ProjectExplorer::Project *project) { disconnect(project, SIGNAL(addedTarget(ProjectExplorer::Target*)), this, SLOT(targetAdded(ProjectExplorer::Target*))); disconnect(project, SIGNAL(removedTarget(ProjectExplorer::Target*)), this, SLOT(targetRemoved(ProjectExplorer::Target*))); foreach (Target *target, project->targets()) targetAdded(target); } void MaemoRunConfigurationFactory::projectRemoved( ProjectExplorer::Project *project) { connect(project, SIGNAL(addedTarget(ProjectExplorer::Target*)), this, SLOT(targetAdded(ProjectExplorer::Target*))); connect(project, SIGNAL(removedTarget(ProjectExplorer::Target*)), this, SLOT(targetRemoved(ProjectExplorer::Target*))); foreach (Target *target, project->targets()) targetRemoved(target); } void MaemoRunConfigurationFactory::targetAdded(ProjectExplorer::Target *target) { if (target->id() != QLatin1String(MAEMO_EMULATOR_TARGET_ID) && target->id() != QLatin1String(MAEMO_DEVICE_TARGET_ID)) return; MaemoManager::instance()->addQemuSimulatorStarter(target->project()); } void MaemoRunConfigurationFactory::targetRemoved(ProjectExplorer::Target *target) { if (target->id() != QLatin1String(MAEMO_EMULATOR_TARGET_ID) && target->id() != QLatin1String(MAEMO_DEVICE_TARGET_ID)) return; MaemoManager::instance()->removeQemuSimulatorStarter(target->project()); } void MaemoRunConfigurationFactory::currentProjectChanged( ProjectExplorer::Project *project) { if (!project) return; Target *maemoTarget(project->target(QLatin1String(MAEMO_EMULATOR_TARGET_ID))); if (!maemoTarget) maemoTarget = project->target(QLatin1String(MAEMO_DEVICE_TARGET_ID)); MaemoManager::instance()->setQemuSimulatorStarterEnabled(maemoTarget); bool isRunning(false); if (maemoTarget && project->activeTarget() == maemoTarget && maemoTarget->activeRunConfiguration()) { MaemoRunConfiguration *mrc = qobject_cast(maemoTarget->activeRunConfiguration()); if (mrc) isRunning = mrc->isQemuRunning(); } MaemoManager::instance()->updateQemuSimulatorStarter(isRunning); } // #pragma mark -- MaemoRunControlFactory MaemoRunControlFactory::MaemoRunControlFactory(QObject *parent) : IRunControlFactory(parent) { } bool MaemoRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const { return qobject_cast(runConfiguration) && (mode == ProjectExplorer::Constants::RUNMODE || mode == ProjectExplorer::Constants::DEBUGMODE); } RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig, const QString &mode) { MaemoRunConfiguration *rc = qobject_cast(runConfig); Q_ASSERT(rc); 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 { return tr("Run on device"); } QWidget* MaemoRunControlFactory::configurationWidget(RunConfiguration *config) { Q_UNUSED(config) return 0; } } // namespace Internal } // namespace Qt4ProjectManager