s60devicerunconfiguration.cpp 28.2 KB
Newer Older
con's avatar
con committed
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** 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 "s60deployconfiguration.h"
33
#include "qt4project.h"
Tobias Hunger's avatar
Tobias Hunger committed
34
#include "qt4target.h"
35
36
37
38
#include "qtversionmanager.h"
#include "profilereader.h"
#include "s60manager.h"
#include "s60devices.h"
39
40
#include "s60runconfigbluetoothstarter.h"
#include "bluetoothlistener_gui.h"
41
#include "symbiandevicemanager.h"
42
#include "qt4buildconfiguration.h"
43
#include "qt4projectmanagerconstants.h"
44
#include "s60createpackagestep.h"
dt's avatar
dt committed
45
#include "qtoutputformatter.h"
46
47
48

#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
49
#include <coreplugin/progressmanager/progressmanager.h>
50
#include <utils/qtcassert.h>
con's avatar
con committed
51
#include <utils/pathchooser.h>
Tobias Hunger's avatar
Tobias Hunger committed
52
#include <projectexplorer/buildsteplist.h>
53
#include <projectexplorer/deployconfiguration.h>
54
55
56
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>

57
58
#include <debugger/debuggerengine.h>
#include <debugger/debuggerplugin.h>
59

60
61
#include <QtGui/QMessageBox>
#include <QtGui/QMainWindow>
62
#include <QtCore/QCoreApplication>
63

64
using namespace ProjectExplorer;
dt's avatar
dt committed
65
using namespace Qt4ProjectManager;
66
67
using namespace Qt4ProjectManager::Internal;

68
69
70
71
72
73
74
75
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 COMMUNICATION_TYPE_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.CommunicationType");
const char * const COMMAND_LINE_ARGUMENTS_KEY("Qt4ProjectManager.S60DeviceRunConfiguration.CommandLineArguments");

76
const int    PROGRESS_MAX = 200;
77

78
enum { debug = 0 };
79

80
// Format information about a file
81
static inline QString msgListFile(const QString &f)
82
83
84
85
{
    QString rc;
    const QFileInfo fi(f);
    QTextStream str(&rc);
86
87
88
89
90
    if (fi.exists()) {
        str << fi.size() << ' ' << fi.lastModified().toString(Qt::ISODate) << ' ' << QDir::toNativeSeparators(fi.absoluteFilePath());
    } else {
        str << "<non-existent> " << QDir::toNativeSeparators(fi.absoluteFilePath());
    }
91
92
    return rc;
}
93

94
95
96
97
98
99
100
101
102
103
104
105
106
107
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;
}

}

108
// ======== S60DeviceRunConfiguration
109

Tobias Hunger's avatar
Tobias Hunger committed
110
111
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QString &proFilePath) :
    RunConfiguration(parent,  QLatin1String(S60_DEVICE_RC_ID)),
112
    m_proFilePath(proFilePath)
113
114
115
116
{
    ctor();
}

Tobias Hunger's avatar
Tobias Hunger committed
117
118
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRunConfiguration *source) :
    RunConfiguration(target, source),
119
    m_proFilePath(source->m_proFilePath),
120
    m_commandLineArguments(source->m_commandLineArguments)
121
122
123
124
125
{
    ctor();
}

void S60DeviceRunConfiguration::ctor()
126
127
{
    if (!m_proFilePath.isEmpty())
128
129
        //: S60 device runconfiguration default display name, %1 is base pro-File name
        setDefaultDisplayName(tr("%1 on Symbian Device").arg(QFileInfo(m_proFilePath).completeBaseName()));
130
    else
131
132
        //: S60 device runconfiguration default display name (no profile set)
        setDefaultDisplayName(tr("Run on Symbian device"));
dt's avatar
dt committed
133
134
135
136
137
138
}

void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro)
{
    if (m_proFilePath == pro->path())
        emit targetInformationChanged();
139
140
141
142
143
144
}

S60DeviceRunConfiguration::~S60DeviceRunConfiguration()
{
}

Tobias Hunger's avatar
Tobias Hunger committed
145
Qt4Target *S60DeviceRunConfiguration::qt4Target() const
dt's avatar
dt committed
146
{
Tobias Hunger's avatar
Tobias Hunger committed
147
    return static_cast<Qt4Target *>(target());
dt's avatar
dt committed
148
149
}

150
151
152
ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainType(
        ProjectExplorer::BuildConfiguration *configuration) const
{
153
154
    if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(configuration))
        return bc->toolChainType();
155
156
157
    return ProjectExplorer::ToolChain::INVALID;
}

158
159
ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainType() const
{
Tobias Hunger's avatar
Tobias Hunger committed
160
    if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(target()->activeBuildConfiguration()))
161
        return bc->toolChainType();
162
    return ProjectExplorer::ToolChain::INVALID;
163
164
}

165
bool S60DeviceRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *configuration) const
166
{
167
168
169
170
171
172
173
174
175
176
177
178
    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;
179
180
}

181
QWidget *S60DeviceRunConfiguration::createConfigurationWidget()
182
183
184
185
{
    return new S60DeviceRunConfigurationWidget(this);
}

dt's avatar
dt committed
186
187
188
189
190
ProjectExplorer::OutputFormatter *S60DeviceRunConfiguration::createOutputFormatter() const
{
    return new QtOutputFormatter(qt4Target()->qt4Project());
}

191
QVariantMap S60DeviceRunConfiguration::toMap() const
192
{
193
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());
194
    const QDir projectDir = QDir(target()->project()->projectDirectory());
195
196
197
198
199

    map.insert(QLatin1String(PRO_FILE_KEY), projectDir.relativeFilePath(m_proFilePath));
    map.insert(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY), m_commandLineArguments);

    return map;
200
201
}

202
bool S60DeviceRunConfiguration::fromMap(const QVariantMap &map)
203
{
204
    const QDir projectDir = QDir(target()->project()->projectDirectory());
205
206
207
208

    m_proFilePath = projectDir.filePath(map.value(QLatin1String(PRO_FILE_KEY)).toString());
    m_commandLineArguments = map.value(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY)).toStringList();

209
210
211
212
213
214
    if (m_proFilePath.isEmpty())
        return false;
    if (!QFileInfo(m_proFilePath).exists())
        return false;
    setDefaultDisplayName(tr("%1 on Symbian Device").arg(QFileInfo(m_proFilePath).completeBaseName()));

215
    return RunConfiguration::fromMap(map);
con's avatar
con committed
216
217
}

dt's avatar
dt committed
218
219
220
221
222
223
224
static inline QString fixBaseNameTarget(const QString &in)
{
    if (in == QLatin1String("udeb"))
        return QLatin1String("debug");
    if (in == QLatin1String("urel"))
        return QLatin1String("release");
    return in;
225
226
}

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
QString S60DeviceRunConfiguration::targetName() const
{
    TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(projectFilePath());
    if (!ti.valid)
        return QString();
    return ti.target;
}

const QtVersion *S60DeviceRunConfiguration::qtVersion() const
{
    if (const BuildConfiguration *bc = target()->activeBuildConfiguration())
        if (const Qt4BuildConfiguration *qt4bc = qobject_cast<const Qt4BuildConfiguration *>(bc))
            return qt4bc->qtVersion();
    return 0;
}

bool S60DeviceRunConfiguration::isDebug() const
{
    const Qt4BuildConfiguration *qt4bc = qt4Target()->activeBuildConfiguration();
    return (qt4bc->qmakeBuildConfiguration() & QtVersion::DebugBuild);
}

QString S60DeviceRunConfiguration::symbianTarget() const
{
    return isDebug() ? QLatin1String("udeb") : QLatin1String("urel");
}

QString S60DeviceRunConfiguration::symbianPlatform() const
{
    const Qt4BuildConfiguration *qt4bc = qt4Target()->activeBuildConfiguration();
    switch (qt4bc->toolChainType()) {
    case ToolChain::GCCE:
    case ToolChain::GCCE_GNUPOC:
        return QLatin1String("gcce");
    case ToolChain::RVCT_ARMV5:
        return QLatin1String("armv5");
    default: // including ToolChain::RVCT_ARMV6_GNUPOC:
        return QLatin1String("armv6");
    }
}

/* 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)
{
    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();
}

QString S60DeviceRunConfiguration::localExecutableFileName() const
{
    QString localExecutable;
    switch (toolChainType()) {
    case ToolChain::GCCE_GNUPOC:
    case ToolChain::RVCT_ARMV5_GNUPOC: {
        TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(projectFilePath());
        if (!ti.valid)
            return QString();
        localExecutable = executableFromPackageUnix(ti.buildDir + QLatin1Char('/') + ti.target + QLatin1String("_template.pkg"));
        }
        break;
    default: {
            const QtVersion *qtv = qtVersion();
            QTC_ASSERT(qtv, return QString());
            const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(qtv);
            QTextStream(&localExecutable) << device.epocRoot << "/epoc32/release/"
                    << symbianPlatform() << '/' << symbianTarget() << '/' << targetName()
                    << ".exe";
        }
        break;
    }
    return QDir::toNativeSeparators(localExecutable);
}

quint32 S60DeviceRunConfiguration::executableUid() const
{
    quint32 uid = 0;
    QString executablePath(localExecutableFileName());
    if (!executablePath.isEmpty()) {
        QFile file(executablePath);
        if (file.open(QIODevice::ReadOnly)) {
            // executable's UID is 4 bytes starting at 8.
            const QByteArray data = file.read(12);
            if (data.size() == 12) {
                const unsigned char *d = reinterpret_cast<const unsigned char*>(data.data() + 8);
                uid = *d++;
                uid += *d++ << 8;
                uid += *d++ << 16;
                uid += *d++ << 24;
            }
        }
    }
    return uid;
}

342
QString S60DeviceRunConfiguration::projectFilePath() const
343
{
344
    return m_proFilePath;
345
346
}

347
348
349
350
351
352
353
354
355
356
QStringList S60DeviceRunConfiguration::commandLineArguments() const
{
    return m_commandLineArguments;
}

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

357
358
// ======== S60DeviceRunConfigurationFactory

359
360
S60DeviceRunConfigurationFactory::S60DeviceRunConfigurationFactory(QObject *parent) :
    IRunConfigurationFactory(parent)
361
362
363
364
365
366
367
{
}

S60DeviceRunConfigurationFactory::~S60DeviceRunConfigurationFactory()
{
}

Tobias Hunger's avatar
Tobias Hunger committed
368
QStringList S60DeviceRunConfigurationFactory::availableCreationIds(Target *parent) const
369
{
Tobias Hunger's avatar
Tobias Hunger committed
370
371
    Qt4Target *target = qobject_cast<Qt4Target *>(parent);
    if (!target ||
372
        target->id() != QLatin1String(Constants::S60_DEVICE_TARGET_ID))
373
374
        return QStringList();

Tobias Hunger's avatar
Tobias Hunger committed
375
    return target->qt4Project()->applicationProFilePathes(QLatin1String(S60_DEVICE_RC_PREFIX));
376
377
}

378
QString S60DeviceRunConfigurationFactory::displayNameForId(const QString &id) const
379
{
380
381
382
    if (!pathFromId(id).isEmpty())
        return tr("%1 on Symbian Device").arg(QFileInfo(pathFromId(id)).completeBaseName());
    return QString();
383
384
}

Tobias Hunger's avatar
Tobias Hunger committed
385
bool S60DeviceRunConfigurationFactory::canCreate(Target *parent, const QString &id) const
386
{
Tobias Hunger's avatar
Tobias Hunger committed
387
388
    Qt4Target * t(qobject_cast<Qt4Target *>(parent));
    if (!t ||
389
        t->id() != QLatin1String(Constants::S60_DEVICE_TARGET_ID))
390
        return false;
Tobias Hunger's avatar
Tobias Hunger committed
391
    return t->qt4Project()->hasApplicationProFile(pathFromId(id));
392
393
}

Tobias Hunger's avatar
Tobias Hunger committed
394
RunConfiguration *S60DeviceRunConfigurationFactory::create(Target *parent, const QString &id)
395
{
396
397
398
    if (!canCreate(parent, id))
        return 0;

Tobias Hunger's avatar
Tobias Hunger committed
399
400
    Qt4Target *t(static_cast<Qt4Target *>(parent));
    return new S60DeviceRunConfiguration(t, pathFromId(id));
401
402
}

Tobias Hunger's avatar
Tobias Hunger committed
403
bool S60DeviceRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
404
{
Tobias Hunger's avatar
Tobias Hunger committed
405
406
    Qt4Target * t(qobject_cast<Qt4Target *>(parent));
    if (!t ||
407
        t->id() != QLatin1String(Constants::S60_DEVICE_TARGET_ID))
408
409
410
411
412
        return false;
    QString id(ProjectExplorer::idFromMap(map));
    return id == QLatin1String(S60_DEVICE_RC_ID);
}

Tobias Hunger's avatar
Tobias Hunger committed
413
RunConfiguration *S60DeviceRunConfigurationFactory::restore(Target *parent, const QVariantMap &map)
414
415
416
{
    if (!canRestore(parent, map))
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
417
418
    Qt4Target *t(static_cast<Qt4Target *>(parent));
    S60DeviceRunConfiguration *rc(new S60DeviceRunConfiguration(t, QString()));
419
420
421
422
423
424
425
    if (rc->fromMap(map))
        return rc;

    delete rc;
    return 0;
}

Tobias Hunger's avatar
Tobias Hunger committed
426
bool S60DeviceRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const
427
{
Tobias Hunger's avatar
Tobias Hunger committed
428
    if (!qobject_cast<Qt4Target *>(parent))
429
430
431
432
        return false;
    return source->id() == QLatin1String(S60_DEVICE_RC_ID);
}

Tobias Hunger's avatar
Tobias Hunger committed
433
RunConfiguration *S60DeviceRunConfigurationFactory::clone(Target *parent, RunConfiguration *source)
434
435
436
{
    if (!canClone(parent, source))
        return 0;
Tobias Hunger's avatar
Tobias Hunger committed
437
    Qt4Target *t = static_cast<Qt4Target *>(parent);
438
    S60DeviceRunConfiguration * old(static_cast<S60DeviceRunConfiguration *>(source));
Tobias Hunger's avatar
Tobias Hunger committed
439
    return new S60DeviceRunConfiguration(t, old);
440
441
}

442
// ======== S60DeviceRunControlBase
Friedemann Kleint's avatar
Friedemann Kleint committed
443

444
S60DeviceRunControl::S60DeviceRunControl(RunConfiguration *runConfiguration, QString mode) :
dt's avatar
dt committed
445
    RunControl(runConfiguration, mode),
446
    m_toolChain(ProjectExplorer::ToolChain::INVALID),
447
    m_handleDeviceRemoval(true),
448
    m_launcher(0)
449
450
451
452
{
    // connect for automatically reporting the "finished deploy" state to the progress manager
    connect(this, SIGNAL(finished()), this, SLOT(reportDeployFinished()));

453
    S60DeviceRunConfiguration *s60runConfig = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
454
    const Qt4BuildConfiguration *activeBuildConf = s60runConfig->qt4Target()->activeBuildConfiguration();
455
    S60DeployConfiguration *activeDeployConf = qobject_cast<S60DeployConfiguration *>(s60runConfig->qt4Target()->activeDeployConfiguration());
dt's avatar
dt committed
456

457
    QTC_ASSERT(s60runConfig, return);
458
    m_toolChain = s60runConfig->toolChainType();
459
    m_serialPortName = activeDeployConf->serialPortName();
460
    m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
461
    m_targetName = s60runConfig->targetName();
462
    m_commandLineArguments = s60runConfig->commandLineArguments();
463
    m_qtDir = activeBuildConf->qtVersion()->versionInfo().value("QT_INSTALL_DATA");
464
465
    m_installationDrive = activeDeployConf->installationDrive();
    if (const QtVersion *qtv = activeDeployConf->qtVersion())
466
467
        m_qtBinPath = qtv->versionInfo().value(QLatin1String("QT_INSTALL_BINS"));
    QTC_ASSERT(!m_qtBinPath.isEmpty(), return);
468
    m_executableFileName = s60runConfig->localExecutableFileName();
469
    if (debug)
470
        qDebug() << "S60DeviceRunControl::CT" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
471
                 << m_serialPortName;
472
}
473

474
S60DeviceRunControl::~S60DeviceRunControl()
475
476
477
478
479
480
481
{
    if (m_launcher) {
        m_launcher->deleteLater();
        m_launcher = 0;
    }
}

482
void S60DeviceRunControl::start()
483
{
484
485
    m_launchProgress = new QFutureInterface<void>;
    Core::ICore::instance()->progressManager()->addTask(m_launchProgress->future(),
486
487
                                                        tr("Launching"),
                                                        QLatin1String("Symbian.Launch"));
488
489
490
    m_launchProgress->setProgressRange(0, PROGRESS_MAX);
    m_launchProgress->setProgressValue(0);
    m_launchProgress->reportStarted();
491
    emit started();
492
    if (m_serialPortName.isEmpty()) {
493
        m_launchProgress->reportCanceled();
494
        appendMessage(this, tr("There is no device plugged in."), true);
495
496
497
        emit finished();
        return;
    }
498

499
    emit appendMessage(this, tr("Executable file: %1").arg(msgListFile(m_executableFileName)), false);
con's avatar
con committed
500

501
502
503
504
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
    if (!checkConfiguration(&errorMessage, &settingsCategory, &settingsPage)) {
505
        m_launchProgress->reportCanceled();
506
        appendMessage(this, errorMessage, true);
507
        emit finished();
508
509
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger for Symbian Platform"),
                                                        errorMessage, QString(),
510
511
512
513
                                                        settingsCategory, settingsPage);
        return;
    }

514
    startLaunching();
515
516
}

517
RunControl::StopResult S60DeviceRunControl::stop()
518
519
520
{
    if (m_launcher)
        m_launcher->terminate();
521
    return AsynchronousStop;
522
523
}

524
bool S60DeviceRunControl::isRunning() const
525
{
526
527
528
    return m_launcher && (m_launcher->state() == trk::Launcher::Connecting
                          || m_launcher->state() == trk::Launcher::Connected
                          || m_launcher->state() == trk::Launcher::WaitingForTrk);
529
530
}

531
void S60DeviceRunControl::startLaunching()
532
{
533
    QString errorMessage;
534
    if (setupLauncher(errorMessage)) {
535
536
        if (m_launchProgress)
                    m_launchProgress->setProgressValue(PROGRESS_MAX/2);
537
    } else {
538
        if (!errorMessage.isEmpty())
539
            appendMessage(this, errorMessage, true);
540
        stop();
con's avatar
con committed
541
542
        emit finished();
    }
543
544
}

545
bool S60DeviceRunControl::setupLauncher(QString &errorMessage)
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
{
    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)
        return false;

    connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
    connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
    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)));

    if (!m_commandLineArguments.isEmpty())
        m_launcher->setCommandLineArgs(m_commandLineArguments);

    const QString runFileName = QString::fromLatin1("%1:\\sys\\bin\\%2.exe").arg(m_installationDrive).arg(m_targetName);
    initLauncher(runFileName, m_launcher);
    const trk::PromptStartCommunicationResult src =
            S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
                                                             0, &errorMessage);
    if (src != trk::PromptStartCommunicationConnected)
        return false;

    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);
        return false;
    }
    return true;
}

578
void S60DeviceRunControl::printConnectFailed(const QString &errorMessage)
579
{
580
    emit appendMessage(this, tr("Could not connect to App TRK on device: %1. Restarting App TRK might help.").arg(errorMessage), true);
581
582
}

583
void S60DeviceRunControl::launcherFinished()
584
{
585
586
    m_handleDeviceRemoval = false;
    trk::Launcher::releaseToDeviceManager(m_launcher);
587
588
589
590
591
    m_launcher->deleteLater();
    m_launcher = 0;
    handleLauncherFinished();
}

592
void S60DeviceRunControl::reportDeployFinished()
593
{
594
595
596
597
    if (m_launchProgress) {
        m_launchProgress->reportFinished();
        delete m_launchProgress;
        m_launchProgress = 0;
598
599
600
    }
}

601
void S60DeviceRunControl::processStopped(uint pc, uint pid, uint tid, const QString& reason)
602
{
603
    emit addToOutputWindow(this, trk::Launcher::msgStopped(pid, tid, pc, reason), false);
604
605
606
    m_launcher->terminate();
}

607
QMessageBox *S60DeviceRunControl::createTrkWaitingMessageBox(const QString &port, QWidget *parent)
608
{
Friedemann Kleint's avatar
Friedemann Kleint committed
609
610
611
612
613
    const QString title  = tr("Waiting for App TRK");
    const QString text = tr("Qt Creator is waiting for the TRK application to connect.<br>"
                            "Please make sure the application is running on "
                            "your mobile phone and the right port is "
                            "configured in the project settings.").arg(port);
614
615
616
617
618
    QMessageBox *rc = new QMessageBox(QMessageBox::Information, title, text,
                                      QMessageBox::Cancel, parent);
    return rc;
}

619
void S60DeviceRunControl::slotLauncherStateChanged(int s)
620
621
{
    if (s == trk::Launcher::WaitingForTrk) {
622
        QMessageBox *mb = S60DeviceRunControl::createTrkWaitingMessageBox(m_launcher->trkServerName(),
623
624
625
626
627
628
629
                                                     Core::ICore::instance()->mainWindow());
        connect(m_launcher, SIGNAL(stateChanged(int)), mb, SLOT(close()));
        connect(mb, SIGNAL(finished(int)), this, SLOT(slotWaitingForTrkClosed()));
        mb->open();
    }
}

630
void S60DeviceRunControl::slotWaitingForTrkClosed()
631
632
633
{
    if (m_launcher && m_launcher->state() == trk::Launcher::WaitingForTrk) {
        stop();
634
        appendMessage(this, tr("Canceled."), true);
635
636
637
638
        emit finished();
    }
}

639
void S60DeviceRunControl::printApplicationOutput(const QString &output)
640
641
642
643
{
    printApplicationOutput(output, false);
}

644
void S60DeviceRunControl::printApplicationOutput(const QString &output, bool onStdErr)
Friedemann Kleint's avatar
Friedemann Kleint committed
645
{
646
    emit addToOutputWindowInline(this, output, onStdErr);
Friedemann Kleint's avatar
Friedemann Kleint committed
647
648
}

649
void S60DeviceRunControl::deviceRemoved(const SymbianUtils::SymbianDevice &d)
650
651
{
    if (m_handleDeviceRemoval && d.portName() == m_serialPortName) {
652
        appendMessage(this, tr("The device '%1' has been disconnected").arg(d.friendlyName()), true);
653
654
655
656
        emit finished();
    }
}

657
bool S60DeviceRunControl::checkConfiguration(QString * /* errorMessage */,
658
659
660
661
662
663
                                                 QString * /* settingsCategory */,
                                                 QString * /* settingsPage */) const
{
    return true;
}

664
665
666
void S60DeviceRunControl::initLauncher(const QString &executable, trk::Launcher *launcher)
{
     connect(launcher, SIGNAL(startingApplication()), this, SLOT(printStartingNotice()));
667
668
     connect(launcher, SIGNAL(applicationRunning(uint)), this, SLOT(applicationRunNotice(uint)));
     connect(launcher, SIGNAL(canNotRun(QString)), this, SLOT(applicationRunFailedNotice(QString)));
669
     connect(launcher, SIGNAL(applicationOutputReceived(QString)), this, SLOT(printApplicationOutput(QString)));
670
     launcher->addStartupActions(trk::Launcher::ActionRun);
671
672
673
674
675
676
     launcher->setFileName(executable);
}

void S60DeviceRunControl::handleLauncherFinished()
{
     emit finished();
677
     emit appendMessage(this, tr("Finished."), false);
678
679
 }

con's avatar
con committed
680
681
void S60DeviceRunControl::printStartingNotice()
{
682
    emit appendMessage(this, tr("Starting application..."), false);
con's avatar
con committed
683
684
}

685
void S60DeviceRunControl::applicationRunNotice(uint pid)
con's avatar
con committed
686
{
687
    emit appendMessage(this, tr("Application running with pid %1.").arg(pid), false);
688
689
    if (m_launchProgress)
        m_launchProgress->setProgressValue(PROGRESS_MAX);
con's avatar
con committed
690
691
}

692
693
void S60DeviceRunControl::applicationRunFailedNotice(const QString &errorMessage)
{
694
    emit appendMessage(this, tr("Could not start application: %1").arg(errorMessage), true);
695
696
}

697
698
// ======== S60DeviceDebugRunControl

699
static inline QString localExecutable(const S60DeviceRunConfiguration *rc)
700
{
701
702
    if (const S60DeviceRunConfiguration *s60runConfig = qobject_cast<const S60DeviceRunConfiguration *>(rc))
        return s60runConfig->localExecutableFileName();
703
704
    return QString();
}
705

706
707
708
709
710
711
712
// Create start parameters from run configuration
Debugger::DebuggerStartParameters S60DeviceDebugRunControl::s60DebuggerStartParams(const S60DeviceRunConfiguration *rc)
{
    Debugger::DebuggerStartParameters sp;
    QTC_ASSERT(rc, return sp);

    const S60DeployConfiguration *activeDeployConf = qobject_cast<S60DeployConfiguration *>(rc->qt4Target()->activeDeployConfiguration());
713

714
    const QString debugFileName = QString::fromLatin1("%1:\\sys\\bin\\%2.exe")
715
            .arg(activeDeployConf->installationDrive()).arg(rc->targetName());
716

717
718
719
720
721
    sp.remoteChannel = activeDeployConf->serialPortName();
    sp.processArgs = rc->commandLineArguments();
    sp.startMode = Debugger::StartInternal;
    sp.toolChainType = rc->toolChainType();
    sp.executable = debugFileName;
722
    sp.executableUid = rc->executableUid();
723

724
    QTC_ASSERT(sp.executableUid, return sp);
725
726
727

    // Prefer the '*.sym' file over the '.exe', which should exist at the same
    // location in debug builds
728
729
730
731
732
733
    const QString localExecutableFileName = localExecutable(rc);
    const int lastDotPos = localExecutableFileName.lastIndexOf(QLatin1Char('.'));
    if (lastDotPos != -1) {
        const QString symbolFileName = localExecutableFileName.mid(0, lastDotPos) + QLatin1String(".sym");
        if (QFileInfo(symbolFileName).isFile())
            sp.symbolFileName = symbolFileName;
734
    }
735

736
737
738
739
740
741
742
743
744
745
746
747
    return sp;
}

S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *rc,
                                                   const QString &) :
    Debugger::DebuggerRunControl(rc, Debugger::GdbEngineType,
                                 S60DeviceDebugRunControl::s60DebuggerStartParams(rc))
{
    if (startParameters().symbolFileName.isEmpty()) {
        const QString msg = tr("Warning: Cannot locate the symbol file belonging to %1.").
                               arg(localExecutable(rc));
        emit appendMessage(this, msg, true);
748
    }
749
    connect(this, SIGNAL(finished()), this, SLOT(slotFinished()));
750
751
}

752
void S60DeviceDebugRunControl::start()
753
{
754
755
756
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
757
758
    if (!Debugger::DebuggerRunControl::checkDebugConfiguration(startParameters().toolChainType,
                                                               &errorMessage, &settingsCategory, &settingsPage)) {
759
760
761
762
763
764
        appendMessage(this, errorMessage, true);
        emit finished();
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger for Symbian Platform"),
                                                        errorMessage, QString(),
                                                        settingsCategory, settingsPage);
        return;
765
    }
766
767
768
769
770
771
772
    m_debugProgress.reset(new QFutureInterface<void>);
    Core::ICore::instance()->progressManager()->addTask(m_debugProgress->future(),
                                                        tr("Debugging"),
                                                        QLatin1String("Symbian.Debug"));
    m_debugProgress->setProgressRange(0, PROGRESS_MAX);
    m_debugProgress->setProgressValue(0);
    m_debugProgress->reportStarted();
773

774
    emit appendMessage(this, tr("Launching debugger..."), false);
775
    Debugger::DebuggerRunControl::start();
776
777
}

778
779
780
781
S60DeviceDebugRunControl::~S60DeviceDebugRunControl()
{
}

782
783
RunControl::StopResult S60DeviceDebugRunControl::stop()
{
784
    if (!m_debugProgress.isNull()) {
785
        m_debugProgress->reportCanceled();
786
787
788
        m_debugProgress.reset();
    }
    return Debugger::DebuggerRunControl::stop();
789
790
}

791
void S60DeviceDebugRunControl::slotFinished()
792
{
793
    if (!m_debugProgress.isNull()) {
794
795
        m_debugProgress->setProgressValue(PROGRESS_MAX);
        m_debugProgress->reportFinished();
796
        m_debugProgress.reset();
797
    }
798
}