1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "kitmanager.h"
27
28 #include "abi.h"
29 #include "devicesupport/idevicefactory.h"
30 #include "kit.h"
31 #include "kitfeatureprovider.h"
32 #include "kitinformation.h"
33 #include "kitmanagerconfigwidget.h"
34 #include "project.h"
35 #include "projectexplorerconstants.h"
36 #include "task.h"
37 #include "toolchainmanager.h"
38
39 #include <coreplugin/icore.h>
40
41 #include <android/androidconstants.h>
42 #include <baremetal/baremetalconstants.h>
43 #include <qnx/qnxconstants.h>
44 #include <remotelinux/remotelinux_constants.h>
45
46 #include <utils/environment.h>
47 #include <utils/layoutbuilder.h>
48 #include <utils/persistentsettings.h>
49 #include <utils/pointeralgorithm.h>
50 #include <utils/qtcassert.h>
51 #include <utils/stringutils.h>
52
53 #include <QAction>
54 #include <QHash>
55 #include <QLabel>
56 #include <QPushButton>
57 #include <QSettings>
58 #include <QStyle>
59
60 using namespace Core;
61 using namespace Utils;
62 using namespace ProjectExplorer::Internal;
63
64 namespace ProjectExplorer {
65
66 class KitList
67 {
68 public:
69 Utils::Id defaultKit;
70 std::vector<std::unique_ptr<Kit>> kits;
71 };
72
73 static KitList restoreKitsHelper(const Utils::FilePath &fileName);
74
75 namespace Internal {
76
77 const char KIT_DATA_KEY[] = "Profile.";
78 const char KIT_COUNT_KEY[] = "Profile.Count";
79 const char KIT_FILE_VERSION_KEY[] = "Version";
80 const char KIT_DEFAULT_KEY[] = "Profile.Default";
81 const char KIT_IRRELEVANT_ASPECTS_KEY[] = "Kit.IrrelevantAspects";
82 const char KIT_FILENAME[] = "profiles.xml";
83
settingsFileName()84 static FilePath settingsFileName()
85 {
86 return ICore::userResourcePath(KIT_FILENAME);
87 }
88
89 // --------------------------------------------------------------------------
90 // KitManagerPrivate:
91 // --------------------------------------------------------------------------
92
93 class KitManagerPrivate
94 {
95 public:
96 Kit *m_defaultKit = nullptr;
97 bool m_initialized = false;
98 std::vector<std::unique_ptr<Kit>> m_kitList;
99 std::unique_ptr<PersistentSettingsWriter> m_writer;
100 QSet<Id> m_irrelevantAspects;
101
addKitAspect(KitAspect * ki)102 void addKitAspect(KitAspect *ki)
103 {
104 QTC_ASSERT(!m_aspectList.contains(ki), return);
105 m_aspectList.append(ki);
106 m_aspectListIsSorted = false;
107 }
108
removeKitAspect(KitAspect * ki)109 void removeKitAspect(KitAspect *ki)
110 {
111 int removed = m_aspectList.removeAll(ki);
112 QTC_CHECK(removed == 1);
113 }
114
kitAspects()115 const QList<KitAspect *> kitAspects()
116 {
117 if (!m_aspectListIsSorted) {
118 Utils::sort(m_aspectList, [](const KitAspect *a, const KitAspect *b) {
119 return a->priority() > b->priority();
120 });
121 m_aspectListIsSorted = true;
122 }
123 return m_aspectList;
124 }
125
setBinaryForKit(const FilePath & fp)126 void setBinaryForKit(const FilePath &fp) { m_binaryForKit = fp; }
binaryForKit() const127 FilePath binaryForKit() const { return m_binaryForKit; }
128
129 private:
130 // Sorted by priority, in descending order...
131 QList<KitAspect *> m_aspectList;
132 // ... if this here is set:
133 bool m_aspectListIsSorted = true;
134
135 FilePath m_binaryForKit;
136 };
137
138 } // namespace Internal
139
140 // --------------------------------------------------------------------------
141 // KitManager:
142 // --------------------------------------------------------------------------
143
144 static Internal::KitManagerPrivate *d = nullptr;
145 static KitManager *m_instance = nullptr;
146
instance()147 KitManager *KitManager::instance()
148 {
149 if (!m_instance)
150 m_instance = new KitManager;
151 return m_instance;
152 }
153
KitManager()154 KitManager::KitManager()
155 {
156 d = new KitManagerPrivate;
157 QTC_CHECK(!m_instance);
158 m_instance = this;
159
160 connect(ICore::instance(), &ICore::saveSettingsRequested, this, &KitManager::saveKits);
161
162 connect(this, &KitManager::kitAdded, this, &KitManager::kitsChanged);
163 connect(this, &KitManager::kitRemoved, this, &KitManager::kitsChanged);
164 connect(this, &KitManager::kitUpdated, this, &KitManager::kitsChanged);
165 }
166
destroy()167 void KitManager::destroy()
168 {
169 delete d;
170 d = nullptr;
171 delete m_instance;
172 m_instance = nullptr;
173 }
174
restoreKits()175 void KitManager::restoreKits()
176 {
177 QTC_ASSERT(!d->m_initialized, return );
178
179 std::vector<std::unique_ptr<Kit>> resultList;
180
181 // read all kits from user file
182 Utils::Id defaultUserKit;
183 std::vector<std::unique_ptr<Kit>> kitsToCheck;
184 {
185 KitList userKits = restoreKitsHelper(settingsFileName());
186 defaultUserKit = userKits.defaultKit;
187
188 for (auto &k : userKits.kits) {
189 if (k->isSdkProvided()) {
190 kitsToCheck.emplace_back(std::move(k));
191 } else {
192 completeKit(k.get()); // Store manual kits
193 resultList.emplace_back(std::move(k));
194 }
195 }
196 }
197
198 // read all kits from SDK
199 {
200 KitList system = restoreKitsHelper(ICore::installerResourcePath(KIT_FILENAME));
201
202 // SDK kits need to get updated with the user-provided extra settings:
203 for (auto ¤t : system.kits) {
204 // make sure we mark these as autodetected and run additional setup logic
205 current->setAutoDetected(true);
206 current->setSdkProvided(true);
207 current->makeSticky();
208
209 // Process:
210 auto toStore = std::move(current);
211 toStore->upgrade();
212 toStore->setup(); // Make sure all kitinformation are properly set up before merging them
213 // with the information from the user settings file
214
215 // Check whether we had this kit stored and prefer the stored one:
216 const auto i = std::find_if(std::begin(kitsToCheck),
217 std::end(kitsToCheck),
218 Utils::equal(&Kit::id, toStore->id()));
219 if (i != std::end(kitsToCheck)) {
220 Kit *ptr = i->get();
221
222 // Overwrite settings that the SDK sets to those values:
223 for (const KitAspect *aspect : KitManager::kitAspects()) {
224 // Copy sticky settings over:
225 ptr->setSticky(aspect->id(), toStore->isSticky(aspect->id()));
226 if (ptr->isSticky(aspect->id()))
227 ptr->setValue(aspect->id(), toStore->value(aspect->id()));
228 }
229 toStore = std::move(*i);
230 kitsToCheck.erase(i);
231 }
232 completeKit(toStore.get()); // Store manual kits
233 resultList.emplace_back(std::move(toStore));
234 }
235 }
236
237 // Delete all loaded autodetected kits that were not rediscovered:
238 kitsToCheck.clear();
239
240 // Remove replacement kits for which the original kit has turned up again.
241 Utils::erase(resultList, [&resultList](const std::unique_ptr<Kit> &k) {
242 return k->isReplacementKit()
243 && contains(resultList, [&k](const std::unique_ptr<Kit> &other) {
244 return other->id() == k->id() && other != k;
245 });
246 });
247
248 static const auto kitMatchesAbiList = [](const Kit *kit, const Abis &abis) {
249 const QList<ToolChain *> toolchains = ToolChainKitAspect::toolChains(kit);
250 for (const ToolChain * const tc : toolchains) {
251 const Abi tcAbi = tc->targetAbi();
252 for (const Abi &abi : abis) {
253 if (tcAbi.os() == abi.os() && tcAbi.architecture() == abi.architecture()
254 && (tcAbi.os() != Abi::LinuxOS || tcAbi.osFlavor() == abi.osFlavor())) {
255 return true;
256 }
257 }
258 }
259 return false;
260 };
261
262 const Abis abisOfBinary = d->binaryForKit().isEmpty()
263 ? Abis() : Abi::abisOfBinary(d->binaryForKit());
264 const auto kitMatchesAbiOfBinary = [&abisOfBinary](const Kit *kit) {
265 return kitMatchesAbiList(kit, abisOfBinary);
266 };
267 const bool haveKitForBinary = abisOfBinary.isEmpty()
268 || contains(resultList, [&kitMatchesAbiOfBinary](const std::unique_ptr<Kit> &kit) {
269 return kitMatchesAbiOfBinary(kit.get());
270 });
271 Kit *kitForBinary = nullptr;
272
273 if (resultList.empty() || !haveKitForBinary) {
274 // No kits exist yet, so let's try to autoconfigure some from the toolchains we know.
275 QHash<Abi, QHash<Utils::Id, ToolChain *>> uniqueToolchains;
276
277 // On Linux systems, we usually detect a plethora of same-ish toolchains. The following
278 // algorithm gives precedence to icecc and ccache and otherwise simply chooses the one with
279 // the shortest path. This should also take care of ensuring matching C/C++ pairs.
280 // TODO: This should not need to be done here. Instead, it should be a convenience
281 // operation on some lower level, e.g. in the toolchain class(es).
282 // Also, we shouldn't detect so many doublets in the first place.
283 for (ToolChain * const tc : ToolChainManager::toolChains()) {
284 ToolChain *&bestTc = uniqueToolchains[tc->targetAbi()][tc->language()];
285 if (!bestTc) {
286 bestTc = tc;
287 continue;
288 }
289 const QString bestFilePath = bestTc->compilerCommand().toString();
290 const QString currentFilePath = tc->compilerCommand().toString();
291 if (bestFilePath.contains("icecc"))
292 continue;
293 if (currentFilePath.contains("icecc")) {
294 bestTc = tc;
295 continue;
296 }
297
298 if (bestFilePath.contains("ccache"))
299 continue;
300 if (currentFilePath.contains("ccache")) {
301 bestTc = tc;
302 continue;
303 }
304 if (bestFilePath.length() > currentFilePath.length())
305 bestTc = tc;
306 }
307
308 static const auto isHostKit = [](const Kit *kit) {
309 return kitMatchesAbiList(kit, {Abi::hostAbi()});
310 };
311
312 static const auto deviceTypeForKit = [](const Kit *kit) {
313 if (isHostKit(kit))
314 return Constants::DESKTOP_DEVICE_TYPE;
315 const QList<ToolChain *> toolchains = ToolChainKitAspect::toolChains(kit);
316 for (const ToolChain * const tc : toolchains) {
317 const Abi tcAbi = tc->targetAbi();
318 switch (tcAbi.os()) {
319 case Abi::BareMetalOS:
320 return BareMetal::Constants::BareMetalOsType;
321 case Abi::BsdOS:
322 case Abi::DarwinOS:
323 case Abi::UnixOS:
324 return RemoteLinux::Constants::GenericLinuxOsType;
325 case Abi::LinuxOS:
326 if (tcAbi.osFlavor() == Abi::AndroidLinuxFlavor)
327 return Android::Constants::ANDROID_DEVICE_TYPE;
328 return RemoteLinux::Constants::GenericLinuxOsType;
329 case Abi::QnxOS:
330 return Qnx::Constants::QNX_QNX_OS_TYPE;
331 case Abi::VxWorks:
332 return "VxWorks.Device.Type";
333 default:
334 break;
335 }
336 }
337 return Constants::DESKTOP_DEVICE_TYPE;
338 };
339
340 // Create temporary kits for all toolchains found.
341 decltype(resultList) tempList;
342 for (auto it = uniqueToolchains.cbegin(); it != uniqueToolchains.cend(); ++it) {
343 auto kit = std::make_unique<Kit>();
344 kit->setSdkProvided(false);
345 kit->setAutoDetected(false); // TODO: Why false? What does autodetected mean here?
346 for (ToolChain * const tc : it.value())
347 ToolChainKitAspect::setToolChain(kit.get(), tc);
348 if (contains(resultList, [&kit](const std::unique_ptr<Kit> &existingKit) {
349 return ToolChainKitAspect::toolChains(kit.get())
350 == ToolChainKitAspect::toolChains(existingKit.get());
351 })) {
352 continue;
353 }
354 if (isHostKit(kit.get()))
355 kit->setUnexpandedDisplayName(tr("Desktop (%1)").arg(it.key().toString()));
356 else
357 kit->setUnexpandedDisplayName(it.key().toString());
358 DeviceTypeKitAspect::setDeviceTypeId(kit.get(), deviceTypeForKit(kit.get()));
359 kit->setup();
360 tempList.emplace_back(std::move(kit));
361 }
362
363 // Now make the "best" temporary kits permanent. The logic is as follows:
364 // - If the user has requested a kit for a given binary and one or more kits
365 // with a matching ABI exist, then we randomly choose exactly one among those with
366 // the highest weight.
367 // - If the user has not requested a kit for a given binary or no such kit could
368 // be created, we choose all kits with the highest weight. If none of these
369 // is a host kit, then we also add the host kit with the highest weight.
370 Utils::sort(tempList, [](const std::unique_ptr<Kit> &k1, const std::unique_ptr<Kit> &k2) {
371 return k1->weight() > k2->weight();
372 });
373 if (!abisOfBinary.isEmpty()) {
374 for (auto it = tempList.begin(); it != tempList.end(); ++it) {
375 if (kitMatchesAbiOfBinary(it->get())) {
376 kitForBinary = it->get();
377 resultList.emplace_back(std::move(*it));
378 tempList.erase(it);
379 break;
380 }
381 }
382 }
383 QList<Kit *> hostKits;
384 if (!kitForBinary && !tempList.empty()) {
385 const int maxWeight = tempList.front()->weight();
386 for (auto it = tempList.begin(); it != tempList.end(); it = tempList.erase(it)) {
387 if ((*it)->weight() < maxWeight)
388 break;
389 if (isHostKit(it->get()))
390 hostKits << it->get();
391 resultList.emplace_back(std::move(*it));
392 }
393 if (!contains(resultList, [](const std::unique_ptr<Kit> &kit) {
394 return isHostKit(kit.get());})) {
395 QTC_ASSERT(hostKits.isEmpty(), hostKits.clear());
396 for (auto &kit : tempList) {
397 if (isHostKit(kit.get())) {
398 hostKits << kit.get();
399 resultList.emplace_back(std::move(kit));
400 break;
401 }
402 }
403 }
404 }
405
406 if (hostKits.size() == 1)
407 hostKits.first()->setUnexpandedDisplayName(tr("Desktop"));
408 }
409
410 Kit *k = kitForBinary;
411 if (!k)
412 k = Utils::findOrDefault(resultList, Utils::equal(&Kit::id, defaultUserKit));
413 if (!k)
414 k = Utils::findOrDefault(resultList, &Kit::isValid);
415 std::swap(resultList, d->m_kitList);
416 setDefaultKit(k);
417
418 d->m_writer = std::make_unique<PersistentSettingsWriter>(settingsFileName(), "QtCreatorProfiles");
419 d->m_initialized = true;
420 emit m_instance->kitsLoaded();
421 emit m_instance->kitsChanged();
422 }
423
~KitManager()424 KitManager::~KitManager()
425 {
426 }
427
saveKits()428 void KitManager::saveKits()
429 {
430 QTC_ASSERT(d, return);
431 if (!d->m_writer) // ignore save requests while we are not initialized.
432 return;
433
434 QVariantMap data;
435 data.insert(QLatin1String(KIT_FILE_VERSION_KEY), 1);
436
437 int count = 0;
438 foreach (Kit *k, kits()) {
439 QVariantMap tmp = k->toMap();
440 if (tmp.isEmpty())
441 continue;
442 data.insert(QString::fromLatin1(KIT_DATA_KEY) + QString::number(count), tmp);
443 ++count;
444 }
445 data.insert(QLatin1String(KIT_COUNT_KEY), count);
446 data.insert(QLatin1String(KIT_DEFAULT_KEY),
447 d->m_defaultKit ? QString::fromLatin1(d->m_defaultKit->id().name()) : QString());
448 data.insert(KIT_IRRELEVANT_ASPECTS_KEY,
449 transform<QVariantList>(d->m_irrelevantAspects, &Id::toSetting));
450 d->m_writer->save(data, ICore::dialogParent());
451 }
452
isLoaded()453 bool KitManager::isLoaded()
454 {
455 return d->m_initialized;
456 }
457
registerKitAspect(KitAspect * ki)458 void KitManager::registerKitAspect(KitAspect *ki)
459 {
460 instance();
461 QTC_ASSERT(d, return);
462 d->addKitAspect(ki);
463
464 // Adding this aspect to possibly already existing kits is currently not
465 // needed here as kits are only created after all aspects are created
466 // in *Plugin::initialize().
467 // Make sure we notice when this assumption breaks:
468 QTC_CHECK(d->m_kitList.empty());
469 }
470
deregisterKitAspect(KitAspect * ki)471 void KitManager::deregisterKitAspect(KitAspect *ki)
472 {
473 // Happens regularly for the aspects from the ProjectExplorerPlugin as these
474 // are destroyed after the manual call to KitManager::destroy() there, but as
475 // this here is just for sanity reasons that the KitManager does not access
476 // a destroyed aspect, a destroyed KitManager is not a problem.
477 if (d)
478 d->removeKitAspect(ki);
479 }
480
setBinaryForKit(const FilePath & binary)481 void KitManager::setBinaryForKit(const FilePath &binary)
482 {
483 QTC_ASSERT(d, return);
484 d->setBinaryForKit(binary);
485 }
486
sortKits(const QList<Kit * > & kits)487 QList<Kit *> KitManager::sortKits(const QList<Kit *> &kits)
488 {
489 // This method was added to delay the sorting of kits as long as possible.
490 // Since the displayName can contain variables it can be costly (e.g. involve
491 // calling executables to find version information, etc.) to call that
492 // method!
493 // Avoid lots of potentially expensive calls to Kit::displayName():
494 QList<QPair<QString, Kit *>> sortList = Utils::transform(kits, [](Kit *k) {
495 return qMakePair(k->displayName(), k);
496 });
497 Utils::sort(sortList,
498 [](const QPair<QString, Kit *> &a, const QPair<QString, Kit *> &b) -> bool {
499 if (a.first == b.first)
500 return a.second < b.second;
501 return a.first < b.first;
502 });
503 return Utils::transform(sortList, &QPair<QString, Kit *>::second);
504 }
505
restoreKitsHelper(const FilePath & fileName)506 static KitList restoreKitsHelper(const FilePath &fileName)
507 {
508 KitList result;
509
510 if (!fileName.exists())
511 return result;
512
513 PersistentSettingsReader reader;
514 if (!reader.load(fileName)) {
515 qWarning("Warning: Failed to read \"%s\", cannot restore kits!",
516 qPrintable(fileName.toUserOutput()));
517 return result;
518 }
519 QVariantMap data = reader.restoreValues();
520
521 // Check version:
522 int version = data.value(QLatin1String(KIT_FILE_VERSION_KEY), 0).toInt();
523 if (version < 1) {
524 qWarning("Warning: Kit file version %d not supported, cannot restore kits!", version);
525 return result;
526 }
527
528 const int count = data.value(QLatin1String(KIT_COUNT_KEY), 0).toInt();
529 for (int i = 0; i < count; ++i) {
530 const QString key = QString::fromLatin1(KIT_DATA_KEY) + QString::number(i);
531 if (!data.contains(key))
532 break;
533
534 const QVariantMap stMap = data.value(key).toMap();
535
536 auto k = std::make_unique<Kit>(stMap);
537 if (k->id().isValid()) {
538 result.kits.emplace_back(std::move(k));
539 } else {
540 qWarning("Warning: Unable to restore kits stored in %s at position %d.",
541 qPrintable(fileName.toUserOutput()),
542 i);
543 }
544 }
545 const Id id = Id::fromSetting(data.value(QLatin1String(KIT_DEFAULT_KEY)));
546 if (!id.isValid())
547 return result;
548
549 if (Utils::contains(result.kits, [id](const std::unique_ptr<Kit> &k) { return k->id() == id; }))
550 result.defaultKit = id;
551 const auto it = data.constFind(KIT_IRRELEVANT_ASPECTS_KEY);
552 if (it != data.constEnd())
553 d->m_irrelevantAspects = transform<QSet<Id>>(it.value().toList(), &Id::fromSetting);
554
555 return result;
556 }
557
kits()558 const QList<Kit *> KitManager::kits()
559 {
560 return Utils::toRawPointer<QList>(d->m_kitList);
561 }
562
kit(Id id)563 Kit *KitManager::kit(Id id)
564 {
565 if (!id.isValid())
566 return nullptr;
567
568 return Utils::findOrDefault(d->m_kitList, Utils::equal(&Kit::id, id));
569 }
570
kit(const Kit::Predicate & predicate)571 Kit *KitManager::kit(const Kit::Predicate &predicate)
572 {
573 return Utils::findOrDefault(kits(), predicate);
574 }
575
defaultKit()576 Kit *KitManager::defaultKit()
577 {
578 return d->m_defaultKit;
579 }
580
kitAspects()581 const QList<KitAspect *> KitManager::kitAspects()
582 {
583 return d->kitAspects();
584 }
585
irrelevantAspects()586 const QSet<Id> KitManager::irrelevantAspects()
587 {
588 return d->m_irrelevantAspects;
589 }
590
setIrrelevantAspects(const QSet<Id> & aspects)591 void KitManager::setIrrelevantAspects(const QSet<Id> &aspects)
592 {
593 d->m_irrelevantAspects = aspects;
594 }
595
notifyAboutUpdate(Kit * k)596 void KitManager::notifyAboutUpdate(Kit *k)
597 {
598 if (!k || !isLoaded())
599 return;
600
601 if (Utils::contains(d->m_kitList, k))
602 emit m_instance->kitUpdated(k);
603 else
604 emit m_instance->unmanagedKitUpdated(k);
605 }
606
registerKit(const std::function<void (Kit *)> & init,Utils::Id id)607 Kit *KitManager::registerKit(const std::function<void (Kit *)> &init, Utils::Id id)
608 {
609 QTC_ASSERT(isLoaded(), return nullptr);
610
611 auto k = std::make_unique<Kit>(id);
612 QTC_ASSERT(k->id().isValid(), return nullptr);
613
614 Kit *kptr = k.get();
615 if (init)
616 init(kptr);
617
618 // make sure we have all the information in our kits:
619 completeKit(kptr);
620
621 d->m_kitList.emplace_back(std::move(k));
622
623 if (!d->m_defaultKit || (!d->m_defaultKit->isValid() && kptr->isValid()))
624 setDefaultKit(kptr);
625
626 emit m_instance->kitAdded(kptr);
627 return kptr;
628 }
629
deregisterKit(Kit * k)630 void KitManager::deregisterKit(Kit *k)
631 {
632 if (!k || !Utils::contains(d->m_kitList, k))
633 return;
634 auto taken = Utils::take(d->m_kitList, k);
635 if (defaultKit() == k) {
636 Kit *newDefault = Utils::findOrDefault(kits(), [](Kit *k) { return k->isValid(); });
637 setDefaultKit(newDefault);
638 }
639 emit m_instance->kitRemoved(k);
640 }
641
setDefaultKit(Kit * k)642 void KitManager::setDefaultKit(Kit *k)
643 {
644 if (defaultKit() == k)
645 return;
646 if (k && !Utils::contains(d->m_kitList, k))
647 return;
648 d->m_defaultKit = k;
649 emit m_instance->defaultkitChanged();
650 }
651
completeKit(Kit * k)652 void KitManager::completeKit(Kit *k)
653 {
654 QTC_ASSERT(k, return);
655 KitGuard g(k);
656 for (KitAspect *ki : d->kitAspects()) {
657 ki->upgrade(k);
658 if (!k->hasValue(ki->id()))
659 ki->setup(k);
660 else
661 ki->fix(k);
662 }
663 }
664
665 // --------------------------------------------------------------------
666 // KitAspect:
667 // --------------------------------------------------------------------
668
KitAspect()669 KitAspect::KitAspect()
670 {
671 KitManager::registerKitAspect(this);
672 }
673
~KitAspect()674 KitAspect::~KitAspect()
675 {
676 KitManager::deregisterKitAspect(this);
677 }
678
weight(const Kit * k) const679 int KitAspect::weight(const Kit *k) const
680 {
681 return k->value(id()).isValid() ? 1 : 0;
682 }
683
addToBuildEnvironment(const Kit * k,Environment & env) const684 void KitAspect::addToBuildEnvironment(const Kit *k, Environment &env) const
685 {
686 Q_UNUSED(k)
687 Q_UNUSED(env)
688 }
689
addToRunEnvironment(const Kit * k,Environment & env) const690 void KitAspect::addToRunEnvironment(const Kit *k, Environment &env) const
691 {
692 Q_UNUSED(k)
693 Q_UNUSED(env)
694 }
695
createOutputParsers(const Kit * k) const696 QList<OutputLineParser *> KitAspect::createOutputParsers(const Kit *k) const
697 {
698 Q_UNUSED(k)
699 return {};
700 }
701
displayNamePostfix(const Kit * k) const702 QString KitAspect::displayNamePostfix(const Kit *k) const
703 {
704 Q_UNUSED(k)
705 return QString();
706 }
707
supportedPlatforms(const Kit * k) const708 QSet<Id> KitAspect::supportedPlatforms(const Kit *k) const
709 {
710 Q_UNUSED(k)
711 return QSet<Id>();
712 }
713
availableFeatures(const Kit * k) const714 QSet<Id> KitAspect::availableFeatures(const Kit *k) const
715 {
716 Q_UNUSED(k)
717 return QSet<Id>();
718 }
719
addToMacroExpander(Kit * k,MacroExpander * expander) const720 void KitAspect::addToMacroExpander(Kit *k, MacroExpander *expander) const
721 {
722 Q_UNUSED(k)
723 Q_UNUSED(expander)
724 }
725
notifyAboutUpdate(Kit * k)726 void KitAspect::notifyAboutUpdate(Kit *k)
727 {
728 if (k)
729 k->kitUpdated();
730 }
731
KitAspectWidget(Kit * kit,const KitAspect * ki)732 KitAspectWidget::KitAspectWidget(Kit *kit, const KitAspect *ki)
733 : m_kit(kit), m_kitInformation(ki)
734 {
735 const Id id = ki->id();
736 m_mutableAction = new QAction(tr("Mark as Mutable"));
737 m_mutableAction->setCheckable(true);
738 m_mutableAction->setChecked(m_kit->isMutable(id));
739 m_mutableAction->setEnabled(!m_kit->isSticky(id));
740 connect(m_mutableAction, &QAction::toggled, this, [this, id] {
741 m_kit->setMutable(id, m_mutableAction->isChecked());
742 });
743 }
744
~KitAspectWidget()745 KitAspectWidget::~KitAspectWidget()
746 {
747 delete m_mutableAction;
748 }
749
addToLayoutWithLabel(QWidget * parent)750 void KitAspectWidget::addToLayoutWithLabel(QWidget *parent)
751 {
752 QTC_ASSERT(parent, return);
753 auto label = createSubWidget<QLabel>(m_kitInformation->displayName() + ':');
754 label->setToolTip(m_kitInformation->description());
755
756 LayoutExtender builder(parent->layout());
757 builder.finishRow();
758 builder.addItem(label);
759 addToLayout(builder);
760 }
761
addMutableAction(QWidget * child)762 void KitAspectWidget::addMutableAction(QWidget *child)
763 {
764 QTC_ASSERT(child, return);
765 child->addAction(m_mutableAction);
766 child->setContextMenuPolicy(Qt::ActionsContextMenu);
767 }
768
createManageButton(Id pageId)769 QWidget *KitAspectWidget::createManageButton(Id pageId)
770 {
771 auto button = createSubWidget<QPushButton>(msgManage());
772 connect(button, &QPushButton::clicked, this, [pageId] {
773 Core::ICore::showOptionsDialog(pageId);
774 });
775 return button;
776 }
777
msgManage()778 QString KitAspectWidget::msgManage()
779 {
780 return tr("Manage...");
781 }
782
783 // --------------------------------------------------------------------
784 // KitFeatureProvider:
785 // --------------------------------------------------------------------
786
787 // This FeatureProvider maps the platforms onto the device types.
788
availableFeatures(Id id) const789 QSet<Id> KitFeatureProvider::availableFeatures(Id id) const
790 {
791 QSet<Id> features;
792 for (const Kit *k : KitManager::kits()) {
793 if (k->supportedPlatforms().contains(id))
794 features.unite(k->availableFeatures());
795 }
796 return features;
797 }
798
availablePlatforms() const799 QSet<Id> KitFeatureProvider::availablePlatforms() const
800 {
801 QSet<Id> platforms;
802 for (const Kit *k : KitManager::kits())
803 platforms.unite(k->supportedPlatforms());
804 return platforms;
805 }
806
displayNameForPlatform(Id id) const807 QString KitFeatureProvider::displayNameForPlatform(Id id) const
808 {
809 if (IDeviceFactory *f = IDeviceFactory::find(id)) {
810 const QString dn = f->displayName();
811 QTC_CHECK(!dn.isEmpty());
812 return dn;
813 }
814 return QString();
815 }
816
817 } // namespace ProjectExplorer
818