s60devicerunconfiguration.cpp 39.2 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
QString S60DeviceRunConfiguration::localExecutableFileName() const
313
{
Tobias Hunger's avatar
Tobias Hunger committed
314
    Qt4BuildConfiguration *qt4bc = qobject_cast<Qt4BuildConfiguration *>(target()->activeBuildConfiguration());
315
    S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(qt4bc->qtVersion());
316
317
318
319
320
321

    QString localExecutable = device.epocRoot;
    localExecutable += QString::fromLatin1("/epoc32/release/%1/%2/%3.exe")
                       .arg(symbianPlatform()).arg(symbianTarget()).arg(targetName());
    qDebug() << localExecutable;
    return QDir::toNativeSeparators(localExecutable);
322
323
}

324
325
326
327
328
329
330
331
332
333
QStringList S60DeviceRunConfiguration::commandLineArguments() const
{
    return m_commandLineArguments;
}

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

334
335
336
337
void S60DeviceRunConfiguration::updateTarget()
{
    if (m_cachedTargetInformationValid)
        return;
Tobias Hunger's avatar
Tobias Hunger committed
338
    Qt4TargetInformation info = qt4Target()->targetInformation(qt4Target()->activeBuildConfiguration(),
339
340
341
342
                                                                m_proFilePath);
    if (info.error != Qt4TargetInformation::NoError) {
        if (info.error == Qt4TargetInformation::ProParserError) {
            Core::ICore::instance()->messageManager()->printToOutputPane(
343
                    tr("Could not parse %1. The Qt Symbian Device run configuration %2 can not be started.")
344
                    .arg(m_proFilePath).arg(displayName()));
345
        }
346
347
348
349
        m_targetName.clear();
        m_baseFileName.clear();
        m_packageTemplateFileName.clear();
        m_platform.clear();
350
351
352
353
        m_cachedTargetInformationValid = true;
        emit targetInformationChanged();
        return;
    }
354

355
    m_targetName = info.target;
dt's avatar
dt committed
356

357
    m_baseFileName = info.workingDir + QLatin1Char('/') + m_targetName;
358
    m_packageTemplateFileName = m_baseFileName + QLatin1String("_template.pkg");
359

Tobias Hunger's avatar
Tobias Hunger committed
360
    Qt4BuildConfiguration *qt4bc = qt4Target()->activeBuildConfiguration();
361
    switch (qt4bc->toolChainType()) {
362
363
    case ToolChain::GCCE:
    case ToolChain::GCCE_GNUPOC:
364
        m_platform = QLatin1String("gcce");
365
366
        break;
    case ToolChain::RVCT_ARMV5:
367
        m_platform = QLatin1String("armv5");
368
369
        break;
    default: // including ToolChain::RVCT_ARMV6_GNUPOC:
370
        m_platform = QLatin1String("armv6");
371
372
        break;
    }
373
    if (qt4bc->qmakeBuildConfiguration() & QtVersion::DebugBuild)
374
        m_target = QLatin1String("udeb");
con's avatar
con committed
375
    else
376
377
        m_target = QLatin1String("urel");
    m_baseFileName += QLatin1Char('_') + m_platform + QLatin1Char('_') + m_target;
378

379
380
381
382
383
384
385
386
387
388
    m_cachedTargetInformationValid = true;
    emit targetInformationChanged();
}

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

con's avatar
con committed
389

390
391
// ======== S60DeviceRunConfigurationFactory

392
393
S60DeviceRunConfigurationFactory::S60DeviceRunConfigurationFactory(QObject *parent) :
    IRunConfigurationFactory(parent)
394
395
396
397
398
399
400
{
}

S60DeviceRunConfigurationFactory::~S60DeviceRunConfigurationFactory()
{
}

Tobias Hunger's avatar
Tobias Hunger committed
401
QStringList S60DeviceRunConfigurationFactory::availableCreationIds(Target *parent) const
402
{
Tobias Hunger's avatar
Tobias Hunger committed
403
404
405
    Qt4Target *target = qobject_cast<Qt4Target *>(parent);
    if (!target ||
        target->id() != QLatin1String(S60_DEVICE_TARGET_ID))
406
407
        return QStringList();

Tobias Hunger's avatar
Tobias Hunger committed
408
    return target->qt4Project()->applicationProFilePathes(QLatin1String(S60_DEVICE_RC_PREFIX));
409
410
}

411
QString S60DeviceRunConfigurationFactory::displayNameForId(const QString &id) const
412
{
413
414
415
    if (!pathFromId(id).isEmpty())
        return tr("%1 on Symbian Device").arg(QFileInfo(pathFromId(id)).completeBaseName());
    return QString();
416
417
}

Tobias Hunger's avatar
Tobias Hunger committed
418
bool S60DeviceRunConfigurationFactory::canCreate(Target *parent, const QString &id) const
419
{
Tobias Hunger's avatar
Tobias Hunger committed
420
421
422
    Qt4Target * t(qobject_cast<Qt4Target *>(parent));
    if (!t ||
        t->id() != QLatin1String(S60_DEVICE_TARGET_ID))
423
        return false;
Tobias Hunger's avatar
Tobias Hunger committed
424
    return t->qt4Project()->hasApplicationProFile(pathFromId(id));
425
426
}

Tobias Hunger's avatar
Tobias Hunger committed
427
RunConfiguration *S60DeviceRunConfigurationFactory::create(Target *parent, const QString &id)
428
{
429
430
431
    if (!canCreate(parent, id))
        return 0;

Tobias Hunger's avatar
Tobias Hunger committed
432
433
    Qt4Target *t(static_cast<Qt4Target *>(parent));
    return new S60DeviceRunConfiguration(t, pathFromId(id));
434
435
}

Tobias Hunger's avatar
Tobias Hunger committed
436
bool S60DeviceRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
437
{
Tobias Hunger's avatar
Tobias Hunger committed
438
439
440
    Qt4Target * t(qobject_cast<Qt4Target *>(parent));
    if (!t ||
        t->id() != QLatin1String(S60_DEVICE_TARGET_ID))
441
442
443
444
445
        return false;
    QString id(ProjectExplorer::idFromMap(map));
    return id == QLatin1String(S60_DEVICE_RC_ID);
}

Tobias Hunger's avatar
Tobias Hunger committed
446
RunConfiguration *S60DeviceRunConfigurationFactory::restore(Target *parent, const QVariantMap &map)
447
448
449
{
    if (!canRestore(parent, map))
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
450
451
    Qt4Target *t(static_cast<Qt4Target *>(parent));
    S60DeviceRunConfiguration *rc(new S60DeviceRunConfiguration(t, QString()));
452
453
454
455
456
457
458
    if (rc->fromMap(map))
        return rc;

    delete rc;
    return 0;
}

Tobias Hunger's avatar
Tobias Hunger committed
459
bool S60DeviceRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const
460
{
Tobias Hunger's avatar
Tobias Hunger committed
461
    if (!qobject_cast<Qt4Target *>(parent))
462
463
464
465
        return false;
    return source->id() == QLatin1String(S60_DEVICE_RC_ID);
}

Tobias Hunger's avatar
Tobias Hunger committed
466
RunConfiguration *S60DeviceRunConfigurationFactory::clone(Target *parent, RunConfiguration *source)
467
468
469
{
    if (!canClone(parent, source))
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
470
    Qt4Target *t = static_cast<Qt4Target *>(parent);
471
    S60DeviceRunConfiguration * old(static_cast<S60DeviceRunConfiguration *>(source));
Tobias Hunger's avatar
Tobias Hunger committed
472
    return new S60DeviceRunConfiguration(t, old);
473
474
}

475
// ======== S60DeviceRunControlBase
Friedemann Kleint's avatar
Friedemann Kleint committed
476

477
S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration) :
478
    RunControl(runConfiguration),
479
    m_toolChain(ProjectExplorer::ToolChain::INVALID),
480
481
    m_makesisProcess(new QProcess(this)),
    m_signsisProcess(0),
482
483
    m_releaseDeviceAfterLauncherFinish(false),
    m_handleDeviceRemoval(true),
484
    m_launcher(0)
485
486
487
488
{
    // connect for automatically reporting the "finished deploy" state to the progress manager
    connect(this, SIGNAL(finished()), this, SLOT(reportDeployFinished()));

489
    connect(m_makesisProcess, SIGNAL(readyReadStandardError()),
con's avatar
con committed
490
            this, SLOT(readStandardError()));
491
    connect(m_makesisProcess, SIGNAL(readyReadStandardOutput()),
con's avatar
con committed
492
            this, SLOT(readStandardOutput()));
493
    connect(m_makesisProcess, SIGNAL(error(QProcess::ProcessError)),
con's avatar
con committed
494
            this, SLOT(makesisProcessFailed()));
495
    connect(m_makesisProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
con's avatar
con committed
496
            this, SLOT(makesisProcessFinished()));
497

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

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

502
    QTC_ASSERT(s60runConfig, return);
503
    m_toolChain = s60runConfig->toolChainType();
504
    m_serialPortName = s60runConfig->serialPortName();
505
    m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
506
507
    m_targetName = s60runConfig->targetName();
    m_baseFileName = s60runConfig->basePackageFilePath();
508
    m_commandLineArguments = s60runConfig->commandLineArguments();
509
510
511
    m_symbianPlatform = s60runConfig->symbianPlatform();
    m_symbianTarget = s60runConfig->symbianTarget();
    m_packageTemplateFile = s60runConfig->packageTemplateFileName();
con's avatar
con committed
512
    m_workingDirectory = QFileInfo(m_baseFileName).absolutePath();
513
    m_qtDir = activeBuildConf->qtVersion()->versionInfo().value("QT_INSTALL_DATA");
514
515
516
    m_useCustomSignature = (s60runConfig->signingMode() == S60DeviceRunConfiguration::SignCustom);
    m_customSignaturePath = s60runConfig->customSignaturePath();
    m_customKeyPath = s60runConfig->customKeyPath();
517

518
    const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(activeBuildConf->qtVersion());
519
520
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
521
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: {
522
            // 'sis' is a make target here. Set up with correct environment
523
            ProjectExplorer::ToolChain *toolchain = activeBuildConf->toolChain();
524
525
526
            m_makesisTool = toolchain->makeCommand();
            m_toolsDirectory = device.epocRoot + QLatin1String("/epoc32/tools");
            ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
527
528
            env.set(QLatin1String("QT_SIS_CERTIFICATE"), signSisCertificate());
            env.set(QLatin1String("QT_SIS_KEY"), signSisKey());
529
            toolchain->addToEnvironment(env);
530
            m_makesisProcess->setEnvironment(env.toStringList());
531
532
        }
        break;
533
534
    default:
        m_toolsDirectory = device.toolsRoot + QLatin1String("/epoc32/tools");
535
536
        m_makesisTool = m_toolsDirectory + "/makesis.exe";
        // Set up signing packages
537
538
        m_signsisProcess = new QProcess(this);
        connect(m_signsisProcess, SIGNAL(readyReadStandardError()),
539
                this, SLOT(readStandardError()));
540
        connect(m_signsisProcess, SIGNAL(readyReadStandardOutput()),
541
                this, SLOT(readStandardOutput()));
542
        connect(m_signsisProcess, SIGNAL(error(QProcess::ProcessError)),
543
                this, SLOT(signsisProcessFailed()));
544
        connect(m_signsisProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
545
546
547
548
                this, SLOT(signsisProcessFinished()));
        break;
    }
    m_executableFileName = s60runConfig->localExecutableFileName();
549
550
    m_packageFilePath = s60runConfig->packageFileName();
    m_packageFile = QFileInfo(m_packageFilePath).fileName();
551
552
    if (debug)
        qDebug() << "S60DeviceRunControlBase" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
553
                 << m_serialPortName << m_workingDirectory;
554
}
555

556
557
558
559
560
561
562
563
S60DeviceRunControlBase::~S60DeviceRunControlBase()
{
    if (m_launcher) {
        m_launcher->deleteLater();
        m_launcher = 0;
    }
}

564
565
566
567
568
void S60DeviceRunControlBase::setReleaseDeviceAfterLauncherFinish(bool v)
{
    m_releaseDeviceAfterLauncherFinish = v;
}

569
void S60DeviceRunControlBase::start()
570
{
571
572
573
574
575
576
577
    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();
578
    emit started();
579
580
581
582
583
    if (m_serialPortName.isEmpty()) {
        error(this, tr("There is no device plugged in."));
        emit finished();
        return;
    }
584

con's avatar
con committed
585
    emit addToOutputWindow(this, tr("Creating %1.sisx ...").arg(QDir::toNativeSeparators(m_baseFileName)));
586
    emit addToOutputWindow(this, tr("Executable file: %1").arg(lsFile(m_executableFileName)));
con's avatar
con committed
587

588
589
590
591
592
593
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
    if (!checkConfiguration(&errorMessage, &settingsCategory, &settingsPage)) {
        error(this, errorMessage);
        emit finished();
594
595
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger for Symbian Platform"),
                                                        errorMessage, QString(),
596
597
598
599
                                                        settingsCategory, settingsPage);
        return;
    }

600
601
602
    QStringList makeSisArgs;
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
603
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
604
605
606
607
608
609
610
611
612
613
        makeSisArgs.push_back(QLatin1String("sis"));
        break;
    default:
        makeSisArgs.push_back(m_packageFile);
        if (!createPackageFileFromTemplate(&errorMessage)) {
            error(this, errorMessage);
            emit finished();
            return;
        }
        break;
614
    }
615

616
    m_makesisProcess->setWorkingDirectory(m_workingDirectory);
617
    emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(m_makesisTool), m_packageFile));
618
619
    if (debug)
        qDebug() << m_makesisTool <<  makeSisArgs << m_workingDirectory;
620
    m_makesisProcess->start(m_makesisTool, makeSisArgs, QIODevice::ReadOnly);
621
622
}

623
624
625
626
627
628
629
630
631
632
633
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();
}

634
void S60DeviceRunControlBase::stop()
635
{
636
637
638
639
    if (m_makesisProcess)
        stopProcess(m_makesisProcess);
    if (m_signsisProcess)
        stopProcess(m_signsisProcess);
640
641
    if (m_launcher)
        m_launcher->terminate();
642
643
}

644
bool S60DeviceRunControlBase::isRunning() const
645
{
646
    return m_makesisProcess->state() != QProcess::NotRunning;
647
648
}

649
void S60DeviceRunControlBase::readStandardError()
650
{
con's avatar
con committed
651
652
653
    QProcess *process = static_cast<QProcess *>(sender());
    QByteArray data = process->readAllStandardError();
    emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
654
655
}

656
void S60DeviceRunControlBase::readStandardOutput()
657
{
con's avatar
con committed
658
659
660
661
662
    QProcess *process = static_cast<QProcess *>(sender());
    QByteArray data = process->readAllStandardOutput();
    emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
}

663
bool S60DeviceRunControlBase::createPackageFileFromTemplate(QString *errorMessage)
664
665
666
{
    QFile packageTemplate(m_packageTemplateFile);
    if (!packageTemplate.open(QIODevice::ReadOnly)) {
667
        *errorMessage = tr("Could not read template package file '%1'").arg(QDir::toNativeSeparators(m_packageTemplateFile));
668
669
670
671
672
673
674
675
        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)) {
676
        *errorMessage = tr("Could not write package file '%1'").arg(QDir::toNativeSeparators(m_packageFilePath));
677
678
679
680
681
682
683
        return false;
    }
    packageFile.write(contents.toLocal8Bit());
    packageFile.close();
    return true;
}

684
void S60DeviceRunControlBase::makesisProcessFailed()
685
{
686
    processFailed(m_makesisTool, m_makesisProcess->error());
687
688
}

689
void S60DeviceRunControlBase::makesisProcessFinished()
690
{
691
    if (m_makesisProcess->exitCode() != 0) {
692
        error(this, tr("An error occurred while creating the package."));
693
        stop();
694
695
696
        emit finished();
        return;
    }
697
    m_deployProgress->setProgressValue(PROGRESS_PACKAGECREATED);
698
699
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
700
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
701
702
703
704
705
706
707
708
        startDeployment();
        break;
    default:
        startSigning();
        break;
    }
}

709
710
711
712
713
714
715
716
717
718
719
720
721
722
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);
}

723
724
void S60DeviceRunControlBase::startSigning()
{
725
726
727
728
729
730
731
732
    // Signis creates a signed package ('.sisx') from a '.sis'
    // using certificate and key.
    QString signsisTool = m_toolsDirectory + QLatin1String("/signsis");
#ifdef Q_OS_WIN
    signsisTool += QLatin1String(".exe");
#endif
    const QString sisFile = QFileInfo(m_baseFileName + QLatin1String(".sis")).fileName();
    const QString sisxFile = sisFile + QLatin1Char('x');
733
    QStringList arguments;
734
735
    arguments << sisFile << sisxFile << signSisCertificate() << signSisKey();
    m_signsisProcess->setWorkingDirectory(m_workingDirectory);
736
    emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(signsisTool), arguments.join(QString(QLatin1Char(' ')))));
737
    m_signsisProcess->start(signsisTool, arguments, QIODevice::ReadOnly);
738
739
}

740
void S60DeviceRunControlBase::signsisProcessFailed()
741
{
742
    processFailed("signsis.exe", m_signsisProcess->error());
743
744
}

745
void S60DeviceRunControlBase::signsisProcessFinished()
746
{
747
    if (m_signsisProcess->exitCode() != 0) {
748
        error(this, tr("An error occurred while creating the package."));
749
        stop();
750
        emit finished();
751
    } else {
752
        m_deployProgress->setProgressValue(PROGRESS_PACKAGESIGNED);
753
        startDeployment();
754
    }
755
756
}

757

758
759
void S60DeviceRunControlBase::startDeployment()
{
760
    QString errorMessage;
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
    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);
        const QString copySrc(m_baseFileName + QLatin1String(".sisx"));
        const QString copyDst = QString::fromLatin1("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName());
        const QString runFileName = QString::fromLatin1("C:\\sys\\bin\\%1.exe").arg(m_targetName);
        m_launcher->setCopyFileName(copySrc, copyDst);
        m_launcher->setInstallFileName(copyDst);
        initLauncher(runFileName, m_launcher);
        emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(copySrc), m_serialPortFriendlyName));
        // Prompt the user to start up the Blue tooth connection
        const trk::PromptStartCommunicationResult src =
795
            S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
796
797
798
799
800
801
802
803
804
805
                                                             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);
806

807
808
809
    if (!success) {
        if (!errorMessage.isEmpty())
            error(this, errorMessage);
810
        stop();
con's avatar
con committed
811
812
        emit finished();
    }
813
814
}

815
void S60DeviceRunControlBase::printCreateFileFailed(const QString &filename, const QString &errorMessage)
con's avatar
con committed
816
{
817
    emit addToOutputWindow(this, tr("Could not create file %1 on device: %2").arg(filename, errorMessage));
con's avatar
con committed
818
819
}

820
821
822
823
824
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));
}

825
826
827
828
829
830
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));
}

831
832
833
834
835
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));
}

836
void S60DeviceRunControlBase::printCopyingNotice()
837
{
838
    emit addToOutputWindow(this, tr("Copying install file..."));
839
840
}

841
void S60DeviceRunControlBase::printCopyProgress(int progress)
con's avatar
con committed
842
{
843
    m_deployProgress->setProgressValue(PROGRESS_DEPLOYBASE + progress);
con's avatar
con committed
844
845
}

846
void S60DeviceRunControlBase::printInstallingNotice()
con's avatar
con committed
847
{
848
    m_deployProgress->setProgressValue(PROGRESS_PACKAGEDEPLOYED);
con's avatar
con committed
849
850
851
    emit addToOutputWindow(this, tr("Installing application..."));
}

852
853
854
855
856
857
858
859
void S60DeviceRunControlBase::printInstallingFinished()
{
    m_deployProgress->setProgressValue(PROGRESS_PACKAGEINSTALLED);
    m_deployProgress->reportFinished();
    delete m_deployProgress;
    m_deployProgress = 0;
}

860
861
862
863
864
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));
}

865
866
void S60DeviceRunControlBase::launcherFinished()
{
867
868
869
870
    if (m_releaseDeviceAfterLauncherFinish) {
        m_handleDeviceRemoval = false;
        trk::Launcher::releaseToDeviceManager(m_launcher);
    }
871
872
873
874
875
    m_launcher->deleteLater();
    m_launcher = 0;
    handleLauncherFinished();
}

876
877
878
879
880
881
882
883
884
void S60DeviceRunControlBase::reportDeployFinished()
{
    if (m_deployProgress) {
        m_deployProgress->reportFinished();
        delete m_deployProgress;
        m_deployProgress = 0;
    }
}

885
886
887
888
889
890
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();
}

891
892
893
QMessageBox *S60DeviceRunControlBase::createTrkWaitingMessageBox(const QString &port, QWidget *parent)
{
    const QString title  = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
Robert Loehning's avatar
Robert Loehning committed
894
                                                       "Waiting for App TRK");
895
    const QString text = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
Robert Loehning's avatar
Robert Loehning committed
896
                                                     "Please start App TRK on %1.").arg(port);
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
    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();
917
        error(this, tr("Canceled."));
918
919
920
921
        emit finished();
    }
}

922
923
924
925
926
927
928
929
930
931
932
933
934
935
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));
936
    stop();
937
938
939
    emit finished();
}

Friedemann Kleint's avatar
Friedemann Kleint committed
940
941
942
943
944
void S60DeviceRunControlBase::printApplicationOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

945
946
947
948
949
950
951
952
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();
    }
}

953
954
955
956
957
958
959
bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
                                                 QString * /* settingsCategory */,
                                                 QString * /* settingsPage */) const
{
    return true;
}

960
// =============== S60DeviceRunControl
961

962
S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration) :
963
964
965
966
967
968
969
970
971
972
    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)));
973
     launcher->addStartupActions(trk::Launcher::ActionCopyInstallRun);
974
975
976
977
978
979
980
981
982
     launcher->setFileName(executable);
}

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

con's avatar
con committed
983
984
void S60DeviceRunControl::printStartingNotice()
{
985
    emit addToOutputWindow(this, tr("Starting application..."));
con's avatar
con committed
986
987
988
989
}

void S60DeviceRunControl::printRunNotice(uint pid)
{
con's avatar
con committed
990
    emit addToOutputWindow(this, tr("Application running with pid %1.").arg(pid));
con's avatar
con committed
991
992
}

993
994
995
996
void S60DeviceRunControl::printRunFailNotice(const QString &errorMessage) {
    emit addToOutputWindow(this, tr("Could not start application: %1").arg(errorMessage));
}

997
998
// ======== S60DeviceDebugRunControl

999
S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration) :
1000
1001
    S60DeviceRunControlBase(runConfiguration),
    m_startParams(new Debugger::DebuggerStartParameters)
1002
{
1003
    setReleaseDeviceAfterLauncherFinish(true); // Debugger controls device after install
1004
    Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
1005
1006
    S60DeviceRunConfiguration *rc = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
    QTC_ASSERT(dm && rc, return);
1007
1008
1009
1010

    connect(dm, SIGNAL(debuggingFinished()),
            this, SLOT(debuggingFinished()), Qt::QueuedConnection);
    connect(dm, SIGNAL(applicationOutputAvailable(QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
1011
            this, SLOT(printApplicationOutput(QString)),
1012
1013
1014
            Qt::QueuedConnection);

    m_startParams->remoteChannel = rc->serialPortName();
1015
    m_startParams->processArgs = rc->commandLineArguments();
1016
1017
    m_startParams->startMode = Debugger::StartInternal;
    m_startParams->toolChainType = rc->toolChainType();
1018
1019
1020
1021
1022
1023

    m_localExecutableFileName = rc->localExecutableFileName();
    const int lastDotPos = m_localExecutableFileName.lastIndexOf(QLatin1Char('.'));
    if (lastDotPos != -1) {
        m_startParams->symbolFileName = m_localExecutableFileName.mid(0, lastDotPos) + QLatin1String(".sym");
    }
1024
1025
}

1026
void S60DeviceDebugRunControl::stop()
con's avatar
con committed
1027
{
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
    S60DeviceRunControlBase::stop();
    Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
    QTC_ASSERT(dm, return)
    if (dm->state() == Debugger::DebuggerNotReady)
        dm->exitDebugger();
}

S60DeviceDebugRunControl::~S60DeviceDebugRunControl()
{
}

1039
void S60DeviceDebugRunControl::initLauncher(const QString &executable, trk::Launcher *launcher)
1040
1041
1042
{
    // No setting an executable on the launcher causes it to deploy only
    m_startParams->executable = executable;
1043
1044
    // Prefer the '*.sym' file over the '.exe', which should exist at the same
    // location in debug builds
1045
1046
1047
1048

    if (!QFileInfo(m_startParams->symbolFileName).isFile()) {
        m_startParams->symbolFileName.clear();
        emit addToOutputWindow(this, tr("Warning: Cannot locate the symbol file belonging to %1.").arg(m_localExecutableFileName));
1049
    }
1050

1051
    launcher->addStartupActions(trk::Launcher::ActionCopyInstall);
1052
1053
    // Avoid close/open sequence in quick s