1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
31 **************************************************************************/
33 #include "s60deploystep.h"
35 #include "qt4buildconfiguration.h"
36 #include "s60deployconfiguration.h"
37 #include "s60devicerunconfiguration.h"
38 #include "codadevice.h"
39 #include "codaruncontrol.h"
41 #include <coreplugin/icore.h>
42 #include <projectexplorer/buildsteplist.h>
43 #include <projectexplorer/target.h>
44 #include <projectexplorer/projectexplorerconstants.h>
45 #include <qt4projectmanagerconstants.h>
47 #include <symbianutils/symbiandevicemanager.h>
48 #include <utils/qtcassert.h>
50 #include <QtGui/QMessageBox>
51 #include <QtGui/QMainWindow>
53 #include <QtCore/QTimer>
54 #include <QtCore/QDateTime>
55 #include <QtCore/QDir>
56 #include <QtCore/QEventLoop>
57 #include <QtCore/QFile>
58 #include <QtCore/QFileInfo>
60 #include <QtNetwork/QTcpSocket>
62 using namespace ProjectExplorer;
63 using namespace SymbianUtils;
64 using namespace Qt4ProjectManager::Internal;
68 static const quint64 DEFAULT_CHUNK_SIZE = 40000;
71 const char * const S60_DEPLOY_STEP_ID = "Qt4ProjectManager.S60DeployStep";
74 static inline bool ensureDeleteFile(const QString &fileName, QString *errorMessage)
77 if (file.exists() && !file.remove()) {
78 *errorMessage = S60DeployStep::tr("Unable to remove existing file '%1': %2").arg(fileName, file.errorString());
84 static inline bool renameFile(const QString &sourceName, const QString &targetName,
85 QString *errorMessage)
87 if (sourceName == targetName)
89 if (!ensureDeleteFile(targetName, errorMessage))
91 QFile source(sourceName);
92 if (!source.rename(targetName)) {
93 *errorMessage = S60DeployStep::tr("Unable to rename file '%1' to '%2': %3")
94 .arg(sourceName, targetName, source.errorString());
100 // #pragma mark -- S60DeployStep
102 S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc,
104 BuildStep(bc, bs), m_timer(0),
105 m_timeoutTimer(new QTimer(this)),
107 m_state(StateUninit),
109 m_putLastChunkSize(0),
110 m_putChunkSize(DEFAULT_CHUNK_SIZE),
111 m_currentFileIndex(0),
112 m_channel(bs->m_channel),
113 m_deployCanceled(false),
119 S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc):
120 BuildStep(bc, QLatin1String(S60_DEPLOY_STEP_ID)), m_timer(0),
121 m_timeoutTimer(new QTimer(this)),
123 m_state(StateUninit),
125 m_putLastChunkSize(0),
126 m_putChunkSize(DEFAULT_CHUNK_SIZE),
127 m_currentFileIndex(0),
128 m_channel(S60DeployConfiguration::CommunicationCodaSerialConnection),
129 m_deployCanceled(false),
135 void S60DeployStep::ctor()
137 //: Qt4 Deploystep display name
138 setDefaultDisplayName(tr("Deploy"));
139 m_timeoutTimer->setSingleShot(true);
140 m_timeoutTimer->setInterval(2000);
141 connect(m_timeoutTimer, SIGNAL(timeout()), this, SLOT(timeout()));
144 S60DeployStep::~S60DeployStep()
151 bool S60DeployStep::init()
153 Qt4BuildConfiguration *bc = static_cast<Qt4BuildConfiguration *>(buildConfiguration());
154 S60DeployConfiguration *deployConfiguration = static_cast<S60DeployConfiguration *>(bc->target()->activeDeployConfiguration());
155 if (!deployConfiguration)
157 m_serialPortName = deployConfiguration->serialPortName();
158 m_serialPortFriendlyName = SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
159 m_packageFileNamesWithTarget = deployConfiguration->packageFileNamesWithTargetInfo();
160 m_signedPackages = deployConfiguration->signedPackages();
161 m_installationDrive = deployConfiguration->installationDrive();
162 m_silentInstall = deployConfiguration->silentInstall();
163 m_channel = deployConfiguration->communicationChannel();
165 if (m_signedPackages.isEmpty()) {
166 appendMessage(tr("No package has been found. Please specify at least one installation package."), true);
170 if (m_channel == S60DeployConfiguration::CommunicationCodaTcpConnection) {
171 m_address = deployConfiguration->deviceAddress();
172 m_port = deployConfiguration->devicePort().toInt();
177 QVariantMap S60DeployStep::toMap() const
179 return BuildStep::toMap();
182 bool S60DeployStep::fromMap(const QVariantMap &map)
184 return BuildStep::fromMap(map);
187 void S60DeployStep::appendMessage(const QString &error, bool isError)
189 emit addOutput(error, isError?ProjectExplorer::BuildStep::ErrorMessageOutput:
190 ProjectExplorer::BuildStep::MessageOutput);
193 void S60DeployStep::reportError(const QString &error)
195 emit addOutput(error, ProjectExplorer::BuildStep::ErrorMessageOutput);
196 emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error,
199 ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
200 emit finished(false);
203 bool S60DeployStep::processPackageName(QString &errorMessage)
205 for (int i = 0; i < m_signedPackages.count(); ++i) {
206 QFileInfo packageInfo(m_signedPackages.at(i));
207 // support for 4.6.1 and pre, where make sis creates 'targetname_armX_udeb.sis' instead of 'targetname.sis'
208 QFileInfo packageWithTargetInfo(m_packageFileNamesWithTarget.at(i));
209 // does the 4.6.1 version exist?
210 if (packageWithTargetInfo.exists() && packageWithTargetInfo.isFile()) {
211 // is the 4.6.1 version newer? (to guard against behavior change Qt Creator 1.3 --> 2.0)
212 if (!packageInfo.exists() || packageInfo.lastModified() < packageWithTargetInfo.lastModified()) { //TODO change the QtCore
213 // the 'targetname_armX_udeb.sis' crap exists and is new, rename it
214 appendMessage(tr("Renaming new package '%1' to '%2'")
215 .arg(QDir::toNativeSeparators(m_packageFileNamesWithTarget.at(i)),
216 QDir::toNativeSeparators(m_signedPackages.at(i))), false);
217 return renameFile(m_packageFileNamesWithTarget.at(i), m_signedPackages.at(i), &errorMessage);
219 // the 'targetname_armX_udeb.sis' crap exists but is old, remove it
220 appendMessage(tr("Removing old package '%1'")
221 .arg(QDir::toNativeSeparators(m_packageFileNamesWithTarget.at(i))),
223 ensureDeleteFile(m_packageFileNamesWithTarget.at(i), &errorMessage);
226 if (!packageInfo.exists() || !packageInfo.isFile()) {
227 errorMessage = tr("'%1': Package file not found").arg(m_signedPackages.at(i));
234 void S60DeployStep::start()
236 QString errorMessage;
238 bool serialConnection = m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection;
240 if (serialConnection && m_serialPortName.isEmpty()) {
241 errorMessage = tr("No device is connected. Please connect a device and try again.");
242 reportError(errorMessage);
245 QTC_ASSERT(!m_codaDevice.data(), return);
246 if (m_address.isEmpty() && !serialConnection) {
247 errorMessage = tr("No address for a device has been defined. Please define an address and try again.");
248 reportError(errorMessage);
252 // make sure we have the right name of the sis package
253 if (processPackageName(errorMessage))
256 errorMessage = tr("Failed to find package %1").arg(errorMessage);
257 reportError(errorMessage);
262 void S60DeployStep::stop()
266 case StateSendingData:
270 break; //should also stop the package installation, but CODA does not support it yet
272 disconnect(m_codaDevice.data(), 0, this, 0);
273 SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
275 setState(StateUninit);
276 emit finished(false);
279 void S60DeployStep::setupConnections()
281 if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection)
282 connect(SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(SymbianDevice)), this, SLOT(deviceRemoved(SymbianDevice)));
284 connect(m_codaDevice.data(), SIGNAL(error(QString)), this, SLOT(slotError(QString)));
285 connect(m_codaDevice.data(), SIGNAL(logMessage(QString)), this, SLOT(slotCodaLogMessage(QString)));
286 connect(m_codaDevice.data(), SIGNAL(codaEvent(Coda::CodaEvent)), this, SLOT(slotCodaEvent(Coda::CodaEvent)), Qt::DirectConnection);
287 connect(m_codaDevice.data(), SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString)));
288 connect(this, SIGNAL(manualInstallation()), this, SLOT(showManualInstallationInfo()));
291 void S60DeployStep::startDeployment()
293 QTC_ASSERT(!m_codaDevice.data(), return);
295 // We need to defer setupConnections() in the case of CommunicationCodaSerialConnection
296 //setupConnections();
298 if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) {
299 appendMessage(tr("Deploying application to '%1'...").arg(m_serialPortFriendlyName), false);
300 m_codaDevice = SymbianDeviceManager::instance()->getCodaDevice(m_serialPortName);
301 bool ok = m_codaDevice && m_codaDevice->device()->isOpen();
303 QString deviceError = tr("No such port");
305 deviceError = m_codaDevice->device()->errorString();
306 reportError(tr("Could not open serial device: %1").arg(deviceError));
311 setState(StateConnecting);
312 m_codaDevice->sendSerialPing(false);
314 m_codaDevice = QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice);
316 const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket);
317 m_codaDevice->setDevice(codaSocket);
318 codaSocket->connectToHost(m_address, m_port);
319 setState(StateConnecting);
320 appendMessage(tr("Connecting to %1:%2...").arg(m_address).arg(m_port), false);
322 QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
325 void S60DeployStep::run(QFutureInterface<bool> &fi)
327 m_futureInterface = &fi;
328 m_deployResult = true;
329 m_deployCanceled = false;
332 m_futureInterface->setProgressRange(0, 100*m_signedPackages.count());
334 connect(this, SIGNAL(finished(bool)), this, SLOT(deploymentFinished(bool)));
335 connect(this, SIGNAL(finishNow(bool)), this, SLOT(deploymentFinished(bool)), Qt::DirectConnection);
336 connect(this, SIGNAL(allFilesSent()), this, SLOT(startInstalling()), Qt::DirectConnection);
337 connect(this, SIGNAL(allFilesInstalled()), this, SIGNAL(finished()), Qt::DirectConnection);
338 connect(this, SIGNAL(copyProgressChanged(int)), this, SLOT(updateProgress(int)));
341 m_timer = new QTimer();
342 connect(m_timer, SIGNAL(timeout()), this, SLOT(checkForCancel()), Qt::DirectConnection);
344 m_eventLoop = new QEventLoop();
351 disconnect(m_codaDevice.data(), 0, this, 0);
352 SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
357 fi.reportResult(m_deployResult);
358 m_futureInterface = 0;
361 void S60DeployStep::slotWaitingForCodaClosed(int result)
363 if (result == QMessageBox::Cancel)
364 m_deployCanceled = true;
367 void S60DeployStep::slotError(const QString &error)
369 reportError(tr("Error: %1").arg(error));
372 void S60DeployStep::slotCodaLogMessage(const QString &log)
375 qDebug() << "CODA log:" << log;
378 void S60DeployStep::slotSerialPong(const QString &message)
381 qDebug() << "CODA serial pong:" << message;
385 void S60DeployStep::slotCodaEvent(const Coda::CodaEvent &event)
388 qDebug() << "CODA event:" << "Type:" << event.type() << "Message:" << event.toString();
390 switch (event.type()) {
391 case Coda::CodaEvent::LocatorHello:
396 qDebug() << "Unhandled event:" << "Type:" << event.type() << "Message:" << event.toString();
401 void S60DeployStep::handleConnected()
403 if (state() >= StateConnected)
405 setState(StateConnected);
406 emit codaConnected();
410 void S60DeployStep::initFileSending()
412 QTC_ASSERT(m_currentFileIndex < m_signedPackages.count(), return);
413 QTC_ASSERT(m_currentFileIndex >= 0, return);
414 QTC_ASSERT(m_codaDevice, return);
416 const unsigned flags =
417 Coda::CodaDevice::FileSystem_TCF_O_WRITE
418 |Coda::CodaDevice::FileSystem_TCF_O_CREAT
419 |Coda::CodaDevice::FileSystem_TCF_O_TRUNC;
420 m_putWriteOk = false;
422 QString packageName(QFileInfo(m_signedPackages.at(m_currentFileIndex)).fileName());
423 QString remoteFileLocation = QString::fromLatin1("%1:\\Data\\%2").arg(m_installationDrive).arg(packageName);
424 m_codaDevice->sendFileSystemOpenCommand(Coda::CodaCallback(this, &S60DeployStep::handleFileSystemOpen),
425 remoteFileLocation.toAscii(), flags);
426 appendMessage(tr("Copying \"%1\"...").arg(packageName), false);
427 m_timeoutTimer->start();
430 void S60DeployStep::initFileInstallation()
432 QTC_ASSERT(m_currentFileIndex < m_signedPackages.count(), return);
433 QTC_ASSERT(m_currentFileIndex >= 0, return);
438 QString packageName(QFileInfo(m_signedPackages.at(m_currentFileIndex)).fileName());
439 QString remoteFileLocation = QString::fromLatin1("%1:\\Data\\%2").arg(m_installationDrive).arg(packageName);
440 if (m_silentInstall) {
441 m_codaDevice->sendSymbianInstallSilentInstallCommand(Coda::CodaCallback(this, &S60DeployStep::handleSymbianInstall),
442 remoteFileLocation.toAscii(), QString::fromLatin1("%1:").arg(m_installationDrive).toAscii());
443 appendMessage(tr("Installing package \"%1\" on drive %2:...").arg(packageName).arg(m_installationDrive), false);
445 m_codaDevice->sendSymbianInstallUIInstallCommand(Coda::CodaCallback(this, &S60DeployStep::handleSymbianInstall),
446 remoteFileLocation.toAscii());
447 appendMessage(tr("Please continue the installation on your device."), false);
448 emit manualInstallation();
452 void S60DeployStep::startTransferring()
454 m_currentFileIndex = 0;
456 setState(StateSendingData);
459 void S60DeployStep::startInstalling()
461 m_currentFileIndex = 0;
462 initFileInstallation();
463 setState(StateInstalling);
466 void S60DeployStep::handleFileSystemOpen(const Coda::CodaCommandResult &result)
468 if (result.type != Coda::CodaCommandResult::SuccessReply) {
469 reportError(tr("Could not open remote file: %1").arg(result.errorString()));
473 if (result.values.size() < 1 || result.values.at(0).data().isEmpty()) {
474 reportError(tr("Internal error: No filehandle obtained"));
478 m_remoteFileHandle = result.values.at(0).data();
480 const QString fileName = m_signedPackages.at(m_currentFileIndex);
481 m_putFile.reset(new QFile(fileName));
482 if (!m_putFile->open(QIODevice::ReadOnly)) { // Should not fail, was checked before
483 reportError(tr("Could not open local file %1: %2").arg(fileName, m_putFile->errorString()));
489 void S60DeployStep::handleSymbianInstall(const Coda::CodaCommandResult &result)
491 if (result.type == Coda::CodaCommandResult::SuccessReply) {
492 appendMessage(tr("Installation has finished"), false);
493 if (++m_currentFileIndex >= m_signedPackages.count()) {
494 setState(StateFinished);
495 emit allFilesInstalled();
497 initFileInstallation();
499 reportError(tr("Installation failed: %1; "
500 "see %2 for descriptions of the error codes")
501 .arg(result.errorString(),
502 QLatin1String("http://wiki.forum.nokia.com/index.php/Symbian_OS_Error_Codes")));
506 void S60DeployStep::putSendNextChunk()
510 QTC_ASSERT(m_putFile, return);
512 // Read and send off next chunk
513 const quint64 pos = m_putFile->pos();
514 const QByteArray data = m_putFile->read(m_putChunkSize);
515 const quint64 size = m_putFile->size();
516 if (data.isEmpty()) {
519 setCopyProgress(100);
521 m_putLastChunkSize = data.size();
523 qDebug("Writing %llu bytes to remote file '%s' at %llu\n",
525 m_remoteFileHandle.constData(), pos);
526 m_codaDevice->sendFileSystemWriteCommand(Coda::CodaCallback(this, &S60DeployStep::handleFileSystemWrite),
527 m_remoteFileHandle, data, unsigned(pos));
528 setCopyProgress((100*(m_putLastChunkSize+pos))/size);
529 m_timeoutTimer->start();
533 void S60DeployStep::closeFiles()
536 QTC_ASSERT(m_codaDevice, return);
538 emit addOutput(QLatin1String("\n"), ProjectExplorer::BuildStep::MessageOutput);
539 m_codaDevice->sendFileSystemCloseCommand(Coda::CodaCallback(this, &S60DeployStep::handleFileSystemClose),
543 void S60DeployStep::handleFileSystemWrite(const Coda::CodaCommandResult &result)
545 m_timeoutTimer->stop();
546 // Close remote file even if copy fails
547 m_putWriteOk = result;
549 QString packageName(QFileInfo(m_signedPackages.at(m_currentFileIndex)).fileName());
550 reportError(tr("Could not write to file %1 on device: %2").arg(packageName).arg(result.errorString()));
553 if (!m_putWriteOk || m_putLastChunkSize < m_putChunkSize) {
560 void S60DeployStep::handleFileSystemClose(const Coda::CodaCommandResult &result)
562 if (result.type == Coda::CodaCommandResult::SuccessReply) {
564 qDebug("File closed.\n");
565 if (++m_currentFileIndex >= m_signedPackages.count())
570 reportError(tr("Failed to close the remote file: %1").arg(result.toString()));
574 void S60DeployStep::checkForTimeout()
576 if (state() != StateConnecting)
578 QMessageBox *mb = CodaRunControl::createCodaWaitingMessageBox(Core::ICore::instance()->mainWindow());
579 connect(this, SIGNAL(codaConnected()), mb, SLOT(close()));
580 connect(this, SIGNAL(finished()), mb, SLOT(close()));
581 connect(this, SIGNAL(finishNow()), mb, SLOT(close()));
582 connect(mb, SIGNAL(finished(int)), this, SLOT(slotWaitingForCodaClosed(int)));
586 void S60DeployStep::showManualInstallationInfo()
588 const QString title = tr("Installation");
589 const QString text = tr("Please continue the installation on your device.");
590 QMessageBox *mb = new QMessageBox(QMessageBox::Information, title, text,
591 QMessageBox::Ok, Core::ICore::instance()->mainWindow());
592 connect(this, SIGNAL(allFilesInstalled()), mb, SLOT(close()));
593 connect(this, SIGNAL(finished()), mb, SLOT(close()));
594 connect(this, SIGNAL(finishNow()), mb, SLOT(close()));
598 void S60DeployStep::checkForCancel()
600 if ((m_futureInterface->isCanceled() || m_deployCanceled) && m_timer->isActive()) {
603 QString canceledText(tr("Deployment has been cancelled."));
604 appendMessage(canceledText, true);
605 emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error,
608 ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
609 emit finishNow(false);
613 void S60DeployStep::deploymentFinished(bool success)
615 m_deployResult = success;
616 if(m_deployResult && m_futureInterface)
617 m_futureInterface->setProgressValue(m_futureInterface->progressMaximum());
622 void S60DeployStep::deviceRemoved(const SymbianDevice &device)
624 if (device.portName() == m_serialPortName)
625 reportError(tr("The device '%1' has been disconnected").arg(device.friendlyName()));
628 void S60DeployStep::setCopyProgress(int progress)
632 else if (progress > 100)
634 if (copyProgress() == progress)
636 m_copyProgress = progress;
637 emit addOutput(QLatin1String("."), ProjectExplorer::BuildStep::MessageOutput, DontAppendNewline);
638 emit copyProgressChanged(m_copyProgress);
641 int S60DeployStep::copyProgress() const
643 return m_copyProgress;
646 void S60DeployStep::updateProgress(int progress)
648 //This would show the percentage on the Compile output
649 //appendMessage(tr("Copy percentage: %1%").arg((m_currentFileIndex*100 + progress) /m_signedPackages.count()), false);
650 int copyProgress = ((m_currentFileIndex*100 + progress) /m_signedPackages.count());
651 int entireProgress = copyProgress * 0.8; //the copy progress is just 80% of the whole deployment progress
652 m_futureInterface->setProgressValueAndText(entireProgress, tr("Copy progress: %1%").arg(copyProgress));
655 void S60DeployStep::timeout()
657 reportError(tr("A timeout while deploying has occurred. CODA might not be responding. Try reconnecting the device."));
660 // #pragma mark -- S60DeployStepWidget
662 BuildStepConfigWidget *S60DeployStep::createConfigWidget()
664 return new S60DeployStepWidget();
667 S60DeployStepWidget::S60DeployStepWidget() : ProjectExplorer::BuildStepConfigWidget()
671 QString S60DeployStepWidget::summaryText() const
673 return QString("<b>%1</b>").arg(displayName());
676 QString S60DeployStepWidget::displayName() const
678 return tr("Deploy SIS Package");
681 // #pragma mark -- S60DeployStepFactory
683 S60DeployStepFactory::S60DeployStepFactory(QObject *parent) :
684 ProjectExplorer::IBuildStepFactory(parent)
688 S60DeployStepFactory::~S60DeployStepFactory()
692 bool S60DeployStepFactory::canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const
694 if (parent->id() != QLatin1String(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY))
696 if (parent->target()->id() != QLatin1String(Constants::S60_DEVICE_TARGET_ID))
698 return (id == QLatin1String(S60_DEPLOY_STEP_ID));
701 ProjectExplorer::BuildStep *S60DeployStepFactory::create(ProjectExplorer::BuildStepList *parent, const QString &id)
703 if (!canCreate(parent, id))
705 return new S60DeployStep(parent);
708 bool S60DeployStepFactory::canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const
710 if (!canCreate(parent, source->id()))
712 if (!qobject_cast<S60DeployStep *>(source))
717 ProjectExplorer::BuildStep *S60DeployStepFactory::clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source)
719 if (!canClone(parent, source))
721 return new S60DeployStep(parent, static_cast<S60DeployStep *>(source));
724 bool S60DeployStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const
726 QString id(ProjectExplorer::idFromMap(map));
727 return canCreate(parent, id);
730 ProjectExplorer::BuildStep *S60DeployStepFactory::restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map)
732 if (!canRestore(parent, map))
734 S60DeployStep *bs = new S60DeployStep(parent);
735 if (bs->fromMap(map))
741 QStringList S60DeployStepFactory::availableCreationIds(ProjectExplorer::BuildStepList *parent) const
743 if (parent->id() == QLatin1String(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
744 && parent->target()->id() == QLatin1String(Constants::S60_DEVICE_TARGET_ID))
745 return QStringList() << QLatin1String(S60_DEPLOY_STEP_ID);
746 return QStringList();
749 QString S60DeployStepFactory::displayNameForId(const QString &id) const
751 if (id == QLatin1String(S60_DEPLOY_STEP_ID))
752 return tr("Deploy SIS Package");