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 "debuggerrunconfigurationaspect.h"
27
28 #include "debuggerconstants.h"
29
30 #include <coreplugin/helpmanager.h>
31 #include <coreplugin/icontext.h>
32 #include <coreplugin/icore.h>
33 #include <projectexplorer/buildconfiguration.h>
34 #include <projectexplorer/buildstep.h>
35 #include <projectexplorer/buildsteplist.h>
36 #include <projectexplorer/kitinformation.h>
37 #include <projectexplorer/project.h>
38 #include <projectexplorer/projectexplorerconstants.h>
39 #include <projectexplorer/runconfiguration.h>
40 #include <projectexplorer/target.h>
41 #include <qtsupport/qtbuildaspects.h>
42
43 #include <utils/layoutbuilder.h>
44
45 #include <QCheckBox>
46 #include <QDebug>
47 #include <QFormLayout>
48 #include <QLabel>
49 #include <QTextEdit>
50
51 using namespace Debugger::Internal;
52 using namespace ProjectExplorer;
53 using namespace Utils;
54
55 namespace Debugger {
56 namespace Internal {
57
58 enum DebuggerLanguageStatus {
59 DisabledLanguage = 0,
60 EnabledLanguage,
61 AutoEnabledLanguage
62 };
63
64 class DebuggerLanguageAspect : public BaseAspect
65 {
66 public:
67 DebuggerLanguageAspect() = default;
68
69 void addToLayout(LayoutBuilder &builder) override;
70
71 bool value() const;
72 void setValue(bool val);
73
74 void setAutoSettingsKey(const QString &settingsKey);
75 void setLabel(const QString &label);
setInfoLabelText(const QString & text)76 void setInfoLabelText(const QString &text) { m_infoLabelText = text; }
77
setClickCallBack(const std::function<void (bool)> & clickCallBack)78 void setClickCallBack(const std::function<void (bool)> &clickCallBack)
79 {
80 m_clickCallBack = clickCallBack;
81 }
82
83 void fromMap(const QVariantMap &map) override;
84 void toMap(QVariantMap &map) const override;
85
86 public:
87 DebuggerLanguageStatus m_value = AutoEnabledLanguage;
88 bool m_defaultValue = false;
89 QString m_label;
90 QString m_infoLabelText;
91 QPointer<QCheckBox> m_checkBox; // Owned by configuration widget
92 QPointer<QLabel> m_infoLabel; // Owned by configuration widget
93 QString m_autoSettingsKey;
94
95 std::function<void(bool)> m_clickCallBack;
96 };
97
addToLayout(LayoutBuilder & builder)98 void DebuggerLanguageAspect::addToLayout(LayoutBuilder &builder)
99 {
100 QTC_CHECK(!m_checkBox);
101 m_checkBox = new QCheckBox(m_label);
102 m_checkBox->setChecked(m_value);
103
104 QTC_CHECK(m_clickCallBack);
105 connect(m_checkBox, &QAbstractButton::clicked, this, m_clickCallBack, Qt::QueuedConnection);
106
107 connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] {
108 m_value = m_checkBox->isChecked() ? EnabledLanguage : DisabledLanguage;
109 emit changed();
110 });
111 builder.addItem(QString());
112 builder.addItem(m_checkBox.data());
113
114 if (!m_infoLabelText.isEmpty()) {
115 QTC_CHECK(!m_infoLabel);
116 m_infoLabel = new QLabel(m_infoLabelText);
117 connect(m_infoLabel, &QLabel::linkActivated, [](const QString &link) {
118 Core::HelpManager::showHelpUrl(link);
119 });
120 builder.addItem(m_infoLabel.data());
121 }
122 }
123
setAutoSettingsKey(const QString & settingsKey)124 void DebuggerLanguageAspect::setAutoSettingsKey(const QString &settingsKey)
125 {
126 m_autoSettingsKey = settingsKey;
127 }
128
fromMap(const QVariantMap & map)129 void DebuggerLanguageAspect::fromMap(const QVariantMap &map)
130 {
131 const bool val = map.value(settingsKey(), false).toBool();
132 const bool autoVal = map.value(m_autoSettingsKey, false).toBool();
133 m_value = autoVal ? AutoEnabledLanguage : val ? EnabledLanguage : DisabledLanguage;
134 }
135
toMap(QVariantMap & data) const136 void DebuggerLanguageAspect::toMap(QVariantMap &data) const
137 {
138 data.insert(settingsKey(), m_value == EnabledLanguage);
139 data.insert(m_autoSettingsKey, m_value == AutoEnabledLanguage);
140 }
141
142
value() const143 bool DebuggerLanguageAspect::value() const
144 {
145 return m_value;
146 }
147
setValue(bool value)148 void DebuggerLanguageAspect::setValue(bool value)
149 {
150 m_value = value ? EnabledLanguage : DisabledLanguage;
151 if (m_checkBox)
152 m_checkBox->setChecked(m_value);
153 }
154
setLabel(const QString & label)155 void DebuggerLanguageAspect::setLabel(const QString &label)
156 {
157 m_label = label;
158 }
159
160 } // Internal
161
162 /*!
163 \class Debugger::DebuggerRunConfigurationAspect
164 */
165
DebuggerRunConfigurationAspect(Target * target)166 DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
167 : m_target(target)
168 {
169 setId("DebuggerAspect");
170 setDisplayName(tr("Debugger settings"));
171
172 setConfigWidgetCreator([this] {
173 Layouting::Form builder;
174 builder.addRow(m_cppAspect);
175 builder.addRow(m_qmlAspect);
176 builder.addRow(m_overrideStartupAspect);
177
178 static const QByteArray env = qgetenv("QTC_DEBUGGER_MULTIPROCESS");
179 if (env.toInt())
180 builder.addRow(m_multiProcessAspect);
181 return builder.emerge(false);
182 });
183
184 m_cppAspect = new DebuggerLanguageAspect;
185 m_cppAspect->setLabel(tr("Enable C++"));
186 m_cppAspect->setSettingsKey("RunConfiguration.UseCppDebugger");
187 m_cppAspect->setAutoSettingsKey("RunConfiguration.UseCppDebuggerAuto");
188
189 m_qmlAspect = new DebuggerLanguageAspect;
190 m_qmlAspect->setLabel(tr("Enable QML"));
191 m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger");
192 m_qmlAspect->setAutoSettingsKey("RunConfiguration.UseQmlDebuggerAuto");
193 m_qmlAspect->setInfoLabelText(tr("<a href=\""
194 "qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"
195 "\">What are the prerequisites?</a>"));
196
197 // Make sure at least one of the debuggers is set to be active.
198 m_cppAspect->setClickCallBack([this](bool on) {
199 if (!on && !m_qmlAspect->value())
200 m_qmlAspect->setValue(true);
201 });
202 m_qmlAspect->setClickCallBack([this](bool on) {
203 if (!on && !m_cppAspect->value())
204 m_cppAspect->setValue(true);
205 });
206
207 m_multiProcessAspect = new BoolAspect;
208 m_multiProcessAspect->setSettingsKey("RunConfiguration.UseMultiProcess");
209 m_multiProcessAspect->setLabel(tr("Enable Debugging of Subprocesses"),
210 BoolAspect::LabelPlacement::AtCheckBox);
211
212 m_overrideStartupAspect = new StringAspect;
213 m_overrideStartupAspect->setSettingsKey("RunConfiguration.OverrideDebuggerStartup");
214 m_overrideStartupAspect->setDisplayStyle(StringAspect::TextEditDisplay);
215 m_overrideStartupAspect->setLabelText(tr("Additional startup commands:"));
216 }
217
~DebuggerRunConfigurationAspect()218 DebuggerRunConfigurationAspect::~DebuggerRunConfigurationAspect()
219 {
220 delete m_cppAspect;
221 delete m_qmlAspect;
222 delete m_multiProcessAspect;
223 delete m_overrideStartupAspect;
224 }
225
setUseQmlDebugger(bool value)226 void DebuggerRunConfigurationAspect::setUseQmlDebugger(bool value)
227 {
228 m_qmlAspect->setValue(value);
229 }
230
useCppDebugger() const231 bool DebuggerRunConfigurationAspect::useCppDebugger() const
232 {
233 if (m_cppAspect->m_value == AutoEnabledLanguage)
234 return m_target->project()->projectLanguages().contains(
235 ProjectExplorer::Constants::CXX_LANGUAGE_ID);
236 return m_cppAspect->m_value == EnabledLanguage;
237 }
238
useQmlDebugger() const239 bool DebuggerRunConfigurationAspect::useQmlDebugger() const
240 {
241 if (m_qmlAspect->m_value == AutoEnabledLanguage) {
242 const Core::Context languages = m_target->project()->projectLanguages();
243 if (!languages.contains(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID))
244 return false;
245
246 //
247 // Try to find a build configuration to check whether qml debugging is enabled there
248 if (BuildConfiguration *bc = m_target->activeBuildConfiguration()) {
249 const auto aspect = bc->aspect<QtSupport::QmlDebuggingAspect>();
250 return aspect && aspect->value() == TriState::Enabled;
251 }
252
253 return !languages.contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID);
254 }
255 return m_qmlAspect->m_value == EnabledLanguage;
256 }
257
useMultiProcess() const258 bool DebuggerRunConfigurationAspect::useMultiProcess() const
259 {
260 return m_multiProcessAspect->value();
261 }
262
setUseMultiProcess(bool value)263 void DebuggerRunConfigurationAspect::setUseMultiProcess(bool value)
264 {
265 m_multiProcessAspect->setValue(value);
266 }
267
overrideStartup() const268 QString DebuggerRunConfigurationAspect::overrideStartup() const
269 {
270 return m_overrideStartupAspect->value();
271 }
272
portsUsedByDebugger() const273 int DebuggerRunConfigurationAspect::portsUsedByDebugger() const
274 {
275 int ports = 0;
276 if (useQmlDebugger())
277 ++ports;
278 if (useCppDebugger())
279 ++ports;
280 return ports;
281 }
282
toMap(QVariantMap & map) const283 void DebuggerRunConfigurationAspect::toMap(QVariantMap &map) const
284 {
285 m_cppAspect->toMap(map);
286 m_qmlAspect->toMap(map);
287 m_multiProcessAspect->toMap(map);
288 m_overrideStartupAspect->toMap(map);
289 }
290
fromMap(const QVariantMap & map)291 void DebuggerRunConfigurationAspect::fromMap(const QVariantMap &map)
292 {
293 m_cppAspect->fromMap(map);
294 m_qmlAspect->fromMap(map);
295 m_multiProcessAspect->fromMap(map);
296 m_overrideStartupAspect->fromMap(map);
297 }
298
299 } // namespace Debugger
300