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 "debuggerdialogs.h"
27
28 #include "debuggerkitinformation.h"
29 #include "debuggerruncontrol.h"
30 #include "cdb/cdbengine.h"
31
32 #include <coreplugin/icore.h>
33 #include <projectexplorer/projectexplorerconstants.h>
34 #include <projectexplorer/toolchain.h>
35
36 #include <app/app_version.h>
37 #include <utils/pathchooser.h>
38 #include <utils/fancylineedit.h>
39 #include <utils/qtcassert.h>
40
41 #include <ssh/sshconnection.h>
42
43 #include <QButtonGroup>
44 #include <QCheckBox>
45 #include <QComboBox>
46 #include <QDebug>
47 #include <QDialogButtonBox>
48 #include <QDir>
49 #include <QFormLayout>
50 #include <QGroupBox>
51 #include <QLabel>
52 #include <QPlainTextEdit>
53 #include <QPushButton>
54 #include <QRadioButton>
55 #include <QRegularExpression>
56 #include <QScrollArea>
57 #include <QSpinBox>
58
59 using namespace Core;
60 using namespace ProjectExplorer;
61 using namespace Utils;
62
63 namespace Debugger {
64 namespace Internal {
65
66 ///////////////////////////////////////////////////////////////////////
67 //
68 // StartApplicationDialogPrivate
69 //
70 ///////////////////////////////////////////////////////////////////////
71
72 class StartApplicationDialogPrivate
73 {
74 public:
75 KitChooser *kitChooser;
76 QLabel *serverPortLabel;
77 QLabel *channelOverrideHintLabel;
78 QLabel *channelOverrideLabel;
79 QLineEdit *channelOverrideEdit;
80 QSpinBox *serverPortSpinBox;
81 PathChooser *localExecutablePathChooser;
82 FancyLineEdit *arguments;
83 PathChooser *workingDirectory;
84 QCheckBox *breakAtMainCheckBox;
85 QCheckBox *runInTerminalCheckBox;
86 QCheckBox *useTargetExtendedRemoteCheckBox;
87 PathChooser *debuginfoPathChooser;
88 QLabel *sysRootLabel;
89 PathChooser *sysRootPathChooser;
90 QLabel *serverInitCommandsLabel;
91 QPlainTextEdit *serverInitCommandsTextEdit;
92 QLabel *serverResetCommandsLabel;
93 QPlainTextEdit *serverResetCommandsTextEdit;
94 QComboBox *historyComboBox;
95 QDialogButtonBox *buttonBox;
96 };
97
98 } // namespace Internal
99 } // namespace Debugger
100
101 Q_DECLARE_METATYPE(Debugger::Internal::StartApplicationParameters)
102
103 namespace Debugger {
104 namespace Internal {
105
106 ///////////////////////////////////////////////////////////////////////
107 //
108 // StartApplicationParameters
109 //
110 ///////////////////////////////////////////////////////////////////////
111
112 class StartApplicationParameters
113 {
114 public:
115 QString displayName() const;
116 bool equals(const StartApplicationParameters &rhs) const;
117 void toSettings(QSettings *) const;
118 void fromSettings(const QSettings *settings);
119
operator ==(const StartApplicationParameters & p) const120 bool operator==(const StartApplicationParameters &p) const { return equals(p); }
operator !=(const StartApplicationParameters & p) const121 bool operator!=(const StartApplicationParameters &p) const { return !equals(p); }
122
123 Id kitId;
124 uint serverPort;
125 QString serverAddress;
126 Runnable runnable;
127 bool breakAtMain = false;
128 bool runInTerminal = false;
129 bool useTargetExtendedRemote = false;
130 FilePath sysRoot;
131 QString serverInitCommands;
132 QString serverResetCommands;
133 QString debugInfoLocation;
134 };
135
equals(const StartApplicationParameters & rhs) const136 bool StartApplicationParameters::equals(const StartApplicationParameters &rhs) const
137 {
138 return runnable.executable == rhs.runnable.executable
139 && serverPort == rhs.serverPort
140 && runnable.commandLineArguments == rhs.runnable.commandLineArguments
141 && runnable.workingDirectory == rhs.runnable.workingDirectory
142 && breakAtMain == rhs.breakAtMain
143 && runInTerminal == rhs.runInTerminal
144 && sysRoot == rhs.sysRoot
145 && serverInitCommands == rhs.serverInitCommands
146 && serverResetCommands == rhs.serverResetCommands
147 && kitId == rhs.kitId
148 && debugInfoLocation == rhs.debugInfoLocation
149 && serverAddress == rhs.serverAddress;
150 }
151
displayName() const152 QString StartApplicationParameters::displayName() const
153 {
154 const int maxLength = 60;
155
156 QString name = runnable.executable.fileName()
157 + ' ' + runnable.commandLineArguments;
158 if (name.size() > 60) {
159 int index = name.lastIndexOf(' ', maxLength);
160 if (index == -1)
161 index = maxLength;
162 name.truncate(index);
163 name += "...";
164 }
165
166 if (Kit *kit = KitManager::kit(kitId))
167 name += QString::fromLatin1(" (%1)").arg(kit->displayName());
168
169 return name;
170 }
171
toSettings(QSettings * settings) const172 void StartApplicationParameters::toSettings(QSettings *settings) const
173 {
174 settings->setValue("LastKitId", kitId.toSetting());
175 settings->setValue("LastServerPort", serverPort);
176 settings->setValue("LastServerAddress", serverAddress);
177 settings->setValue("LastExternalExecutable", runnable.executable.toVariant());
178 settings->setValue("LastExternalExecutableArguments", runnable.commandLineArguments);
179 settings->setValue("LastExternalWorkingDirectory", runnable.workingDirectory);
180 settings->setValue("LastExternalBreakAtMain", breakAtMain);
181 settings->setValue("LastExternalRunInTerminal", runInTerminal);
182 settings->setValue("LastExternalUseTargetExtended", useTargetExtendedRemote);
183 settings->setValue("LastServerInitCommands", serverInitCommands);
184 settings->setValue("LastServerResetCommands", serverResetCommands);
185 settings->setValue("LastDebugInfoLocation", debugInfoLocation);
186 settings->setValue("LastSysRoot", sysRoot.toVariant());
187 }
188
fromSettings(const QSettings * settings)189 void StartApplicationParameters::fromSettings(const QSettings *settings)
190 {
191 kitId = Id::fromSetting(settings->value("LastKitId"));
192 serverPort = settings->value("LastServerPort").toUInt();
193 serverAddress = settings->value("LastServerAddress").toString();
194 runnable.executable = FilePath::fromVariant(settings->value("LastExternalExecutable"));
195 runnable.commandLineArguments = settings->value("LastExternalExecutableArguments").toString();
196 runnable.workingDirectory = settings->value("LastExternalWorkingDirectory").toString();
197 breakAtMain = settings->value("LastExternalBreakAtMain").toBool();
198 runInTerminal = settings->value("LastExternalRunInTerminal").toBool();
199 useTargetExtendedRemote = settings->value("LastExternalUseTargetExtended").toBool();
200 serverInitCommands = settings->value("LastServerInitCommands").toString();
201 serverResetCommands = settings->value("LastServerResetCommands").toString();
202 debugInfoLocation = settings->value("LastDebugInfoLocation").toString();
203 sysRoot = FilePath::fromVariant(settings->value("LastSysRoot"));
204 }
205
206 ///////////////////////////////////////////////////////////////////////
207 //
208 // StartApplicationDialog
209 //
210 ///////////////////////////////////////////////////////////////////////
211
StartApplicationDialog(QWidget * parent)212 StartApplicationDialog::StartApplicationDialog(QWidget *parent)
213 : QDialog(parent), d(new StartApplicationDialogPrivate)
214 {
215 setWindowTitle(tr("Start Debugger"));
216
217 d->kitChooser = new KitChooser(this);
218 d->kitChooser->setShowIcons(true);
219 d->kitChooser->populate();
220
221 d->serverPortLabel = new QLabel(tr("Server port:"), this);
222 d->serverPortSpinBox = new QSpinBox(this);
223 d->serverPortSpinBox->setRange(1, 65535);
224
225 d->channelOverrideHintLabel =
226 new QLabel(tr("Normally, the running server is identified by the IP of the "
227 "device in the kit and the server port selected above.\n"
228 "You can choose another communication channel here, such as "
229 "a serial line or custom ip:port."));
230
231 d->channelOverrideLabel = new QLabel(tr("Override server channel:"), this);
232 d->channelOverrideEdit = new QLineEdit(this);
233 //: "For example, /dev/ttyS0, COM1, 127.0.0.1:1234"
234 d->channelOverrideEdit->setPlaceholderText(
235 tr("For example, %1").arg("/dev/ttyS0, COM1, 127.0.0.1:1234"));
236
237 d->localExecutablePathChooser = new PathChooser(this);
238 d->localExecutablePathChooser->setExpectedKind(PathChooser::File);
239 d->localExecutablePathChooser->setPromptDialogTitle(tr("Select Executable"));
240 d->localExecutablePathChooser->setHistoryCompleter("LocalExecutable");
241
242 d->arguments = new FancyLineEdit(this);
243 d->arguments->setHistoryCompleter("CommandlineArguments");
244
245 d->workingDirectory = new PathChooser(this);
246 d->workingDirectory->setExpectedKind(PathChooser::ExistingDirectory);
247 d->workingDirectory->setPromptDialogTitle(tr("Select Working Directory"));
248 d->workingDirectory->setHistoryCompleter("WorkingDirectory");
249
250 d->runInTerminalCheckBox = new QCheckBox(this);
251
252 d->breakAtMainCheckBox = new QCheckBox(this);
253 d->breakAtMainCheckBox->setText(QString());
254
255 d->useTargetExtendedRemoteCheckBox = new QCheckBox(this);
256
257 d->sysRootPathChooser = new PathChooser(this);
258 d->sysRootPathChooser->setExpectedKind(PathChooser::Directory);
259 d->sysRootPathChooser->setHistoryCompleter("Debugger.SysRoot.History");
260 d->sysRootPathChooser->setPromptDialogTitle(tr("Select SysRoot Directory"));
261 d->sysRootPathChooser->setToolTip(tr(
262 "This option can be used to override the kit's SysRoot setting."));
263 d->sysRootLabel = new QLabel(tr("Override S&ysRoot:"), this);
264 d->sysRootLabel->setBuddy(d->sysRootPathChooser);
265 d->sysRootLabel->setToolTip(d->sysRootPathChooser->toolTip());
266
267 d->serverInitCommandsTextEdit = new QPlainTextEdit(this);
268 d->serverInitCommandsTextEdit->setToolTip(tr(
269 "This option can be used to send the target init commands."));
270
271 d->serverInitCommandsLabel = new QLabel(tr("&Init commands:"), this);
272 d->serverInitCommandsLabel->setBuddy(d->serverInitCommandsTextEdit);
273 d->serverInitCommandsLabel->setToolTip(d->serverInitCommandsTextEdit->toolTip());
274
275 d->serverResetCommandsTextEdit = new QPlainTextEdit(this);
276 d->serverResetCommandsTextEdit->setToolTip(tr(
277 "This option can be used to send the target reset commands."));
278
279 d->serverResetCommandsLabel = new QLabel(tr("&Reset commands:"), this);
280 d->serverResetCommandsLabel->setBuddy(d->serverResetCommandsTextEdit);
281 d->serverResetCommandsLabel->setToolTip(d->serverResetCommandsTextEdit->toolTip());
282
283 d->debuginfoPathChooser = new PathChooser(this);
284 d->debuginfoPathChooser->setPromptDialogTitle(tr("Select Location of Debugging Information"));
285 d->debuginfoPathChooser->setToolTip(tr(
286 "Base path for external debug information and debug sources. "
287 "If empty, $SYSROOT/usr/lib/debug will be chosen."));
288 d->debuginfoPathChooser->setHistoryCompleter("Debugger.DebugLocation.History");
289
290 auto line = new QFrame(this);
291 line->setFrameShape(QFrame::HLine);
292 line->setFrameShadow(QFrame::Sunken);
293
294 auto line2 = new QFrame(this);
295 line2->setFrameShape(QFrame::HLine);
296 line2->setFrameShadow(QFrame::Sunken);
297
298 d->historyComboBox = new QComboBox(this);
299
300 d->buttonBox = new QDialogButtonBox(this);
301 d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
302 d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
303
304 auto formLayout = new QFormLayout();
305 formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
306 formLayout->addRow(tr("&Kit:"), d->kitChooser);
307 formLayout->addRow(d->serverPortLabel, d->serverPortSpinBox);
308 formLayout->addRow(tr("Local &executable:"), d->localExecutablePathChooser);
309 formLayout->addRow(tr("Command line &arguments:"), d->arguments);
310 formLayout->addRow(tr("&Working directory:"), d->workingDirectory);
311 formLayout->addRow(tr("Run in &terminal:"), d->runInTerminalCheckBox);
312 formLayout->addRow(tr("Break at \"&main\":"), d->breakAtMainCheckBox);
313 formLayout->addRow(tr("Use target extended-remote to connect:"), d->useTargetExtendedRemoteCheckBox);
314 formLayout->addRow(d->sysRootLabel, d->sysRootPathChooser);
315 formLayout->addRow(d->serverInitCommandsLabel, d->serverInitCommandsTextEdit);
316 formLayout->addRow(d->serverResetCommandsLabel, d->serverResetCommandsTextEdit);
317 formLayout->addRow(tr("Debug &information:"), d->debuginfoPathChooser);
318 formLayout->addRow(d->channelOverrideHintLabel);
319 formLayout->addRow(d->channelOverrideLabel, d->channelOverrideEdit);
320 formLayout->addRow(line2);
321 formLayout->addRow(tr("&Recent:"), d->historyComboBox);
322
323 auto verticalLayout = new QVBoxLayout(this);
324 verticalLayout->addLayout(formLayout);
325 verticalLayout->addStretch();
326 verticalLayout->addWidget(line);
327 verticalLayout->addWidget(d->buttonBox);
328
329 connect(d->localExecutablePathChooser, &PathChooser::rawPathChanged,
330 this, &StartApplicationDialog::updateState);
331 connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
332 connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
333 connect(d->historyComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
334 this, &StartApplicationDialog::historyIndexChanged);
335
336 connect(d->channelOverrideEdit, &QLineEdit::textChanged,
337 this, &StartApplicationDialog::onChannelOverrideChanged);
338
339 updateState();
340 }
341
~StartApplicationDialog()342 StartApplicationDialog::~StartApplicationDialog()
343 {
344 delete d;
345 }
346
setHistory(const QList<StartApplicationParameters> & l)347 void StartApplicationDialog::setHistory(const QList<StartApplicationParameters> &l)
348 {
349 d->historyComboBox->clear();
350 for (int i = l.size(); --i >= 0; ) {
351 const StartApplicationParameters &p = l.at(i);
352 if (!p.runnable.executable.isEmpty())
353 d->historyComboBox->addItem(p.displayName(), QVariant::fromValue(p));
354 }
355 }
356
onChannelOverrideChanged(const QString & channel)357 void StartApplicationDialog::onChannelOverrideChanged(const QString &channel)
358 {
359 d->serverPortSpinBox->setEnabled(channel.isEmpty());
360 d->serverPortLabel->setEnabled(channel.isEmpty());
361 }
362
historyIndexChanged(int index)363 void StartApplicationDialog::historyIndexChanged(int index)
364 {
365 if (index < 0)
366 return;
367 const QVariant v = d->historyComboBox->itemData(index);
368 QTC_ASSERT(v.canConvert<StartApplicationParameters>(), return);
369 setParameters(v.value<StartApplicationParameters>());
370 }
371
updateState()372 void StartApplicationDialog::updateState()
373 {
374 bool okEnabled = d->localExecutablePathChooser->isValid();
375 d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(okEnabled);
376 }
377
run(bool attachRemote)378 void StartApplicationDialog::run(bool attachRemote)
379 {
380 const QString settingsGroup = "DebugMode";
381 const QString arrayName = "StartApplication";
382
383 QList<StartApplicationParameters> history;
384 QSettings *settings = ICore::settings();
385 settings->beginGroup(settingsGroup);
386 if (const int arraySize = settings->beginReadArray(arrayName)) {
387 for (int i = 0; i < arraySize; ++i) {
388 settings->setArrayIndex(i);
389 StartApplicationParameters p;
390 p.fromSettings(settings);
391 history.append(p);
392 }
393 } else {
394 history.append(StartApplicationParameters());
395 }
396 settings->endArray();
397 settings->endGroup();
398
399 StartApplicationDialog dialog(ICore::dialogParent());
400 dialog.setHistory(history);
401 dialog.setParameters(history.back());
402 if (!attachRemote) {
403 dialog.d->serverInitCommandsTextEdit->setVisible(false);
404 dialog.d->serverInitCommandsLabel->setVisible(false);
405 dialog.d->serverResetCommandsTextEdit->setVisible(false);
406 dialog.d->serverResetCommandsLabel->setVisible(false);
407 dialog.d->serverPortSpinBox->setVisible(false);
408 dialog.d->serverPortLabel->setVisible(false);
409 dialog.d->channelOverrideHintLabel->setVisible(false);
410 dialog.d->channelOverrideLabel->setVisible(false);
411 dialog.d->channelOverrideEdit->setVisible(false);
412 }
413 if (dialog.exec() != QDialog::Accepted)
414 return;
415
416 Kit *k = dialog.d->kitChooser->currentKit();
417
418 auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
419 runControl->setKit(k);
420 auto debugger = new DebuggerRunTool(runControl);
421
422 const StartApplicationParameters newParameters = dialog.parameters();
423 if (newParameters != history.back()) {
424 history.append(newParameters);
425 while (history.size() > 10)
426 history.takeFirst();
427 settings->beginGroup(settingsGroup);
428 settings->beginWriteArray(arrayName);
429 for (int i = 0; i < history.size(); ++i) {
430 settings->setArrayIndex(i);
431 history.at(i).toSettings(settings);
432 }
433 settings->endArray();
434 settings->endGroup();
435 }
436
437 IDevice::ConstPtr dev = DeviceKitAspect::device(k);
438 Runnable inferior = newParameters.runnable;
439 const QString inputAddress = dialog.d->channelOverrideEdit->text();
440 if (!inputAddress.isEmpty())
441 debugger->setRemoteChannel(inputAddress);
442 else
443 debugger->setRemoteChannel(dev->sshParameters().host(), newParameters.serverPort);
444 debugger->setRunControlName(newParameters.displayName());
445 debugger->setBreakOnMain(newParameters.breakAtMain);
446 debugger->setDebugInfoLocation(newParameters.debugInfoLocation);
447 debugger->setInferior(inferior);
448 debugger->setCommandsAfterConnect(newParameters.serverInitCommands);
449 debugger->setCommandsForReset(newParameters.serverResetCommands);
450 debugger->setUseTerminal(newParameters.runInTerminal);
451 debugger->setUseExtendedRemote(newParameters.useTargetExtendedRemote);
452 if (!newParameters.sysRoot.isEmpty())
453 debugger->setSysRoot(newParameters.sysRoot);
454
455 bool isLocal = !dev || (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
456 if (isLocal) // FIXME: Restriction needed?
457 debugger->setInferiorEnvironment(k->runEnvironment());
458
459 if (!attachRemote)
460 debugger->setStartMode(isLocal ? StartExternal : StartRemoteProcess);
461
462 if (attachRemote) {
463 debugger->setStartMode(AttachToRemoteServer);
464 debugger->setCloseMode(KillAtClose);
465 debugger->setUseContinueInsteadOfRun(true);
466 debugger->setRunControlName(tr("Attach to %1").arg(debugger->remoteChannel()));
467 }
468 debugger->startRunControl();
469 }
470
attachToRemoteServer()471 void StartApplicationDialog::attachToRemoteServer()
472 {
473 run(true);
474 }
475
startAndDebugApplication()476 void StartApplicationDialog::startAndDebugApplication()
477 {
478 run(false);
479 }
480
parameters() const481 StartApplicationParameters StartApplicationDialog::parameters() const
482 {
483 StartApplicationParameters result;
484 result.serverPort = d->serverPortSpinBox->value();
485 result.serverAddress = d->channelOverrideEdit->text();
486 result.runnable.executable = d->localExecutablePathChooser->filePath();
487 result.sysRoot = d->sysRootPathChooser->filePath();
488 result.serverInitCommands = d->serverInitCommandsTextEdit->toPlainText();
489 result.serverResetCommands = d->serverResetCommandsTextEdit->toPlainText();
490 result.kitId = d->kitChooser->currentKitId();
491 result.debugInfoLocation = d->debuginfoPathChooser->filePath().toString();
492 result.runnable.commandLineArguments = d->arguments->text();
493 result.runnable.workingDirectory = d->workingDirectory->filePath().toString();
494 result.breakAtMain = d->breakAtMainCheckBox->isChecked();
495 result.runInTerminal = d->runInTerminalCheckBox->isChecked();
496 result.useTargetExtendedRemote = d->useTargetExtendedRemoteCheckBox->isChecked();
497 return result;
498 }
499
setParameters(const StartApplicationParameters & p)500 void StartApplicationDialog::setParameters(const StartApplicationParameters &p)
501 {
502 d->kitChooser->setCurrentKitId(p.kitId);
503 d->serverPortSpinBox->setValue(p.serverPort);
504 d->channelOverrideEdit->setText(p.serverAddress);
505 d->localExecutablePathChooser->setFilePath(p.runnable.executable);
506 d->sysRootPathChooser->setFilePath(p.sysRoot);
507 d->serverInitCommandsTextEdit->setPlainText(p.serverInitCommands);
508 d->serverResetCommandsTextEdit->setPlainText(p.serverResetCommands);
509 d->debuginfoPathChooser->setPath(p.debugInfoLocation);
510 d->arguments->setText(p.runnable.commandLineArguments);
511 d->workingDirectory->setPath(p.runnable.workingDirectory);
512 d->breakAtMainCheckBox->setChecked(p.breakAtMain);
513 d->runInTerminalCheckBox->setChecked(p.runInTerminal);
514 d->useTargetExtendedRemoteCheckBox->setChecked(p.useTargetExtendedRemote);
515 updateState();
516 }
517
518 ///////////////////////////////////////////////////////////////////////
519 //
520 // AttachToQmlPortDialog
521 //
522 ///////////////////////////////////////////////////////////////////////
523
524 class AttachToQmlPortDialogPrivate
525 {
526 public:
527 QSpinBox *portSpinBox;
528 KitChooser *kitChooser;
529 };
530
AttachToQmlPortDialog(QWidget * parent)531 AttachToQmlPortDialog::AttachToQmlPortDialog(QWidget *parent)
532 : QDialog(parent),
533 d(new AttachToQmlPortDialogPrivate)
534 {
535 setWindowTitle(tr("Start Debugger"));
536
537 d->kitChooser = new KitChooser(this);
538 d->kitChooser->setShowIcons(true);
539 d->kitChooser->populate();
540
541 d->portSpinBox = new QSpinBox(this);
542 d->portSpinBox->setMaximum(65535);
543 d->portSpinBox->setValue(3768);
544
545 auto buttonBox = new QDialogButtonBox(this);
546 buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
547 buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
548
549 auto formLayout = new QFormLayout();
550 formLayout->addRow(tr("Kit:"), d->kitChooser);
551 formLayout->addRow(tr("&Port:"), d->portSpinBox);
552
553 auto verticalLayout = new QVBoxLayout(this);
554 verticalLayout->addLayout(formLayout);
555 verticalLayout->addWidget(buttonBox);
556
557 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
558 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
559 }
560
~AttachToQmlPortDialog()561 AttachToQmlPortDialog::~AttachToQmlPortDialog()
562 {
563 delete d;
564 }
565
setPort(const int port)566 void AttachToQmlPortDialog::setPort(const int port)
567 {
568 d->portSpinBox->setValue(port);
569 }
570
port() const571 int AttachToQmlPortDialog::port() const
572 {
573 return d->portSpinBox->value();
574 }
575
kit() const576 Kit *AttachToQmlPortDialog::kit() const
577 {
578 return d->kitChooser->currentKit();
579 }
580
setKitId(Id id)581 void AttachToQmlPortDialog::setKitId(Id id)
582 {
583 d->kitChooser->setCurrentKitId(id);
584 }
585
586 // --------- StartRemoteCdbDialog
cdbRemoteHelp()587 static QString cdbRemoteHelp()
588 {
589 const char cdbConnectionSyntax[] =
590 "Server:Port<br>"
591 "tcp:server=Server,port=Port[,password=Password][,ipversion=6]\n"
592 "tcp:clicon=Server,port=Port[,password=Password][,ipversion=6]\n"
593 "npipe:server=Server,pipe=PipeName[,password=Password]\n"
594 "com:port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]\n"
595 "spipe:proto=Protocol,{certuser=Cert|machuser=Cert},server=Server,pipe=PipeName[,password=Password]\n"
596 "ssl:proto=Protocol,{certuser=Cert|machuser=Cert},server=Server,port=Socket[,password=Password]\n"
597 "ssl:proto=Protocol,{certuser=Cert|machuser=Cert},clicon=Server,port=Socket[,password=Password]";
598
599 const QString ext32 = QDir::toNativeSeparators(CdbEngine::extensionLibraryName(false));
600 const QString ext64 = QDir::toNativeSeparators(CdbEngine::extensionLibraryName(true));
601 return StartRemoteCdbDialog::tr(
602 "<html><body><p>The remote CDB needs to load the matching %1 CDB extension "
603 "(<code>%2</code> or <code>%3</code>, respectively).</p><p>Copy it onto the remote machine and set the "
604 "environment variable <code>%4</code> to point to its folder.</p><p>"
605 "Launch the remote CDB as <code>%5 <executable></code> "
606 "to use TCP/IP as communication protocol.</p><p>Enter the connection parameters as:</p>"
607 "<pre>%6</pre></body></html>")
608 .arg(QString(Core::Constants::IDE_DISPLAY_NAME),
609 ext32, ext64, QString("_NT_DEBUGGER_EXTENSION_PATH"),
610 QString("cdb.exe -server tcp:port=1234"),
611 QString(cdbConnectionSyntax));
612 }
613
StartRemoteCdbDialog(QWidget * parent)614 StartRemoteCdbDialog::StartRemoteCdbDialog(QWidget *parent) :
615 QDialog(parent), m_lineEdit(new QLineEdit)
616 {
617 setWindowTitle(tr("Start a CDB Remote Session"));
618
619 auto groupBox = new QGroupBox;
620
621 auto helpLabel = new QLabel(cdbRemoteHelp());
622 helpLabel->setWordWrap(true);
623 helpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
624
625 auto label = new QLabel(tr("&Connection:"));
626 label->setBuddy(m_lineEdit);
627 m_lineEdit->setMinimumWidth(400);
628
629 auto box = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
630
631 auto formLayout = new QFormLayout;
632 formLayout->addRow(helpLabel);
633 formLayout->addRow(label, m_lineEdit);
634 groupBox->setLayout(formLayout);
635
636 auto vLayout = new QVBoxLayout(this);
637 vLayout->addWidget(groupBox);
638 vLayout->addWidget(box);
639
640 m_okButton = box->button(QDialogButtonBox::Ok);
641 m_okButton->setEnabled(false);
642
643 connect(m_lineEdit, &QLineEdit::textChanged,
644 this, &StartRemoteCdbDialog::textChanged);
645 connect(m_lineEdit, &QLineEdit::returnPressed,
646 [this] { m_okButton->animateClick(); });
647 connect(box, &QDialogButtonBox::accepted,
648 this, &StartRemoteCdbDialog::accept);
649 connect(box, &QDialogButtonBox::rejected,
650 this, &QDialog::reject);
651 }
652
accept()653 void StartRemoteCdbDialog::accept()
654 {
655 if (!m_lineEdit->text().isEmpty())
656 QDialog::accept();
657 }
658
659 StartRemoteCdbDialog::~StartRemoteCdbDialog() = default;
660
textChanged(const QString & t)661 void StartRemoteCdbDialog::textChanged(const QString &t)
662 {
663 m_okButton->setEnabled(!t.isEmpty());
664 }
665
connection() const666 QString StartRemoteCdbDialog::connection() const
667 {
668 const QString rc = m_lineEdit->text();
669 // Transform an IP:POrt ('localhost:1234') specification into full spec
670 QRegularExpression ipRegexp("([\\w\\.\\-_]+):([0-9]{1,4})");
671 QTC_ASSERT(ipRegexp.isValid(), return QString());
672 const QRegularExpressionMatch match = ipRegexp.match(rc);
673 if (match.hasMatch())
674 return QString::fromLatin1("tcp:server=%1,port=%2").arg(match.captured(1), match.captured(2));
675 return rc;
676 }
677
setConnection(const QString & c)678 void StartRemoteCdbDialog::setConnection(const QString &c)
679 {
680 m_lineEdit->setText(c);
681 m_okButton->setEnabled(!c.isEmpty());
682 }
683
AddressDialog(QWidget * parent)684 AddressDialog::AddressDialog(QWidget *parent) :
685 QDialog(parent),
686 m_lineEdit(new QLineEdit),
687 m_box(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
688 {
689 setWindowTitle(tr("Select Start Address"));
690
691 auto hLayout = new QHBoxLayout;
692 hLayout->addWidget(new QLabel(tr("Enter an address:") + ' '));
693 hLayout->addWidget(m_lineEdit);
694
695 auto vLayout = new QVBoxLayout;
696 vLayout->addLayout(hLayout);
697 vLayout->addWidget(m_box);
698 setLayout(vLayout);
699
700 connect(m_box, &QDialogButtonBox::accepted, this, &AddressDialog::accept);
701 connect(m_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
702 connect(m_lineEdit, &QLineEdit::returnPressed, this, &AddressDialog::accept);
703 connect(m_lineEdit, &QLineEdit::textChanged, this, &AddressDialog::textChanged);
704
705 setOkButtonEnabled(false);
706 }
707
setOkButtonEnabled(bool v)708 void AddressDialog::setOkButtonEnabled(bool v)
709 {
710 m_box->button(QDialogButtonBox::Ok)->setEnabled(v);
711 }
712
isOkButtonEnabled() const713 bool AddressDialog::isOkButtonEnabled() const
714 {
715 return m_box->button(QDialogButtonBox::Ok)->isEnabled();
716 }
717
setAddress(quint64 a)718 void AddressDialog::setAddress(quint64 a)
719 {
720 m_lineEdit->setText("0x" + QString::number(a, 16));
721 }
722
address() const723 quint64 AddressDialog::address() const
724 {
725 return m_lineEdit->text().toULongLong(nullptr, 16);
726 }
727
accept()728 void AddressDialog::accept()
729 {
730 if (isOkButtonEnabled())
731 QDialog::accept();
732 }
733
textChanged()734 void AddressDialog::textChanged()
735 {
736 setOkButtonEnabled(isValid());
737 }
738
isValid() const739 bool AddressDialog::isValid() const
740 {
741 const QString text = m_lineEdit->text();
742 bool ok = false;
743 text.toULongLong(&ok, 16);
744 return ok;
745 }
746
747 ///////////////////////////////////////////////////////////////////////
748 //
749 // StartRemoteEngineDialog
750 //
751 ///////////////////////////////////////////////////////////////////////
752
753 class StartRemoteEngineDialogPrivate
754 {
755 public:
756 FancyLineEdit *host;
757 FancyLineEdit *username;
758 QLineEdit *password;
759 FancyLineEdit *enginePath;
760 FancyLineEdit *inferiorPath;
761 QDialogButtonBox *buttonBox;
762 };
763
StartRemoteEngineDialog(QWidget * parent)764 StartRemoteEngineDialog::StartRemoteEngineDialog(QWidget *parent)
765 : QDialog(parent), d(new StartRemoteEngineDialogPrivate)
766 {
767 setWindowTitle(tr("Start Remote Engine"));
768
769 d->host = new FancyLineEdit(this);
770 d->host->setHistoryCompleter("HostName");
771
772 d->username = new FancyLineEdit(this);
773 d->username->setHistoryCompleter("UserName");
774
775 d->password = new QLineEdit(this);
776 d->password->setEchoMode(QLineEdit::Password);
777
778 d->enginePath = new FancyLineEdit(this);
779 d->enginePath->setHistoryCompleter("EnginePath");
780
781 d->inferiorPath = new FancyLineEdit(this);
782 d->inferiorPath->setHistoryCompleter("InferiorPath");
783
784 d->buttonBox = new QDialogButtonBox(this);
785 d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
786
787 auto formLayout = new QFormLayout();
788 formLayout->addRow(tr("&Host:"), d->host);
789 formLayout->addRow(tr("&Username:"), d->username);
790 formLayout->addRow(tr("&Password:"), d->password);
791 formLayout->addRow(tr("&Engine path:"), d->enginePath);
792 formLayout->addRow(tr("&Inferior path:"), d->inferiorPath);
793
794 auto verticalLayout = new QVBoxLayout(this);
795 verticalLayout->addLayout(formLayout);
796 verticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
797 verticalLayout->addWidget(d->buttonBox);
798
799 connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
800 connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
801 }
802
~StartRemoteEngineDialog()803 StartRemoteEngineDialog::~StartRemoteEngineDialog()
804 {
805 delete d;
806 }
807
host() const808 QString StartRemoteEngineDialog::host() const
809 {
810 return d->host->text();
811 }
812
username() const813 QString StartRemoteEngineDialog::username() const
814 {
815 return d->username->text();
816 }
817
password() const818 QString StartRemoteEngineDialog::password() const
819 {
820 return d->password->text();
821 }
822
inferiorPath() const823 QString StartRemoteEngineDialog::inferiorPath() const
824 {
825 return d->inferiorPath->text();
826 }
827
enginePath() const828 QString StartRemoteEngineDialog::enginePath() const
829 {
830 return d->enginePath->text();
831 }
832
833 ///////////////////////////////////////////////////////////////////////
834 //
835 // TypeFormatsDialogUi
836 //
837 ///////////////////////////////////////////////////////////////////////
838
839 class TypeFormatsDialogPage : public QWidget
840 {
841 public:
TypeFormatsDialogPage()842 TypeFormatsDialogPage()
843 {
844 m_layout = new QGridLayout;
845 m_layout->setColumnStretch(0, 2);
846 auto vboxLayout = new QVBoxLayout;
847 vboxLayout->addLayout(m_layout);
848 vboxLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Ignored,
849 QSizePolicy::MinimumExpanding));
850 setLayout(vboxLayout);
851 }
852
addTypeFormats(const QString & type,const DisplayFormats & typeFormats,int current)853 void addTypeFormats(const QString &type,
854 const DisplayFormats &typeFormats, int current)
855 {
856 const int row = m_layout->rowCount();
857 int column = 0;
858 auto group = new QButtonGroup(this);
859 m_layout->addWidget(new QLabel(type), row, column++);
860 for (int i = -1; i != typeFormats.size(); ++i) {
861 auto choice = new QRadioButton(this);
862 choice->setText(i == -1 ? TypeFormatsDialog::tr("Reset")
863 : WatchHandler::nameForFormat(typeFormats.at(i)));
864 m_layout->addWidget(choice, row, column++);
865 if (i == current)
866 choice->setChecked(true);
867 group->addButton(choice, i);
868 }
869 }
870 private:
871 QGridLayout *m_layout;
872 };
873
874 class TypeFormatsDialogUi
875 {
876 public:
TypeFormatsDialogUi(TypeFormatsDialog * q)877 TypeFormatsDialogUi(TypeFormatsDialog *q)
878 {
879 tabs = new QTabWidget(q);
880
881 buttonBox = new QDialogButtonBox(q);
882 buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
883
884 auto layout = new QVBoxLayout(q);
885 layout->addWidget(tabs);
886 layout->addWidget(buttonBox);
887 q->setLayout(layout);
888 }
889
addPage(const QString & name)890 void addPage(const QString &name)
891 {
892 auto page = new TypeFormatsDialogPage;
893 pages.append(page);
894 auto scroller = new QScrollArea;
895 scroller->setWidgetResizable(true);
896 scroller->setWidget(page);
897 scroller->setFrameStyle(QFrame::NoFrame);
898 tabs->addTab(scroller, name);
899 }
900
901 public:
902 QList<TypeFormatsDialogPage *> pages;
903 QDialogButtonBox *buttonBox;
904
905 private:
906 QTabWidget *tabs;
907 };
908
909
910 ///////////////////////////////////////////////////////////////////////
911 //
912 // TypeFormatsDialog
913 //
914 ///////////////////////////////////////////////////////////////////////
915
TypeFormatsDialog(QWidget * parent)916 TypeFormatsDialog::TypeFormatsDialog(QWidget *parent)
917 : QDialog(parent), m_ui(new TypeFormatsDialogUi(this))
918 {
919 setWindowTitle(tr("Type Formats"));
920 m_ui->addPage(tr("Qt Types"));
921 m_ui->addPage(tr("Standard Types"));
922 m_ui->addPage(tr("Misc Types"));
923
924 connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
925 connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
926 }
927
~TypeFormatsDialog()928 TypeFormatsDialog::~TypeFormatsDialog()
929 {
930 delete m_ui;
931 }
932
addTypeFormats(const QString & type0,const DisplayFormats & typeFormats,int current)933 void TypeFormatsDialog::addTypeFormats(const QString &type0,
934 const DisplayFormats &typeFormats, int current)
935 {
936 QString type = type0;
937 type.replace("__", "::");
938 int pos = 2;
939 if (type.startsWith('Q'))
940 pos = 0;
941 else if (type.startsWith("std::"))
942 pos = 1;
943 m_ui->pages[pos]->addTypeFormats(type, typeFormats, current);
944 }
945
946 } // namespace Internal
947 } // namespace Debugger
948