s60devicerunconfiguration.cpp 42.4 KB
Newer Older
con's avatar
con committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**************************************************************************
**
** 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
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
28
29
**
**************************************************************************/

30
#include "s60devicerunconfiguration.h"
31
#include "s60devicerunconfigurationwidget.h"
32
#include "qt4project.h"
Tobias Hunger's avatar
Tobias Hunger committed
33
#include "qt4target.h"
34
35
36
37
#include "qtversionmanager.h"
#include "profilereader.h"
#include "s60manager.h"
#include "s60devices.h"
38
39
#include "s60runconfigbluetoothstarter.h"
#include "bluetoothlistener_gui.h"
40
#include "symbiandevicemanager.h"
41
#include "qt4buildconfiguration.h"
42
43
44

#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
45
#include <coreplugin/progressmanager/progressmanager.h>
46
#include <utils/qtcassert.h>
con's avatar
con committed
47
#include <utils/pathchooser.h>
48
49
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
con's avatar
con committed
50
#include <projectexplorer/buildconfiguration.h>
51

52
53
#include <debugger/debuggermanager.h>

54
55
56
#include <QtGui/QMessageBox>
#include <QtGui/QMainWindow>

57
using namespace ProjectExplorer;
dt's avatar
dt committed
58
using namespace Qt4ProjectManager;
59
60
using namespace Qt4ProjectManager::Internal;

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
namespace {
const char * const S60_DEVICE_RC_ID("Qt4ProjectManager.S60DeviceRunConfiguration");
const char * const S60_DEVICE_RC_PREFIX("Qt4ProjectManager.S60DeviceRunConfiguration.");

const char * const PRO_FILE_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.ProFile");
const char * const SIGNING_MODE_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.SigningMode");
const char * const CUSTOM_SIGNATURE_PATH_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.CustomSignaturePath");
const char * const CUSTOM_KEY_PATH_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.CustomKeyPath");
const char * const SERIAL_PORT_NAME_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.SerialPortName");
const char * const COMMUNICATION_TYPE_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.CommunicationType");
const char * const COMMAND_LINE_ARGUMENTS_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.CommandLineArguments");

const int    PROGRESS_PACKAGECREATED = 100;
const int    PROGRESS_PACKAGESIGNED = 200;
const int    PROGRESS_DEPLOYBASE = 200;
const int    PROGRESS_PACKAGEDEPLOYED = 300;
const int    PROGRESS_PACKAGEINSTALLED = 400;
const int    PROGRESS_MAX = 400;

80
enum { debug = 0 };
81

82
// Format information about a file
83
QString lsFile(const QString &f)
84
85
86
87
88
89
90
{
    QString rc;
    const QFileInfo fi(f);
    QTextStream str(&rc);
    str << fi.size() << ' ' << fi.lastModified().toString(Qt::ISODate) << ' ' << QDir::toNativeSeparators(fi.absoluteFilePath());
    return rc;
}
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

QString pathFromId(const QString &id)
{
    if (!id.startsWith(QLatin1String(S60_DEVICE_RC_PREFIX)))
        return QString();
    return id.mid(QString::fromLatin1(S60_DEVICE_RC_PREFIX).size());
}

QString pathToId(const QString &path)
{
    return QString::fromLatin1(S60_DEVICE_RC_PREFIX) + path;
}

}

107
// ======== S60DeviceRunConfiguration
108

Tobias Hunger's avatar
Tobias Hunger committed
109
110
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QString &proFilePath) :
    RunConfiguration(parent,  QLatin1String(S60_DEVICE_RC_ID)),
111
    m_proFilePath(proFilePath),
con's avatar
con committed
112
    m_cachedTargetInformationValid(false),
113
114
115
#ifdef Q_OS_WIN
    m_serialPortName(QLatin1String("COM5")),
#else
116
    m_serialPortName(QLatin1String(SymbianUtils::SymbianDeviceManager::linuxBlueToothDeviceRootC) + QLatin1Char('0')),
117
#endif
con's avatar
con committed
118
    m_signingMode(SignSelf)
119
120
121
122
{
    ctor();
}

Tobias Hunger's avatar
Tobias Hunger committed
123
124
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRunConfiguration *source) :
    RunConfiguration(target, source),
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
    m_proFilePath(source->m_proFilePath),
    m_cachedTargetInformationValid(false),
    m_serialPortName(source->m_serialPortName),
    m_signingMode(source->m_signingMode),
    m_customSignaturePath(source->m_customSignaturePath),
    m_customKeyPath(source->m_customKeyPath)
{
    ctor();
}

void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro)
{
    if (m_proFilePath == pro->path())
        invalidateCachedTargetInformation();
}

void S60DeviceRunConfiguration::ctor()
142
143
{
    if (!m_proFilePath.isEmpty())
144
        setDisplayName(tr("%1 on Symbian Device").arg(QFileInfo(m_proFilePath).completeBaseName()));
145
    else
146
        setDisplayName(tr("QtS60DeviceRunConfiguration"));
147

Tobias Hunger's avatar
Tobias Hunger committed
148
    connect(target(), SIGNAL(targetInformationChanged()),
149
            this, SLOT(invalidateCachedTargetInformation()));
150

Tobias Hunger's avatar
Tobias Hunger committed
151
    connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)),
152
            this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*)));
153
154
}

155

156
157
158
159
S60DeviceRunConfiguration::~S60DeviceRunConfiguration()
{
}

Tobias Hunger's avatar
Tobias Hunger committed
160
Qt4Target *S60DeviceRunConfiguration::qt4Target() const
dt's avatar
dt committed
161
{
Tobias Hunger's avatar
Tobias Hunger committed
162
    return static_cast<Qt4Target *>(target());
dt's avatar
dt committed
163
164
}

165
166
167
ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainType(
        ProjectExplorer::BuildConfiguration *configuration) const
{
168
169
    if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(configuration))
        return bc->toolChainType();
170
171
172
    return ProjectExplorer::ToolChain::INVALID;
}

173
174
ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainType() const
{
Tobias Hunger's avatar
Tobias Hunger committed
175
    if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(target()->activeBuildConfiguration()))
176
        return bc->toolChainType();
177
    return ProjectExplorer::ToolChain::INVALID;
178
179
}

180
bool S60DeviceRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *configuration) const
181
{
182
183
184
185
186
187
188
189
190
191
192
193
    const Qt4BuildConfiguration *qt4bc = static_cast<const Qt4BuildConfiguration *>(configuration);
    switch (qt4bc->toolChainType()) {
    case ToolChain::GCCE:
    case ToolChain::RVCT_ARMV5:
    case ToolChain::RVCT_ARMV6:
    case ToolChain::GCCE_GNUPOC:
    case ToolChain::RVCT_ARMV5_GNUPOC:
        return true;
    default:
        break;
    }
    return false;
194
195
196
197
198
199
200
}

QWidget *S60DeviceRunConfiguration::configurationWidget()
{
    return new S60DeviceRunConfigurationWidget(this);
}

201
QVariantMap S60DeviceRunConfiguration::toMap() const
202
{
203
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());
Tobias Hunger's avatar
Tobias Hunger committed
204
    const QDir projectDir = QFileInfo(target()->project()->file()->fileName()).absoluteDir();
205
206
207
208
209
210
211
212
213

    map.insert(QLatin1String(PRO_FILE_KEY), projectDir.relativeFilePath(m_proFilePath));
    map.insert(QLatin1String(SIGNING_MODE_KEY), (int)m_signingMode);
    map.insert(QLatin1String(CUSTOM_SIGNATURE_PATH_KEY), m_customSignaturePath);
    map.insert(QLatin1String(CUSTOM_KEY_PATH_KEY), m_customKeyPath);
    map.insert(QLatin1String(SERIAL_PORT_NAME_KEY), m_serialPortName);
    map.insert(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY), m_commandLineArguments);

    return map;
214
215
}

216
bool S60DeviceRunConfiguration::fromMap(const QVariantMap &map)
217
{
Tobias Hunger's avatar
Tobias Hunger committed
218
    const QDir projectDir = QFileInfo(target()->project()->file()->fileName()).absoluteDir();
219
220
221
222
223
224
225
226
227

    m_proFilePath = projectDir.filePath(map.value(QLatin1String(PRO_FILE_KEY)).toString());
    m_signingMode = static_cast<SigningMode>(map.value(QLatin1String(SIGNING_MODE_KEY)).toInt());
    m_customSignaturePath = map.value(QLatin1String(CUSTOM_SIGNATURE_PATH_KEY)).toString();
    m_customKeyPath = map.value(QLatin1String(CUSTOM_KEY_PATH_KEY)).toString();
    m_serialPortName = map.value(QLatin1String(SERIAL_PORT_NAME_KEY)).toString().trimmed();
    m_commandLineArguments = map.value(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY)).toStringList();

    return RunConfiguration::fromMap(map);
con's avatar
con committed
228
229
230
231
232
233
234
235
236
}

QString S60DeviceRunConfiguration::serialPortName() const
{
    return m_serialPortName;
}

void S60DeviceRunConfiguration::setSerialPortName(const QString &name)
{
con's avatar
con committed
237
238
239
240
241
    const QString &candidate = name.trimmed();
    if (m_serialPortName == candidate)
        return;
    m_serialPortName = candidate;
    emit serialPortNameChanged();
242
243
}

244
245
246
247
248
249
QString S60DeviceRunConfiguration::targetName() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return m_targetName;
}

con's avatar
con committed
250
QString S60DeviceRunConfiguration::basePackageFilePath() const
251
252
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
con's avatar
con committed
253
    return m_baseFileName;
254
255
}

256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
QString S60DeviceRunConfiguration::symbianPlatform() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return m_platform;
}

QString S60DeviceRunConfiguration::symbianTarget() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return m_target;
}

QString S60DeviceRunConfiguration::packageTemplateFileName() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return m_packageTemplateFileName;
}

con's avatar
con committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
S60DeviceRunConfiguration::SigningMode S60DeviceRunConfiguration::signingMode() const
{
    return m_signingMode;
}

void S60DeviceRunConfiguration::setSigningMode(SigningMode mode)
{
    m_signingMode = mode;
}

QString S60DeviceRunConfiguration::customSignaturePath() const
{
    return m_customSignaturePath;
}

void S60DeviceRunConfiguration::setCustomSignaturePath(const QString &path)
{
    m_customSignaturePath = path;
}

QString S60DeviceRunConfiguration::customKeyPath() const
{
    return m_customKeyPath;
}

void S60DeviceRunConfiguration::setCustomKeyPath(const QString &path)
{
    m_customKeyPath = path;
}

304
305
306
307
308
309
310
311
QString S60DeviceRunConfiguration::packageFileName() const
{
    QString rc = basePackageFilePath();
    if (!rc.isEmpty())
        rc += QLatin1String(".pkg");
    return rc;
}

312
313
314
315
316
317
318
319
/* Grep a package file for the '.exe' file. Curently for use on Linux only
 * as the '.pkg'-files on Windows do not contain drive letters, which is not
 * handled here. \code
; Executable and default resource files
"./foo.exe"    - "!:\sys\bin\foo.exe"
\endcode  */

static inline QString executableFromPackageUnix(const QString &packageFileName)
320
{
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
    QFile packageFile(packageFileName);
    if (!packageFile.open(QIODevice::ReadOnly|QIODevice::Text))
        return QString();
    QRegExp pattern(QLatin1String("^\"(.*.exe)\" *- \"!:.*.exe\"$"));
    QTC_ASSERT(pattern.isValid(), return QString());
    foreach(const QString &line, QString::fromLocal8Bit(packageFile.readAll()).split(QLatin1Char('\n')))
        if (pattern.exactMatch(line)) {
            // Expand relative paths by package file paths
            QString rc = pattern.cap(1);
            if (rc.startsWith(QLatin1String("./")))
                rc.remove(0, 2);
            const QFileInfo fi(rc);
            if (fi.isAbsolute())
                return rc;
            return QFileInfo(packageFileName).absolutePath() + QLatin1Char('/') + rc;
        }
    return QString();
}
339

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
QString S60DeviceRunConfiguration::localExecutableFileName() const
{
    QString localExecutable;
    switch (toolChainType()) {
    case ToolChain::GCCE_GNUPOC:
    case ToolChain::RVCT_ARMV5_GNUPOC:
        localExecutable = executableFromPackageUnix(packageTemplateFileName());
        break;
    default: {
            const Qt4BuildConfiguration *qt4bc = qobject_cast<Qt4BuildConfiguration *>(target()->activeBuildConfiguration());
            const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(qt4bc->qtVersion());
            QTextStream(&localExecutable) << device.epocRoot << "/epoc32/release/"
                    << symbianPlatform() << '/' << symbianTarget() << '/' << targetName()
                    << ".exe";
        }
        break;
    }
    if (debug)
        qDebug() << "Local executable" << localExecutable;
359
    return QDir::toNativeSeparators(localExecutable);
360
361
}

362
363
364
365
366
367
368
369
370
371
372
373
QString S60DeviceRunConfiguration::unsignedPackage() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return QDir::toNativeSeparators(m_baseFileName + QLatin1String("_unsigned.sis"));
}

QString S60DeviceRunConfiguration::signedPackage() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return QDir::toNativeSeparators(m_baseFileName + QLatin1String(".sis"));
}

374
375
376
377
378
379
380
381
382
383
QStringList S60DeviceRunConfiguration::commandLineArguments() const
{
    return m_commandLineArguments;
}

void S60DeviceRunConfiguration::setCommandLineArguments(const QStringList &args)
{
    m_commandLineArguments = args;
}

384
385
386
387
void S60DeviceRunConfiguration::updateTarget()
{
    if (m_cachedTargetInformationValid)
        return;
Tobias Hunger's avatar
Tobias Hunger committed
388
    Qt4TargetInformation info = qt4Target()->targetInformation(qt4Target()->activeBuildConfiguration(),
389
390
391
392
                                                                m_proFilePath);
    if (info.error != Qt4TargetInformation::NoError) {
        if (info.error == Qt4TargetInformation::ProParserError) {
            Core::ICore::instance()->messageManager()->printToOutputPane(
393
                    tr("Could not parse %1. The Qt Symbian Device run configuration %2 can not be started.")
394
                    .arg(m_proFilePath).arg(displayName()));
395
        }
396
397
398
399
        m_targetName.clear();
        m_baseFileName.clear();
        m_packageTemplateFileName.clear();
        m_platform.clear();
400
401
402
403
        m_cachedTargetInformationValid = true;
        emit targetInformationChanged();
        return;
    }
404

405
    m_targetName = info.target;
dt's avatar
dt committed
406

407
    m_baseFileName = info.workingDir + QLatin1Char('/') + m_targetName;
408
    m_packageTemplateFileName = m_baseFileName + QLatin1String("_template.pkg");
409

Tobias Hunger's avatar
Tobias Hunger committed
410
    Qt4BuildConfiguration *qt4bc = qt4Target()->activeBuildConfiguration();
411
    switch (qt4bc->toolChainType()) {
412
413
    case ToolChain::GCCE:
    case ToolChain::GCCE_GNUPOC:
414
        m_platform = QLatin1String("gcce");
415
416
        break;
    case ToolChain::RVCT_ARMV5:
417
    case ToolChain::RVCT_ARMV5_GNUPOC:
418
        m_platform = QLatin1String("armv5");
419
        break;
420
    default:
421
        m_platform = QLatin1String("armv6");
422
423
        break;
    }
424
    if (qt4bc->qmakeBuildConfiguration() & QtVersion::DebugBuild)
425
        m_target = QLatin1String("udeb");
con's avatar
con committed
426
    else
427
428
        m_target = QLatin1String("urel");
    m_baseFileName += QLatin1Char('_') + m_platform + QLatin1Char('_') + m_target;
429

430
431
432
433
434
435
436
437
438
439
    m_cachedTargetInformationValid = true;
    emit targetInformationChanged();
}

void S60DeviceRunConfiguration::invalidateCachedTargetInformation()
{
    m_cachedTargetInformationValid = false;
    emit targetInformationChanged();
}

con's avatar
con committed
440

441
442
// ======== S60DeviceRunConfigurationFactory

443
444
S60DeviceRunConfigurationFactory::S60DeviceRunConfigurationFactory(QObject *parent) :
    IRunConfigurationFactory(parent)
445
446
447
448
449
450
451
{
}

S60DeviceRunConfigurationFactory::~S60DeviceRunConfigurationFactory()
{
}

Tobias Hunger's avatar
Tobias Hunger committed
452
QStringList S60DeviceRunConfigurationFactory::availableCreationIds(Target *parent) const
453
{
Tobias Hunger's avatar
Tobias Hunger committed
454
455
456
    Qt4Target *target = qobject_cast<Qt4Target *>(parent);
    if (!target ||
        target->id() != QLatin1String(S60_DEVICE_TARGET_ID))
457
458
        return QStringList();

Tobias Hunger's avatar
Tobias Hunger committed
459
    return target->qt4Project()->applicationProFilePathes(QLatin1String(S60_DEVICE_RC_PREFIX));
460
461
}

462
QString S60DeviceRunConfigurationFactory::displayNameForId(const QString &id) const
463
{
464
465
466
    if (!pathFromId(id).isEmpty())
        return tr("%1 on Symbian Device").arg(QFileInfo(pathFromId(id)).completeBaseName());
    return QString();
467
468
}

Tobias Hunger's avatar
Tobias Hunger committed
469
bool S60DeviceRunConfigurationFactory::canCreate(Target *parent, const QString &id) const
470
{
Tobias Hunger's avatar
Tobias Hunger committed
471
472
473
    Qt4Target * t(qobject_cast<Qt4Target *>(parent));
    if (!t ||
        t->id() != QLatin1String(S60_DEVICE_TARGET_ID))
474
        return false;
Tobias Hunger's avatar
Tobias Hunger committed
475
    return t->qt4Project()->hasApplicationProFile(pathFromId(id));
476
477
}

Tobias Hunger's avatar
Tobias Hunger committed
478
RunConfiguration *S60DeviceRunConfigurationFactory::create(Target *parent, const QString &id)
479
{
480
481
482
    if (!canCreate(parent, id))
        return 0;

Tobias Hunger's avatar
Tobias Hunger committed
483
484
    Qt4Target *t(static_cast<Qt4Target *>(parent));
    return new S60DeviceRunConfiguration(t, pathFromId(id));
485
486
}

Tobias Hunger's avatar
Tobias Hunger committed
487
bool S60DeviceRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
488
{
Tobias Hunger's avatar
Tobias Hunger committed
489
490
491
    Qt4Target * t(qobject_cast<Qt4Target *>(parent));
    if (!t ||
        t->id() != QLatin1String(S60_DEVICE_TARGET_ID))
492
493
494
495
496
        return false;
    QString id(ProjectExplorer::idFromMap(map));
    return id == QLatin1String(S60_DEVICE_RC_ID);
}

Tobias Hunger's avatar
Tobias Hunger committed
497
RunConfiguration *S60DeviceRunConfigurationFactory::restore(Target *parent, const QVariantMap &map)
498
499
500
{
    if (!canRestore(parent, map))
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
501
502
    Qt4Target *t(static_cast<Qt4Target *>(parent));
    S60DeviceRunConfiguration *rc(new S60DeviceRunConfiguration(t, QString()));
503
504
505
506
507
508
509
    if (rc->fromMap(map))
        return rc;

    delete rc;
    return 0;
}

Tobias Hunger's avatar
Tobias Hunger committed
510
bool S60DeviceRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const
511
{
Tobias Hunger's avatar
Tobias Hunger committed
512
    if (!qobject_cast<Qt4Target *>(parent))
513
514
515
516
        return false;
    return source->id() == QLatin1String(S60_DEVICE_RC_ID);
}

Tobias Hunger's avatar
Tobias Hunger committed
517
RunConfiguration *S60DeviceRunConfigurationFactory::clone(Target *parent, RunConfiguration *source)
518
519
520
{
    if (!canClone(parent, source))
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
521
    Qt4Target *t = static_cast<Qt4Target *>(parent);
522
    S60DeviceRunConfiguration * old(static_cast<S60DeviceRunConfiguration *>(source));
Tobias Hunger's avatar
Tobias Hunger committed
523
    return new S60DeviceRunConfiguration(t, old);
524
525
}

526
// ======== S60DeviceRunControlBase
Friedemann Kleint's avatar
Friedemann Kleint committed
527

528
S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration) :
529
    RunControl(runConfiguration),
530
    m_toolChain(ProjectExplorer::ToolChain::INVALID),
531
532
    m_makesisProcess(new QProcess(this)),
    m_signsisProcess(0),
533
534
    m_releaseDeviceAfterLauncherFinish(false),
    m_handleDeviceRemoval(true),
535
    m_launcher(0)
536
537
538
539
{
    // connect for automatically reporting the "finished deploy" state to the progress manager
    connect(this, SIGNAL(finished()), this, SLOT(reportDeployFinished()));

540
    connect(m_makesisProcess, SIGNAL(readyReadStandardError()),
con's avatar
con committed
541
            this, SLOT(readStandardError()));
542
    connect(m_makesisProcess, SIGNAL(readyReadStandardOutput()),
con's avatar
con committed
543
            this, SLOT(readStandardOutput()));
544
    connect(m_makesisProcess, SIGNAL(error(QProcess::ProcessError)),
con's avatar
con committed
545
            this, SLOT(makesisProcessFailed()));
546
    connect(m_makesisProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
con's avatar
con committed
547
            this, SLOT(makesisProcessFinished()));
548

549
    S60DeviceRunConfiguration *s60runConfig = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
dt's avatar
dt committed
550

Tobias Hunger's avatar
Tobias Hunger committed
551
    Qt4BuildConfiguration *activeBuildConf = s60runConfig->qt4Target()->activeBuildConfiguration();
dt's avatar
dt committed
552

553
    QTC_ASSERT(s60runConfig, return);
554
    m_toolChain = s60runConfig->toolChainType();
555
    m_serialPortName = s60runConfig->serialPortName();
556
    m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
557
558
    m_targetName = s60runConfig->targetName();
    m_baseFileName = s60runConfig->basePackageFilePath();
559
560
    m_unsignedPackage = s60runConfig->unsignedPackage();
    m_signedPackage = s60runConfig->signedPackage();
561
    m_commandLineArguments = s60runConfig->commandLineArguments();
562
563
564
    m_symbianPlatform = s60runConfig->symbianPlatform();
    m_symbianTarget = s60runConfig->symbianTarget();
    m_packageTemplateFile = s60runConfig->packageTemplateFileName();
con's avatar
con committed
565
    m_workingDirectory = QFileInfo(m_baseFileName).absolutePath();
566
    m_qtDir = activeBuildConf->qtVersion()->versionInfo().value("QT_INSTALL_DATA");
567
568
569
    m_useCustomSignature = (s60runConfig->signingMode() == S60DeviceRunConfiguration::SignCustom);
    m_customSignaturePath = s60runConfig->customSignaturePath();
    m_customKeyPath = s60runConfig->customKeyPath();
570

571
    const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(activeBuildConf->qtVersion());
572
573
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
574
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: {
575
            // 'sis' is a make target here. Set up with correct environment
576
            ProjectExplorer::ToolChain *toolchain = activeBuildConf->toolChain();
577
578
579
580
            m_makesisTool = toolchain->makeCommand();
            m_toolsDirectory = device.epocRoot + QLatin1String("/epoc32/tools");
            ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
            toolchain->addToEnvironment(env);
581
            m_makesisProcess->setEnvironment(env.toStringList());
582
583
        }
        break;
584
585
    default:
        m_toolsDirectory = device.toolsRoot + QLatin1String("/epoc32/tools");
586
587
        m_makesisTool = m_toolsDirectory + "/makesis.exe";
        // Set up signing packages
588
589
        m_signsisProcess = new QProcess(this);
        connect(m_signsisProcess, SIGNAL(readyReadStandardError()),
590
                this, SLOT(readStandardError()));
591
        connect(m_signsisProcess, SIGNAL(readyReadStandardOutput()),
592
                this, SLOT(readStandardOutput()));
593
        connect(m_signsisProcess, SIGNAL(error(QProcess::ProcessError)),
594
                this, SLOT(signsisProcessFailed()));
595
        connect(m_signsisProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
596
597
598
599
                this, SLOT(signsisProcessFinished()));
        break;
    }
    m_executableFileName = s60runConfig->localExecutableFileName();
600
601
    m_packageFilePath = s60runConfig->packageFileName();
    m_packageFile = QFileInfo(m_packageFilePath).fileName();
602
    if (debug)
603
        qDebug() << "S60DeviceRunControlBase::CT" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
604
                 << m_serialPortName << m_workingDirectory;
605
}
606

607
608
609
610
611
612
613
614
S60DeviceRunControlBase::~S60DeviceRunControlBase()
{
    if (m_launcher) {
        m_launcher->deleteLater();
        m_launcher = 0;
    }
}

615
616
617
618
619
void S60DeviceRunControlBase::setReleaseDeviceAfterLauncherFinish(bool v)
{
    m_releaseDeviceAfterLauncherFinish = v;
}

620
621
622
623
624
625
626
// Format a message with command line
static inline QString msgRun(const QString &cmd, const QStringList &args)
{
    const QChar blank = QLatin1Char(' ');
    return QDir::toNativeSeparators(cmd) + blank + args.join(QString(blank));
}

627
void S60DeviceRunControlBase::start()
628
{
629
630
631
632
633
634
635
    m_deployProgress = new QFutureInterface<void>;
    Core::ICore::instance()->progressManager()->addTask(m_deployProgress->future(),
                                                        tr("Deploying"),
                                                        QLatin1String("Symbian.Deploy"));
    m_deployProgress->setProgressRange(0, PROGRESS_MAX);
    m_deployProgress->setProgressValue(0);
    m_deployProgress->reportStarted();
636
    emit started();
637
638
639
640
641
    if (m_serialPortName.isEmpty()) {
        error(this, tr("There is no device plugged in."));
        emit finished();
        return;
    }
642

643
    emit addToOutputWindow(this, tr("Creating %1 ...").arg(m_signedPackage));
644
    emit addToOutputWindow(this, tr("Executable file: %1").arg(lsFile(m_executableFileName)));
con's avatar
con committed
645

646
647
648
649
650
651
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
    if (!checkConfiguration(&errorMessage, &settingsCategory, &settingsPage)) {
        error(this, errorMessage);
        emit finished();
652
653
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger for Symbian Platform"),
                                                        errorMessage, QString(),
654
655
656
657
                                                        settingsCategory, settingsPage);
        return;
    }

658
659
660
661
662
663
    if (!createPackageFileFromTemplate(&errorMessage)) {
        error(this, errorMessage);
        emit finished();
        return;
    }

664
665
666
    QStringList makeSisArgs;
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
667
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
668
669
670
671
        makeSisArgs << QLatin1String("sis")
                    << QLatin1String("QT_SIS_OPTIONS=-i")
                    << (QLatin1String("QT_SIS_CERTIFICATE=") + signSisCertificate())
                    << (QLatin1String("QT_SIS_KEY=") + signSisKey());
672
673
674
675
        break;
    default:
        makeSisArgs.push_back(m_packageFile);
        break;
676
    }
677
    m_makesisProcess->setWorkingDirectory(m_workingDirectory);
678
    emit addToOutputWindow(this, msgRun(m_makesisTool, makeSisArgs));
679
680
    if (debug)
        qDebug() << m_makesisTool <<  makeSisArgs << m_workingDirectory;
681
    m_makesisProcess->start(m_makesisTool, makeSisArgs, QIODevice::ReadOnly);
682
683
}

684
685
686
687
688
689
690
691
692
693
694
static inline void stopProcess(QProcess *p)
{
    const int timeOutMS = 200;
    if (p->state() != QProcess::Running)
        return;
    p->terminate();
    if (p->waitForFinished(timeOutMS))
        return;
    p->kill();
}

695
void S60DeviceRunControlBase::stop()
696
{
697
698
699
700
    if (m_makesisProcess)
        stopProcess(m_makesisProcess);
    if (m_signsisProcess)
        stopProcess(m_signsisProcess);
701
702
    if (m_launcher)
        m_launcher->terminate();
703
704
}

705
bool S60DeviceRunControlBase::isRunning() const
706
{
707
    return m_makesisProcess->state() != QProcess::NotRunning;
708
709
}

710
void S60DeviceRunControlBase::readStandardError()
711
{
con's avatar
con committed
712
713
714
    QProcess *process = static_cast<QProcess *>(sender());
    QByteArray data = process->readAllStandardError();
    emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
715
716
}

717
void S60DeviceRunControlBase::readStandardOutput()
718
{
con's avatar
con committed
719
720
721
722
723
    QProcess *process = static_cast<QProcess *>(sender());
    QByteArray data = process->readAllStandardOutput();
    emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
}

724
bool S60DeviceRunControlBase::createPackageFileFromTemplate(QString *errorMessage)
725
{
726
727
728
    if (debug)
        qDebug() << "Creating package file" << m_packageFilePath << " from " << m_packageTemplateFile
                << m_symbianPlatform << m_symbianTarget;
729
730
    QFile packageTemplate(m_packageTemplateFile);
    if (!packageTemplate.open(QIODevice::ReadOnly)) {
731
        *errorMessage = tr("Could not read template package file '%1'").arg(QDir::toNativeSeparators(m_packageTemplateFile));
732
733
734
735
736
737
738
739
        return false;
    }
    QString contents = packageTemplate.readAll();
    packageTemplate.close();
    contents.replace(QLatin1String("$(PLATFORM)"), m_symbianPlatform);
    contents.replace(QLatin1String("$(TARGET)"), m_symbianTarget);
    QFile packageFile(m_packageFilePath);
    if (!packageFile.open(QIODevice::WriteOnly)) {
740
        *errorMessage = tr("Could not write package file '%1'").arg(QDir::toNativeSeparators(m_packageFilePath));
741
742
743
744
        return false;
    }
    packageFile.write(contents.toLocal8Bit());
    packageFile.close();
745
746
    if (debug > 1)
        qDebug() << contents;
747
748
749
    return true;
}

750
void S60DeviceRunControlBase::makesisProcessFailed()
751
{
752
    processFailed(m_makesisTool, m_makesisProcess->error());
753
754
}

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772

static inline bool renameFile(const QString &sourceName, const QString &targetName,
                              QString *errorMessage)
{
    QFile target(targetName);
    if (target.exists() && !target.remove()) {
        *errorMessage = S60DeviceRunControlBase::tr("Unable to remove existing file '%1': %2").arg(targetName, target.errorString());
        return false;
    }
    QFile source(sourceName);
    if (!source.rename(targetName)) {
        *errorMessage = S60DeviceRunControlBase::tr("Unable to rename file '%1' to '%2': %3")
                        .arg(sourceName, targetName, source.errorString());
        return false;
    }
    return true;
}

773
void S60DeviceRunControlBase::makesisProcessFinished()
774
{
775
    if (m_makesisProcess->exitCode() != 0) {
776
        error(this, tr("An error occurred while creating the package."));
777
        stop();
778
779
780
        emit finished();
        return;
    }
781
    m_deployProgress->setProgressValue(PROGRESS_PACKAGECREATED);
782
783
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
784
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
785
786
787
        startDeployment();
        break;
    default:
788
789
790
791
792
793
794
795
796
797
798
        // makesis.exe derives the sis file name from the package,
        // it thus needs to renamed to '_unsigned.sis'.
        QString errorMessage;
        if (renameFile(m_signedPackage, m_unsignedPackage, &errorMessage)) {
            startSigning();
        } else {
            error(this, errorMessage);
            stop();
            emit finished();
            return;
        }
799
800
801
802
        break;
    }
}

803
804
805
806
807
808
809
810
811
812
813
814
815
816
QString S60DeviceRunControlBase::signSisKey() const
{
    const QString key = m_useCustomSignature ? m_customKeyPath:
                        m_qtDir + QLatin1String("/src/s60installs/selfsigned.key");
    return QDir::toNativeSeparators(key);
}

QString S60DeviceRunControlBase::signSisCertificate() const
{
    const QString cert = m_useCustomSignature ? m_customSignaturePath :
                         m_qtDir + QLatin1String("/src/s60installs/selfsigned.cer");
    return QDir::toNativeSeparators(cert);
}

817
818
void S60DeviceRunControlBase::startSigning()
{
819
    // Signis creates a signed package ('.sis') from an 'unsigned.sis'
820
821
822
823
824
    // using certificate and key.
    QString signsisTool = m_toolsDirectory + QLatin1String("/signsis");
#ifdef Q_OS_WIN
    signsisTool += QLatin1String(".exe");
#endif
825
    QStringList arguments;
826
    arguments << m_unsignedPackage << m_signedPackage << signSisCertificate() << signSisKey();
827
    m_signsisProcess->setWorkingDirectory(m_workingDirectory);
828
    emit addToOutputWindow(this, msgRun(signsisTool, arguments));
829
    m_signsisProcess->start(signsisTool, arguments, QIODevice::ReadOnly);
830
831
}

832
void S60DeviceRunControlBase::signsisProcessFailed()
833
{
834
    processFailed("signsis.exe", m_signsisProcess->error());
835
836
}

837
void S60DeviceRunControlBase::signsisProcessFinished()
838
{
839
    if (m_signsisProcess->exitCode() != 0) {
840
        error(this, tr("An error occurred while creating the package."));
841
        stop();
842
        emit finished();
843
    } else {
844
        m_deployProgress->setProgressValue(PROGRESS_PACKAGESIGNED);
845
        startDeployment();
846
    }
847
848
}

849

850
851
void S60DeviceRunControlBase::startDeployment()
{
852
    QString errorMessage;
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
    bool success = false;
    do {
        connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)),
                this, SLOT(deviceRemoved(SymbianUtils::SymbianDevice)));
        m_launcher = trk::Launcher::acquireFromDeviceManager(m_serialPortName, 0, &errorMessage);
        if (!m_launcher)
            break;

        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(copyProgress(int)), this, SLOT(printCopyProgress(int)));
        connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
        connect(m_launcher, SIGNAL(processStopped(uint,uint,uint,QString)),
                this, SLOT(processStopped(uint,uint,uint,QString)));

        //TODO sisx destination and file path user definable
        if (!m_commandLineArguments.isEmpty())
            m_launcher->setCommandLineArgs(m_commandLineArguments);
878
        const QString copyDst = QString::fromLatin1("C:\\Data\\%1.sis").arg(QFileInfo(m_baseFileName).fileName());
879
        const QString runFileName = QString::fromLatin1("C:\\sys\\bin\\%1.exe").arg(m_targetName);
880
        m_launcher->setCopyFileName(m_signedPackage, copyDst);
881
882
        m_launcher->setInstallFileName(copyDst);
        initLauncher(runFileName, m_launcher);
883
        emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(m_signedPackage), m_serialPortFriendlyName));
884
885
        // Prompt the user to start up the Blue tooth connection
        const trk::PromptStartCommunicationResult src =
886
            S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
887
888
889
890
891
892
893
894
895
896
                                                             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);
897

898
899
900
    if (!success) {
        if (!errorMessage.isEmpty())
            error(this, errorMessage);
901
        stop();
con's avatar
con committed
902
903
        emit finished();
    }
904
905
}

906
void S60DeviceRunControlBase::printCreateFileFailed(const QString &filename, const QString &errorMessage)
con's avatar
con committed
907
{
908
    emit addToOutputWindow(this, tr("Could not create file %1 on device: %2").arg(filename, errorMessage));
con's avatar
con committed
909
910
}

911
912
913
914
915
void S60DeviceRunControlBase::printWriteFileFailed(const QString &filename, const QString &errorMessage)
{
    emit addToOutputWindow(this, tr("Could not write to file %1 on device: %2").arg(filename, errorMessage));
}

916
917
918
919
920
921
void S60DeviceRunControlBase::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.");
    emit addToOutputWindow(this, msg.arg(filename, errorMessage));
}

922
923
924
925
926
void S60DeviceRunControlBase::printConnectFailed(const QString &errorMessage)
{
    emit addToOutputWindow(this, tr("Could not connect to App TRK on device: %1. Restarting App TRK might help.").arg(errorMessage));
}

927
void S60DeviceRunControlBase::printCopyingNotice()
928
{
929
    emit addToOutputWindow(this, tr("Copying install file..."));
930
931
}

932
void S60DeviceRunControlBase::printCopyProgress(int progress)
con's avatar
con committed
933
{
934
    m_deployProgress->setProgressValue(PROGRESS_DEPLOYBASE + progress);
con's avatar
con committed
935
936
}

937
void S60DeviceRunControlBase::printInstallingNotice()
con's avatar
con committed
938
{
939
    m_deployProgress->setProgressValue(PROGRESS_PACKAGEDEPLOYED);
con's avatar
con committed
940
941
942
    emit addToOutputWindow(this, tr("Installing application..."));
}

943
944
945
946
947
948
949
950
void S60DeviceRunControlBase::printInstallingFinished()
{
    m_deployProgress->setProgressValue(PROGRESS_PACKAGEINSTALLED);
    m_deployProgress->reportFinished();
    delete m_deployProgress;
    m_deployProgress = 0;
}

951
952
953
954
955
void S60DeviceRunControlBase::printInstallFailed(const QString &filename, const QString &errorMessage)
{
    emit addToOutputWindow(this, tr("Could not install from package %1 on device: %2").arg(filename, errorMessage));
}

956
957
void S60DeviceRunControlBase::launcherFinished()
{
958
959
960
961
    if (m_releaseDeviceAfterLauncherFinish) {
        m_handleDeviceRemoval = false;
        trk::Launcher::releaseToDeviceManager(m_launcher);
    }
962
963
964
965
966
    m_launcher->deleteLater();
    m_launcher = 0;
    handleLauncherFinished();
}

967
968
969
970
971
972
973
974
975
void S60DeviceRunControlBase::reportDeployFinished()
{
    if (m_deployProgress) {
        m_deployProgress->reportFinished();
        delete m_deployProgress;
        m_deployProgress = 0;
    }
}

976
977
978
979
980
981
void S60DeviceRunControlBase::processStopped(uint pc, uint pid, uint tid, const QString& reason)
{
    emit addToOutputWindow(this, trk::Launcher::msgStopped(pid, tid, pc, reason));
    m_launcher->terminate();
}

982
983
984
QMessageBox *S60DeviceRunControlBase::createTrkWaitingMessageBox(const QString &port, QWidget *parent)
{
    const QString title  = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
Robert Loehning's avatar
Robert Loehning committed
985
                                                       "Waiting for App TRK");
986
    const QString text = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
Robert Loehning's avatar
Robert Loehning committed
987
                                                     "Please start App TRK on %1.").arg(port);
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
    QMessageBox *rc = new QMessageBox(QMessageBox::Information, title, text,
                                      QMessageBox::Cancel, parent);
    return rc;
}

void S60DeviceRunControlBase::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 S60DeviceRunControlBase::slotWaitingForTrkClosed()
{
    if (m_launcher && m_launcher->state() == trk::Launcher::WaitingForTrk) {
        stop();
1008
        error(this, tr("Canceled."));
1009
1010
1011
1012
        emit finished();
    }
}

1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
void S60DeviceRunControlBase::processFailed(const QString &program, QProcess::ProcessError errorCode)
{
    QString errorString;
    switch (errorCode) {
    case QProcess::FailedToStart:
        errorString = tr("Failed to start %1.");
        break;
    case QProcess::Crashed:
        errorString = tr("%1 has unexpectedly finished.");
        break;
    default:
        errorString = tr("An error has occurred while running %1.");
    }
    error(this, errorString.arg(program));
1027
    stop();
1028
1029
1030
    emit finished();
}

Friedemann Kleint's avatar
Friedemann Kleint committed
1031
1032
1033
1034
1035
void S60DeviceRunControlBase::printApplicationOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

1036
1037
1038
1039
1040
1041
1042
1043
void S60DeviceRunControlBase::deviceRemoved(const SymbianUtils::SymbianDevice &d)
{
    if (m_handleDeviceRemoval && d.portName() == m_serialPortName) {
        error(this, tr("The device '%1' has been disconnected").arg(d.friendlyName()));
        emit finished();
    }
}

1044
1045
1046
1047
1048
1049
1050
bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
                                                 QString * /* settingsCategory */,
                                                 QString * /* settingsPage */) const
{
    return true;
}

1051
// =============== S60DeviceRunControl
1052

1053
S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration) :
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
    S60DeviceRunControlBase(runConfiguration)
{
}

void S60DeviceRunControl::initLauncher(const QString &executable, trk::Launcher *launcher)
{
     connect(launcher, SIGNAL(startingApplication()), this, SLOT(printStartingNotice()));
     connect(launcher, SIGNAL(applicationRunning(uint)), this, SLOT(printRunNotice(uint)));
     connect(launcher, SIGNAL(canNotRun(QString)), this, SLOT(printRunFailNotice(QString)));
     connect(launcher, SIGNAL(applicationOutputReceived(QString)), this, SLOT(printApplicationOutput(QString)));
1064
     launcher->addStartupActions(trk::Launcher::ActionCopyInstallRun);
1065
1066
1067
1068
1069
1070
1071
1072
1073
     launcher->setFileName(executable);
}

void S60DeviceRunControl::handleLauncherFinished()
{
     emit finished();
     emit addToOutputWindow(this, tr("Finished."));
 }

con's avatar
con committed
1074
1075
void S60DeviceRunControl::printStartingNotice()
{
1076
    emit addToOutputWindow(this, tr("Starting application..."));
con's avatar
con committed
1077
1078
1079
1080
}

void S60DeviceRunControl::printRunNotice(uint pid)
{
con's avatar
con committed