s60devicerunconfiguration.cpp 34.6 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
33
34
35
36
#include "qt4project.h"
#include "qtversionmanager.h"
#include "profilereader.h"
#include "s60manager.h"
#include "s60devices.h"
37
38
#include "s60runconfigbluetoothstarter.h"
#include "bluetoothlistener_gui.h"
39
#include "serialdevicelister.h"
40
41
42
43

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

51
52
#include <debugger/debuggermanager.h>

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

56
57
58
using namespace ProjectExplorer;
using namespace Qt4ProjectManager::Internal;

59
60
enum { debug = 0 };

61
62
63
64
65
66
67
68
69
// Format information about a file
static QString lsFile(const QString &f)
{
    QString rc;
    const QFileInfo fi(f);
    QTextStream str(&rc);
    str << fi.size() << ' ' << fi.lastModified().toString(Qt::ISODate) << ' ' << QDir::toNativeSeparators(fi.absoluteFilePath());
    return rc;
}
70

71
72
73
74
// ======== S60DeviceRunConfiguration
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Project *project, const QString &proFilePath)
    : RunConfiguration(project),
    m_proFilePath(proFilePath),
con's avatar
con committed
75
    m_cachedTargetInformationValid(false),
76
77
78
79
80
81
82
#ifdef Q_OS_WIN
    m_serialPortName(QLatin1String("COM5")),
    m_communicationType(SerialPortCommunication),
#else
    m_serialPortName(QLatin1String(SerialDeviceLister::linuxBlueToothDeviceRootC) + QLatin1Char('0')),
    m_communicationType(BlueToothCommunication),
#endif
con's avatar
con committed
83
    m_signingMode(SignSelf)
84
85
{
    if (!m_proFilePath.isEmpty())
86
        setName(tr("%1 on Symbian Device").arg(QFileInfo(m_proFilePath).completeBaseName()));
87
88
89
90
91
    else
        setName(tr("QtS60DeviceRunConfiguration"));

    connect(project, SIGNAL(activeBuildConfigurationChanged()),
            this, SLOT(invalidateCachedTargetInformation()));
92
93
94

    connect(project, SIGNAL(targetInformationChanged()),
            this, SLOT(invalidateCachedTargetInformation()));
95
96
97
98
99
100
101
102
}

S60DeviceRunConfiguration::~S60DeviceRunConfiguration()
{
}

QString S60DeviceRunConfiguration::type() const
{
103
104
105
    return QLatin1String("Qt4ProjectManager.DeviceRunConfiguration");
}

106
107
108
109
110
111
112
113
ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainType(
        ProjectExplorer::BuildConfiguration *configuration) const
{
    if (const Qt4Project *pro = qobject_cast<const Qt4Project*>(project()))
        return pro->toolChainType(configuration);
    return ProjectExplorer::ToolChain::INVALID;
}

114
115
116
117
118
ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainType() const
{
    if (const Qt4Project *pro = qobject_cast<const Qt4Project*>(project()))
        return pro->toolChainType(pro->activeBuildConfiguration());
    return ProjectExplorer::ToolChain::INVALID;
119
120
}

121
bool S60DeviceRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *configuration) const
122
{
123
    const ToolChain::ToolChainType type = toolChainType(configuration);
con's avatar
con committed
124
    return type == ToolChain::GCCE || type == ToolChain::RVCT_ARMV5 || type == ToolChain::RVCT_ARMV6;
125
126
127
128
129
130
131
132
133
134
135
}

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

void S60DeviceRunConfiguration::save(PersistentSettingsWriter &writer) const
{
    const QDir projectDir = QFileInfo(project()->file()->fileName()).absoluteDir();
    writer.saveValue("ProFile", projectDir.relativeFilePath(m_proFilePath));
con's avatar
con committed
136
137
138
    writer.saveValue("SigningMode", (int)m_signingMode);
    writer.saveValue("CustomSignaturePath", m_customSignaturePath);
    writer.saveValue("CustomKeyPath", m_customKeyPath);
con's avatar
con committed
139
    writer.saveValue("SerialPortName", m_serialPortName);
140
    writer.saveValue("CommunicationType", m_communicationType);
141
142
143
144
145
146
147
148
    RunConfiguration::save(writer);
}

void S60DeviceRunConfiguration::restore(const PersistentSettingsReader &reader)
{
    RunConfiguration::restore(reader);
    const QDir projectDir = QFileInfo(project()->file()->fileName()).absoluteDir();
    m_proFilePath = projectDir.filePath(reader.restoreValue("ProFile").toString());
con's avatar
con committed
149
150
151
    m_signingMode = (SigningMode)reader.restoreValue("SigningMode").toInt();
    m_customSignaturePath = reader.restoreValue("CustomSignaturePath").toString();
    m_customKeyPath = reader.restoreValue("CustomKeyPath").toString();
con's avatar
con committed
152
    m_serialPortName = reader.restoreValue("SerialPortName").toString().trimmed();
153
    m_communicationType = reader.restoreValue("CommunicationType").toInt();
con's avatar
con committed
154
155
156
157
158
159
160
161
162
163
}

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

void S60DeviceRunConfiguration::setSerialPortName(const QString &name)
{
    m_serialPortName = name.trimmed();
164
165
}

166
167
168
169
170
171
172
173
174
175
int S60DeviceRunConfiguration::communicationType() const
{
    return m_communicationType;
}

void S60DeviceRunConfiguration::setCommunicationType(int t)
{
    m_communicationType = t;
}

176
177
178
179
180
181
QString S60DeviceRunConfiguration::targetName() const
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
    return m_targetName;
}

con's avatar
con committed
182
QString S60DeviceRunConfiguration::basePackageFilePath() const
183
184
{
    const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
con's avatar
con committed
185
    return m_baseFileName;
186
187
}

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
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;
}

236
237
238
239
240
241
242
243
QString S60DeviceRunConfiguration::packageFileName() const
{
    QString rc = basePackageFilePath();
    if (!rc.isEmpty())
        rc += QLatin1String(".pkg");
    return rc;
}

244
QString S60DeviceRunConfiguration::localExecutableFileName() const
245
{
246
247
248
249
250
251
252
253
254
    Qt4Project *qt4project = qobject_cast<Qt4Project *>(project());
    S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(
            qt4project->qtVersion(qt4project->activeBuildConfiguration()));

    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);
255
256
}

257
258
259
260
261
262
263
void S60DeviceRunConfiguration::updateTarget()
{
    if (m_cachedTargetInformationValid)
        return;
    Qt4Project *pro = static_cast<Qt4Project *>(project());
    Qt4PriFileNode * priFileNode = static_cast<Qt4Project *>(project())->rootProjectNode()->findProFileFor(m_proFilePath);
    if (!priFileNode) {
con's avatar
con committed
264
        m_baseFileName = QString::null;
265
266
267
268
269
270
271
272
273
274
        m_cachedTargetInformationValid = true;
        emit targetInformationChanged();
        return;
    }
    QtVersion *qtVersion = pro->qtVersion(pro->activeBuildConfiguration());
    ProFileReader *reader = priFileNode->createProFileReader();
    reader->setCumulative(false);
    reader->setQtVersion(qtVersion);

    // Find out what flags we pass on to qmake, this code is duplicated in the qmake step
275
    QtVersion::QmakeBuildConfigs defaultBuildConfiguration = qtVersion->defaultBuildConfig();
dt's avatar
dt committed
276
277
    QtVersion::QmakeBuildConfigs projectBuildConfiguration =
            QtVersion::QmakeBuildConfigs(pro->activeBuildConfiguration()->value("buildConfiguration").toInt());
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    QStringList addedUserConfigArguments;
    QStringList removedUserConfigArguments;
    if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll))
        removedUserConfigArguments << "debug_and_release";
    if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll))
        addedUserConfigArguments << "debug_and_release";
    if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild))
        addedUserConfigArguments << "release";
    if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild))
        addedUserConfigArguments << "debug";

    reader->setUserConfigCmdArgs(addedUserConfigArguments, removedUserConfigArguments);

    if (!reader->readProFile(m_proFilePath)) {
        delete reader;
        Core::ICore::instance()->messageManager()->printToOutputPane(tr("Could not parse %1. The QtS60 Device run configuration %2 can not be started.").arg(m_proFilePath).arg(name()));
        return;
    }

con's avatar
con committed
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
    // Extract data
    const QDir baseProjectDirectory = QFileInfo(project()->file()->fileName()).absoluteDir();
    const QString relSubDir = baseProjectDirectory.relativeFilePath(QFileInfo(m_proFilePath).path());
    const QDir baseBuildDirectory = project()->buildDirectory(project()->activeBuildConfiguration());
    const QString baseDir = baseBuildDirectory.absoluteFilePath(relSubDir);

    // Directory
    QString m_workingDir;
    if (reader->contains("DESTDIR")) {
        m_workingDir = reader->value("DESTDIR");
        if (QDir::isRelativePath(m_workingDir)) {
            m_workingDir = baseDir + QLatin1Char('/') + m_workingDir;
        }
    } else {
        m_workingDir = baseDir;
    }
313

314
    m_targetName = reader->value("TARGET");
dt's avatar
dt committed
315
316
317
    if (m_targetName.isEmpty())
        m_targetName = QFileInfo(m_proFilePath).baseName();

318
    m_baseFileName = QDir::cleanPath(m_workingDir + QLatin1Char('/') + m_targetName);
319
320
321
    m_packageTemplateFileName = QDir::cleanPath(
            m_workingDir + QLatin1Char('/') + m_targetName + QLatin1String("_template.pkg"));

322
323
324
    switch (pro->toolChainType(pro->activeBuildConfiguration())) {
    case ToolChain::GCCE:
    case ToolChain::GCCE_GNUPOC:
325
        m_platform = QLatin1String("gcce");
326
327
        break;
    case ToolChain::RVCT_ARMV5:
328
        m_platform = QLatin1String("armv5");
329
330
        break;
    default: // including ToolChain::RVCT_ARMV6_GNUPOC:
331
        m_platform = QLatin1String("armv6");
332
333
        break;
    }
con's avatar
con committed
334
    if (projectBuildConfiguration & QtVersion::DebugBuild)
335
        m_target = QLatin1String("udeb");
con's avatar
con committed
336
    else
337
338
        m_target = QLatin1String("urel");
    m_baseFileName += QLatin1Char('_') + m_platform + QLatin1Char('_') + m_target;
339
340
341
342
343
344
345
346
347
348
349
    delete reader;
    m_cachedTargetInformationValid = true;
    emit targetInformationChanged();
}

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

con's avatar
con committed
350

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
// ======== S60DeviceRunConfigurationFactory

S60DeviceRunConfigurationFactory::S60DeviceRunConfigurationFactory(QObject *parent)
    : IRunConfigurationFactory(parent)
{
}

S60DeviceRunConfigurationFactory::~S60DeviceRunConfigurationFactory()
{
}

bool S60DeviceRunConfigurationFactory::canRestore(const QString &type) const
{
    return type == "Qt4ProjectManager.DeviceRunConfiguration";
}

QStringList S60DeviceRunConfigurationFactory::availableCreationTypes(Project *pro) const
{
    Qt4Project *qt4project = qobject_cast<Qt4Project *>(pro);
    if (qt4project) {
        QStringList applicationProFiles;
        QList<Qt4ProFileNode *> list = qt4project->applicationProFiles();
        foreach (Qt4ProFileNode * node, list) {
374
            applicationProFiles.append("QtSymbianDeviceRunConfiguration." + node->path());
375
376
377
378
379
380
381
382
383
        }
        return applicationProFiles;
    } else {
        return QStringList();
    }
}

QString S60DeviceRunConfigurationFactory::displayNameForType(const QString &type) const
{
384
385
    QString fileName = type.mid(QString("QtSymbianDeviceRunConfiguration.").size());
    return tr("%1 on Symbian Device").arg(QFileInfo(fileName).completeBaseName());
386
387
}

388
RunConfiguration *S60DeviceRunConfigurationFactory::create(Project *project, const QString &type)
389
390
391
{
    Qt4Project *p = qobject_cast<Qt4Project *>(project);
    Q_ASSERT(p);
392
    if (type.startsWith("QtSymbianDeviceRunConfiguration.")) {
393
        QString fileName = type.mid(QString("QtSymbianDeviceRunConfiguration.").size());
394
        return new S60DeviceRunConfiguration(p, fileName);
395
396
397
    }
    Q_ASSERT(type == "Qt4ProjectManager.DeviceRunConfiguration");
    // The right path is set in restoreSettings
398
    RunConfiguration *rc = new S60DeviceRunConfiguration(p, QString::null);
399
400
401
    return rc;
}

402
// ======== S60DeviceRunControlBase
Friedemann Kleint's avatar
Friedemann Kleint committed
403

404
S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration) :
405
    RunControl(runConfiguration),    
406
    m_toolChain(ProjectExplorer::ToolChain::INVALID),
407
    m_makesis(new QProcess(this)),
408
    m_signsis(0),
409
410
    m_launcher(0)
{    
con's avatar
con committed
411
412
413
414
415
416
417
418
    connect(m_makesis, SIGNAL(readyReadStandardError()),
            this, SLOT(readStandardError()));
    connect(m_makesis, SIGNAL(readyReadStandardOutput()),
            this, SLOT(readStandardOutput()));
    connect(m_makesis, SIGNAL(error(QProcess::ProcessError)),
            this, SLOT(makesisProcessFailed()));
    connect(m_makesis, SIGNAL(finished(int,QProcess::ExitStatus)),
            this, SLOT(makesisProcessFinished()));
419

420
    Qt4Project *project = qobject_cast<Qt4Project *>(runConfiguration->project());
421
    QTC_ASSERT(project, return);
422

423
    S60DeviceRunConfiguration *s60runConfig = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
424
    QTC_ASSERT(s60runConfig, return);
425
    m_toolChain = s60runConfig->toolChainType();
426
    m_serialPortName = s60runConfig->serialPortName();
427
    m_serialPortFriendlyName = S60Manager::instance()->serialDeviceLister()->friendlyNameForPort(m_serialPortName);
428
    m_communicationType = s60runConfig->communicationType();
429
430
    m_targetName = s60runConfig->targetName();
    m_baseFileName = s60runConfig->basePackageFilePath();
431
432
433
    m_symbianPlatform = s60runConfig->symbianPlatform();
    m_symbianTarget = s60runConfig->symbianTarget();
    m_packageTemplateFile = s60runConfig->packageTemplateFileName();
con's avatar
con committed
434
    m_workingDirectory = QFileInfo(m_baseFileName).absolutePath();
435
    m_qtDir = project->qtVersion(project->activeBuildConfiguration())->versionInfo().value("QT_INSTALL_DATA");
436
437
438
    m_useCustomSignature = (s60runConfig->signingMode() == S60DeviceRunConfiguration::SignCustom);
    m_customSignaturePath = s60runConfig->customSignaturePath();
    m_customKeyPath = s60runConfig->customKeyPath();
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469

    ProjectExplorer::BuildConfiguration *const activeBuildConf = project->activeBuildConfiguration();
    const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(project->qtVersion(activeBuildConf));
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
    case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: {
            // 'sis' is a make target here. Set up with correct environment
            ProjectExplorer::ToolChain *toolchain = project->toolChain(activeBuildConf);
            m_makesisTool = toolchain->makeCommand();
            m_toolsDirectory = device.epocRoot + QLatin1String("/epoc32/tools");
            ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
            toolchain->addToEnvironment(env);
            m_makesis->setEnvironment(env.toStringList());
        }
        break;
    default:        
        m_toolsDirectory = device.toolsRoot + QLatin1String("/epoc32/tools");        
        m_makesisTool = m_toolsDirectory + "/makesis.exe";
        // Set up signing packages
        m_signsis = new QProcess(this);
        connect(m_signsis, SIGNAL(readyReadStandardError()),
                this, SLOT(readStandardError()));
        connect(m_signsis, SIGNAL(readyReadStandardOutput()),
                this, SLOT(readStandardOutput()));
        connect(m_signsis, SIGNAL(error(QProcess::ProcessError)),
                this, SLOT(signsisProcessFailed()));
        connect(m_signsis, SIGNAL(finished(int,QProcess::ExitStatus)),
                this, SLOT(signsisProcessFinished()));
        break;
    }
    m_executableFileName = s60runConfig->localExecutableFileName();
470
471
    m_packageFilePath = s60runConfig->packageFileName();
    m_packageFile = QFileInfo(m_packageFilePath).fileName();
472
473
474
    if (debug)
        qDebug() << "S60DeviceRunControlBase" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
                 << m_serialPortName << m_communicationType << m_workingDirectory;
475
}
476

477
478
479
480
481
482
483
484
S60DeviceRunControlBase::~S60DeviceRunControlBase()
{
    if (m_launcher) {
        m_launcher->deleteLater();
        m_launcher = 0;
    }
}

485
void S60DeviceRunControlBase::start()
486
{
487
    emit started();
488
489
490
491
492
    if (m_serialPortName.isEmpty()) {
        error(this, tr("There is no device plugged in."));
        emit finished();
        return;
    }
493

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

497
498
499
500
501
502
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
    if (!checkConfiguration(&errorMessage, &settingsCategory, &settingsPage)) {
        error(this, errorMessage);
        emit finished();
503
504
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger for Symbian Platform"),
                                                        errorMessage, QString(),
505
506
507
508
                                                        settingsCategory, settingsPage);
        return;
    }

509
510
511
512
513
514
515
516
517
518
519
520
521
522
    QStringList makeSisArgs;
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
    case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC:
        makeSisArgs.push_back(QLatin1String("sis"));
        break;
    default:
        makeSisArgs.push_back(m_packageFile);
        if (!createPackageFileFromTemplate(&errorMessage)) {
            error(this, errorMessage);
            emit finished();
            return;
        }
        break;
523
    }
524

con's avatar
con committed
525
    m_makesis->setWorkingDirectory(m_workingDirectory);
526
527
528
529
    emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(m_makesisTool), m_packageFile));    
    if (debug)
        qDebug() << m_makesisTool <<  makeSisArgs << m_workingDirectory;
    m_makesis->start(m_makesisTool, makeSisArgs, QIODevice::ReadOnly);
530
531
}

532
533
534
535
536
537
538
539
540
541
542
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();
}

543
void S60DeviceRunControlBase::stop()
544
{
545
546
547
548
    if (m_makesis)
        stopProcess(m_makesis);
    if (m_signsis)
        stopProcess(m_signsis);
549
550
    if (m_launcher)
        m_launcher->terminate();
551
552
}

553
bool S60DeviceRunControlBase::isRunning() const
554
{
con's avatar
con committed
555
    return m_makesis->state() != QProcess::NotRunning;
556
557
}

558
void S60DeviceRunControlBase::readStandardError()
559
{
con's avatar
con committed
560
561
562
    QProcess *process = static_cast<QProcess *>(sender());
    QByteArray data = process->readAllStandardError();
    emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
563
564
}

565
void S60DeviceRunControlBase::readStandardOutput()
566
{
con's avatar
con committed
567
568
569
570
571
    QProcess *process = static_cast<QProcess *>(sender());
    QByteArray data = process->readAllStandardOutput();
    emit addToOutputWindowInline(this, QString::fromLocal8Bit(data.constData(), data.length()));
}

572
bool S60DeviceRunControlBase::createPackageFileFromTemplate(QString *errorMessage)
573
574
575
{
    QFile packageTemplate(m_packageTemplateFile);
    if (!packageTemplate.open(QIODevice::ReadOnly)) {
576
        *errorMessage = tr("Could not read template package file '%1'").arg(QDir::toNativeSeparators(m_packageTemplateFile));
577
578
579
580
581
582
583
584
        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)) {
585
        *errorMessage = tr("Could not write package file '%1'").arg(QDir::toNativeSeparators(m_packageFilePath));
586
587
588
589
590
591
592
        return false;
    }
    packageFile.write(contents.toLocal8Bit());
    packageFile.close();
    return true;
}

593
void S60DeviceRunControlBase::makesisProcessFailed()
594
{
595
    processFailed(m_makesisTool, m_makesis->error());
596
597
}

598
void S60DeviceRunControlBase::makesisProcessFinished()
599
{
600
    if (m_makesis->exitCode() != 0) {
601
        error(this, tr("An error occurred while creating the package."));
602
        stop();
603
604
605
        emit finished();
        return;
    }
606
607
608
609
610
611
612
613
614
615
616
617
618
    switch (m_toolChain) {
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
    case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC:
        startDeployment();
        break;
    default:
        startSigning();
        break;
    }
}

void S60DeviceRunControlBase::startSigning()
{
619
620
621
    QString signsisTool = m_toolsDirectory + QLatin1String("/signsis.exe");
    QString sisFile = QFileInfo(m_baseFileName + QLatin1String(".sis")).fileName();
    QString sisxFile = QFileInfo(m_baseFileName + QLatin1String(".sisx")).fileName();
con's avatar
con committed
622
    QString signature = (m_useCustomSignature ? m_customSignaturePath
623
                         : m_qtDir + QLatin1String("/src/s60installs/selfsigned.cer"));
con's avatar
con committed
624
    QString key = (m_useCustomSignature ? m_customKeyPath
625
                         : m_qtDir + QLatin1String("/src/s60installs/selfsigned.key"));
626
    QStringList arguments;
627
    arguments << sisFile
con's avatar
con committed
628
629
            << sisxFile << QDir::toNativeSeparators(signature)
            << QDir::toNativeSeparators(key);
630
    m_signsis->setWorkingDirectory(m_workingDirectory);
631
    emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(signsisTool), arguments.join(QString(QLatin1Char(' ')))));
632
633
634
    m_signsis->start(signsisTool, arguments, QIODevice::ReadOnly);
}

635
void S60DeviceRunControlBase::signsisProcessFailed()
636
637
638
639
{
    processFailed("signsis.exe", m_signsis->error());
}

640
void S60DeviceRunControlBase::signsisProcessFinished()
641
{
642
    if (m_signsis->exitCode() != 0) {
643
        error(this, tr("An error occurred while creating the package."));
644
        stop();
645
        emit finished();
646
647
    } else {
        startDeployment();
648
    }
649
650
651
652
}

void S60DeviceRunControlBase::startDeployment()
{
653
    m_launcher = new trk::Launcher();
654
    connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
655
    connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
656
    connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice()));
657
    connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(printCreateFileFailed(QString,QString)));
658
    connect(m_launcher, SIGNAL(canNotWriteFile(QString,QString)), this, SLOT(printWriteFileFailed(QString,QString)));
659
    connect(m_launcher, SIGNAL(canNotCloseFile(QString,QString)), this, SLOT(printCloseFileFailed(QString,QString)));
660
    connect(m_launcher, SIGNAL(installingStarted()), this, SLOT(printInstallingNotice()));
661
    connect(m_launcher, SIGNAL(canNotInstall(QString,QString)), this, SLOT(printInstallFailed(QString,QString)));
con's avatar
con committed
662
    connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(printCopyProgress(int)));
663
    connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
con's avatar
con committed
664

con's avatar
con committed
665
    //TODO sisx destination and file path user definable
666
    m_launcher->setTrkServerName(m_serialPortName);
667
    m_launcher->setSerialFrame(m_communicationType == SerialPortCommunication);
con's avatar
con committed
668
669
670
    const QString copySrc(m_baseFileName + ".sisx");
    const QString copyDst = QString("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName());
    const QString runFileName = QString("C:\\sys\\bin\\%1.exe").arg(m_targetName);
671
672
    m_launcher->setCopyFileName(copySrc, copyDst);
    m_launcher->setInstallFileName(copyDst);
673
    initLauncher(runFileName, m_launcher);
674
675
    emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(copySrc), m_serialPortFriendlyName));
    QString errorMessage;
676
677
678
679
680
681
682
683
684
685
686
687
    // Prompt the user to start up the Blue tooth connection    
    const trk::PromptStartCommunicationResult src =
            S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
                                                             m_serialPortName,
                                                             m_communicationType, 0,
                                                             &errorMessage);
    switch (src) {
    case trk::PromptStartCommunicationConnected:
        break;
    case trk::PromptStartCommunicationCanceled:
    case trk::PromptStartCommunicationError:
        error(this, errorMessage);
688
        stop();
689
690
691
692
        emit finished();
        return;
    };

693
    if (!m_launcher->startServer(&errorMessage)) {
694

695
        error(this, tr("Could not connect to phone on port '%1': %2\n"
Robert Loehning's avatar
Robert Loehning committed
696
                       "Check if the phone is connected and App TRK is running.").arg(m_serialPortName, errorMessage));
697
        stop();
con's avatar
con committed
698
699
        emit finished();
    }
700
701
}

702
void S60DeviceRunControlBase::printCreateFileFailed(const QString &filename, const QString &errorMessage)
con's avatar
con committed
703
{
704
    emit addToOutputWindow(this, tr("Could not create file %1 on device: %2").arg(filename, errorMessage));
con's avatar
con committed
705
706
}

707
708
709
710
711
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));
}

712
713
714
715
716
717
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));
}

718
719
720
721
722
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));
}

723
void S60DeviceRunControlBase::printCopyingNotice()
724
{
725
    emit addToOutputWindow(this, tr("Copying install file..."));
726
727
}

728
void S60DeviceRunControlBase::printCopyProgress(int progress)
con's avatar
con committed
729
730
{
    emit addToOutputWindow(this, tr("%1% copied.").arg(progress));
con's avatar
con committed
731
732
}

733
void S60DeviceRunControlBase::printInstallingNotice()
con's avatar
con committed
734
735
736
737
{
    emit addToOutputWindow(this, tr("Installing application..."));
}

738
739
740
741
742
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));
}

743
744
745
746
747
748
749
void S60DeviceRunControlBase::launcherFinished()
{
    m_launcher->deleteLater();
    m_launcher = 0;
    handleLauncherFinished();
}

750
751
752
QMessageBox *S60DeviceRunControlBase::createTrkWaitingMessageBox(const QString &port, QWidget *parent)
{
    const QString title  = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
Robert Loehning's avatar
Robert Loehning committed
753
                                                       "Waiting for App TRK");
754
    const QString text = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
Robert Loehning's avatar
Robert Loehning committed
755
                                                     "Please start App TRK on %1.").arg(port);
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
    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();
        error(this, tr("Canceled."));        
        emit finished();
    }
}

781
782
783
784
785
786
787
788
789
790
791
792
793
794
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));
795
    stop();
796
797
798
    emit finished();
}

Friedemann Kleint's avatar
Friedemann Kleint committed
799
800
801
802
803
void S60DeviceRunControlBase::printApplicationOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

804
805
806
807
808
809
810
bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
                                                 QString * /* settingsCategory */,
                                                 QString * /* settingsPage */) const
{
    return true;
}

811
// =============== S60DeviceRunControl
812
S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration) :
813
814
815
816
817
818
819
820
821
822
    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)));
823
     launcher->addStartupActions(trk::Launcher::ActionCopyInstallRun);
824
825
826
827
828
829
830
831
832
     launcher->setFileName(executable);
}

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

con's avatar
con committed
833
834
void S60DeviceRunControl::printStartingNotice()
{
835
    emit addToOutputWindow(this, tr("Starting application..."));
con's avatar
con committed
836
837
838
839
}

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

843
844
845
846
void S60DeviceRunControl::printRunFailNotice(const QString &errorMessage) {
    emit addToOutputWindow(this, tr("Could not start application: %1").arg(errorMessage));
}

847
848
// ======== S60DeviceDebugRunControl

849
S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration) :
850
851
    S60DeviceRunControlBase(runConfiguration),
    m_startParams(new Debugger::DebuggerStartParameters)
852
{
853
    Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
854
855
    S60DeviceRunConfiguration *rc = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
    QTC_ASSERT(dm && rc, return);
856
857
858
859

    connect(dm, SIGNAL(debuggingFinished()),
            this, SLOT(debuggingFinished()), Qt::QueuedConnection);
    connect(dm, SIGNAL(applicationOutputAvailable(QString)),
Friedemann Kleint's avatar
Friedemann Kleint committed
860
            this, SLOT(printApplicationOutput(QString)),
861
862
863
            Qt::QueuedConnection);

    m_startParams->remoteChannel = rc->serialPortName();
864
    m_startParams->remoteChannelType = rc->communicationType();
865
866
    m_startParams->startMode = Debugger::StartInternal;
    m_startParams->toolChainType = rc->toolChainType();
867
868
869
870
871
872

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

875
void S60DeviceDebugRunControl::stop()
con's avatar
con committed
876
{
877
878
879
880
881
882
883
884
885
886
887
    S60DeviceRunControlBase::stop();
    Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
    QTC_ASSERT(dm, return)
    if (dm->state() == Debugger::DebuggerNotReady)
        dm->exitDebugger();
}

S60DeviceDebugRunControl::~S60DeviceDebugRunControl()
{
}

888
void S60DeviceDebugRunControl::initLauncher(const QString &executable, trk::Launcher *launcher)
889
890
891
{
    // No setting an executable on the launcher causes it to deploy only
    m_startParams->executable = executable;
892
893
    // Prefer the '*.sym' file over the '.exe', which should exist at the same
    // location in debug builds
894
895
896
897

    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));
898
    }
899

900
    launcher->addStartupActions(trk::Launcher::ActionCopyInstall);
901
902
903
904
905
906
907
908
909
910
911
}

void S60DeviceDebugRunControl::handleLauncherFinished()
{
    emit addToOutputWindow(this, tr("Launching debugger..."));
    Debugger::DebuggerManager::instance()->startNewDebugger(m_startParams);
}

void S60DeviceDebugRunControl::debuggingFinished()
{
    emit addToOutputWindow(this, tr("Debugging finished."));
con's avatar
con committed
912
    emit finished();
913
}
914
915
916
917
918
919
920
921
922
923

bool S60DeviceDebugRunControl::checkConfiguration(QString *errorMessage,
                                                  QString *settingsCategory,
                                                  QString *settingsPage) const
{
    return Debugger::DebuggerManager::instance()->checkDebugConfiguration(m_startParams->toolChainType,
                                                                          errorMessage,
                                                                          settingsCategory,
                                                                          settingsPage);
}