1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 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 "mcusupportconstants.h"
27 #include "mcusupportoptionspage.h"
28 #include "mcusupportoptions.h"
29 #include "mcusupportsdk.h"
30
31 #include <cmakeprojectmanager/cmakeprojectconstants.h>
32 #include <cmakeprojectmanager/cmaketoolmanager.h>
33 #include <coreplugin/icore.h>
34 #include <projectexplorer/kitmanager.h>
35 #include <projectexplorer/projectexplorerconstants.h>
36 #include <utils/algorithm.h>
37 #include <utils/infolabel.h>
38 #include <utils/qtcassert.h>
39 #include <utils/utilsicons.h>
40
41 #include <QCheckBox>
42 #include <QComboBox>
43 #include <QDir>
44 #include <QHBoxLayout>
45 #include <QFormLayout>
46 #include <QGroupBox>
47 #include <QLabel>
48 #include <QPushButton>
49 #include <QVBoxLayout>
50
51 namespace McuSupport {
52 namespace Internal {
53
54 class McuSupportOptionsWidget : public Core::IOptionsPageWidget
55 {
56 Q_DECLARE_TR_FUNCTIONS(McuSupport::Internal::McuSupportOptionsWidget)
57
58 public:
59 McuSupportOptionsWidget();
60
61 void updateStatus();
62 void showMcuTargetPackages();
63 McuTarget *currentMcuTarget() const;
64
65 private:
66 void apply() final;
67
68 void populateMcuTargetsComboBox();
69 void showEvent(QShowEvent *event) final;
70
71 QString m_armGccPath;
72 McuSupportOptions m_options;
73 QMap <McuPackage*, QWidget*> m_packageWidgets;
74 QMap <McuTarget*, QWidget*> m_mcuTargetPacketWidgets;
75 QFormLayout *m_packagesLayout = nullptr;
76 QGroupBox *m_qtForMCUsSdkGroupBox = nullptr;
77 QGroupBox *m_packagesGroupBox = nullptr;
78 QGroupBox *m_mcuTargetsGroupBox = nullptr;
79 QComboBox *m_mcuTargetsComboBox = nullptr;
80 QGroupBox *m_kitCreationGroupBox = nullptr;
81 QCheckBox *m_kitAutomaticCreationCheckBox = nullptr;
82 Utils::InfoLabel *m_kitCreationInfoLabel = nullptr;
83 Utils::InfoLabel *m_statusInfoLabel = nullptr;
84 Utils::InfoLabel *m_mcuTargetsInfoLabel = nullptr;
85 QPushButton *m_kitCreationPushButton = nullptr;
86 QPushButton *m_kitUpdatePushButton = nullptr;
87 };
88
McuSupportOptionsWidget()89 McuSupportOptionsWidget::McuSupportOptionsWidget()
90 {
91 auto mainLayout = new QVBoxLayout(this);
92
93 {
94 m_statusInfoLabel = new Utils::InfoLabel;
95 m_statusInfoLabel->setElideMode(Qt::ElideNone);
96 m_statusInfoLabel->setOpenExternalLinks(false);
97 mainLayout->addWidget(m_statusInfoLabel);
98 connect(m_statusInfoLabel, &QLabel::linkActivated, this, [] {
99 Core::ICore::showOptionsDialog(CMakeProjectManager::Constants::CMAKE_SETTINGS_PAGE_ID);
100 });
101 }
102
103 {
104 m_qtForMCUsSdkGroupBox = new QGroupBox(m_options.qtForMCUsSdkPackage->label());
105 m_qtForMCUsSdkGroupBox->setFlat(true);
106 auto layout = new QVBoxLayout(m_qtForMCUsSdkGroupBox);
107 layout->addWidget(m_options.qtForMCUsSdkPackage->widget());
108 mainLayout->addWidget(m_qtForMCUsSdkGroupBox);
109 }
110
111 {
112 m_mcuTargetsGroupBox = new QGroupBox(tr("Targets supported by the %1")
113 .arg(m_qtForMCUsSdkGroupBox->title()));
114 m_mcuTargetsGroupBox->setFlat(true);
115 mainLayout->addWidget(m_mcuTargetsGroupBox);
116 m_mcuTargetsComboBox = new QComboBox;
117 auto layout = new QVBoxLayout(m_mcuTargetsGroupBox);
118 layout->addWidget(m_mcuTargetsComboBox);
119 connect(m_mcuTargetsComboBox, &QComboBox::currentTextChanged,
120 this, &McuSupportOptionsWidget::showMcuTargetPackages);
121 connect(m_options.qtForMCUsSdkPackage, &McuPackage::changed,
122 this, &McuSupportOptionsWidget::populateMcuTargetsComboBox);
123 }
124
125 {
126 m_packagesGroupBox = new QGroupBox(tr("Requirements"));
127 m_packagesGroupBox->setFlat(true);
128 mainLayout->addWidget(m_packagesGroupBox);
129 m_packagesLayout = new QFormLayout;
130 m_packagesGroupBox->setLayout(m_packagesLayout);
131 }
132
133 {
134 m_mcuTargetsInfoLabel = new Utils::InfoLabel;
135 mainLayout->addWidget(m_mcuTargetsInfoLabel);
136 }
137
138 {
139 m_kitAutomaticCreationCheckBox = new QCheckBox(tr("Automatically create kits for all available targets on start"));
140 connect(m_kitAutomaticCreationCheckBox, &QCheckBox::stateChanged, this, [this] (int state) {
141 m_options.qtForMCUsSdkPackage->setAutomaticKitCreationEnabled(state == Qt::CheckState::Checked);
142 });
143 mainLayout->addWidget(m_kitAutomaticCreationCheckBox);
144 }
145
146 {
147 m_kitCreationGroupBox = new QGroupBox(tr("Create a Kit"));
148 m_kitCreationGroupBox->setFlat(true);
149 mainLayout->addWidget(m_kitCreationGroupBox);
150 m_kitCreationInfoLabel = new Utils::InfoLabel;
151 auto vLayout = new QHBoxLayout(m_kitCreationGroupBox);
152 vLayout->addWidget(m_kitCreationInfoLabel);
153 m_kitCreationPushButton = new QPushButton(tr("Create Kit"));
154 m_kitCreationPushButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
155 connect(m_kitCreationPushButton, &QPushButton::clicked, this, [this] {
156 McuSupportOptions::newKit(currentMcuTarget(), m_options.qtForMCUsSdkPackage);
157 McuSupportOptions::registerQchFiles();
158 updateStatus();
159 });
160 m_kitUpdatePushButton = new QPushButton(tr("Update Kit"));
161 m_kitUpdatePushButton->setSizePolicy(m_kitCreationPushButton->sizePolicy());
162 connect(m_kitUpdatePushButton, &QPushButton::clicked, this, [this] {
163 for (auto kit: McuSupportOptions::upgradeableKits(currentMcuTarget(), m_options.qtForMCUsSdkPackage))
164 m_options.upgradeKitInPlace(kit, currentMcuTarget(), m_options.qtForMCUsSdkPackage);
165 updateStatus();
166 });
167 vLayout->addWidget(m_kitCreationPushButton);
168 vLayout->addWidget(m_kitUpdatePushButton);
169 }
170
171 mainLayout->addStretch();
172
173 connect(&m_options, &McuSupportOptions::changed, this, &McuSupportOptionsWidget::updateStatus);
174
175 showMcuTargetPackages();
176 }
177
updateStatus()178 void McuSupportOptionsWidget::updateStatus()
179 {
180 const McuTarget *mcuTarget = currentMcuTarget();
181
182 const bool cMakeAvailable = !CMakeProjectManager::CMakeToolManager::cmakeTools().isEmpty();
183
184 // Page elements
185 {
186 m_qtForMCUsSdkGroupBox->setVisible(cMakeAvailable);
187 const bool valid = cMakeAvailable &&
188 m_options.qtForMCUsSdkPackage->validStatus();
189 const bool ready = valid && mcuTarget;
190 m_mcuTargetsGroupBox->setVisible(ready);
191 m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty());
192 m_kitCreationGroupBox->setVisible(ready);
193 m_mcuTargetsInfoLabel->setVisible(valid && m_options.mcuTargets.isEmpty());
194 if (m_mcuTargetsInfoLabel->isVisible()) {
195 m_mcuTargetsInfoLabel->setType(Utils::InfoLabel::NotOk);
196 const auto sdkPath = Utils::FilePath::fromString(m_options.qtForMCUsSdkPackage->basePath());
197 QString deprecationMessage;
198 if (Sdk::checkDeprecatedSdkError(sdkPath, deprecationMessage))
199 m_mcuTargetsInfoLabel->setText(deprecationMessage);
200 else
201 m_mcuTargetsInfoLabel->setText(tr("No valid kit descriptions found at %1.")
202 .arg(Sdk::kitsPath(sdkPath).toUserOutput()));
203 }
204 }
205
206 // Kit creation status
207 if (mcuTarget) {
208 const bool mcuTargetValid = mcuTarget->isValid();
209 m_kitCreationPushButton->setVisible(mcuTargetValid);
210 m_kitUpdatePushButton->setVisible(mcuTargetValid);
211 if (mcuTargetValid) {
212 const bool hasMatchingKits = !McuSupportOptions::matchingKits(
213 mcuTarget, m_options.qtForMCUsSdkPackage).isEmpty();
214 const bool hasUpgradeableKits = !hasMatchingKits &&
215 !McuSupportOptions::upgradeableKits(
216 mcuTarget, m_options.qtForMCUsSdkPackage).isEmpty();
217
218 m_kitCreationPushButton->setEnabled(!hasMatchingKits);
219 m_kitUpdatePushButton->setEnabled(hasUpgradeableKits);
220
221 m_kitCreationInfoLabel->setType(!hasMatchingKits
222 ? Utils::InfoLabel::Information
223 : Utils::InfoLabel::Ok);
224
225 m_kitCreationInfoLabel->setText(
226 hasMatchingKits ?
227 tr("A kit for the selected target and SDK version already exists.")
228 : hasUpgradeableKits ?
229 tr("Kits for a different SDK version exist.")
230 : tr("A kit for the selected target can be created."));
231 } else {
232 m_kitCreationInfoLabel->setType(Utils::InfoLabel::NotOk);
233 m_kitCreationInfoLabel->setText("Provide the package paths in order to create a kit "
234 "for your target.");
235 }
236 }
237
238 // Automatic Kit creation
239 m_kitAutomaticCreationCheckBox->setChecked(m_options.qtForMCUsSdkPackage->automaticKitCreationEnabled());
240
241 // Status label in the bottom
242 {
243 m_statusInfoLabel->setVisible(!cMakeAvailable);
244 if (m_statusInfoLabel->isVisible()) {
245 m_statusInfoLabel->setType(Utils::InfoLabel::NotOk);
246 m_statusInfoLabel->setText("No CMake tool was detected. Add a CMake tool in the "
247 "<a href=\"cmake\">CMake options</a> and press Apply.");
248 }
249 }
250 }
251
showMcuTargetPackages()252 void McuSupportOptionsWidget::showMcuTargetPackages()
253 {
254 const McuTarget *mcuTarget = currentMcuTarget();
255 if (!mcuTarget)
256 return;
257
258 while (m_packagesLayout->rowCount() > 0) {
259 QFormLayout::TakeRowResult row = m_packagesLayout->takeRow(0);
260 row.labelItem->widget()->hide();
261 row.fieldItem->widget()->hide();
262 }
263
264 for (auto package : qAsConst(m_options.packages)) {
265 QWidget *packageWidget = package->widget();
266 if (!mcuTarget->packages().contains(package))
267 continue;
268 m_packagesLayout->addRow(package->label(), packageWidget);
269 packageWidget->show();
270 }
271
272 updateStatus();
273 }
274
currentMcuTarget() const275 McuTarget *McuSupportOptionsWidget::currentMcuTarget() const
276 {
277 const int mcuTargetIndex = m_mcuTargetsComboBox->currentIndex();
278 return (mcuTargetIndex == -1 || m_options.mcuTargets.isEmpty())
279 ? nullptr
280 : m_options.mcuTargets.at(mcuTargetIndex);
281 }
282
showEvent(QShowEvent * event)283 void McuSupportOptionsWidget::showEvent(QShowEvent *event)
284 {
285 Q_UNUSED(event)
286 populateMcuTargetsComboBox();
287 }
288
apply()289 void McuSupportOptionsWidget::apply()
290 {
291 bool pathsChanged = false;
292
293 m_options.qtForMCUsSdkPackage->writeGeneralSettings();
294 pathsChanged |= m_options.qtForMCUsSdkPackage->writeToSettings();
295 for (auto package : qAsConst(m_options.packages))
296 pathsChanged |= package->writeToSettings();
297
298 if (pathsChanged) {
299 m_options.checkUpgradeableKits();
300 m_options.fixKitsDependencies();
301 }
302 }
303
populateMcuTargetsComboBox()304 void McuSupportOptionsWidget::populateMcuTargetsComboBox()
305 {
306 m_options.populatePackagesAndTargets();
307 m_mcuTargetsComboBox->clear();
308 m_mcuTargetsComboBox->addItems(
309 Utils::transform<QStringList>(m_options.mcuTargets, [](McuTarget *t) {
310 return McuSupportOptions::kitName(t);
311 }));
312 updateStatus();
313 }
314
McuSupportOptionsPage()315 McuSupportOptionsPage::McuSupportOptionsPage()
316 {
317 setId(Utils::Id(Constants::SETTINGS_ID));
318 setDisplayName(McuSupportOptionsWidget::tr("MCU"));
319 setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY);
320 setWidgetCreator([] { return new McuSupportOptionsWidget; });
321 }
322
323 } // Internal
324 } // McuSupport
325