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 &current : 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