OSDN Git Service

a2151e3154dc153431f28a47e146d6523a3b494a
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt-s60 / s60deploystep.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
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.
18 **
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.
22 **
23 ** Other Usage
24 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
30 **
31 **************************************************************************/
32
33 #include "s60deploystep.h"
34
35 #include "qt4buildconfiguration.h"
36 #include "s60deployconfiguration.h"
37 #include "s60devicerunconfiguration.h"
38 #include "codadevice.h"
39 #include "codaruncontrol.h"
40
41 #include <coreplugin/icore.h>
42 #include <projectexplorer/buildsteplist.h>
43 #include <projectexplorer/target.h>
44 #include <projectexplorer/projectexplorerconstants.h>
45 #include <qt4projectmanagerconstants.h>
46
47 #include <symbianutils/symbiandevicemanager.h>
48 #include <utils/qtcassert.h>
49
50 #include <QtGui/QMessageBox>
51 #include <QtGui/QMainWindow>
52
53 #include <QtCore/QTimer>
54 #include <QtCore/QDateTime>
55 #include <QtCore/QDir>
56 #include <QtCore/QEventLoop>
57 #include <QtCore/QFile>
58 #include <QtCore/QFileInfo>
59
60 #include <QtNetwork/QTcpSocket>
61
62 using namespace ProjectExplorer;
63 using namespace SymbianUtils;
64 using namespace Qt4ProjectManager::Internal;
65
66 enum { debug = 0 };
67
68 static const quint64  DEFAULT_CHUNK_SIZE = 40000;
69
70 namespace {
71 const char * const S60_DEPLOY_STEP_ID = "Qt4ProjectManager.S60DeployStep";
72 }
73
74 static inline bool ensureDeleteFile(const QString &fileName, QString *errorMessage)
75 {
76     QFile file(fileName);
77     if (file.exists() && !file.remove()) {
78         *errorMessage = S60DeployStep::tr("Unable to remove existing file '%1': %2").arg(fileName, file.errorString());
79         return false;
80     }
81     return true;
82 }
83
84 static inline bool renameFile(const QString &sourceName, const QString &targetName,
85                               QString *errorMessage)
86 {
87     if (sourceName == targetName)
88         return true;
89     if (!ensureDeleteFile(targetName, errorMessage))
90         return false;
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());
95         return false;
96     }
97     return true;
98 }
99
100 // #pragma mark -- S60DeployStep
101
102 S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc,
103                              S60DeployStep *bs):
104     BuildStep(bc, bs), m_timer(0),
105     m_timeoutTimer(new QTimer(this)),
106     m_eventLoop(0),
107     m_state(StateUninit),
108     m_putWriteOk(false),
109     m_putLastChunkSize(0),
110     m_putChunkSize(DEFAULT_CHUNK_SIZE),
111     m_currentFileIndex(0),
112     m_channel(bs->m_channel),
113     m_deployCanceled(false),
114     m_copyProgress(0)
115 {
116     ctor();
117 }
118
119 S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc):
120     BuildStep(bc, QLatin1String(S60_DEPLOY_STEP_ID)), m_timer(0),
121     m_timeoutTimer(new QTimer(this)),
122     m_eventLoop(0),
123     m_state(StateUninit),
124     m_putWriteOk(false),
125     m_putLastChunkSize(0),
126     m_putChunkSize(DEFAULT_CHUNK_SIZE),
127     m_currentFileIndex(0),
128     m_channel(S60DeployConfiguration::CommunicationCodaSerialConnection),
129     m_deployCanceled(false),
130     m_copyProgress(0)
131 {
132     ctor();
133 }
134
135 void S60DeployStep::ctor()
136 {
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()));
142 }
143
144 S60DeployStep::~S60DeployStep()
145 {
146     delete m_timer;
147     delete m_eventLoop;
148 }
149
150
151 bool S60DeployStep::init()
152 {
153     Qt4BuildConfiguration *bc = static_cast<Qt4BuildConfiguration *>(buildConfiguration());
154     S60DeployConfiguration *deployConfiguration = static_cast<S60DeployConfiguration *>(bc->target()->activeDeployConfiguration());
155     if (!deployConfiguration)
156         return false;
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();
164
165     if (m_signedPackages.isEmpty()) {
166         appendMessage(tr("No package has been found. Please specify at least one installation package."), true);
167         return false;
168     }
169
170     if (m_channel == S60DeployConfiguration::CommunicationCodaTcpConnection) {
171         m_address = deployConfiguration->deviceAddress();
172         m_port = deployConfiguration->devicePort().toInt();
173     }
174     return true;
175 }
176
177 QVariantMap S60DeployStep::toMap() const
178 {
179     return BuildStep::toMap();
180 }
181
182 bool S60DeployStep::fromMap(const QVariantMap &map)
183 {
184     return BuildStep::fromMap(map);
185 }
186
187 void S60DeployStep::appendMessage(const QString &error, bool isError)
188 {
189     emit addOutput(error, isError?ProjectExplorer::BuildStep::ErrorMessageOutput:
190                                   ProjectExplorer::BuildStep::MessageOutput);
191 }
192
193 void S60DeployStep::reportError(const QString &error)
194 {
195     emit addOutput(error, ProjectExplorer::BuildStep::ErrorMessageOutput);
196     emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error,
197                                        error,
198                                        QString(), -1,
199                                        ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
200     emit finished(false);
201 }
202
203 bool S60DeployStep::processPackageName(QString &errorMessage)
204 {
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);
218             } else {
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))),
222                               false);
223                 ensureDeleteFile(m_packageFileNamesWithTarget.at(i), &errorMessage);
224             }
225         }
226         if (!packageInfo.exists() || !packageInfo.isFile()) {
227             errorMessage = tr("'%1': Package file not found").arg(m_signedPackages.at(i));
228             return false;
229         }
230     }
231     return true;
232 }
233
234 void S60DeployStep::start()
235 {
236     QString errorMessage;
237
238     bool serialConnection = m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection;
239
240     if (serialConnection && m_serialPortName.isEmpty()) {
241         errorMessage = tr("No device is connected. Please connect a device and try again.");
242         reportError(errorMessage);
243         return;
244     }
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);
249         return;
250     }
251
252     // make sure we have the right name of the sis package
253     if (processPackageName(errorMessage))
254         startDeployment();
255     else {
256         errorMessage = tr("Failed to find package %1").arg(errorMessage);
257         reportError(errorMessage);
258         stop();
259     }
260 }
261
262 void S60DeployStep::stop()
263 {
264     if (m_codaDevice) {
265         switch (state()) {
266         case StateSendingData:
267             closeFiles();
268             break;
269         default:
270             break; //should also stop the package installation, but CODA does not support it yet
271         }
272         disconnect(m_codaDevice.data(), 0, this, 0);
273         SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
274     }
275     setState(StateUninit);
276     emit finished(false);
277 }
278
279 void S60DeployStep::setupConnections()
280 {
281     if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection)
282         connect(SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(SymbianDevice)), this, SLOT(deviceRemoved(SymbianDevice)));
283
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()));
289 }
290
291 void S60DeployStep::startDeployment()
292 {
293     QTC_ASSERT(!m_codaDevice.data(), return);
294
295     // We need to defer setupConnections() in the case of CommunicationCodaSerialConnection
296     //setupConnections();
297
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();
302         if (!ok) {
303             QString deviceError = tr("No such port");
304             if (m_codaDevice)
305                 deviceError = m_codaDevice->device()->errorString();
306             reportError(tr("Could not open serial device: %1").arg(deviceError));
307             stop();
308             return;
309         }
310         setupConnections();
311         setState(StateConnecting);
312         m_codaDevice->sendSerialPing(false);
313     } else {
314         m_codaDevice = QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice);
315         setupConnections();
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);
321     }
322     QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
323 }
324
325 void S60DeployStep::run(QFutureInterface<bool> &fi)
326 {
327     m_futureInterface = &fi;
328     m_deployResult = true;
329     m_deployCanceled = false;
330     disconnect(this);
331
332     m_futureInterface->setProgressRange(0, 100*m_signedPackages.count());
333
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)));
339
340     start();
341     m_timer = new QTimer();
342     connect(m_timer, SIGNAL(timeout()), this, SLOT(checkForCancel()), Qt::DirectConnection);
343     m_timer->start(500);
344     m_eventLoop = new QEventLoop();
345     m_eventLoop->exec();
346     m_timer->stop();
347     delete m_timer;
348     m_timer = 0;
349
350     if (m_codaDevice) {
351         disconnect(m_codaDevice.data(), 0, this, 0);
352         SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
353     }
354
355     delete m_eventLoop;
356     m_eventLoop = 0;
357     fi.reportResult(m_deployResult);
358     m_futureInterface = 0;
359 }
360
361 void S60DeployStep::slotWaitingForCodaClosed(int result)
362 {
363     if (result == QMessageBox::Cancel)
364         m_deployCanceled = true;
365 }
366
367 void S60DeployStep::slotError(const QString &error)
368 {
369     reportError(tr("Error: %1").arg(error));
370 }
371
372 void S60DeployStep::slotCodaLogMessage(const QString &log)
373 {
374     if (debug > 1)
375         qDebug() << "CODA log:" << log;
376 }
377
378 void S60DeployStep::slotSerialPong(const QString &message)
379 {
380     if (debug)
381         qDebug() << "CODA serial pong:" << message;
382     handleConnected();
383 }
384
385 void S60DeployStep::slotCodaEvent(const Coda::CodaEvent &event)
386 {
387     if (debug)
388         qDebug() << "CODA event:" << "Type:" << event.type() << "Message:" << event.toString();
389
390     switch (event.type()) {
391     case Coda::CodaEvent::LocatorHello:
392         handleConnected();
393         break;
394     default:
395         if (debug)
396             qDebug() << "Unhandled event:" << "Type:" << event.type() << "Message:" << event.toString();
397         break;
398     }
399 }
400
401 void S60DeployStep::handleConnected()
402 {
403     if (state() >= StateConnected)
404         return;
405     setState(StateConnected);
406     emit codaConnected();
407     startTransferring();
408 }
409
410 void S60DeployStep::initFileSending()
411 {
412     QTC_ASSERT(m_currentFileIndex < m_signedPackages.count(), return);
413     QTC_ASSERT(m_currentFileIndex >= 0, return);
414     QTC_ASSERT(m_codaDevice, return);
415
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;
421
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();
428 }
429
430 void S60DeployStep::initFileInstallation()
431 {
432     QTC_ASSERT(m_currentFileIndex < m_signedPackages.count(), return);
433     QTC_ASSERT(m_currentFileIndex >= 0, return);
434
435     if (!m_codaDevice)
436         return;
437
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);
444     } else {
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();
449     }
450 }
451
452 void S60DeployStep::startTransferring()
453 {
454     m_currentFileIndex = 0;
455     initFileSending();
456     setState(StateSendingData);
457 }
458
459 void S60DeployStep::startInstalling()
460 {
461     m_currentFileIndex = 0;
462     initFileInstallation();
463     setState(StateInstalling);
464 }
465
466 void S60DeployStep::handleFileSystemOpen(const Coda::CodaCommandResult &result)
467 {
468     if (result.type != Coda::CodaCommandResult::SuccessReply) {
469         reportError(tr("Could not open remote file: %1").arg(result.errorString()));
470         return;
471     }
472
473     if (result.values.size() < 1 || result.values.at(0).data().isEmpty()) {
474         reportError(tr("Internal error: No filehandle obtained"));
475         return;
476     }
477
478     m_remoteFileHandle = result.values.at(0).data();
479
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()));
484         return;
485     }
486     putSendNextChunk();
487 }
488
489 void S60DeployStep::handleSymbianInstall(const Coda::CodaCommandResult &result)
490 {
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();
496         } else
497             initFileInstallation();
498     } else {
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")));
503     }
504 }
505
506 void S60DeployStep::putSendNextChunk()
507 {
508     if (!m_codaDevice)
509         return;
510     QTC_ASSERT(m_putFile, return);
511
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()) {
517         m_putWriteOk = true;
518         closeFiles();
519         setCopyProgress(100);
520     } else {
521         m_putLastChunkSize = data.size();
522         if (debug > 1)
523             qDebug("Writing %llu bytes to remote file '%s' at %llu\n",
524                    m_putLastChunkSize,
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();
530     }
531 }
532
533 void S60DeployStep::closeFiles()
534 {
535     m_putFile.reset();
536     QTC_ASSERT(m_codaDevice, return);
537
538     emit addOutput(QLatin1String("\n"), ProjectExplorer::BuildStep::MessageOutput);
539     m_codaDevice->sendFileSystemCloseCommand(Coda::CodaCallback(this, &S60DeployStep::handleFileSystemClose),
540                                             m_remoteFileHandle);
541 }
542
543 void S60DeployStep::handleFileSystemWrite(const Coda::CodaCommandResult &result)
544 {
545     m_timeoutTimer->stop();
546     // Close remote file even if copy fails
547     m_putWriteOk = result;
548     if (!m_putWriteOk) {
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()));
551     }
552
553     if (!m_putWriteOk || m_putLastChunkSize < m_putChunkSize) {
554         closeFiles();
555     } else {
556         putSendNextChunk();
557     }
558 }
559
560 void S60DeployStep::handleFileSystemClose(const Coda::CodaCommandResult &result)
561 {
562     if (result.type == Coda::CodaCommandResult::SuccessReply) {
563         if (debug)
564             qDebug("File closed.\n");
565         if (++m_currentFileIndex >= m_signedPackages.count())
566             emit allFilesSent();
567         else
568             initFileSending();
569     } else {
570         reportError(tr("Failed to close the remote file: %1").arg(result.toString()));
571     }
572 }
573
574 void S60DeployStep::checkForTimeout()
575 {
576     if (state() != StateConnecting)
577         return;
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)));
583     mb->open();
584 }
585
586 void S60DeployStep::showManualInstallationInfo()
587 {
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()));
595     mb->open();
596 }
597
598 void S60DeployStep::checkForCancel()
599 {
600     if ((m_futureInterface->isCanceled() || m_deployCanceled) && m_timer->isActive()) {
601         m_timer->stop();
602         stop();
603         QString canceledText(tr("Deployment has been cancelled."));
604         appendMessage(canceledText, true);
605         emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error,
606                                            canceledText,
607                                            QString(), -1,
608                                            ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
609         emit finishNow(false);
610     }
611 }
612
613 void S60DeployStep::deploymentFinished(bool success)
614 {
615     m_deployResult = success;
616     if(m_deployResult && m_futureInterface)
617         m_futureInterface->setProgressValue(m_futureInterface->progressMaximum());
618     if (m_eventLoop)
619         m_eventLoop->exit();
620 }
621
622 void S60DeployStep::deviceRemoved(const SymbianDevice &device)
623 {
624     if (device.portName() == m_serialPortName)
625         reportError(tr("The device '%1' has been disconnected").arg(device.friendlyName()));
626 }
627
628 void S60DeployStep::setCopyProgress(int progress)
629 {
630     if (progress < 0)
631         progress = 0;
632     else if (progress > 100)
633         progress = 100;
634     if (copyProgress() == progress)
635         return;
636     m_copyProgress = progress;
637     emit addOutput(QLatin1String("."), ProjectExplorer::BuildStep::MessageOutput, DontAppendNewline);
638     emit copyProgressChanged(m_copyProgress);
639 }
640
641 int S60DeployStep::copyProgress() const
642 {
643     return m_copyProgress;
644 }
645
646 void S60DeployStep::updateProgress(int progress)
647 {
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));
653 }
654
655 void S60DeployStep::timeout()
656 {
657     reportError(tr("A timeout while deploying has occurred. CODA might not be responding. Try reconnecting the device."));
658 }
659
660 // #pragma mark -- S60DeployStepWidget
661
662 BuildStepConfigWidget *S60DeployStep::createConfigWidget()
663 {
664     return new S60DeployStepWidget();
665 }
666
667 S60DeployStepWidget::S60DeployStepWidget() : ProjectExplorer::BuildStepConfigWidget()
668 {
669 }
670
671 QString S60DeployStepWidget::summaryText() const
672 {
673     return QString("<b>%1</b>").arg(displayName());
674 }
675
676 QString S60DeployStepWidget::displayName() const
677 {
678     return tr("Deploy SIS Package");
679 }
680
681 // #pragma mark -- S60DeployStepFactory
682
683 S60DeployStepFactory::S60DeployStepFactory(QObject *parent) :
684     ProjectExplorer::IBuildStepFactory(parent)
685 {
686 }
687
688 S60DeployStepFactory::~S60DeployStepFactory()
689 {
690 }
691
692 bool S60DeployStepFactory::canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const
693 {
694     if (parent->id() != QLatin1String(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY))
695         return false;
696     if (parent->target()->id() != QLatin1String(Constants::S60_DEVICE_TARGET_ID))
697         return false;
698     return (id == QLatin1String(S60_DEPLOY_STEP_ID));
699 }
700
701 ProjectExplorer::BuildStep *S60DeployStepFactory::create(ProjectExplorer::BuildStepList *parent, const QString &id)
702 {
703     if (!canCreate(parent, id))
704         return 0;
705     return new S60DeployStep(parent);
706 }
707
708 bool S60DeployStepFactory::canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const
709 {
710     if (!canCreate(parent, source->id()))
711         return false;
712     if (!qobject_cast<S60DeployStep *>(source))
713         return false;
714     return true;
715 }
716
717 ProjectExplorer::BuildStep *S60DeployStepFactory::clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source)
718 {
719     if (!canClone(parent, source))
720         return 0;
721     return new S60DeployStep(parent, static_cast<S60DeployStep *>(source));
722 }
723
724 bool S60DeployStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const
725 {
726     QString id(ProjectExplorer::idFromMap(map));
727     return canCreate(parent, id);
728 }
729
730 ProjectExplorer::BuildStep *S60DeployStepFactory::restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map)
731 {
732     if (!canRestore(parent, map))
733         return 0;
734     S60DeployStep *bs = new S60DeployStep(parent);
735     if (bs->fromMap(map))
736         return bs;
737     delete bs;
738     return 0;
739 }
740
741 QStringList S60DeployStepFactory::availableCreationIds(ProjectExplorer::BuildStepList *parent) const
742 {
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();
747 }
748
749 QString S60DeployStepFactory::displayNameForId(const QString &id) const
750 {
751     if (id == QLatin1String(S60_DEPLOY_STEP_ID))
752         return tr("Deploy SIS Package");
753     return QString();
754 }