devicemanager.cpp 17.1 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30
31
32
33
#include "devicemanager.h"

#include "idevicefactory.h"

#include <coreplugin/icore.h>
34
#include <coreplugin/id.h>
35
#include <extensionsystem/pluginmanager.h>
36
#include <projectexplorer/project.h>
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <utils/persistentsettings.h>
#include <utils/qtcassert.h>

#include <QFileInfo>
#include <QHash>
#include <QList>
#include <QSettings>
#include <QString>
#include <QVariantHash>
#include <QVariantList>

#include <limits>

namespace ProjectExplorer {
namespace Internal {

const char DeviceManagerKey[] = "DeviceManager";
const char DeviceListKey[] = "DeviceList";
const char DefaultDevicesKey[] = "DefaultDevices";

class DeviceManagerPrivate
{
public:
60
61
62
    DeviceManagerPrivate() : writer(0)
    { }

63
64
65
66
67
68
69
70
71
    int indexForId(Core::Id id) const
    {
        for (int i = 0; i < devices.count(); ++i) {
            if (devices.at(i)->id() == id)
                return i;
        }
        return -1;
    }

72
    static DeviceManager *instance;
73
74
    static DeviceManager *clonedInstance;
    QList<IDevice::Ptr> devices;
75
    QHash<Core::Id, Core::Id> defaultDevices;
Tobias Hunger's avatar
Tobias Hunger committed
76
77

    Utils::PersistentSettingsWriter *writer;
78
79
};
DeviceManager *DeviceManagerPrivate::clonedInstance = 0;
80
DeviceManager *DeviceManagerPrivate::instance = 0;
81
82
83
84
85
86

} // namespace Internal

using namespace Internal;


87
DeviceManager *DeviceManager::instance()
88
{
89
    return DeviceManagerPrivate::instance;
90
91
92
93
94
95
96
97
98
}

int DeviceManager::deviceCount() const
{
    return d->devices.count();
}

void DeviceManager::replaceInstance()
{
99
100
101
    copy(DeviceManagerPrivate::clonedInstance, instance(), false);
    emit instance()->deviceListChanged();
    emit instance()->updated();
102
103
104
105
106
107
108
109
110
111
112
113
}

void DeviceManager::removeClonedInstance()
{
    delete DeviceManagerPrivate::clonedInstance;
    DeviceManagerPrivate::clonedInstance = 0;
}

DeviceManager *DeviceManager::cloneInstance()
{
    QTC_ASSERT(!DeviceManagerPrivate::clonedInstance, return 0);

114
    DeviceManagerPrivate::clonedInstance = new DeviceManager(false);
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    copy(instance(), DeviceManagerPrivate::clonedInstance, true);
    return DeviceManagerPrivate::clonedInstance;
}

void DeviceManager::copy(const DeviceManager *source, DeviceManager *target, bool deep)
{
    if (deep) {
        foreach (const IDevice::ConstPtr &device, source->d->devices)
            target->d->devices << device->clone();
    } else {
        target->d->devices = source->d->devices;
    }
    target->d->defaultDevices = source->d->defaultDevices;
}

void DeviceManager::save()
{
132
    if (d->clonedInstance == this || !d->writer)
133
        return;
134
135
136
    QVariantMap data;
    data.insert(QLatin1String(DeviceManagerKey), toMap());
    d->writer->save(data, Core::ICore::mainWindow());
137
138
139
140
}

void DeviceManager::load()
{
141
142
143
144
145
146
147
    QTC_ASSERT(!d->writer, return);

    // Only create writer now: We do not want to save before the settings were read!
    d->writer = new Utils::PersistentSettingsWriter(
                settingsFilePath(QLatin1String("/qtcreator/devices.xml")),
                QLatin1String("QtCreatorDevices"));

148
    Utils::PersistentSettingsReader reader;
149
150
151
152
153
154
    // read devices file from global settings path
    QList<IDevice::Ptr> sdkDevices;
    if (reader.load(systemSettingsFilePath(QLatin1String("/qtcreator/devices.xml"))))
        sdkDevices = fromMap(reader.restoreValues().value(QLatin1String(DeviceManagerKey)).toMap());
    // read devices file from user settings path
    QList<IDevice::Ptr> userDevices;
Tobias Hunger's avatar
Tobias Hunger committed
155
    if (reader.load(settingsFilePath(QLatin1String("/qtcreator/devices.xml"))))
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
        userDevices = fromMap(reader.restoreValues().value(QLatin1String(DeviceManagerKey)).toMap());
    // Insert devices into the model. Prefer the higher device version when there are multiple
    // devices with the same id.
    foreach (IDevice::Ptr device, userDevices) {
        foreach (const IDevice::Ptr &sdkDevice, sdkDevices) {
            if (device->id() == sdkDevice->id()) {
                if (device->version() < sdkDevice->version())
                    device = sdkDevice;
                sdkDevices.removeOne(sdkDevice);
                break;
            }
        }
        d->devices << device;
    }
    // Append the new SDK devices to the model.
    d->devices << sdkDevices;

173
    ensureOneDefaultDevicePerType();
174
175

    emit devicesLoaded();
176
177
}

178
QList<IDevice::Ptr> DeviceManager::fromMap(const QVariantMap &map)
179
{
180
    QList<IDevice::Ptr> devices;
181
182
183
    const QVariantMap defaultDevsMap = map.value(QLatin1String(DefaultDevicesKey)).toMap();
    for (QVariantMap::ConstIterator it = defaultDevsMap.constBegin();
         it != defaultDevsMap.constEnd(); ++it) {
184
        d->defaultDevices.insert(Core::Id(it.key()), Core::Id(it.value().toString()));
185
186
187
188
    }
    const QVariantList deviceList = map.value(QLatin1String(DeviceListKey)).toList();
    foreach (const QVariant &v, deviceList) {
        const QVariantMap map = v.toMap();
189
        const IDeviceFactory * const factory = restoreFactory(map);
190
191
        if (!factory)
            continue;
192
        const IDevice::Ptr device = factory->restore(map);
193
        QTC_ASSERT(device, continue);
194
        addDevice(device);
195
    }
196
    return devices;
197
198
199
200
201
202
}

QVariantMap DeviceManager::toMap() const
{
    QVariantMap map;
    QVariantMap defaultDeviceMap;
203
    typedef QHash<Core::Id, Core::Id> TypeIdHash;
204
205
    for (TypeIdHash::ConstIterator it = d->defaultDevices.constBegin();
             it != d->defaultDevices.constEnd(); ++it) {
206
        defaultDeviceMap.insert(it.key().toString(), it.value().toString());
207
208
209
    }
    map.insert(QLatin1String(DefaultDevicesKey), defaultDeviceMap);
    QVariantList deviceList;
210
211
    foreach (const IDevice::ConstPtr &device, d->devices)
        deviceList << device->toMap();
212
213
214
215
    map.insert(QLatin1String(DeviceListKey), deviceList);
    return map;
}

216
Utils::FileName DeviceManager::settingsFilePath(const QString &extension)
217
{
218
    return Utils::FileName::fromString(QFileInfo(ExtensionSystem::PluginManager::settings()->fileName()).absolutePath() + extension);
219
220
}

221
222
223
224
225
226
227
Utils::FileName DeviceManager::systemSettingsFilePath(const QString &deviceFileRelativePath)
{
    return Utils::FileName::fromString(
              QFileInfo(ExtensionSystem::PluginManager::globalSettings()->fileName()).absolutePath()
              + deviceFileRelativePath);
}

228
void DeviceManager::addDevice(const IDevice::ConstPtr &_device)
229
{
230
    const IDevice::Ptr device = _device->clone();
231

232
233
234
235
    QStringList names;
    foreach (const IDevice::ConstPtr &tmp, d->devices) {
        if (tmp->id() != device->id())
            names << tmp->displayName();
236
    }
237

238
239
240
    device->setDisplayName(Project::makeUnique(device->displayName(), names));

    const int pos = d->indexForId(device->id());
241

242
    if (!defaultDevice(device->type()))
243
        d->defaultDevices.insert(device->type(), device->id());
244
    if (this == DeviceManagerPrivate::instance && d->clonedInstance)
245
        d->clonedInstance->addDevice(device->clone());
246
247

    if (pos >= 0) {
248
        d->devices[pos] = device;
249
250
251
252
        emit deviceUpdated(device->id());
    } else {
        d->devices << device;
        emit deviceAdded(device->id());
253
254
    }

255
256
257
    emit updated();
}

258
void DeviceManager::removeDevice(Core::Id id)
259
{
260
    const IDevice::Ptr device = mutableDevice(id);
261
    QTC_ASSERT(device, return);
262
    QTC_ASSERT(this != instance() || device->isAutoDetected(), return);
263

264
    const bool wasDefault = d->defaultDevices.value(device->type()) == device->id();
265
    const Core::Id deviceType = device->type();
266
    d->devices.removeAt(d->indexForId(id));
267
    emit deviceRemoved(device->id());
268
269
270
271

    if (wasDefault) {
        for (int i = 0; i < d->devices.count(); ++i) {
            if (deviceAt(i)->type() == deviceType) {
272
                d->defaultDevices.insert(deviceAt(i)->type(), deviceAt(i)->id());
273
                emit deviceUpdated(deviceAt(i)->id());
274
275
276
277
                break;
            }
        }
    }
278
279
    if (this == instance() && d->clonedInstance)
        d->clonedInstance->removeDevice(id);
280
281
282
283

    emit updated();
}

284
285
286
287
288
289
290
void DeviceManager::setDeviceState(Core::Id deviceId, IDevice::DeviceState deviceState)
{
    const int pos = d->indexForId(deviceId);
    QTC_ASSERT(pos != -1, return);
    IDevice::Ptr &device = d->devices[pos];
    if (device->deviceState() == deviceState)
        return;
291
292
293
294
295

    // To see the state change in the DeviceSettingsWidget
    if (this == instance() && d->clonedInstance)
        d->clonedInstance->setDeviceState(deviceId, deviceState);

296
297
298
299
300
    device->setDeviceState(deviceState);
    emit deviceUpdated(deviceId);
    emit updated();
}

301
302
303
304
305
bool DeviceManager::isLoaded() const
{
    return d->writer;
}

306
307
void DeviceManager::setDefaultDevice(int idx)
{
308
    QTC_ASSERT(this != instance(), return);
309
310
311
312
313
314
    QTC_ASSERT(idx >= 0 && idx < deviceCount(), return);

    const IDevice::ConstPtr &device = d->devices.at(idx);
    const IDevice::ConstPtr &oldDefaultDevice = defaultDevice(device->type());
    if (device == oldDefaultDevice)
        return;
315
    d->defaultDevices.insert(device->type(), device->id());
316
317
    emit deviceUpdated(device->id());
    emit deviceUpdated(oldDefaultDevice->id());
318
319
320
321

    emit updated();
}

322
const IDeviceFactory *DeviceManager::restoreFactory(const QVariantMap &map)
323
324
{
    const QList<IDeviceFactory *> &factories
325
        = ExtensionSystem::PluginManager::getObjects<IDeviceFactory>();
326
    foreach (const IDeviceFactory * const factory, factories) {
327
        if (factory->canRestore(map))
328
329
            return factory;
    }
330
331
332
    qWarning("Warning: No factory found for device '%s' of type '%s'.",
             qPrintable(IDevice::idFromMap(map).toString()),
             qPrintable(IDevice::typeFromMap(map).toString()));
333
334
335
    return 0;
}

336
DeviceManager::DeviceManager(bool isInstance) : d(new DeviceManagerPrivate)
337
{
338
339
    if (isInstance) {
        connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), SLOT(save()));
340
341
        QTC_CHECK(!DeviceManagerPrivate::instance);
        DeviceManagerPrivate::instance = this;
342
    }
343
344
345
346
}

DeviceManager::~DeviceManager()
{
347
348
    if (d->clonedInstance != this)
        delete d->writer;
349
350
351
352
353
354
355
356
357
    delete d;
}

IDevice::ConstPtr DeviceManager::deviceAt(int idx) const
{
    QTC_ASSERT(idx >= 0 && idx < deviceCount(), return IDevice::ConstPtr());
    return d->devices.at(idx);
}

358
IDevice::Ptr DeviceManager::mutableDevice(Core::Id id) const
359
{
360
    const int index = d->indexForId(id);
361
    return index == -1 ? IDevice::Ptr() : d->devices.at(index);
362
363
364
365
366
367
368
369
370
371
372
}

bool DeviceManager::hasDevice(const QString &name) const
{
    foreach (const IDevice::Ptr &device, d->devices) {
        if (device->displayName() == name)
            return true;
    }
    return false;
}

373
IDevice::ConstPtr DeviceManager::find(Core::Id id) const
374
{
375
    const int index = d->indexForId(id);
376
377
378
    return index == -1 ? IDevice::ConstPtr() : deviceAt(index);
}

379
IDevice::ConstPtr DeviceManager::defaultDevice(Core::Id deviceType) const
380
{
381
382
    const Core::Id id = d->defaultDevices.value(deviceType);
    return id.isValid() ? find(id) : IDevice::ConstPtr();
383
384
385
386
387
388
}

void DeviceManager::ensureOneDefaultDevicePerType()
{
    foreach (const IDevice::Ptr &device, d->devices) {
        if (!defaultDevice(device->type()))
389
            d->defaultDevices.insert(device->type(), device->id());
390
391
392
    }
}

393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
IDevice::Ptr DeviceManager::fromRawPointer(IDevice *device) const
{
    foreach (const IDevice::Ptr &devPtr, d->devices) {
        if (devPtr == device)
            return devPtr;
    }

    if (this == instance() && d->clonedInstance)
        return d->clonedInstance->fromRawPointer(device);

    qWarning("%s: Device not found.", Q_FUNC_INFO);
    return IDevice::Ptr();
}

IDevice::ConstPtr DeviceManager::fromRawPointer(const IDevice *device) const
{
    // The const_cast is safe, because we convert the Ptr back to a ConstPtr before returning it.
    return fromRawPointer(const_cast<IDevice *>(device));
}

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
} // namespace ProjectExplorer


#ifdef WITH_TESTS
#include "projectexplorer.h"
#include <QSignalSpy>
#include <QTest>
#include <QUuid>

namespace ProjectExplorer {

class TestDevice : public IDevice
{
public:
    TestDevice()
428
        : IDevice(testTypeId(), AutoDetected, Hardware, Core::Id::fromString(QUuid::createUuid().toString())) {}
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

    static Core::Id testTypeId() { return Core::Id("TestType"); }
private:
    TestDevice(const TestDevice &other) : IDevice(other) {}
    QString displayType() const { return QLatin1String("blubb"); }
    IDeviceWidget *createWidget() { return 0; }
    QList<Core::Id> actionIds() const { return QList<Core::Id>(); }
    QString displayNameForActionId(Core::Id) const { return QString(); }
    void executeAction(Core::Id, QWidget *) const { }
    Ptr clone() const { return Ptr(new TestDevice(*this)); }
};

void ProjectExplorerPlugin::testDeviceManager()
{
    TestDevice::Ptr dev = IDevice::Ptr(new TestDevice);
    dev->setDisplayName(QLatin1String("blubbdiblubbfurz!"));
    QVERIFY(dev->isAutoDetected());
446
    QCOMPARE(dev->deviceState(), IDevice::DeviceStateUnknown);
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    QCOMPARE(dev->type(), TestDevice::testTypeId());

    TestDevice::Ptr dev2 = dev->clone();
    QCOMPARE(dev->id(), dev2->id());

    DeviceManager * const mgr = DeviceManager::instance();
    QVERIFY(!mgr->find(dev->id()));
    const int oldDeviceCount = mgr->deviceCount();

    QSignalSpy deviceAddedSpy(mgr, SIGNAL(deviceAdded(Core::Id)));
    QSignalSpy deviceRemovedSpy(mgr, SIGNAL(deviceRemoved(Core::Id)));
    QSignalSpy deviceUpdatedSpy(mgr, SIGNAL(deviceUpdated(Core::Id)));
    QSignalSpy deviceListChangedSpy(mgr, SIGNAL(deviceListChanged()));
    QSignalSpy updatedSpy(mgr, SIGNAL(updated()));

    mgr->addDevice(dev);
    QCOMPARE(mgr->deviceCount(), oldDeviceCount + 1);
    QVERIFY(mgr->find(dev->id()));
    QVERIFY(mgr->hasDevice(dev->displayName()));
    QCOMPARE(deviceAddedSpy.count(), 1);
    QCOMPARE(deviceRemovedSpy.count(), 0);
    QCOMPARE(deviceUpdatedSpy.count(), 0);
    QCOMPARE(deviceListChangedSpy.count(), 0);
    QCOMPARE(updatedSpy.count(), 1);
    deviceAddedSpy.clear();
    updatedSpy.clear();

474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
    mgr->setDeviceState(dev->id(), IDevice::DeviceStateUnknown);
    QCOMPARE(deviceAddedSpy.count(), 0);
    QCOMPARE(deviceRemovedSpy.count(), 0);
    QCOMPARE(deviceUpdatedSpy.count(), 0);
    QCOMPARE(deviceListChangedSpy.count(), 0);
    QCOMPARE(updatedSpy.count(), 0);

    mgr->setDeviceState(dev->id(), IDevice::DeviceReadyToUse);
    QCOMPARE(mgr->find(dev->id())->deviceState(), IDevice::DeviceReadyToUse);
    QCOMPARE(deviceAddedSpy.count(), 0);
    QCOMPARE(deviceRemovedSpy.count(), 0);
    QCOMPARE(deviceUpdatedSpy.count(), 1);
    QCOMPARE(deviceListChangedSpy.count(), 0);
    QCOMPARE(updatedSpy.count(), 1);
    deviceUpdatedSpy.clear();
    updatedSpy.clear();

491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
    mgr->addDevice(dev2);
    QCOMPARE(mgr->deviceCount(), oldDeviceCount + 1);
    QVERIFY(mgr->find(dev->id()));
    QCOMPARE(deviceAddedSpy.count(), 0);
    QCOMPARE(deviceRemovedSpy.count(), 0);
    QCOMPARE(deviceUpdatedSpy.count(), 1);
    QCOMPARE(deviceListChangedSpy.count(), 0);
    QCOMPARE(updatedSpy.count(), 1);
    deviceUpdatedSpy.clear();
    updatedSpy.clear();

    TestDevice::Ptr dev3 = IDevice::Ptr(new TestDevice);
    QVERIFY(dev->id() != dev3->id());

    dev3->setDisplayName(dev->displayName());
    mgr->addDevice(dev3);
    QCOMPARE(mgr->deviceAt(mgr->deviceCount() - 1)->displayName(),
508
             QString(dev3->displayName() + QLatin1String("2")));
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
    QCOMPARE(deviceAddedSpy.count(), 1);
    QCOMPARE(deviceRemovedSpy.count(), 0);
    QCOMPARE(deviceUpdatedSpy.count(), 0);
    QCOMPARE(deviceListChangedSpy.count(), 0);
    QCOMPARE(updatedSpy.count(), 1);
    deviceAddedSpy.clear();
    updatedSpy.clear();

    mgr->removeDevice(dev->id());
    mgr->removeDevice(dev3->id());
    QCOMPARE(mgr->deviceCount(), oldDeviceCount);
    QVERIFY(!mgr->find(dev->id()));
    QVERIFY(!mgr->find(dev3->id()));
    QCOMPARE(deviceAddedSpy.count(), 0);
    QCOMPARE(deviceRemovedSpy.count(), 2);
//    QCOMPARE(deviceUpdatedSpy.count(), 0); Uncomment once the "default" stuff is gone.
    QCOMPARE(deviceListChangedSpy.count(), 0);
    QCOMPARE(updatedSpy.count(), 2);
}
528

529
} // namespace ProjectExplorer
530
531

#endif // WITH_TESTS