1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "cdboptionspage.h"
35 #include "cdboptions.h"
36 #include "debuggerconstants.h"
37 #include "cdbengine.h"
40 # include <utils/winutils.h>
42 #include <utils/synchronousprocess.h>
44 #include <coreplugin/icore.h>
46 #include <QtCore/QCoreApplication>
47 #include <QtCore/QUrl>
48 #include <QtCore/QFileInfo>
49 #include <QtCore/QDir>
50 #include <QtCore/QDateTime>
51 #include <QtCore/QTextStream>
52 #include <QtCore/QTimer>
53 #include <QtCore/QProcess>
54 #include <QtGui/QMessageBox>
55 #include <QtGui/QLineEdit>
56 #include <QtGui/QDesktopServices>
58 static const char *dgbToolsDownloadLink32C = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx";
59 static const char *dgbToolsDownloadLink64C = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx";
64 struct EventsDescription {
65 const char *abbreviation;
67 const char *description;
70 // Parameters of the "sxe" command
71 const EventsDescription eventDescriptions[] =
73 {"eh", false, QT_TRANSLATE_NOOP("Debugger::Cdb::CdbBreakEventWidget",
75 {"ct", false, QT_TRANSLATE_NOOP("Debugger::Cdb::CdbBreakEventWidget",
77 {"et", false, QT_TRANSLATE_NOOP("Debugger::Cdb::CdbBreakEventWidget",
79 {"ld", true, QT_TRANSLATE_NOOP("Debugger::Cdb::CdbBreakEventWidget",
81 {"ud", true, QT_TRANSLATE_NOOP("Debugger::Cdb::CdbBreakEventWidget",
83 {"out", true, QT_TRANSLATE_NOOP("Debugger::Cdb::CdbBreakEventWidget",
87 static inline int indexOfEvent(const QString &abbrev)
89 const size_t eventCount = sizeof(eventDescriptions) / sizeof(EventsDescription);
90 for (size_t e = 0; e < eventCount; e++)
91 if (abbrev == QLatin1String(eventDescriptions[e].abbreviation))
96 CdbBreakEventWidget::CdbBreakEventWidget(QWidget *parent) : QWidget(parent)
98 // 1 column with checkboxes only,
99 // further columns with checkbox + parameter
100 QHBoxLayout *mainLayout = new QHBoxLayout;
101 QVBoxLayout *leftLayout = new QVBoxLayout;
102 QFormLayout *parameterLayout = 0;
103 mainLayout->addLayout(leftLayout);
104 const size_t eventCount = sizeof(eventDescriptions) / sizeof(EventsDescription);
105 for (size_t e = 0; e < eventCount; e++) {
106 QCheckBox *cb = new QCheckBox(tr(eventDescriptions[e].description));
108 if (eventDescriptions[e].hasParameter) {
109 if (!parameterLayout) {
110 parameterLayout = new QFormLayout;
111 mainLayout->addSpacerItem(new QSpacerItem(20, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
112 mainLayout->addLayout(parameterLayout);
115 parameterLayout->addRow(cb, le);
116 if (parameterLayout->count() >= 4) // New column
119 leftLayout->addWidget(cb);
121 m_checkBoxes.push_back(cb);
122 m_lineEdits.push_back(le);
124 setLayout(mainLayout);
127 void CdbBreakEventWidget::clear()
129 foreach (QLineEdit *l, m_lineEdits) {
133 foreach (QCheckBox *c, m_checkBoxes)
134 c->setChecked(false);
137 void CdbBreakEventWidget::setBreakEvents(const QStringList &l)
140 // Split the list of ("eh", "out:MyOutput")
141 foreach (const QString &evt, l) {
142 const int colonPos = evt.indexOf(QLatin1Char(':'));
143 const QString abbrev = colonPos != -1 ? evt.mid(0, colonPos) : evt;
144 const int index = indexOfEvent(abbrev);
146 m_checkBoxes.at(index)->setChecked(true);
147 if (colonPos != -1 && m_lineEdits.at(index))
148 m_lineEdits.at(index)->setText(evt.mid(colonPos + 1));
152 QString CdbBreakEventWidget::filterText(int i) const
154 return m_lineEdits.at(i) ? m_lineEdits.at(i)->text() : QString();
157 QStringList CdbBreakEventWidget::breakEvents() const
159 // Compile a list of ("eh", "out:MyOutput")
161 const int eventCount = sizeof(eventDescriptions) / sizeof(EventsDescription);
162 for (int e = 0; e < eventCount; e++) {
163 if (m_checkBoxes.at(e)->isChecked()) {
164 const QString filter = filterText(e);
165 QString s = QLatin1String(eventDescriptions[e].abbreviation);
166 if (!filter.isEmpty()) {
167 s += QLatin1Char(':');
176 static inline QString msgPathConfigNote()
179 const bool is64bit = Utils::winIs64BitSystem();
181 const bool is64bit = false;
183 const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
184 //: Label text for path configuration. %2 is "x-bit version".
185 return CdbOptionsPageWidget::tr(
186 "<html><body><p>Specify the path to the "
187 "<a href=\"%1\">Windows Console Debugger executable</a>"
189 "</body></html>").arg(link, (is64bit ? CdbOptionsPageWidget::tr("64-bit version")
190 : CdbOptionsPageWidget::tr("32-bit version")));
193 CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) :
194 QWidget(parent), m_breakEventWidget(new CdbBreakEventWidget),
198 m_ui.noteLabel->setText(msgPathConfigNote());
199 m_ui.noteLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
200 connect(m_ui.noteLabel, SIGNAL(linkActivated(QString)), this, SLOT(downLoadLinkActivated(QString)));
202 m_ui.pathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
203 m_ui.pathChooser->addButton(tr("Autodetect"), this, SLOT(autoDetect()));
204 m_ui.cdbPathGroupBox->installEventFilter(this);
205 QVBoxLayout *eventLayout = new QVBoxLayout;
206 eventLayout->addWidget(m_breakEventWidget);
207 m_ui.eventGroupBox->setLayout(eventLayout);
210 void CdbOptionsPageWidget::setOptions(CdbOptions &o)
212 m_ui.pathChooser->setPath(o.executable);
213 m_ui.is64BitCheckBox->setChecked(o.is64bit);
214 m_ui.cdbPathGroupBox->setChecked(o.enabled);
215 setSymbolPaths(o.symbolPaths);
216 m_ui.sourcePathListEditor->setPathList(o.sourcePaths);
217 m_breakEventWidget->setBreakEvents(o.breakEvents);
220 bool CdbOptionsPageWidget::is64Bit() const
222 return m_ui.is64BitCheckBox->isChecked();
225 QString CdbOptionsPageWidget::path() const
227 return m_ui.pathChooser->path();
230 CdbOptions CdbOptionsPageWidget::options() const
233 rc.executable = path();
234 rc.enabled = m_ui.cdbPathGroupBox->isChecked();
235 rc.is64bit = is64Bit();
236 rc.symbolPaths = symbolPaths();
237 rc.sourcePaths = m_ui.sourcePathListEditor->pathList();
238 rc.breakEvents = m_breakEventWidget->breakEvents();
242 QStringList CdbOptionsPageWidget::symbolPaths() const
244 return m_ui.symbolPathListEditor->pathList();
247 void CdbOptionsPageWidget::setSymbolPaths(const QStringList &s)
249 m_ui.symbolPathListEditor->setPathList(s);
252 void CdbOptionsPageWidget::hideReportLabel()
254 m_ui.reportLabel->clear();
255 m_ui.reportLabel->setVisible(false);
258 void CdbOptionsPageWidget::autoDetect()
261 QStringList checkedDirectories;
263 const bool ok = CdbOptions::autoDetectExecutable(&executable, &is64bit, &checkedDirectories);
264 m_ui.cdbPathGroupBox->setChecked(ok);
266 m_ui.is64BitCheckBox->setChecked(is64bit);
267 m_ui.pathChooser->setPath(executable);
269 // Now check for the extension library as well.
270 const bool allOk = checkInstallation(executable, is64Bit(), &report);
271 setReport(report, allOk);
272 // On this occasion, if no symbol paths are specified, check for an
273 // old CDB installation
274 if (symbolPaths().isEmpty())
275 setSymbolPaths(CdbOptions::oldEngineSymbolPaths(Core::ICore::instance()->settings()));
277 const QString msg = tr("\"Debugging Tools for Windows\" could not be found.");
278 const QString details = tr("Checked:\n%1").arg(checkedDirectories.join(QString(QLatin1Char('\n'))));
279 QMessageBox msbBox(QMessageBox::Information, tr("Autodetection"), msg, QMessageBox::Ok, this);
280 msbBox.setDetailedText(details);
285 void CdbOptionsPageWidget::setReport(const QString &msg, bool success)
287 // Hide label after some interval
288 if (!m_reportTimer) {
289 m_reportTimer = new QTimer(this);
290 m_reportTimer->setSingleShot(true);
291 connect(m_reportTimer, SIGNAL(timeout()), this, SLOT(hideReportLabel()));
293 if (m_reportTimer->isActive())
294 m_reportTimer->stop();
296 m_reportTimer->setInterval(success ? 10000 : 20000);
297 m_reportTimer->start();
299 m_ui.reportLabel->setText(msg);
300 m_ui.reportLabel->setStyleSheet(success ? QString() : QString::fromAscii("background-color : 'red'"));
301 m_ui.reportLabel->setVisible(true);
304 void CdbOptionsPageWidget::downLoadLinkActivated(const QString &link)
306 QDesktopServices::openUrl(QUrl(link));
309 QString CdbOptionsPageWidget::searchKeywords() const
312 QTextStream(&rc) << m_ui.pathLabel->text() << ' ' << m_ui.symbolPathLabel->text()
313 << ' ' << m_ui.sourcePathLabel->text();
314 rc.remove(QLatin1Char('&'));
318 static QString cdbVersion(const QString &executable)
321 cdb.start(executable, QStringList(QLatin1String("-version")));
322 cdb.closeWriteChannel();
323 if (!cdb.waitForStarted())
325 if (!cdb.waitForFinished()) {
326 Utils::SynchronousProcess::stopProcess(cdb);
329 return QString::fromLocal8Bit(cdb.readAllStandardOutput());
332 bool CdbOptionsPageWidget::checkInstallation(const QString &executable,
333 bool is64Bit, QString *message)
335 // 1) Check on executable
336 unsigned checkedItems = 0;
338 if (executable.isEmpty()) {
339 message->append(tr("No cdb executable specified.\n"));
341 const QString version = cdbVersion(executable);
342 if (version.isEmpty()) {
343 message->append(tr("Unable to determine version of %1.\n").
346 message->append(tr("Version: %1").arg(version));
351 // 2) Check on extension library
352 const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64Bit));
353 if (extensionFi.isFile()) {
354 message->append(tr("Extension library: %1, built: %3.\n").
355 arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath())).
356 arg(extensionFi.lastModified().toString(Qt::SystemLocaleShortDate)));
359 message->append("Extension library not found.\n");
361 return checkedItems == 2u;
364 bool CdbOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
366 if (o != m_ui.cdbPathGroupBox || e->type() != QEvent::ToolTip)
367 return QWidget::eventFilter(o, e);
369 checkInstallation(path(), is64Bit(), &message);
370 m_ui.cdbPathGroupBox->setToolTip(message);
374 // ---------- CdbOptionsPage
376 CdbOptionsPage *CdbOptionsPage::m_instance = 0;
378 CdbOptionsPage::CdbOptionsPage() :
379 m_options(new CdbOptions)
381 CdbOptionsPage::m_instance = this;
382 m_options->fromSettings(Core::ICore::instance()->settings());
385 CdbOptionsPage::~CdbOptionsPage()
387 CdbOptionsPage::m_instance = 0;
390 QString CdbOptionsPage::settingsId()
392 return QLatin1String("F.Cda"); // before old CDB
395 QString CdbOptionsPage::displayName() const
400 QString CdbOptionsPage::category() const
402 return QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
405 QString CdbOptionsPage::displayCategory() const
407 return QCoreApplication::translate("Debugger", Debugger::Constants::DEBUGGER_SETTINGS_TR_CATEGORY);
410 QIcon CdbOptionsPage::categoryIcon() const
412 return QIcon(QLatin1String(Debugger::Constants::DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON));
415 QWidget *CdbOptionsPage::createPage(QWidget *parent)
417 m_widget = new CdbOptionsPageWidget(parent);
418 m_widget->setOptions(*m_options);
419 if (m_searchKeywords.isEmpty())
420 m_searchKeywords = m_widget->searchKeywords();
424 void CdbOptionsPage::apply()
428 const CdbOptions newOptions = m_widget->options();
429 if (*m_options != newOptions) {
430 *m_options = newOptions;
431 m_options->toSettings(Core::ICore::instance()->settings());
435 void CdbOptionsPage::finish()
439 bool CdbOptionsPage::matches(const QString &s) const
441 return m_searchKeywords.contains(s, Qt::CaseInsensitive);
444 CdbOptionsPage *CdbOptionsPage::instance()
449 } // namespace Internal
450 } // namespace Debugger