Newer
Older
/**************************************************************************
**
** 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 "qt4buildconfiguration.h"

Pawel Polanski
committed
#include "s60deployconfiguration.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/target.h>
#include <projectexplorer/ioutputparser.h>
#include <projectexplorer/projectexplorerconstants.h>
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#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::BuildStepList *bc,
m_releaseDeviceAfterLauncherFinish(bs->m_releaseDeviceAfterLauncherFinish),
m_handleDeviceRemoval(bs->m_handleDeviceRemoval),
ctor();
S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc):
BuildStep(bc, QLatin1String(S60_DEPLOY_STEP_ID)), m_timer(0),
m_releaseDeviceAfterLauncherFinish(true),
m_handleDeviceRemoval(true), m_launcher(0), m_eventLoop(0)
ctor();
}
void S60DeployStep::ctor()
{
//: Qt4 Deploystep display name
setDefaultDisplayName(tr("Deploy"));
}
S60DeployStep::~S60DeployStep()
{
delete m_timer;
delete m_launcher;
delete m_eventLoop;
}
bool S60DeployStep::init()
{
Qt4BuildConfiguration *bc = static_cast<Qt4BuildConfiguration *>(buildConfiguration());

Pawel Polanski
committed
S60DeployConfiguration* deployConfiguration = static_cast<S60DeployConfiguration *>(bc->target()->activeDeployConfiguration());
if(!deployConfiguration)

Pawel Polanski
committed
m_serialPortName = deployConfiguration->serialPortName();
m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);

Pawel Polanski
committed
m_packageFileNamesWithTarget = deployConfiguration->packageFileNamesWithTargetInfo();
m_signedPackages = deployConfiguration->signedPackages();
m_installationDrive = deployConfiguration->installationDrive();
m_silentInstall = deployConfiguration->silentInstall();
if (m_launcher) {
trk::Launcher::releaseToDeviceManager(m_launcher);
delete m_launcher;
m_launcher = 0;
}
m_launcher = trk::Launcher::acquireFromDeviceManager(m_serialPortName, this, &message);
if (!message.isEmpty() || !m_launcher) {
if (m_launcher)
trk::Launcher::releaseToDeviceManager(m_launcher);
delete m_launcher;
m_launcher = 0;
appendMessage(message, true);
return false;
}

Pawel Polanski
committed
// Prompt the user to start up the Blue tooth connection
const trk::PromptStartCommunicationResult src =
S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
0, &message);
if (src != trk::PromptStartCommunicationConnected) {
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)
{
for (int i = 0; i < m_signedPackages.count(); ++i) {
QFileInfo packageInfo(m_signedPackages.at(i));
// support for 4.6.1 and pre, where make sis creates 'targetname_armX_udeb.sis' instead of 'targetname.sis'
QFileInfo packageWithTargetInfo(m_packageFileNamesWithTarget.at(i));
// 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_packageFileNamesWithTarget.at(i)),
QDir::toNativeSeparators(m_signedPackages.at(i))), false);
return renameFile(m_packageFileNamesWithTarget.at(i), m_signedPackages.at(i), &errorMessage);
} else {
// the 'targetname_armX_udeb.sis' crap exists but is old, remove it
appendMessage(tr("Removing old package '%1'")
.arg(QDir::toNativeSeparators(m_packageFileNamesWithTarget.at(i))),
ensureDeleteFile(m_packageFileNamesWithTarget.at(i), &errorMessage);
if (!packageInfo.exists() || !packageInfo.isFile()) {
errorMessage = tr("'%1': Package file not found").arg(m_signedPackages.at(i));
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").arg(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()));

Pawel Polanski
committed
connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(connectFailed(QString)));
connect(m_launcher, SIGNAL(copyingStarted(QString)), this, SLOT(printCopyingNotice(QString)));

Pawel Polanski
committed
connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(createFileFailed(QString,QString)));
connect(m_launcher, SIGNAL(canNotWriteFile(QString,QString)), this, SLOT(writeFileFailed(QString,QString)));
connect(m_launcher, SIGNAL(canNotCloseFile(QString,QString)), this, SLOT(closeFileFailed(QString,QString)));
connect(m_launcher, SIGNAL(installingStarted(QString)), this, SLOT(printInstallingNotice(QString)));

Pawel Polanski
committed
connect(m_launcher, SIGNAL(canNotInstall(QString,QString)), this, SLOT(installFailed(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);

Pawel Polanski
committed
setupConnections();
QStringList copyDst;
foreach (const QString &signedPackage, m_signedPackages)
copyDst << QString::fromLatin1("%1:\\Data\\%2").arg(m_installationDrive).arg(QFileInfo(signedPackage).fileName());

Pawel Polanski
committed
m_launcher->setCopyFileNames(m_signedPackages, copyDst);
m_launcher->setInstallFileNames(copyDst);
m_launcher->setInstallationDrive(m_installationDrive);
m_launcher->setInstallationMode(m_silentInstall?trk::Launcher::InstallationModeSilentAndUser:
trk::Launcher::InstallationModeUser);

Pawel Polanski
committed
m_launcher->addStartupActions(trk::Launcher::ActionCopyInstall);
// TODO readd information about packages? msgListFile(m_signedPackage)
appendMessage(tr("Deploying application to '%2'...").arg(m_serialPortFriendlyName), false);

Pawel Polanski
committed
QString errorMessage;
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);
appendMessage(errorMessage, true);
stop();
emit finished();
}
}
void S60DeployStep::run(QFutureInterface<bool> &fi)
{
m_futureInterface = &fi;

Pawel Polanski
committed
m_deployResult = true;
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
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) {

Pawel Polanski
committed
QMessageBox *mb = S60DeviceRunControl::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();
}
}

Pawel Polanski
committed
void S60DeployStep::createFileFailed(const QString &filename, const QString &errorMessage)
{
appendMessage(tr("Could not create file %1 on device: %2").arg(filename, errorMessage), true);

Pawel Polanski
committed
m_deployResult = false;

Pawel Polanski
committed
void S60DeployStep::writeFileFailed(const QString &filename, const QString &errorMessage)
{
appendMessage(tr("Could not write to file %1 on device: %2").arg(filename, errorMessage), true);

Pawel Polanski
committed
m_deployResult = false;

Pawel Polanski
committed
void S60DeployStep::closeFileFailed(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);

Pawel Polanski
committed
m_deployResult = false;

Pawel Polanski
committed
void S60DeployStep::connectFailed(const QString &errorMessage)
{
appendMessage(tr("Could not connect to App TRK on device: %1. Restarting App TRK might help.").arg(errorMessage), true);

Pawel Polanski
committed
m_deployResult = false;
void S60DeployStep::printCopyingNotice(const QString &fileName)
appendMessage(tr("Copying \"%1\"...").arg(fileName), false);
void S60DeployStep::printInstallingNotice(const QString &packageName)
appendMessage(tr("Installing package \"%1\" on drive %2:...").arg(packageName).arg(m_installationDrive), false);
}
void S60DeployStep::printInstallingFinished()
{
appendMessage(tr("Installation has finished"), false);
}

Pawel Polanski
committed
void S60DeployStep::installFailed(const QString &filename, const QString &errorMessage)
{
appendMessage(tr("Could not install from package %1 on device: %2").arg(filename, errorMessage), true);

Pawel Polanski
committed
m_deployResult = false;
}
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);
}
if(m_launcher)
m_launcher->deleteLater();
m_launcher = 0;
if(m_eventLoop)

Pawel Polanski
committed
m_eventLoop->exit();
}
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
{
}
QString S60DeployStepWidget::displayName() const
{
}
// #pragma mark -- S60DeployStepFactory
S60DeployStepFactory::S60DeployStepFactory(QObject *parent) :
ProjectExplorer::IBuildStepFactory(parent)
{
}
S60DeployStepFactory::~S60DeployStepFactory()
{
}
bool S60DeployStepFactory::canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const
if (parent->id() != QLatin1String(ProjectExplorer::Constants::BUILDSTEPS_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::BuildStepList *parent, const QString &id)
bool S60DeployStepFactory::canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const
if (!canCreate(parent, source->id()))
return false;
if (!qobject_cast<S60DeployStep *>(source))
return false;
return true;
ProjectExplorer::BuildStep *S60DeployStepFactory::clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source)
return 0;
return new S60DeployStep(parent, static_cast<S60DeployStep *>(source));
}
bool S60DeployStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const
{
QString id(ProjectExplorer::idFromMap(map));
ProjectExplorer::BuildStep *S60DeployStepFactory::restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map)
return 0;
S60DeployStep *bs = new S60DeployStep(parent);
if (bs->fromMap(map))
return bs;
delete bs;
return 0;
}
QStringList S60DeployStepFactory::availableCreationIds(ProjectExplorer::BuildStepList *parent) const
if (parent->id() == QLatin1String(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
&& 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();
}