summaryrefslogtreecommitdiff
path: root/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp')
-rw-r--r--src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp b/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp
new file mode 100644
index 0000000000..6c78d6adbc
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp
@@ -0,0 +1,489 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 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 "S60deployStep.h"
+
+#include "qt4buildconfiguration.h"
+#include "s60devicerunconfiguration.h"
+#include "symbiandevicemanager.h"
+#include "s60runconfigbluetoothstarter.h"
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QMainWindow>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTimer>
+#include <QDateTime>
+#include <QFile>
+#include <QFileInfo>
+#include <QDir>
+
+#include <coreplugin/icore.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/ioutputparser.h>
+#include <qt4projectmanagerconstants.h>
+
+using namespace ProjectExplorer;
+using namespace Qt4ProjectManager::Internal;
+
+namespace {
+ const char * const S60_DEPLOY_STEP_ID = "Qt4ProjectManager.S60DeployStep";
+}
+
+static inline bool ensureDeleteFile(const QString &fileName, QString *errorMessage)
+{
+ QFile file(fileName);
+ if (file.exists() && !file.remove()) {
+ *errorMessage = S60DeployStep::tr("Unable to remove existing file '%1': %2").arg(fileName, file.errorString());
+ return false;
+ }
+ return true;
+}
+
+static inline bool renameFile(const QString &sourceName, const QString &targetName,
+ QString *errorMessage)
+{
+ if (sourceName == targetName)
+ return true;
+ if (!ensureDeleteFile(targetName, errorMessage))
+ return false;
+ QFile source(sourceName);
+ if (!source.rename(targetName)) {
+ *errorMessage = S60DeployStep::tr("Unable to rename file '%1' to '%2': %3")
+ .arg(sourceName, targetName, source.errorString());
+ return false;
+ }
+ return true;
+}
+
+// #pragma mark -- S60DeployStep
+
+S60DeployStep::S60DeployStep(ProjectExplorer::BuildConfiguration *bc, const QString &id) :
+ BuildStep(bc, id), m_timer(0), m_launcher(0),
+ m_releaseDeviceAfterLauncherFinish(true), m_handleDeviceRemoval(true),
+ m_eventLoop(0)
+{
+}
+
+S60DeployStep::S60DeployStep(ProjectExplorer::BuildConfiguration *bc,
+ S60DeployStep *bs):
+ BuildStep(bc, bs), m_timer(0), m_launcher(0),
+ m_releaseDeviceAfterLauncherFinish(bs->m_releaseDeviceAfterLauncherFinish),
+ m_handleDeviceRemoval(bs->m_handleDeviceRemoval),
+ m_eventLoop(0)
+{
+}
+
+S60DeployStep::S60DeployStep(ProjectExplorer::BuildConfiguration *bc):
+ BuildStep(bc, QLatin1String(S60_DEPLOY_STEP_ID)), m_timer(0),
+ m_launcher(0), m_releaseDeviceAfterLauncherFinish(true),
+ m_handleDeviceRemoval(true), m_eventLoop(0)
+{
+}
+
+S60DeployStep::~S60DeployStep()
+{
+ delete m_timer;
+ delete m_launcher;
+ delete m_eventLoop;
+}
+
+
+bool S60DeployStep::init()
+{
+ Qt4BuildConfiguration *bc = static_cast<Qt4BuildConfiguration *>(buildConfiguration());
+ S60DeviceRunConfiguration* runConfiguration = static_cast<S60DeviceRunConfiguration *>(bc->target()->activeRunConfiguration());
+
+ if(!runConfiguration) {
+ return false;
+ }
+ m_serialPortName = runConfiguration->serialPortName();
+ m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
+ m_packageFileNameWithTarget = runConfiguration->packageFileNameWithTargetInfo();
+ m_signedPackage = runConfiguration->signedPackage();
+
+ setDisplayName(tr("Deploy", "Qt4 DeployStep display name."));
+ QString message;
+ m_launcher = trk::Launcher::acquireFromDeviceManager(m_serialPortName, this, &message);
+ if (!message.isEmpty()) {
+ trk::Launcher::releaseToDeviceManager(m_launcher);
+ delete m_launcher;
+ m_launcher = 0;
+ appendMessage(message, true);
+ return false;
+ }
+ return true;
+}
+
+QVariantMap S60DeployStep::toMap() const
+{
+ return BuildStep::toMap();
+}
+
+bool S60DeployStep::fromMap(const QVariantMap &map)
+{
+ return BuildStep::fromMap(map);
+}
+
+void S60DeployStep::appendMessage(const QString &error, bool isError)
+{
+ emit addOutput(error, isError?ProjectExplorer::BuildStep::ErrorMessageOutput:
+ ProjectExplorer::BuildStep::MessageOutput);
+}
+
+bool S60DeployStep::processPackageName(QString &errorMessage)
+{
+ QFileInfo packageInfo(m_signedPackage);
+ {
+ // support for 4.6.1 and pre, where make sis creates 'targetname_armX_udeb.sis' instead of 'targetname.sis'
+ QFileInfo packageWithTargetInfo(m_packageFileNameWithTarget);
+ // does the 4.6.1 version exist?
+ if (packageWithTargetInfo.exists() && packageWithTargetInfo.isFile()) {
+ // is the 4.6.1 version newer? (to guard against behavior change Qt Creator 1.3 --> 2.0)
+ if (!packageInfo.exists() || packageInfo.lastModified() < packageWithTargetInfo.lastModified()) { //TODO change the QtCore
+ // the 'targetname_armX_udeb.sis' crap exists and is new, rename it
+ appendMessage(tr("Renaming new package '%1' to '%2'")
+ .arg(QDir::toNativeSeparators(m_packageFileNameWithTarget),
+ QDir::toNativeSeparators(m_signedPackage)), false);
+ return renameFile(m_packageFileNameWithTarget, m_signedPackage, &errorMessage);
+ } else {
+ // the 'targetname_armX_udeb.sis' crap exists but is old, remove it
+ appendMessage(tr("Removing old package '%1'")
+ .arg(QDir::toNativeSeparators(m_packageFileNameWithTarget)),
+ false);
+ ensureDeleteFile(m_packageFileNameWithTarget, &errorMessage);
+ }
+ }
+ }
+ if (!packageInfo.exists() || !packageInfo.isFile()) {
+ errorMessage = tr("Package file not found");
+ return false;
+ }
+ return true;
+}
+
+void S60DeployStep::start()
+{
+ if (m_serialPortName.isEmpty()) {
+ appendMessage(tr("There is no device plugged in."), true);
+ emit finished();
+ return;
+ }
+
+ QString errorMessage;
+
+ // make sure we have the right name of the sis package
+ if (processPackageName(errorMessage)) {
+ startDeployment();
+ } else {
+ errorMessage = tr("Failed to find package '%1': %2").arg(m_signedPackage, errorMessage);
+ appendMessage(errorMessage, true);
+ stop();
+ emit finished();
+ }
+}
+
+void S60DeployStep::stop()
+{
+ if (m_launcher)
+ m_launcher->terminate();
+ emit finished();
+}
+
+void S60DeployStep::setupConnections()
+{
+ connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(SymbianUtils::SymbianDevice)),
+ this, SLOT(deviceRemoved(SymbianUtils::SymbianDevice)));
+ connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
+ connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
+ connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice()));
+ connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(printCreateFileFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(canNotWriteFile(QString,QString)), this, SLOT(printWriteFileFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(canNotCloseFile(QString,QString)), this, SLOT(printCloseFileFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(installingStarted()), this, SLOT(printInstallingNotice()));
+ connect(m_launcher, SIGNAL(canNotInstall(QString,QString)), this, SLOT(printInstallFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(installingFinished()), this, SLOT(printInstallingFinished()));
+ connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
+}
+
+void S60DeployStep::startDeployment()
+{
+ Q_ASSERT(m_launcher);
+
+ QString errorMessage;
+ bool success = false;
+ do {
+ setupConnections();
+ //TODO sisx destination and file path user definable
+ const QString copyDst = QString::fromLatin1("C:\\Data\\%1").arg(QFileInfo(m_signedPackage).fileName());
+
+ m_launcher->setCopyFileName(m_signedPackage, copyDst);
+ m_launcher->setInstallFileName(copyDst);
+ m_launcher->addStartupActions(trk::Launcher::ActionCopyInstall);
+
+ appendMessage(tr("Package: %1\nDeploying application to '%2'...").arg(m_signedPackage, m_serialPortFriendlyName), false);
+
+ // Prompt the user to start up the Blue tooth connection
+ const trk::PromptStartCommunicationResult src =
+ S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
+ 0, &errorMessage);
+ if (src != trk::PromptStartCommunicationConnected)
+ break;
+ if (!m_launcher->startServer(&errorMessage)) {
+ errorMessage = tr("Could not connect to phone on port '%1': %2\n"
+ "Check if the phone is connected and App TRK is running.").arg(m_serialPortName, errorMessage);
+ break;
+ }
+ success = true;
+ } while (false);
+
+ if (!success) {
+ if (!errorMessage.isEmpty())
+ appendMessage(errorMessage, true);
+ stop();
+ emit finished();
+ }
+}
+
+void S60DeployStep::run(QFutureInterface<bool> &fi)
+{
+ m_futureInterface = &fi;
+ m_deployResult = false;
+ connect(this, SIGNAL(finished()),
+ this, SLOT(launcherFinished()));
+ connect(this, SIGNAL(finishNow()),
+ this, SLOT(launcherFinished()), Qt::DirectConnection);
+
+ start();
+ m_timer = new QTimer();
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(checkForCancel()), Qt::DirectConnection);
+ m_timer->start(500);
+ m_eventLoop = new QEventLoop();
+ m_eventLoop->exec();
+ m_timer->stop();
+ delete m_timer;
+ m_timer = 0;
+
+ delete m_eventLoop;
+ m_eventLoop = 0;
+ fi.reportResult(m_deployResult);
+ m_futureInterface = 0;
+}
+
+void S60DeployStep::setReleaseDeviceAfterLauncherFinish(bool v)
+{
+ m_releaseDeviceAfterLauncherFinish = v;
+}
+
+void S60DeployStep::slotLauncherStateChanged(int s)
+{
+ if (s == trk::Launcher::WaitingForTrk) {
+ QMessageBox *mb = S60DeviceRunControlBase::createTrkWaitingMessageBox(m_launcher->trkServerName(),
+ Core::ICore::instance()->mainWindow());
+ connect(m_launcher, SIGNAL(stateChanged(int)), mb, SLOT(close()));
+ connect(mb, SIGNAL(finished(int)), this, SLOT(slotWaitingForTrkClosed()));
+ mb->open();
+ }
+}
+
+void S60DeployStep::slotWaitingForTrkClosed()
+{
+ if (m_launcher && m_launcher->state() == trk::Launcher::WaitingForTrk) {
+ stop();
+ appendMessage(tr("Canceled."), true);
+ emit finished();
+ }
+}
+
+void S60DeployStep::printCreateFileFailed(const QString &filename, const QString &errorMessage)
+{
+ appendMessage(tr("Could not create file %1 on device: %2").arg(filename, errorMessage), true);
+}
+
+void S60DeployStep::printWriteFileFailed(const QString &filename, const QString &errorMessage)
+{
+ appendMessage(tr("Could not write to file %1 on device: %2").arg(filename, errorMessage), true);
+}
+
+void S60DeployStep::printCloseFileFailed(const QString &filename, const QString &errorMessage)
+{
+ const QString msg = tr("Could not close file %1 on device: %2. It will be closed when App TRK is closed.");
+ appendMessage( msg.arg(filename, errorMessage), true);
+}
+
+void S60DeployStep::printConnectFailed(const QString &errorMessage)
+{
+ appendMessage(tr("Could not connect to App TRK on device: %1. Restarting App TRK might help.").arg(errorMessage), true);
+}
+
+void S60DeployStep::printCopyingNotice()
+{
+ appendMessage(tr("Copying installation file..."), false);
+}
+
+void S60DeployStep::printInstallingNotice()
+{
+ appendMessage(tr("Installing application..."), false);
+}
+
+void S60DeployStep::printInstallingFinished()
+{
+ appendMessage(tr("Installation has finished"), false);
+}
+
+void S60DeployStep::printInstallFailed(const QString &filename, const QString &errorMessage)
+{
+ appendMessage(tr("Could not install from package %1 on device: %2").arg(filename, errorMessage), true);
+}
+
+void S60DeployStep::checkForCancel()
+{
+ if (m_futureInterface->isCanceled() && m_timer->isActive()) {
+ m_timer->stop();
+ stop();
+ appendMessage(tr("Canceled."), true);
+ emit finishNow();
+ }
+}
+
+void S60DeployStep::launcherFinished()
+{
+ if (m_releaseDeviceAfterLauncherFinish && m_launcher) {
+ m_handleDeviceRemoval = false;
+ trk::Launcher::releaseToDeviceManager(m_launcher);
+ }
+ m_deployResult = true;
+ if(m_launcher)
+ m_launcher->deleteLater();
+ m_launcher = 0;
+ if(m_eventLoop)
+ m_eventLoop->exit(0);
+}
+
+void S60DeployStep::deviceRemoved(const SymbianUtils::SymbianDevice &d)
+{
+ if (m_handleDeviceRemoval && d.portName() == m_serialPortName) {
+ appendMessage(tr("The device '%1' has been disconnected").arg(d.friendlyName()), true);
+ emit finished();
+ }
+}
+
+// #pragma mark -- S60DeployStepWidget
+
+BuildStepConfigWidget *S60DeployStep::createConfigWidget()
+{
+ return new S60DeployStepWidget();
+}
+
+void S60DeployStepWidget::init()
+{
+}
+
+QString S60DeployStepWidget::summaryText() const
+{
+ return tr("<b>Deploy SIS Package</b>");
+}
+
+QString S60DeployStepWidget::displayName() const
+{
+ return QString("S60DeployStepWidget::displayName");
+}
+
+// #pragma mark -- S60DeployStepFactory
+
+S60DeployStepFactory::S60DeployStepFactory(QObject *parent) :
+ ProjectExplorer::IBuildStepFactory(parent)
+{
+}
+
+S60DeployStepFactory::~S60DeployStepFactory()
+{
+}
+
+bool S60DeployStepFactory::canCreate(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, const QString &id) const
+{
+ if (type != ProjectExplorer::BuildStep::Deploy)
+ return false;
+ if (parent->target()->id() != QLatin1String(Constants::S60_DEVICE_TARGET_ID))
+ return false;
+ return (id == QLatin1String(S60_DEPLOY_STEP_ID));
+}
+
+ProjectExplorer::BuildStep *S60DeployStepFactory::create(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, const QString &id)
+{
+ if (!canCreate(parent, type, id))
+ return 0;
+ return new S60DeployStep(parent, id);
+}
+
+bool S60DeployStepFactory::canClone(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, ProjectExplorer::BuildStep *source) const
+{
+ return canCreate(parent, type, source->id());
+}
+
+ProjectExplorer::BuildStep *S60DeployStepFactory::clone(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, ProjectExplorer::BuildStep *source)
+{
+ if (!canClone(parent, type, source))
+ return 0;
+ return new S60DeployStep(parent, static_cast<S60DeployStep *>(source));
+}
+
+bool S60DeployStepFactory::canRestore(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, const QVariantMap &map) const
+{
+ QString id(ProjectExplorer::idFromMap(map));
+ return canCreate(parent, type, id);
+}
+
+ProjectExplorer::BuildStep *S60DeployStepFactory::restore(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, const QVariantMap &map)
+{
+ if (!canRestore(parent, type, map))
+ return 0;
+ S60DeployStep *bs = new S60DeployStep(parent);
+ if (bs->fromMap(map))
+ return bs;
+ delete bs;
+ return 0;
+}
+
+QStringList S60DeployStepFactory::availableCreationIds(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type) const
+{
+ if (type != ProjectExplorer::BuildStep::Deploy)
+ return QStringList();
+ if (parent->target()->id() == QLatin1String(Constants::S60_DEVICE_TARGET_ID))
+ return QStringList() << QLatin1String(S60_DEPLOY_STEP_ID);
+ return QStringList();
+}
+
+QString S60DeployStepFactory::displayNameForId(const QString &id) const
+{
+ if (id == QLatin1String(S60_DEPLOY_STEP_ID))
+ return tr("Deploy SIS Package");
+ return QString();
+}