summaryrefslogtreecommitdiff
path: root/src/plugins/debugger
diff options
context:
space:
mode:
authorTobias Hunger <tobias.hunger@digia.com>2013-10-25 13:47:08 +0200
committerhjk <hjk121@nokiamail.com>2013-10-28 17:50:49 +0100
commitab8999832a7ce3dbb5bd6d4a7e9b6c5bc1f322c2 (patch)
tree6e1e1e09c6efb57546443e1a08c34004f20b9ab6 /src/plugins/debugger
parent3a24b2d33239a4666b40c4f54e497f31e283e769 (diff)
downloadqt-creator-ab8999832a7ce3dbb5bd6d4a7e9b6c5bc1f322c2.tar.gz
Debugger: Move classes into their own files
Change-Id: I89853ffb4192b0da1f34d471e250d4ec32daa3da Reviewed-by: hjk <hjk121@nokiamail.com>
Diffstat (limited to 'src/plugins/debugger')
-rw-r--r--src/plugins/debugger/debugger.pro8
-rw-r--r--src/plugins/debugger/debugger.qbs4
-rw-r--r--src/plugins/debugger/debuggeritem.cpp337
-rw-r--r--src/plugins/debugger/debuggeritem.h96
-rw-r--r--src/plugins/debugger/debuggeritemmanager.cpp408
-rw-r--r--src/plugins/debugger/debuggeritemmanager.h92
-rw-r--r--src/plugins/debugger/debuggeritemmodel.cpp198
-rw-r--r--src/plugins/debugger/debuggeritemmodel.h90
-rw-r--r--src/plugins/debugger/debuggerkitconfigwidget.cpp1095
-rw-r--r--src/plugins/debugger/debuggerkitconfigwidget.h85
-rw-r--r--src/plugins/debugger/debuggerkitinformation.cpp476
-rw-r--r--src/plugins/debugger/debuggerkitinformation.h97
-rw-r--r--src/plugins/debugger/debuggeroptionspage.cpp350
-rw-r--r--src/plugins/debugger/debuggeroptionspage.h90
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp2
15 files changed, 1916 insertions, 1512 deletions
diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro
index ce31216535..7798cf0bfe 100644
--- a/src/plugins/debugger/debugger.pro
+++ b/src/plugins/debugger/debugger.pro
@@ -24,9 +24,13 @@ HEADERS += \
debuggercore.h \
debuggerconstants.h \
debuggerinternalconstants.h \
+ debuggeritem.h \
+ debuggeritemmanager.h \
+ debuggeritemmodel.h \
debuggerdialogs.h \
debuggerengine.h \
debuggermainwindow.h \
+ debuggeroptionspage.h \
debuggerplugin.h \
debuggerprotocol.h \
debuggerrunconfigurationaspect.h \
@@ -80,12 +84,16 @@ SOURCES += \
debuggeractions.cpp \
debuggerdialogs.cpp \
debuggerengine.cpp \
+ debuggeritem.cpp \
+ debuggeritemmanager.cpp \
+ debuggeritemmodel.cpp \
debuggermainwindow.cpp \
debuggerplugin.cpp \
debuggerprotocol.cpp \
debuggerrunconfigurationaspect.cpp \
debuggerrunner.cpp \
debuggerstreamops.cpp \
+ debuggeroptionspage.cpp \
debuggerkitconfigwidget.cpp \
debuggerkitinformation.cpp \
disassembleragent.cpp \
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 9032e84660..709dc128c3 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -40,9 +40,13 @@ QtcPlugin {
"debuggerdialogs.cpp", "debuggerdialogs.h",
"debuggerengine.cpp", "debuggerengine.h",
"debuggerinternalconstants.h",
+ "debuggeritem.cpp", "debuggeritem.h",
+ "debuggeritemmanager.cpp", "debuggeritemmanager.h",
+ "debuggeritemmodel.cpp", "debuggeritemmodel.h",
"debuggerkitconfigwidget.cpp", "debuggerkitconfigwidget.h",
"debuggerkitinformation.cpp", "debuggerkitinformation.h",
"debuggermainwindow.cpp", "debuggermainwindow.h",
+ "debuggeroptionspage.cpp", "debuggeroptionspage.h",
"debuggerplugin.cpp", "debuggerplugin.h",
"debuggerprotocol.cpp", "debuggerprotocol.h",
"debuggerruncontrolfactory.h",
diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp
new file mode 100644
index 0000000000..9ac30bbb7d
--- /dev/null
+++ b/src/plugins/debugger/debuggeritem.cpp
@@ -0,0 +1,337 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "debuggerkitinformation.h"
+#include "debuggerkitconfigwidget.h"
+#include "debuggeroptionspage.h"
+
+#include <projectexplorer/abi.h>
+#include <utils/fileutils.h>
+
+#include <QProcess>
+#include <QUuid>
+
+using namespace Debugger::Internal;
+using namespace ProjectExplorer;
+using namespace Utils;
+
+static const char DEBUGGER_INFORMATION_COMMAND[] = "Binary";
+static const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName";
+static const char DEBUGGER_INFORMATION_ID[] = "Id";
+static const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType";
+static const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected";
+static const char DEBUGGER_INFORMATION_ABIS[] = "Abis";
+
+namespace Debugger {
+
+// --------------------------------------------------------------------------
+// DebuggerItem
+// --------------------------------------------------------------------------
+
+DebuggerItem::DebuggerItem()
+{
+ m_id = QUuid::createUuid().toString();
+ m_engineType = NoEngineType;
+ m_isAutoDetected = false;
+}
+
+DebuggerItem::DebuggerItem(const QVariantMap &data)
+{
+ m_command = FileName::fromUserInput(data.value(QLatin1String(DEBUGGER_INFORMATION_COMMAND)).toString());
+ m_id = data.value(QLatin1String(DEBUGGER_INFORMATION_ID)).toString();
+ m_displayName = data.value(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME)).toString();
+ m_isAutoDetected = data.value(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), false).toBool();
+ m_engineType = DebuggerEngineType(data.value(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE),
+ static_cast<int>(NoEngineType)).toInt());
+
+ foreach (const QString &a, data.value(QLatin1String(DEBUGGER_INFORMATION_ABIS)).toStringList()) {
+ Abi abi(a);
+ if (abi.isValid())
+ m_abis.append(abi);
+ }
+}
+
+void DebuggerItem::reinitializeFromFile()
+{
+ QProcess proc;
+ proc.start(m_command.toString(), QStringList() << QLatin1String("--version"));
+ proc.waitForStarted();
+ proc.waitForFinished();
+ QByteArray ba = proc.readAll();
+ if (ba.contains("gdb")) {
+ m_engineType = GdbEngineType;
+ const char needle[] = "This GDB was configured as \"";
+ // E.g. "--host=i686-pc-linux-gnu --target=arm-unknown-nto-qnx6.5.0".
+ // or "i686-linux-gnu"
+ int pos1 = ba.indexOf(needle);
+ if (pos1 != -1) {
+ pos1 += int(sizeof(needle));
+ int pos2 = ba.indexOf('"', pos1 + 1);
+ QByteArray target = ba.mid(pos1, pos2 - pos1);
+ int pos3 = target.indexOf("--target=");
+ if (pos3 >= 0)
+ target = target.mid(pos3 + 9);
+ m_abis.append(Abi::abiFromTargetTriplet(QString::fromLatin1(target)));
+ } else {
+ // Fallback.
+ m_abis = Abi::abisOfBinary(m_command); // FIXME: Wrong.
+ }
+ return;
+ }
+ if (ba.contains("lldb") || ba.startsWith("LLDB")) {
+ m_engineType = LldbEngineType;
+ m_abis = Abi::abisOfBinary(m_command);
+ return;
+ }
+ if (ba.startsWith("Python")) {
+ m_engineType = PdbEngineType;
+ return;
+ }
+ m_engineType = NoEngineType;
+}
+
+QString DebuggerItem::engineTypeName() const
+{
+ switch (m_engineType) {
+ case Debugger::NoEngineType:
+ return DebuggerOptionsPage::tr("Not recognized");
+ case Debugger::GdbEngineType:
+ return QLatin1String("GDB");
+ case Debugger::CdbEngineType:
+ return QLatin1String("CDB");
+ case Debugger::LldbEngineType:
+ return QLatin1String("LLDB");
+ default:
+ return QString();
+ }
+}
+
+QStringList DebuggerItem::abiNames() const
+{
+ QStringList list;
+ foreach (const Abi &abi, m_abis)
+ list.append(abi.toString());
+ return list;
+}
+
+QVariantMap DebuggerItem::toMap() const
+{
+ QVariantMap data;
+ data.insert(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME), m_displayName);
+ data.insert(QLatin1String(DEBUGGER_INFORMATION_ID), m_id);
+ data.insert(QLatin1String(DEBUGGER_INFORMATION_COMMAND), m_command.toUserOutput());
+ data.insert(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE), int(m_engineType));
+ data.insert(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), m_isAutoDetected);
+ data.insert(QLatin1String(DEBUGGER_INFORMATION_ABIS), abiNames());
+ return data;
+}
+
+void DebuggerItem::setDisplayName(const QString &displayName)
+{
+ m_displayName = displayName;
+}
+
+void DebuggerItem::setEngineType(const DebuggerEngineType &engineType)
+{
+ m_engineType = engineType;
+}
+
+void DebuggerItem::setCommand(const Utils::FileName &command)
+{
+ m_command = command;
+}
+
+void DebuggerItem::setAutoDetected(bool isAutoDetected)
+{
+ m_isAutoDetected = isAutoDetected;
+}
+
+void DebuggerItem::setAbis(const QList<ProjectExplorer::Abi> &abis)
+{
+ m_abis = abis;
+}
+
+void DebuggerItem::setAbi(const Abi &abi)
+{
+ m_abis.clear();
+ m_abis.append(abi);
+}
+
+static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &targetAbi)
+{
+ if (debuggerAbi.architecture() != Abi::UnknownArchitecture
+ && debuggerAbi.architecture() != targetAbi.architecture())
+ return DebuggerItem::DoesNotMatch;
+
+ if (debuggerAbi.os() != Abi::UnknownOS
+ && debuggerAbi.os() != targetAbi.os())
+ return DebuggerItem::DoesNotMatch;
+
+ if (debuggerAbi.binaryFormat() != Abi::UnknownFormat
+ && debuggerAbi.binaryFormat() != targetAbi.binaryFormat())
+ return DebuggerItem::DoesNotMatch;
+
+ if (debuggerAbi.os() == Abi::WindowsOS) {
+ if (debuggerAbi.osFlavor() == Abi::WindowsMSysFlavor && targetAbi.osFlavor() != Abi::WindowsMSysFlavor)
+ return DebuggerItem::DoesNotMatch;
+ if (debuggerAbi.osFlavor() != Abi::WindowsMSysFlavor && targetAbi.osFlavor() == Abi::WindowsMSysFlavor)
+ return DebuggerItem::DoesNotMatch;
+ }
+
+ if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32)
+ return DebuggerItem::MatchesSomewhat;
+ if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth())
+ return DebuggerItem::DoesNotMatch;
+
+ return DebuggerItem::MatchesPerfectly;
+}
+
+DebuggerItem::MatchLevel DebuggerItem::matchTarget(const Abi &targetAbi) const
+{
+ MatchLevel bestMatch = DoesNotMatch;
+ foreach (const Abi &debuggerAbi, m_abis) {
+ MatchLevel currentMatch = matchSingle(debuggerAbi, targetAbi);
+ if (currentMatch > bestMatch)
+ bestMatch = currentMatch;
+ }
+ return bestMatch;
+}
+
+bool Debugger::DebuggerItem::isValid() const
+{
+ return m_engineType != NoEngineType;
+}
+
+} // namespace Debugger;
+
+#ifdef WITH_TESTS
+
+# include <QTest>
+# include "debuggerplugin.h"
+
+void Debugger::DebuggerPlugin::testDebuggerMatching_data()
+{
+ QTest::addColumn<QStringList>("debugger");
+ QTest::addColumn<QString>("target");
+ QTest::addColumn<int>("result");
+
+ QTest::newRow("Invalid data")
+ << QStringList()
+ << QString()
+ << int(DebuggerItem::DoesNotMatch);
+ QTest::newRow("Invalid debugger")
+ << QStringList()
+ << QString::fromLatin1("x86-linux-generic-elf-32bit")
+ << int(DebuggerItem::DoesNotMatch);
+ QTest::newRow("Invalid target")
+ << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
+ << QString()
+ << int(DebuggerItem::DoesNotMatch);
+
+ QTest::newRow("Fuzzy match 1")
+ << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit"))
+ << QString::fromLatin1("x86-linux-generic-elf-32bit")
+ << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior?
+ QTest::newRow("Fuzzy match 2")
+ << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit"))
+ << QString::fromLatin1("arm-windows-msys-pe-64bit")
+ << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior?
+
+ QTest::newRow("Architecture mismatch")
+ << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
+ << QString::fromLatin1("arm-linux-generic-elf-32bit")
+ << int(DebuggerItem::DoesNotMatch);
+ QTest::newRow("OS mismatch")
+ << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
+ << QString::fromLatin1("x86-macosx-generic-elf-32bit")
+ << int(DebuggerItem::DoesNotMatch);
+ QTest::newRow("Format mismatch")
+ << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
+ << QString::fromLatin1("x86-linux-generic-pe-32bit")
+ << int(DebuggerItem::DoesNotMatch);
+
+ QTest::newRow("Linux perfect match")
+ << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
+ << QString::fromLatin1("x86-linux-generic-elf-32bit")
+ << int(DebuggerItem::MatchesPerfectly);
+ QTest::newRow("Linux match")
+ << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit"))
+ << QString::fromLatin1("x86-linux-generic-elf-32bit")
+ << int(DebuggerItem::MatchesSomewhat);
+
+ QTest::newRow("Windows perfect match 1")
+ << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
+ << QString::fromLatin1("x86-windows-msvc2013-pe-64bit")
+ << int(DebuggerItem::MatchesPerfectly);
+ QTest::newRow("Windows perfect match 2")
+ << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
+ << QString::fromLatin1("x86-windows-msvc2012-pe-64bit")
+ << int(DebuggerItem::MatchesPerfectly);
+ QTest::newRow("Windows match 1")
+ << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
+ << QString::fromLatin1("x86-windows-msvc2013-pe-32bit")
+ << int(DebuggerItem::MatchesSomewhat);
+ QTest::newRow("Windows match 2")
+ << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
+ << QString::fromLatin1("x86-windows-msvc2012-pe-32bit")
+ << int(DebuggerItem::MatchesSomewhat);
+ QTest::newRow("Windows mismatch on word size")
+ << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit"))
+ << QString::fromLatin1("x86-windows-msvc2013-pe-64bit")
+ << int(DebuggerItem::DoesNotMatch);
+ QTest::newRow("Windows mismatch on osflavor 1")
+ << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit"))
+ << QString::fromLatin1("x86-windows-msys-pe-64bit")
+ << int(DebuggerItem::DoesNotMatch);
+ QTest::newRow("Windows mismatch on osflavor 2")
+ << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit"))
+ << QString::fromLatin1("x86-windows-msvc2010-pe-64bit")
+ << int(DebuggerItem::DoesNotMatch);
+}
+
+void Debugger::DebuggerPlugin::testDebuggerMatching()
+{
+ QFETCH(QStringList, debugger);
+ QFETCH(QString, target);
+ QFETCH(int, result);
+
+ DebuggerItem::MatchLevel expectedLevel = static_cast<DebuggerItem::MatchLevel>(result);
+
+ QList<Abi> debuggerAbis;
+ foreach (const QString &abi, debugger)
+ debuggerAbis << Abi(abi);
+
+ DebuggerItem item;
+ item.setAbis(debuggerAbis);
+
+ DebuggerItem::MatchLevel level = item.matchTarget(Abi(target));
+
+ QCOMPARE(expectedLevel, level);
+}
+#endif
diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h
new file mode 100644
index 0000000000..9809da22c7
--- /dev/null
+++ b/src/plugins/debugger/debuggeritem.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DEBUGGER_DEBUGGERITEM_H
+#define DEBUGGER_DEBUGGERITEM_H
+
+#include "debugger_global.h"
+#include "debuggerconstants.h"
+
+#include <projectexplorer/abi.h>
+
+#include <utils/fileutils.h>
+
+#include <QList>
+#include <QVariant>
+
+namespace Debugger {
+
+// -----------------------------------------------------------------------
+// DebuggerItem
+// -----------------------------------------------------------------------
+
+class DEBUGGER_EXPORT DebuggerItem
+{
+public:
+ DebuggerItem();
+ DebuggerItem(const QVariantMap &data);
+
+ bool canClone() const { return true; }
+ bool isValid() const;
+ QString engineTypeName() const;
+
+ QVariantMap toMap() const;
+ void reinitializeFromFile();
+
+ QVariant id() const { return m_id; }
+
+ QString displayName() const { return m_displayName; }
+ void setDisplayName(const QString &displayName);
+
+ DebuggerEngineType engineType() const { return m_engineType; }
+ void setEngineType(const DebuggerEngineType &engineType);
+
+ Utils::FileName command() const { return m_command; }
+ void setCommand(const Utils::FileName &command);
+
+ bool isAutoDetected() const { return m_isAutoDetected; }
+ void setAutoDetected(bool isAutoDetected);
+
+ QList<ProjectExplorer::Abi> abis() const { return m_abis; }
+ void setAbis(const QList<ProjectExplorer::Abi> &abis);
+ void setAbi(const ProjectExplorer::Abi &abi);
+
+ enum MatchLevel { DoesNotMatch, MatchesSomewhat, MatchesPerfectly };
+ MatchLevel matchTarget(const ProjectExplorer::Abi &targetAbi) const;
+
+ QStringList abiNames() const;
+
+private:
+ QVariant m_id;
+ QString m_displayName;
+ DebuggerEngineType m_engineType;
+ Utils::FileName m_command;
+ bool m_isAutoDetected;
+ QList<ProjectExplorer::Abi> m_abis;
+};
+
+} // namespace Debugger
+
+#endif // DEBUGGER_DEBUGGERITEM_H
diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp
new file mode 100644
index 0000000000..e9df26be1e
--- /dev/null
+++ b/src/plugins/debugger/debuggeritemmanager.cpp
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "debuggeritemmanager.h"
+
+#include "debuggeritemmodel.h"
+#include "debuggerkitinformation.h"
+
+#include <coreplugin/icore.h>
+
+#include <utils/environment.h>
+#include <utils/fileutils.h>
+#include <utils/persistentsettings.h>
+#include <utils/qtcassert.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QFileInfo>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace Debugger {
+
+static const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count";
+static const char DEBUGGER_DATA_KEY[] = "DebuggerItem.";
+static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml";
+static const char DEBUGGER_FILE_VERSION_KEY[] = "Version";
+static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml";
+
+// --------------------------------------------------------------------------
+// DebuggerItemManager
+// --------------------------------------------------------------------------
+
+static DebuggerItemManager *m_instance = 0;
+
+static FileName userSettingsFileName()
+{
+ QFileInfo settingsLocation(Core::ICore::settings()->fileName());
+ return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME));
+}
+
+static void readDebuggers(const FileName &fileName, bool isSystem)
+{
+ PersistentSettingsReader reader;
+ if (!reader.load(fileName))
+ return;
+ QVariantMap data = reader.restoreValues();
+
+ // Check version
+ int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt();
+ if (version < 1)
+ return;
+
+ int count = data.value(QLatin1String(DEBUGGER_COUNT_KEY), 0).toInt();
+ for (int i = 0; i < count; ++i) {
+ const QString key = QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(i);
+ if (!data.contains(key))
+ continue;
+ const QVariantMap dbMap = data.value(key).toMap();
+ DebuggerItem item(dbMap);
+ if (isSystem) {
+ item.setAutoDetected(true);
+ // SDK debuggers are always considered to be up-to-date, so no need to recheck them.
+ } else {
+ // User settings.
+ if (item.isAutoDetected() && !item.isValid()) {
+ qWarning() << QString::fromLatin1("DebuggerItem \"%1\" (%2) dropped since it is not valid")
+ .arg(item.command().toString()).arg(item.id().toString());
+ continue;
+ }
+ }
+ DebuggerItemManager::registerDebugger(item);
+ }
+}
+
+QList<DebuggerItem> DebuggerItemManager::m_debuggers;
+Internal::DebuggerItemModel* DebuggerItemManager::m_model = 0;
+PersistentSettingsWriter * DebuggerItemManager::m_writer = 0;
+
+DebuggerItemManager::DebuggerItemManager(QObject *parent)
+ : QObject(parent)
+{
+ m_instance = this;
+ m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger"));
+ m_model = new Debugger::Internal::DebuggerItemModel(this);
+ connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
+ this, SLOT(saveDebuggers()));
+}
+
+QObject *DebuggerItemManager::instance()
+{
+ return m_instance;
+}
+
+DebuggerItemManager::~DebuggerItemManager()
+{
+ disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
+ this, SLOT(saveDebuggers()));
+ delete m_writer;
+}
+
+QList<DebuggerItem> DebuggerItemManager::debuggers()
+{
+ return m_debuggers;
+}
+
+Internal::DebuggerItemModel *DebuggerItemManager::model()
+{
+ return m_model;
+}
+
+void DebuggerItemManager::autoDetectCdbDebuggers()
+{
+ QList<FileName> cdbs;
+
+ QStringList programDirs;
+ programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles")));
+ programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)")));
+ programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432")));
+
+ foreach (const QString &dirName, programDirs) {
+ if (dirName.isEmpty())
+ continue;
+ QDir dir(dirName);
+ // Windows SDK's starting from version 8 live in
+ // "ProgramDir\Windows Kits\<version>"
+ const QString windowsKitsFolderName = QLatin1String("Windows Kits");
+ if (dir.exists(windowsKitsFolderName)) {
+ QDir windowKitsFolder = dir;
+ if (windowKitsFolder.cd(windowsKitsFolderName)) {
+ // Check in reverse order (latest first)
+ const QFileInfoList kitFolders =
+ windowKitsFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
+ QDir::Time | QDir::Reversed);
+ foreach (const QFileInfo &kitFolderFi, kitFolders) {
+ const QString path = kitFolderFi.absoluteFilePath();
+ const QFileInfo cdb32(path + QLatin1String("/Debuggers/x86/cdb.exe"));
+ if (cdb32.isExecutable())
+ cdbs.append(FileName::fromString(cdb32.absoluteFilePath()));
+ const QFileInfo cdb64(path + QLatin1String("/Debuggers/x64/cdb.exe"));
+ if (cdb64.isExecutable())
+ cdbs.append(FileName::fromString(cdb64.absoluteFilePath()));
+ }
+ }
+ }
+
+ // Pre Windows SDK 8: Check 'Debugging Tools for Windows'
+ foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")),
+ QDir::Dirs | QDir::NoDotAndDotDot)) {
+ FileName filePath(fi);
+ filePath.appendPath(QLatin1String("cdb.exe"));
+ if (!cdbs.contains(filePath))
+ cdbs.append(filePath);
+ }
+ }
+
+ foreach (const FileName &cdb, cdbs) {
+ if (findByCommand(cdb))
+ continue;
+ DebuggerItem item;
+ item.setAutoDetected(true);
+ item.setAbis(Abi::abisOfBinary(cdb));
+ item.setCommand(cdb);
+ item.setEngineType(CdbEngineType);
+ item.setDisplayName(uniqueDisplayName(tr("Auto-detected CDB at %1").arg(cdb.toUserOutput())));
+ addDebugger(item);
+ }
+}
+
+void DebuggerItemManager::autoDetectGdbOrLldbDebuggers()
+{
+ QStringList filters;
+ filters.append(QLatin1String("gdb-i686-pc-mingw32"));
+ filters.append(QLatin1String("gdb"));
+ filters.append(QLatin1String("lldb"));
+ filters.append(QLatin1String("lldb-*"));
+
+// DebuggerItem result;
+// result.setAutoDetected(true);
+// result.setDisplayName(tr("Auto-detected for Tool Chain %1").arg(tc->displayName()));
+ /*
+ // Check suggestions from the SDK.
+ Environment env = Environment::systemEnvironment();
+ if (tc) {
+ tc->addToEnvironment(env); // Find MinGW gdb in toolchain environment.
+ QString path = tc->suggestedDebugger().toString();
+ if (!path.isEmpty()) {
+ const QFileInfo fi(path);
+ if (!fi.isAbsolute())
+ path = env.searchInPath(path);
+ result.command = FileName::fromString(path);
+ result.engineType = engineTypeFromBinary(path);
+ return maybeAddDebugger(result, false);
+ }
+ }
+ */
+
+ QFileInfoList suspects;
+
+ QStringList path = Environment::systemEnvironment().path();
+ foreach (const QString &base, path) {
+ QDir dir(base);
+ dir.setNameFilters(filters);
+ suspects += dir.entryInfoList();
+ }
+
+ foreach (const QFileInfo &fi, suspects) {
+ if (fi.exists()) {
+ FileName command = FileName::fromString(fi.absoluteFilePath());
+ if (findByCommand(command))
+ continue;
+ DebuggerItem item;
+ item.setCommand(command);
+ item.reinitializeFromFile();
+ //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path
+ item.setDisplayName(tr("System %1 at %2")
+ .arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath())));
+ item.setAutoDetected(true);
+ addDebugger(item);
+ }
+ }
+}
+
+void DebuggerItemManager::readLegacyDebuggers()
+{
+ QFileInfo settingsLocation(Core::ICore::settings()->fileName());
+ FileName legacyKits = FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME));
+
+ PersistentSettingsReader reader;
+ if (!reader.load(legacyKits))
+ return;
+
+ foreach (const QVariant &v, reader.restoreValues()) {
+ QVariantMap data1 = v.toMap();
+ QString kitName = data1.value(QLatin1String("PE.Profile.Name")).toString();
+ QVariantMap data2 = data1.value(QLatin1String("PE.Profile.Data")).toMap();
+ QVariant v3 = data2.value(DebuggerKitInformation::id().toString());
+ QString fn;
+ if (v3.type() == QVariant::String)
+ fn = v3.toString();
+ else
+ fn = v3.toMap().value(QLatin1String("Binary")).toString();
+ if (fn.isEmpty())
+ continue;
+ if (fn.startsWith(QLatin1Char('{')))
+ continue;
+ if (fn == QLatin1String("auto"))
+ continue;
+ FileName command = FileName::fromUserInput(fn);
+ if (findByCommand(command))
+ continue;
+ DebuggerItem item;
+ item.setCommand(command);
+ item.setAutoDetected(true);
+ item.reinitializeFromFile();
+ item.setDisplayName(tr("Extracted from Kit %1").arg(kitName));
+ addDebugger(item);
+ }
+}
+
+const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command)
+{
+ foreach (const DebuggerItem &item, m_debuggers)
+ if (item.command() == command)
+ return &item;
+
+ return 0;
+}
+
+const DebuggerItem *DebuggerItemManager::findById(const QVariant &id)
+{
+ foreach (const DebuggerItem &item, m_debuggers)
+ if (item.id() == id)
+ return &item;
+
+ return 0;
+}
+
+void DebuggerItemManager::restoreDebuggers()
+{
+ // Read debuggers from SDK
+ QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
+ readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)), true);
+
+ // Read all debuggers from user file.
+ readDebuggers(userSettingsFileName(), false);
+
+ // Auto detect current.
+ autoDetectCdbDebuggers();
+ autoDetectGdbOrLldbDebuggers();
+
+ // Add debuggers from pre-3.x profiles.xml
+ readLegacyDebuggers();
+}
+
+void DebuggerItemManager::saveDebuggers()
+{
+ QTC_ASSERT(m_writer, return);
+ QVariantMap data;
+ data.insert(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 1);
+
+ int count = 0;
+ foreach (const DebuggerItem &item, m_debuggers) {
+ if (item.isValid()) {
+ QVariantMap tmp = item.toMap();
+ if (tmp.isEmpty())
+ continue;
+ data.insert(QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(count), tmp);
+ ++count;
+ }
+ }
+ data.insert(QLatin1String(DEBUGGER_COUNT_KEY), count);
+ m_writer->save(data, Core::ICore::mainWindow());
+
+ // Do not save default debuggers as they are set by the SDK.
+}
+
+QVariant DebuggerItemManager::registerDebugger(const DebuggerItem &item)
+{
+ if (findByCommand(item.command()))
+ return item.id();
+
+ return addDebugger(item);
+}
+
+void DebuggerItemManager::deregisterDebugger(const DebuggerItem &item)
+{
+ if (findByCommand(item.command()))
+ removeDebugger(item.id());
+}
+
+QVariant DebuggerItemManager::addDebugger(const DebuggerItem &item)
+{
+ QTC_ASSERT(!item.command().isEmpty(), return QVariant());
+ QTC_ASSERT(!item.displayName().isEmpty(), return QVariant());
+ QTC_ASSERT(item.engineType() != NoEngineType, return QVariant());
+ QTC_ASSERT(item.id().isValid(), return QVariant());
+ m_debuggers.append(item);
+ m_model->addDebugger(item);
+ return item.id();
+}
+
+void DebuggerItemManager::removeDebugger(const QVariant &id)
+{
+ bool ok = false;
+ for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
+ if (m_debuggers.at(i).id() == id) {
+ m_debuggers.removeAt(i);
+ ok = true;
+ break;
+ }
+ }
+
+ QTC_ASSERT(ok, return);
+ m_model->removeDebugger(id);
+}
+
+QString DebuggerItemManager::uniqueDisplayName(const QString &base)
+{
+ foreach (const DebuggerItem &item, m_debuggers)
+ if (item.displayName() == base)
+ return uniqueDisplayName(base + QLatin1String(" (1)"));
+
+ return base;
+}
+
+void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName)
+{
+ for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
+ DebuggerItem &item = m_debuggers[i];
+ if (item.id() == id) {
+ item.setDisplayName(displayName);
+ item.setCommand(fileName);
+ item.reinitializeFromFile();
+ emit m_model->updateDebugger(item.id());
+ break;
+ }
+ }
+}
+
+} // namespace Debugger;
diff --git a/src/plugins/debugger/debuggeritemmanager.h b/src/plugins/debugger/debuggeritemmanager.h
new file mode 100644
index 0000000000..057cfd58b1
--- /dev/null
+++ b/src/plugins/debugger/debuggeritemmanager.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DEBUGGER_DEBUGGERITEMMANAGER_H
+#define DEBUGGER_DEBUGGERITEMMANAGER_H
+
+#include "debugger_global.h"
+#include "debuggeritem.h"
+#include "debuggeritemmodel.h"
+
+#include <QList>
+#include <QObject>
+#include <QString>
+
+namespace Utils { class PersistentSettingsWriter; }
+
+namespace Debugger {
+
+// -----------------------------------------------------------------------
+// DebuggerItemManager
+// -----------------------------------------------------------------------
+
+class DEBUGGER_EXPORT DebuggerItemManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ static QObject *instance();
+ ~DebuggerItemManager();
+
+ static QList<DebuggerItem> debuggers();
+ static Debugger::Internal::DebuggerItemModel *model();
+
+ static QVariant registerDebugger(const DebuggerItem &item);
+ static void deregisterDebugger(const DebuggerItem &item);
+
+ static const DebuggerItem *findByCommand(const Utils::FileName &command);
+ static const DebuggerItem *findById(const QVariant &id);
+
+ static void restoreDebuggers();
+ static QString uniqueDisplayName(const QString &base);
+ static void setItemData(const QVariant &id, const QString& displayName, const Utils::FileName &fileName);
+
+ static void removeDebugger(const QVariant &id);
+ static QVariant addDebugger(const DebuggerItem &item);
+
+public slots:
+ void saveDebuggers();
+
+private:
+ explicit DebuggerItemManager(QObject *parent = 0);
+ static void autoDetectGdbOrLldbDebuggers();
+ static void autoDetectCdbDebuggers();
+ static void readLegacyDebuggers();
+
+ static Utils::PersistentSettingsWriter *m_writer;
+ static QList<DebuggerItem> m_debuggers;
+ static Debugger::Internal::DebuggerItemModel *m_model;
+
+ friend class Internal::DebuggerItemModel;
+ friend class DebuggerPlugin; // Enable constrcutor for DebuggerPlugin
+};
+
+} // namespace Debugger
+
+#endif // DEBUGGER_DEBUGGERITEMMANAGER_H
diff --git a/src/plugins/debugger/debuggeritemmodel.cpp b/src/plugins/debugger/debuggeritemmodel.cpp
new file mode 100644
index 0000000000..635404684f
--- /dev/null
+++ b/src/plugins/debugger/debuggeritemmodel.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "debuggeritemmodel.h"
+
+#include "debuggeritem.h"
+#include "debuggeritemmanager.h"
+
+#include <utils/qtcassert.h>
+
+namespace Debugger {
+namespace Internal {
+
+static QList<QStandardItem *> describeItem(const DebuggerItem &item)
+{
+ QList<QStandardItem *> row;
+ row.append(new QStandardItem(item.displayName()));
+ row.append(new QStandardItem(item.command().toUserOutput()));
+ row.append(new QStandardItem(item.engineTypeName()));
+ row.at(0)->setData(item.id());
+ row.at(0)->setEditable(false);
+ row.at(1)->setEditable(false);
+ row.at(2)->setEditable(false);
+ row.at(0)->setSelectable(true);
+ row.at(1)->setSelectable(true);
+ row.at(2)->setSelectable(true);
+ return row;
+}
+
+static QList<QStandardItem *> createRow(const QString &display)
+{
+ QList<QStandardItem *> row;
+ row.append(new QStandardItem(display));
+ row.append(new QStandardItem());
+ row.append(new QStandardItem());
+ row.at(0)->setEditable(false);
+ row.at(1)->setEditable(false);
+ row.at(2)->setEditable(false);
+ row.at(0)->setSelectable(false);
+ row.at(1)->setSelectable(false);
+ row.at(2)->setSelectable(false);
+ return row;
+}
+
+// --------------------------------------------------------------------------
+// DebuggerItemModel
+// --------------------------------------------------------------------------
+
+DebuggerItemModel::DebuggerItemModel(QObject *parent)
+ : QStandardItemModel(parent)
+{
+ setColumnCount(3);
+
+ QList<QStandardItem *> row = createRow(tr("Auto-detected"));
+ m_autoRoot = row.at(0);
+ appendRow(row);
+
+ row = createRow(tr("Manual"));
+ m_manualRoot = row.at(0);
+ appendRow(row);
+}
+
+QVariant DebuggerItemModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
+ switch (section) {
+ case 0:
+ return tr("Name");
+ case 1:
+ return tr("Path");
+ case 2:
+ return tr("Type");
+ }
+ }
+ return QVariant();
+}
+
+QStandardItem *DebuggerItemModel::currentStandardItem() const
+{
+ return findStandardItemById(m_currentDebugger);
+}
+
+QStandardItem *DebuggerItemModel::findStandardItemById(const QVariant &id) const
+{
+ for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) {
+ QStandardItem *sitem = m_autoRoot->child(i);
+ if (sitem->data() == id)
+ return sitem;
+ }
+ for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) {
+ QStandardItem *sitem = m_manualRoot->child(i);
+ if (sitem->data() == id)
+ return sitem;
+ }
+ return 0;
+}
+
+QModelIndex DebuggerItemModel::currentIndex() const
+{
+ QStandardItem *current = currentStandardItem();
+ return current ? current->index() : QModelIndex();
+}
+
+QModelIndex DebuggerItemModel::lastIndex() const
+{
+ int n = m_manualRoot->rowCount();
+ QStandardItem *current = m_manualRoot->child(n - 1);
+ return current ? current->index() : QModelIndex();
+}
+
+void DebuggerItemModel::markCurrentDirty()
+{
+ QStandardItem *sitem = currentStandardItem();
+ QTC_ASSERT(sitem, return);
+ QFont font = sitem->font();
+ font.setBold(true);
+ sitem->setFont(font);
+}
+
+void DebuggerItemModel::addDebugger(const DebuggerItem &item)
+{
+ QTC_ASSERT(item.id().isValid(), return);
+ QList<QStandardItem *> row = describeItem(item);
+ (item.isAutoDetected() ? m_autoRoot : m_manualRoot)->appendRow(row);
+ emit debuggerAdded(item.id(), item.displayName());
+}
+
+void DebuggerItemModel::removeDebugger(const QVariant &id)
+{
+ QStandardItem *sitem = findStandardItemById(id);
+ QTC_ASSERT(sitem, return);
+ QStandardItem *parent = sitem->parent();
+ QTC_ASSERT(parent, return);
+ // This will trigger a change of m_currentDebugger via changing the
+ // view selection.
+ parent->removeRow(sitem->row());
+ emit debuggerRemoved(id);
+}
+
+void DebuggerItemModel::updateDebugger(const QVariant &id)
+{
+ QList<DebuggerItem> debuggers = DebuggerItemManager::debuggers();
+ for (int i = 0, n = debuggers.size(); i != n; ++i) {
+ DebuggerItem &item = debuggers[i];
+ if (item.id() == id) {
+ QStandardItem *sitem = findStandardItemById(id);
+ QTC_ASSERT(sitem, return);
+ QStandardItem *parent = sitem->parent();
+ QTC_ASSERT(parent, return);
+ int row = sitem->row();
+ QFont font = sitem->font();
+ font.setBold(false);
+ parent->child(row, 0)->setData(item.displayName(), Qt::DisplayRole);
+ parent->child(row, 0)->setFont(font);
+ parent->child(row, 1)->setData(item.command().toUserOutput(), Qt::DisplayRole);
+ parent->child(row, 1)->setFont(font);
+ parent->child(row, 2)->setData(item.engineTypeName(), Qt::DisplayRole);
+ parent->child(row, 2)->setFont(font);
+ emit debuggerUpdated(id, item.displayName());
+ return;
+ }
+ }
+}
+
+void DebuggerItemModel::setCurrentIndex(const QModelIndex &index)
+{
+ QStandardItem *sit = itemFromIndex(index);
+ m_currentDebugger = sit ? sit->data() : QVariant();
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/debuggeritemmodel.h b/src/plugins/debugger/debuggeritemmodel.h
new file mode 100644
index 0000000000..bb53c708ab
--- /dev/null
+++ b/src/plugins/debugger/debuggeritemmodel.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DEBUGGER_DEBUGGERITEMMODEL_H
+#define DEBUGGER_DEBUGGERITEMMODEL_H
+
+#include "debuggeritem.h"
+
+#include <QStandardItemModel>
+#include <QVariant>
+
+namespace Debugger {
+namespace Internal {
+
+// -----------------------------------------------------------------------
+// DebuggerItemModel
+//------------------------------------------------------------------------
+
+class DebuggerItemModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ DebuggerItemModel(QObject *parent);
+
+ QModelIndex currentIndex() const;
+ QModelIndex lastIndex() const;
+ void setCurrentIndex(const QModelIndex &index);
+ QVariant currentDebugger() const { return m_currentDebugger; }
+ void addDebugger(const DebuggerItem &item);
+ void removeDebugger(const QVariant &id);
+ void updateDebugger(const QVariant &id);
+
+public slots:
+ void markCurrentDirty();
+
+signals:
+ void debuggerAdded(const QVariant &id, const QString &display);
+ void debuggerUpdated(const QVariant &id, const QString &display);
+ void debuggerRemoved(const QVariant &id);
+
+private:
+ // <debug>
+ // friend class Debugger::DebuggerKitInformation;
+ // friend class DebuggerKitConfigWidget;
+ // friend class DebuggerItemConfigWidget;
+ // friend class DebuggerOptionsPage;
+ // </debug>
+
+ QStandardItem *currentStandardItem() const;
+ QStandardItem *findStandardItemById(const QVariant &id) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ QVariant m_currentDebugger;
+
+ QStandardItem *m_autoRoot;
+ QStandardItem *m_manualRoot;
+ QStringList removed;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_DEBUGGERITEMMODEL_H
diff --git a/src/plugins/debugger/debuggerkitconfigwidget.cpp b/src/plugins/debugger/debuggerkitconfigwidget.cpp
index a3e0b611d3..85f4ded641 100644
--- a/src/plugins/debugger/debuggerkitconfigwidget.cpp
+++ b/src/plugins/debugger/debuggerkitconfigwidget.cpp
@@ -29,6 +29,9 @@
#include "debuggerkitconfigwidget.h"
+#include "debuggeritemmanager.h"
+#include "debuggeritemmodel.h"
+
#include <coreplugin/icore.h>
#include <projectexplorer/abi.h>
@@ -64,811 +67,10 @@ using namespace Utils;
using namespace Debugger::Internal;
namespace Debugger {
-
-static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging";
-
-static const char DEBUGGER_DATA_KEY[] = "DebuggerItem.";
-static const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count";
-static const char DEBUGGER_FILE_VERSION_KEY[] = "Version";
-static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml";
-static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml";
-
-// --------------------------------------------------------------------------
-// DebuggerKitInformation
-// --------------------------------------------------------------------------
-
-DebuggerKitInformation::DebuggerKitInformation()
-{
- setObjectName(QLatin1String("DebuggerKitInformation"));
- setId(DebuggerKitInformation::id());
- setPriority(28000);
-}
-
-QVariant DebuggerKitInformation::defaultValue(Kit *k) const
-{
- ToolChain *tc = ToolChainKitInformation::toolChain(k);
- QTC_ASSERT(tc, return QVariant());
-
- const Abi toolChainAbi = tc->targetAbi();
- foreach (const DebuggerItem &item, DebuggerItemManager::debuggers())
- foreach (const Abi targetAbi, item.abis())
- if (targetAbi.isCompatibleWith(toolChainAbi))
- return item.id();
-
- return QVariant();
-}
-
-void DebuggerKitInformation::setup(Kit *k)
-{
- // Get one of the available debugger matching the kit's toolchain.
- const ToolChain *tc = ToolChainKitInformation::toolChain(k);
- const Abi toolChainAbi = tc ? tc->targetAbi() : Abi::hostAbi();
-
- // This can be anything (Id, binary path, "auto")
- const QVariant rawId = k->value(DebuggerKitInformation::id());
-
- enum {
- NotDetected, DetectedAutomatically, DetectedByFile, DetectedById
- } detection = NotDetected;
- DebuggerEngineType autoEngine = NoEngineType;
- FileName fileName;
-
- // With 3.0 we have:
- // <value type="QString" key="Debugger.Information">{75ecf347-f221-44c3-b613-ea1d29929cd4}</value>
- // Before we had:
- // <valuemap type="QVariantMap" key="Debugger.Information">
- // <value type="QString" key="Binary">/data/dev/debugger/gdb-git/gdb/gdb</value>
- // <value type="int" key="EngineType">1</value>
- // </valuemap>
- // Or for force auto-detected CDB
- // <valuemap type="QVariantMap" key="Debugger.Information">
- // <value type="QString" key="Binary">auto</value>
- // <value type="int" key="EngineType">4</value>
- // </valuemap>
-
- if (rawId.isNull()) {
- // Initial setup of a kit
- detection = NotDetected;
- } else if (rawId.type() == QVariant::String) {
- detection = DetectedById;
- } else {
- QMap<QString, QVariant> map = rawId.toMap();
- QString binary = map.value(QLatin1String("Binary")).toString();
- if (binary == QLatin1String("auto")) {
- detection = DetectedAutomatically;
- autoEngine = DebuggerEngineType(map.value(QLatin1String("EngineType")).toInt());
- } else {
- detection = DetectedByFile;
- fileName = FileName::fromUserInput(binary);
- }
- }
-
- const DebuggerItem *bestItem = 0;
- DebuggerItem::MatchLevel bestLevel = DebuggerItem::DoesNotMatch;
- foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) {
- const DebuggerItem *goodItem = 0;
- if (detection == DetectedById && item.id() == rawId)
- goodItem = &item;
- if (detection == DetectedByFile && item.command() == fileName)
- goodItem = &item;
- if (detection == DetectedAutomatically && item.engineType() == autoEngine)
- goodItem = &item;
-
- if (goodItem) {
- DebuggerItem::MatchLevel level = goodItem->matchTarget(toolChainAbi);
- if (level > bestLevel) {
- bestLevel = level;
- bestItem = goodItem;
- }
- }
- }
-
- // If we have an existing debugger with matching id _and_
- // matching target ABI we are fine.
- if (bestItem) {
- k->setValue(DebuggerKitInformation::id(), bestItem->id());
- return;
- }
-
- // We didn't find an existing debugger that matched by whatever
- // data we found in the kit (i.e. no id, filename, "auto")
- // (or what we found did not match ABI-wise)
- // Let's try to pick one with matching ABI.
- QVariant bestId;
- bestLevel = DebuggerItem::DoesNotMatch;
- foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) {
- DebuggerItem::MatchLevel level = item.matchTarget(toolChainAbi);
- if (level > bestLevel) {
- bestLevel = level;
- bestId = item.id();
- }
- }
-
- k->setValue(DebuggerKitInformation::id(), bestId);
-}
-
-
-// This handles the upgrade path from 2.8 to 3.0
-void DebuggerKitInformation::fix(Kit *k)
-{
- // This can be Id, binary path, but not "auto" anymore.
- const QVariant rawId = k->value(DebuggerKitInformation::id());
-
- if (rawId.isNull()) // No debugger set, that is fine.
- return;
-
- if (rawId.type() == QVariant::String) {
- if (!DebuggerItemManager::findById(rawId)) {
- qWarning("Unknown debugger id %s in kit %s",
- qPrintable(rawId.toString()), qPrintable(k->displayName()));
- k->setValue(DebuggerKitInformation::id(), QVariant());
- }
- return; // All fine (now).
- }
-
- QMap<QString, QVariant> map = rawId.toMap();
- QString binary = map.value(QLatin1String("Binary")).toString();
- if (binary == QLatin1String("auto")) {
- // This should not happen as "auto" is handled by setup() already.
- QTC_CHECK(false);
- k->setValue(DebuggerKitInformation::id(), QVariant());
- return;
- }
-
- FileName fileName = FileName::fromUserInput(binary);
- const DebuggerItem *item = DebuggerItemManager::findByCommand(fileName);
- if (!item) {
- qWarning("Debugger command %s invalid in kit %s",
- qPrintable(binary), qPrintable(k->displayName()));
- k->setValue(DebuggerKitInformation::id(), QVariant());
- return;
- }
-
- k->setValue(DebuggerKitInformation::id(), item->id());
-}
-
-// Check the configuration errors and return a flag mask. Provide a quick check and
-// a verbose one with a list of errors.
-
-enum DebuggerConfigurationErrors {
- NoDebugger = 0x1,
- DebuggerNotFound = 0x2,
- DebuggerNotExecutable = 0x4,
- DebuggerNeedsAbsolutePath = 0x8
-};
-
-static unsigned debuggerConfigurationErrors(const Kit *k)
-{
- QTC_ASSERT(k, return NoDebugger);
-
- const DebuggerItem *item = DebuggerKitInformation::debugger(k);
- if (!item)
- return NoDebugger;
-
- if (item->command().isEmpty())
- return NoDebugger;
-
- unsigned result = 0;
- const QFileInfo fi = item->command().toFileInfo();
- if (!fi.exists() || fi.isDir())
- result |= DebuggerNotFound;
- else if (!fi.isExecutable())
- result |= DebuggerNotExecutable;
-
- if (!fi.exists() || fi.isDir()) {
- if (item->engineType() == NoEngineType)
- return NoDebugger;
-
- // We need an absolute path to be able to locate Python on Windows.
- if (item->engineType() == GdbEngineType)
- if (const ToolChain *tc = ToolChainKitInformation::toolChain(k))
- if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute())
- result |= DebuggerNeedsAbsolutePath;
- }
- return result;
-}
-
-const DebuggerItem *DebuggerKitInformation::debugger(const Kit *kit)
-{
- QTC_ASSERT(kit, return 0);
- const QVariant id = kit->value(DebuggerKitInformation::id());
- return DebuggerItemManager::findById(id);
-}
-
-bool DebuggerKitInformation::isValidDebugger(const Kit *k)
-{
- return debuggerConfigurationErrors(k) == 0;
-}
-
-QList<Task> DebuggerKitInformation::validateDebugger(const Kit *k)
-{
- QList<Task> result;
-
- const unsigned errors = debuggerConfigurationErrors(k);
- if (!errors)
- return result;
-
- QString path;
- if (const DebuggerItem *item = debugger(k))
- path = item->command().toUserOutput();
-
- const Core::Id id = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM;
- if (errors & NoDebugger)
- result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id);
-
- if (errors & DebuggerNotFound)
- result << Task(Task::Error, tr("Debugger '%1' not found.").arg(path),
- FileName(), -1, id);
- if (errors & DebuggerNotExecutable)
- result << Task(Task::Error, tr("Debugger '%1' not executable.").arg(path), FileName(), -1, id);
-
- if (errors & DebuggerNeedsAbsolutePath) {
- const QString message =
- tr("The debugger location must be given as an "
- "absolute path (%1).").arg(path);
- result << Task(Task::Error, message, FileName(), -1, id);
- }
- return result;
-}
-
-KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const
-{
- return new Internal::DebuggerKitConfigWidget(k, this);
-}
-
-KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const
-{
- return ItemList() << qMakePair(tr("Debugger"), displayString(k));
-}
-
-FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k)
-{
- const DebuggerItem *item = debugger(k);
- QTC_ASSERT(item, return FileName());
- return item->command();
-}
-
-DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k)
-{
- const DebuggerItem *item = debugger(k);
- QTC_ASSERT(item, return NoEngineType);
- return item->engineType();
-}
-
-QString DebuggerKitInformation::displayString(const Kit *k)
-{
- const DebuggerItem *item = debugger(k);
- if (!item)
- return tr("No Debugger");
- QString binary = item->command().toUserOutput();
- QString name = tr("%1 Engine").arg(item->engineTypeName());
- return binary.isEmpty() ? tr("%1 <None>").arg(name) : tr("%1 using \"%2\"").arg(name, binary);
-}
-
-void DebuggerKitInformation::setDebugger(Kit *k, const QVariant &id)
-{
- // Only register reasonably complete debuggers.
- QTC_ASSERT(DebuggerItemManager::findById(id), return);
- k->setValue(DebuggerKitInformation::id(), id);
-}
-
-Core::Id DebuggerKitInformation::id()
-{
- return "Debugger.Information";
-}
-
-// --------------------------------------------------------------------------
-// DebuggerItemManager
-// --------------------------------------------------------------------------
-
-static DebuggerItemManager *m_instance = 0;
-
-static FileName userSettingsFileName()
-{
- QFileInfo settingsLocation(Core::ICore::settings()->fileName());
- return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME));
-}
-
-static void readDebuggers(const FileName &fileName, bool isSystem)
-{
- PersistentSettingsReader reader;
- if (!reader.load(fileName))
- return;
- QVariantMap data = reader.restoreValues();
-
- // Check version
- int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt();
- if (version < 1)
- return;
-
- int count = data.value(QLatin1String(DEBUGGER_COUNT_KEY), 0).toInt();
- for (int i = 0; i < count; ++i) {
- const QString key = QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(i);
- if (!data.contains(key))
- continue;
- const QVariantMap dbMap = data.value(key).toMap();
- DebuggerItem item(dbMap);
- if (isSystem) {
- item.setAutoDetected(true);
- // SDK debuggers are always considered to be up-to-date, so no need to recheck them.
- } else {
- // User settings.
- if (item.isAutoDetected() && !item.isValid()) {
- qWarning() << QString::fromLatin1("DebuggerItem \"%1\" (%2) dropped since it is not valid")
- .arg(item.command().toString()).arg(item.id().toString());
- continue;
- }
- }
- DebuggerItemManager::registerDebugger(item);
- }
-}
-
-QList<DebuggerItem> DebuggerItemManager::m_debuggers;
-DebuggerItemModel* DebuggerItemManager::m_model = 0;
-PersistentSettingsWriter * DebuggerItemManager::m_writer = 0;
-
-DebuggerItemManager::DebuggerItemManager(QObject *parent)
- : QObject(parent)
-{
- m_instance = this;
- m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger"));
- m_model = new Debugger::Internal::DebuggerItemModel(this);
- connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
- this, SLOT(saveDebuggers()));
-}
-
-QObject *DebuggerItemManager::instance()
-{
- return m_instance;
-}
-
-DebuggerItemManager::~DebuggerItemManager()
-{
- disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
- this, SLOT(saveDebuggers()));
- delete m_writer;
-}
-
-QList<DebuggerItem> DebuggerItemManager::debuggers()
-{
- return m_debuggers;
-}
-
-DebuggerItemModel *DebuggerItemManager::model()
-{
- return m_model;
-}
-
-void DebuggerItemManager::autoDetectCdbDebuggers()
-{
- QList<FileName> cdbs;
-
- QStringList programDirs;
- programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles")));
- programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)")));
- programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432")));
-
- foreach (const QString &dirName, programDirs) {
- if (dirName.isEmpty())
- continue;
- QDir dir(dirName);
- // Windows SDK's starting from version 8 live in
- // "ProgramDir\Windows Kits\<version>"
- const QString windowsKitsFolderName = QLatin1String("Windows Kits");
- if (dir.exists(windowsKitsFolderName)) {
- QDir windowKitsFolder = dir;
- if (windowKitsFolder.cd(windowsKitsFolderName)) {
- // Check in reverse order (latest first)
- const QFileInfoList kitFolders =
- windowKitsFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
- QDir::Time | QDir::Reversed);
- foreach (const QFileInfo &kitFolderFi, kitFolders) {
- const QString path = kitFolderFi.absoluteFilePath();
- const QFileInfo cdb32(path + QLatin1String("/Debuggers/x86/cdb.exe"));
- if (cdb32.isExecutable())
- cdbs.append(FileName::fromString(cdb32.absoluteFilePath()));
- const QFileInfo cdb64(path + QLatin1String("/Debuggers/x64/cdb.exe"));
- if (cdb64.isExecutable())
- cdbs.append(FileName::fromString(cdb64.absoluteFilePath()));
- }
- }
- }
-
- // Pre Windows SDK 8: Check 'Debugging Tools for Windows'
- foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")),
- QDir::Dirs | QDir::NoDotAndDotDot)) {
- FileName filePath(fi);
- filePath.appendPath(QLatin1String("cdb.exe"));
- if (!cdbs.contains(filePath))
- cdbs.append(filePath);
- }
- }
-
- foreach (const FileName &cdb, cdbs) {
- if (findByCommand(cdb))
- continue;
- DebuggerItem item;
- item.setAutoDetected(true);
- item.setAbis(Abi::abisOfBinary(cdb));
- item.setCommand(cdb);
- item.setEngineType(CdbEngineType);
- item.setDisplayName(uniqueDisplayName(tr("Auto-detected CDB at %1").arg(cdb.toUserOutput())));
- addDebugger(item);
- }
-}
-
-void DebuggerItemManager::autoDetectGdbOrLldbDebuggers()
-{
- QStringList filters;
- filters.append(QLatin1String("gdb-i686-pc-mingw32"));
- filters.append(QLatin1String("gdb"));
- filters.append(QLatin1String("lldb"));
- filters.append(QLatin1String("lldb-*"));
-
-// DebuggerItem result;
-// result.setAutoDetected(true);
-// result.setDisplayName(tr("Auto-detected for Tool Chain %1").arg(tc->displayName()));
- /*
- // Check suggestions from the SDK.
- Environment env = Environment::systemEnvironment();
- if (tc) {
- tc->addToEnvironment(env); // Find MinGW gdb in toolchain environment.
- QString path = tc->suggestedDebugger().toString();
- if (!path.isEmpty()) {
- const QFileInfo fi(path);
- if (!fi.isAbsolute())
- path = env.searchInPath(path);
- result.command = FileName::fromString(path);
- result.engineType = engineTypeFromBinary(path);
- return maybeAddDebugger(result, false);
- }
- }
- */
-
- QFileInfoList suspects;
-
- QStringList path = Environment::systemEnvironment().path();
- foreach (const QString &base, path) {
- QDir dir(base);
- dir.setNameFilters(filters);
- suspects += dir.entryInfoList();
- }
-
- foreach (const QFileInfo &fi, suspects) {
- if (fi.exists()) {
- FileName command = FileName::fromString(fi.absoluteFilePath());
- if (findByCommand(command))
- continue;
- DebuggerItem item;
- item.setCommand(command);
- item.reinitializeFromFile();
- //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path
- item.setDisplayName(tr("System %1 at %2")
- .arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath())));
- item.setAutoDetected(true);
- addDebugger(item);
- }
- }
-}
-
-void DebuggerItemManager::readLegacyDebuggers()
-{
- QFileInfo settingsLocation(Core::ICore::settings()->fileName());
- FileName legacyKits = FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME));
-
- PersistentSettingsReader reader;
- if (!reader.load(legacyKits))
- return;
-
- foreach (const QVariant &v, reader.restoreValues()) {
- QVariantMap data1 = v.toMap();
- QString kitName = data1.value(QLatin1String("PE.Profile.Name")).toString();
- QVariantMap data2 = data1.value(QLatin1String("PE.Profile.Data")).toMap();
- QVariant v3 = data2.value(DebuggerKitInformation::id().toString());
- QString fn;
- if (v3.type() == QVariant::String)
- fn = v3.toString();
- else
- fn = v3.toMap().value(QLatin1String("Binary")).toString();
- if (fn.isEmpty())
- continue;
- if (fn.startsWith(QLatin1Char('{')))
- continue;
- if (fn == QLatin1String("auto"))
- continue;
- FileName command = FileName::fromUserInput(fn);
- if (findByCommand(command))
- continue;
- DebuggerItem item;
- item.setCommand(command);
- item.setAutoDetected(true);
- item.reinitializeFromFile();
- item.setDisplayName(tr("Extracted from Kit %1").arg(kitName));
- addDebugger(item);
- }
-}
-
-const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command)
-{
- foreach (const DebuggerItem &item, m_debuggers)
- if (item.command() == command)
- return &item;
-
- return 0;
-}
-
-const DebuggerItem *DebuggerItemManager::findById(const QVariant &id)
-{
- foreach (const DebuggerItem &item, m_debuggers)
- if (item.id() == id)
- return &item;
-
- return 0;
-}
-
-void DebuggerItemManager::restoreDebuggers()
-{
- // Read debuggers from SDK
- QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
- readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)), true);
-
- // Read all debuggers from user file.
- readDebuggers(userSettingsFileName(), false);
-
- // Auto detect current.
- autoDetectCdbDebuggers();
- autoDetectGdbOrLldbDebuggers();
-
- // Add debuggers from pre-3.x profiles.xml
- readLegacyDebuggers();
-}
-
-void DebuggerItemManager::saveDebuggers()
-{
- QTC_ASSERT(m_writer, return);
- QVariantMap data;
- data.insert(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 1);
-
- int count = 0;
- foreach (const DebuggerItem &item, m_debuggers) {
- if (item.isValid()) {
- QVariantMap tmp = item.toMap();
- if (tmp.isEmpty())
- continue;
- data.insert(QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(count), tmp);
- ++count;
- }
- }
- data.insert(QLatin1String(DEBUGGER_COUNT_KEY), count);
- m_writer->save(data, Core::ICore::mainWindow());
-
- // Do not save default debuggers as they are set by the SDK.
-}
-
-QVariant DebuggerItemManager::registerDebugger(const DebuggerItem &item)
-{
- QTC_ASSERT(!item.command().isEmpty(), return QVariant());
- QTC_ASSERT(!item.displayName().isEmpty(), return QVariant());
- QTC_ASSERT(item.engineType() != NoEngineType, return QVariant());
- if (findByCommand(item.command()))
- return item.id();
-
- return addDebugger(item);
-}
-
-void DebuggerItemManager::deregisterDebugger(const DebuggerItem &item)
-{
- if (findByCommand(item.command()))
- removeDebugger(item.id());
-}
-
-QVariant DebuggerItemManager::addDebugger(const DebuggerItem &item)
-{
- QTC_ASSERT(item.id().isValid(), return QVariant());
- m_debuggers.append(item);
- m_model->addDebugger(item);
- return item.id();
-}
-
-void DebuggerItemManager::removeDebugger(const QVariant &id)
-{
- bool ok = false;
- for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
- if (m_debuggers.at(i).id() == id) {
- m_debuggers.removeAt(i);
- ok = true;
- break;
- }
- }
-
- QTC_ASSERT(ok, return);
- m_model->removeDebugger(id);
-}
-
-QString DebuggerItemManager::uniqueDisplayName(const QString &base)
-{
- foreach (const DebuggerItem &item, m_debuggers)
- if (item.displayName() == base)
- return uniqueDisplayName(base + QLatin1String(" (1)"));
-
- return base;
-}
-
-void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName)
-{
- for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
- DebuggerItem &item = m_debuggers[i];
- if (item.id() == id) {
- item.setDisplayName(displayName);
- item.setCommand(fileName);
- item.reinitializeFromFile();
- emit m_model->updateDebugger(item.id());
- break;
- }
- }
-}
-
namespace Internal {
-static QList<QStandardItem *> describeItem(const DebuggerItem &item)
-{
- QList<QStandardItem *> row;
- row.append(new QStandardItem(item.displayName()));
- row.append(new QStandardItem(item.command().toUserOutput()));
- row.append(new QStandardItem(item.engineTypeName()));
- row.at(0)->setData(item.id());
- row.at(0)->setEditable(false);
- row.at(1)->setEditable(false);
- row.at(2)->setEditable(false);
- row.at(0)->setSelectable(true);
- row.at(1)->setSelectable(true);
- row.at(2)->setSelectable(true);
- return row;
-}
-
-static QList<QStandardItem *> createRow(const QString &display)
-{
- QList<QStandardItem *> row;
- row.append(new QStandardItem(display));
- row.append(new QStandardItem());
- row.append(new QStandardItem());
- row.at(0)->setEditable(false);
- row.at(1)->setEditable(false);
- row.at(2)->setEditable(false);
- row.at(0)->setSelectable(false);
- row.at(1)->setSelectable(false);
- row.at(2)->setSelectable(false);
- return row;
-}
-
class DebuggerItemConfigWidget;
-// --------------------------------------------------------------------------
-// DebuggerItemModel
-// --------------------------------------------------------------------------
-
-DebuggerItemModel::DebuggerItemModel(QObject *parent)
- : QStandardItemModel(parent)
-{
- setColumnCount(3);
-
- QList<QStandardItem *> row = createRow(tr("Auto-detected"));
- m_autoRoot = row.at(0);
- appendRow(row);
-
- row = createRow(tr("Manual"));
- m_manualRoot = row.at(0);
- appendRow(row);
-}
-
-QVariant DebuggerItemModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
- switch (section) {
- case 0:
- return tr("Name");
- case 1:
- return tr("Path");
- case 2:
- return tr("Type");
- }
- }
- return QVariant();
-}
-
-QStandardItem *DebuggerItemModel::currentStandardItem() const
-{
- return findStandardItemById(m_currentDebugger);
-}
-
-QStandardItem *DebuggerItemModel::findStandardItemById(const QVariant &id) const
-{
- for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) {
- QStandardItem *sitem = m_autoRoot->child(i);
- if (sitem->data() == id)
- return sitem;
- }
- for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) {
- QStandardItem *sitem = m_manualRoot->child(i);
- if (sitem->data() == id)
- return sitem;
- }
- return 0;
-}
-
-QModelIndex DebuggerItemModel::currentIndex() const
-{
- QStandardItem *current = currentStandardItem();
- return current ? current->index() : QModelIndex();
-}
-
-QModelIndex DebuggerItemModel::lastIndex() const
-{
- int n = m_manualRoot->rowCount();
- QStandardItem *current = m_manualRoot->child(n - 1);
- return current ? current->index() : QModelIndex();
-}
-
-void DebuggerItemModel::markCurrentDirty()
-{
- QStandardItem *sitem = currentStandardItem();
- QTC_ASSERT(sitem, return);
- QFont font = sitem->font();
- font.setBold(true);
- sitem->setFont(font);
-}
-
-void DebuggerItemModel::addDebugger(const DebuggerItem &item)
-{
- QTC_ASSERT(item.id().isValid(), return);
- QList<QStandardItem *> row = describeItem(item);
- (item.isAutoDetected() ? m_autoRoot : m_manualRoot)->appendRow(row);
- emit debuggerAdded(item.id(), item.displayName());
-}
-
-void DebuggerItemModel::removeDebugger(const QVariant &id)
-{
- QStandardItem *sitem = findStandardItemById(id);
- QTC_ASSERT(sitem, return);
- QStandardItem *parent = sitem->parent();
- QTC_ASSERT(parent, return);
- // This will trigger a change of m_currentDebugger via changing the
- // view selection.
- parent->removeRow(sitem->row());
- emit debuggerRemoved(id);
-}
-
-void DebuggerItemModel::updateDebugger(const QVariant &id)
-{
- QList<DebuggerItem> debuggers = DebuggerItemManager::debuggers();
- for (int i = 0, n = debuggers.size(); i != n; ++i) {
- DebuggerItem &item = debuggers[i];
- if (item.id() == id) {
- QStandardItem *sitem = findStandardItemById(id);
- QTC_ASSERT(sitem, return);
- QStandardItem *parent = sitem->parent();
- QTC_ASSERT(parent, return);
- int row = sitem->row();
- QFont font = sitem->font();
- font.setBold(false);
- parent->child(row, 0)->setData(item.displayName(), Qt::DisplayRole);
- parent->child(row, 0)->setFont(font);
- parent->child(row, 1)->setData(item.command().toUserOutput(), Qt::DisplayRole);
- parent->child(row, 1)->setFont(font);
- parent->child(row, 2)->setData(item.engineTypeName(), Qt::DisplayRole);
- parent->child(row, 2)->setFont(font);
- emit debuggerUpdated(id, item.displayName());
- return;
- }
- }
-}
-
-void DebuggerItemModel::setCurrentIndex(const QModelIndex &index)
-{
- QStandardItem *sit = itemFromIndex(index);
- m_currentDebugger = sit ? sit->data() : QVariant();
-}
-
// -----------------------------------------------------------------------
// DebuggerKitConfigWidget
// -----------------------------------------------------------------------
@@ -1002,296 +204,5 @@ void DebuggerKitConfigWidget::updateComboBox(const QVariant &id)
m_comboBox->setCurrentIndex(0);
}
-// -----------------------------------------------------------------------
-// DebuggerItemConfigWidget
-// -----------------------------------------------------------------------
-
-class DebuggerItemConfigWidget : public QWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerItemConfigWidget)
-public:
- explicit DebuggerItemConfigWidget();
- void loadItem();
- void saveItem();
- void connectDirty();
- void disconnectDirty();
-
-private:
- QLineEdit *m_displayNameLineEdit;
- QLabel *m_cdbLabel;
- PathChooser *m_binaryChooser;
- QLineEdit *m_abis;
-};
-
-DebuggerItemConfigWidget::DebuggerItemConfigWidget()
-{
- m_displayNameLineEdit = new QLineEdit(this);
-
- m_binaryChooser = new PathChooser(this);
- m_binaryChooser->setExpectedKind(PathChooser::ExistingCommand);
- m_binaryChooser->setMinimumWidth(400);
-
- m_cdbLabel = new QLabel(this);
- m_cdbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- m_cdbLabel->setOpenExternalLinks(true);
-
- m_abis = new QLineEdit(this);
- m_abis->setEnabled(false);
-
- QFormLayout *formLayout = new QFormLayout(this);
- formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
- formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit);
-// formLayout->addRow(new QLabel(tr("Type:")), m_engineTypeComboBox);
- formLayout->addRow(m_cdbLabel);
- formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser);
- formLayout->addRow(new QLabel(tr("ABIs:")), m_abis);
-
- connectDirty();
-}
-
-void DebuggerItemConfigWidget::connectDirty()
-{
- DebuggerItemModel *model = DebuggerItemManager::model();
- connect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
- model, SLOT(markCurrentDirty()));
- connect(m_binaryChooser, SIGNAL(changed(QString)),
- model, SLOT(markCurrentDirty()));
-}
-
-void DebuggerItemConfigWidget::disconnectDirty()
-{
- DebuggerItemModel *model = DebuggerItemManager::model();
- disconnect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
- model, SLOT(markCurrentDirty()));
- disconnect(m_binaryChooser, SIGNAL(changed(QString)),
- model, SLOT(markCurrentDirty()));
-}
-
-void DebuggerItemConfigWidget::loadItem()
-{
- DebuggerItemModel *model = DebuggerItemManager::model();
- const DebuggerItem *item = DebuggerItemManager::findById(model->m_currentDebugger);
- if (!item)
- return;
-
- disconnectDirty();
- m_displayNameLineEdit->setEnabled(!item->isAutoDetected());
- m_displayNameLineEdit->setText(item->displayName());
-
- m_binaryChooser->setEnabled(!item->isAutoDetected());
- m_binaryChooser->setFileName(item->command());
- connectDirty();
-
- QString text;
- QString versionCommand;
- if (item->engineType() == CdbEngineType) {
-#ifdef Q_OS_WIN
- const bool is64bit = winIs64BitSystem();
-#else
- const bool is64bit = false;
-#endif
- const QString versionString = is64bit ? tr("64-bit version") : tr("32-bit version");
- //: Label text for path configuration. %2 is "x-bit version".
- text = tr("<html><body><p>Specify the path to the "
- "<a href=\"%1\">Windows Console Debugger executable</a>"
- " (%2) here.</p>""</body></html>").
- arg(QLatin1String(debuggingToolsWikiLinkC), versionString);
- versionCommand = QLatin1String("-version");
- } else {
- versionCommand = QLatin1String("--version");
- }
-
- m_cdbLabel->setText(text);
- m_cdbLabel->setVisible(!text.isEmpty());
- m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand));
-
- m_abis->setText(item->abiNames().join(QLatin1String(", ")));
-}
-
-void DebuggerItemConfigWidget::saveItem()
-{
- DebuggerItemModel *model = DebuggerItemManager::model();
- const DebuggerItem *item = DebuggerItemManager::findById(model->m_currentDebugger);
- QTC_ASSERT(item, return);
- DebuggerItemManager::setItemData(item->id(), m_displayNameLineEdit->text(),
- m_binaryChooser->fileName());
-}
-
-// --------------------------------------------------------------------------
-// DebuggerOptionsPage
-// --------------------------------------------------------------------------
-
-DebuggerOptionsPage::DebuggerOptionsPage()
-{
- m_model = 0;
- m_debuggerView = 0;
- m_container = 0;
- m_addButton = 0;
- m_cloneButton = 0;
- m_delButton = 0;
-
- setId(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID);
- setDisplayName(tr("Debuggers"));
- setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
- setDisplayCategory(QCoreApplication::translate("ProjectExplorer",
- ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY));
- setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON));
-}
-
-QWidget *DebuggerOptionsPage::createPage(QWidget *parent)
-{
- m_configWidget = new QWidget(parent);
-
- m_addButton = new QPushButton(tr("Add"), m_configWidget);
- m_cloneButton = new QPushButton(tr("Clone"), m_configWidget);
- m_delButton = new QPushButton(tr("Remove"), m_configWidget);
-
- m_container = new DetailsWidget(m_configWidget);
- m_container->setState(DetailsWidget::NoSummary);
- m_container->setVisible(false);
-
- m_model = DebuggerItemManager::model();
-
- m_debuggerView = new QTreeView(m_configWidget);
- m_debuggerView->setModel(m_model);
- m_debuggerView->setUniformRowHeights(true);
- m_debuggerView->setSelectionMode(QAbstractItemView::SingleSelection);
- m_debuggerView->setSelectionBehavior(QAbstractItemView::SelectRows);
- m_debuggerView->expandAll();
-
- QHeaderView *header = m_debuggerView->header();
- header->setStretchLastSection(false);
- header->setResizeMode(0, QHeaderView::ResizeToContents);
- header->setResizeMode(1, QHeaderView::ResizeToContents);
- header->setResizeMode(2, QHeaderView::Stretch);
-
- QVBoxLayout *buttonLayout = new QVBoxLayout();
- buttonLayout->setSpacing(6);
- buttonLayout->setContentsMargins(0, 0, 0, 0);
- buttonLayout->addWidget(m_addButton);
- buttonLayout->addWidget(m_cloneButton);
- buttonLayout->addWidget(m_delButton);
- buttonLayout->addItem(new QSpacerItem(10, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
-
- QVBoxLayout *verticalLayout = new QVBoxLayout();
- verticalLayout->addWidget(m_debuggerView);
- verticalLayout->addWidget(m_container);
-
- QHBoxLayout *horizontalLayout = new QHBoxLayout(m_configWidget);
- horizontalLayout->addLayout(verticalLayout);
- horizontalLayout->addLayout(buttonLayout);
-
- connect(m_debuggerView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SLOT(debuggerSelectionChanged()));
-
- connect(m_addButton, SIGNAL(clicked()), this, SLOT(addDebugger()), Qt::QueuedConnection);
- connect(m_cloneButton, SIGNAL(clicked()), this, SLOT(cloneDebugger()), Qt::QueuedConnection);
- connect(m_delButton, SIGNAL(clicked()), this, SLOT(removeDebugger()), Qt::QueuedConnection);
-
- m_searchKeywords = tr("Debuggers");
-
- m_itemConfigWidget = new DebuggerItemConfigWidget;
- m_container->setWidget(m_itemConfigWidget);
-
- updateState();
-
- return m_configWidget;
-}
-
-void DebuggerOptionsPage::apply()
-{
- m_itemConfigWidget->saveItem();
- debuggerModelChanged();
-}
-
-void DebuggerOptionsPage::cloneDebugger()
-{
- const DebuggerItem *item = DebuggerItemManager::findById(m_model->currentDebugger());
- QTC_ASSERT(item, return);
- DebuggerItem newItem;
- newItem.setCommand(item->command());
- newItem.setEngineType(item->engineType());
- newItem.setAbis(item->abis());
- newItem.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("Clone of %1").arg(item->displayName())));
- newItem.setAutoDetected(false);
- DebuggerItemManager::addDebugger(newItem);
- m_debuggerView->setCurrentIndex(m_model->lastIndex());
-}
-
-void DebuggerOptionsPage::addDebugger()
-{
- DebuggerItem item;
- item.setEngineType(NoEngineType);
- item.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("New Debugger")));
- item.setAutoDetected(false);
- DebuggerItemManager::addDebugger(item);
- m_debuggerView->setCurrentIndex(m_model->lastIndex());
-}
-
-void DebuggerOptionsPage::removeDebugger()
-{
- QVariant id = m_model->currentDebugger();
- DebuggerItemManager::removeDebugger(id);
- m_debuggerView->setCurrentIndex(m_model->lastIndex());
-}
-
-void DebuggerOptionsPage::finish()
-{
- // Deleted by settingsdialog.
- m_configWidget = 0;
-
- // Children of m_configWidget.
- m_container = 0;
- m_debuggerView = 0;
- m_addButton = 0;
- m_cloneButton = 0;
- m_delButton = 0;
-}
-
-bool DebuggerOptionsPage::matches(const QString &s) const
-{
- return m_searchKeywords.contains(s, Qt::CaseInsensitive);
-}
-
-void DebuggerOptionsPage::debuggerSelectionChanged()
-{
- QTC_ASSERT(m_container, return);
-
- QModelIndex mi = m_debuggerView->currentIndex();
- mi = mi.sibling(mi.row(), 0);
- m_model->setCurrentIndex(mi);
-
- m_itemConfigWidget->loadItem();
- m_container->setVisible(m_model->m_currentDebugger.isValid());
- updateState();
-}
-
-void DebuggerOptionsPage::debuggerModelChanged()
-{
- QTC_ASSERT(m_container, return);
-
- m_itemConfigWidget->loadItem();
- m_container->setVisible(m_model->m_currentDebugger.isValid());
- m_debuggerView->setCurrentIndex(m_model->currentIndex());
- updateState();
-}
-
-void DebuggerOptionsPage::updateState()
-{
- if (!m_cloneButton)
- return;
-
- bool canCopy = false;
- bool canDelete = false;
-
- if (const DebuggerItem *item = DebuggerItemManager::findById(m_model->m_currentDebugger)) {
- canCopy = item->isValid() && item->canClone();
- canDelete = !item->isAutoDetected();
- canDelete = true; // Do we want to remove auto-detected items?
- }
- m_cloneButton->setEnabled(canCopy);
- m_delButton->setEnabled(canDelete);
-}
-
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/debuggerkitconfigwidget.h b/src/plugins/debugger/debuggerkitconfigwidget.h
index f2ab06695f..c6a5433218 100644
--- a/src/plugins/debugger/debuggerkitconfigwidget.h
+++ b/src/plugins/debugger/debuggerkitconfigwidget.h
@@ -52,52 +52,6 @@ QT_END_NAMESPACE
namespace Debugger {
namespace Internal {
-class DebuggerItemConfigWidget;
-class DebuggerKitConfigWidget;
-
-// -----------------------------------------------------------------------
-// DebuggerItemModel
-//------------------------------------------------------------------------
-class DebuggerItemModel : public QStandardItemModel
-{
- Q_OBJECT
-
-public:
- DebuggerItemModel(QObject *parent);
-
- QModelIndex currentIndex() const;
- QModelIndex lastIndex() const;
- void setCurrentIndex(const QModelIndex &index);
- QVariant currentDebugger() const { return m_currentDebugger; }
- void addDebugger(const DebuggerItem &item);
- void removeDebugger(const QVariant &id);
- void updateDebugger(const QVariant &id);
-
-public slots:
- void markCurrentDirty();
-
-signals:
- void debuggerAdded(const QVariant &id, const QString &display);
- void debuggerUpdated(const QVariant &id, const QString &display);
- void debuggerRemoved(const QVariant &id);
-
-private:
- friend class Debugger::DebuggerKitInformation;
- friend class DebuggerKitConfigWidget;
- friend class DebuggerItemConfigWidget;
- friend class DebuggerOptionsPage;
-
- QStandardItem *currentStandardItem() const;
- QStandardItem *findStandardItemById(const QVariant &id) const;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const;
-
- QVariant m_currentDebugger;
-
- QStandardItem *m_autoRoot;
- QStandardItem *m_manualRoot;
- QStringList removed;
-};
-
// -----------------------------------------------------------------------
// DebuggerKitConfigWidget
// -----------------------------------------------------------------------
@@ -135,44 +89,7 @@ private:
QPushButton *m_manageButton;
};
-// --------------------------------------------------------------------------
-// DebuggerOptionsPage
-// --------------------------------------------------------------------------
-
-class DebuggerOptionsPage : public Core::IOptionsPage
-{
- Q_OBJECT
-
-public:
- DebuggerOptionsPage();
-
- QWidget *createPage(QWidget *parent);
- void apply();
- void finish();
- bool matches(const QString &) const;
-
-private slots:
- void debuggerSelectionChanged();
- void debuggerModelChanged();
- void updateState();
- void cloneDebugger();
- void addDebugger();
- void removeDebugger();
-
-private:
- QWidget *m_configWidget;
- QString m_searchKeywords;
-
- DebuggerItemModel *m_model;
- DebuggerItemConfigWidget *m_itemConfigWidget;
- QTreeView *m_debuggerView;
- Utils::DetailsWidget *m_container;
- QPushButton *m_addButton;
- QPushButton *m_cloneButton;
- QPushButton *m_delButton;
-};
-
} // namespace Internal
} // namespace Debugger
-#endif // DEBUGGER_DEBUGGERKITINFORMATION_H
+#endif // DEBUGGER_DEBUGGERKITCONFIGWIDGET_H
diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp
index 5436206bcb..7ee98c619d 100644
--- a/src/plugins/debugger/debuggerkitinformation.cpp
+++ b/src/plugins/debugger/debuggerkitinformation.cpp
@@ -28,309 +28,305 @@
****************************************************************************/
#include "debuggerkitinformation.h"
+
+#include "debuggeritemmanager.h"
#include "debuggerkitconfigwidget.h"
-#include <projectexplorer/abi.h>
+#include "projectexplorer/toolchain.h"
+#include "projectexplorer/projectexplorerconstants.h"
+
#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
-#include <QProcess>
-#include <QUuid>
+#include <QFileInfo>
-using namespace Debugger::Internal;
using namespace ProjectExplorer;
using namespace Utils;
-static const char DEBUGGER_INFORMATION_COMMAND[] = "Binary";
-static const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName";
-static const char DEBUGGER_INFORMATION_ID[] = "Id";
-static const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType";
-static const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected";
-static const char DEBUGGER_INFORMATION_ABIS[] = "Abis";
-
namespace Debugger {
// --------------------------------------------------------------------------
-// DebuggerItem
+// DebuggerKitInformation
// --------------------------------------------------------------------------
-DebuggerItem::DebuggerItem()
+DebuggerKitInformation::DebuggerKitInformation()
{
- m_id = QUuid::createUuid().toString();
- m_engineType = NoEngineType;
- m_isAutoDetected = false;
+ setObjectName(QLatin1String("DebuggerKitInformation"));
+ setId(DebuggerKitInformation::id());
+ setPriority(28000);
}
-DebuggerItem::DebuggerItem(const QVariantMap &data)
+QVariant DebuggerKitInformation::defaultValue(Kit *k) const
{
- m_command = FileName::fromUserInput(data.value(QLatin1String(DEBUGGER_INFORMATION_COMMAND)).toString());
- m_id = data.value(QLatin1String(DEBUGGER_INFORMATION_ID)).toString();
- m_displayName = data.value(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME)).toString();
- m_isAutoDetected = data.value(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), false).toBool();
- m_engineType = DebuggerEngineType(data.value(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE),
- static_cast<int>(NoEngineType)).toInt());
-
- foreach (const QString &a, data.value(QLatin1String(DEBUGGER_INFORMATION_ABIS)).toStringList()) {
- Abi abi(a);
- if (abi.isValid())
- m_abis.append(abi);
- }
+ ToolChain *tc = ToolChainKitInformation::toolChain(k);
+ QTC_ASSERT(tc, return QVariant());
+
+ const Abi toolChainAbi = tc->targetAbi();
+ foreach (const DebuggerItem &item, DebuggerItemManager::debuggers())
+ foreach (const Abi targetAbi, item.abis())
+ if (targetAbi.isCompatibleWith(toolChainAbi))
+ return item.id();
+
+ return QVariant();
}
-void DebuggerItem::reinitializeFromFile()
+void DebuggerKitInformation::setup(Kit *k)
{
- QProcess proc;
- proc.start(m_command.toString(), QStringList() << QLatin1String("--version"));
- proc.waitForStarted();
- proc.waitForFinished();
- QByteArray ba = proc.readAll();
- if (ba.contains("gdb")) {
- m_engineType = GdbEngineType;
- const char needle[] = "This GDB was configured as \"";
- // E.g. "--host=i686-pc-linux-gnu --target=arm-unknown-nto-qnx6.5.0".
- // or "i686-linux-gnu"
- int pos1 = ba.indexOf(needle);
- if (pos1 != -1) {
- pos1 += int(sizeof(needle));
- int pos2 = ba.indexOf('"', pos1 + 1);
- QByteArray target = ba.mid(pos1, pos2 - pos1);
- int pos3 = target.indexOf("--target=");
- if (pos3 >= 0)
- target = target.mid(pos3 + 9);
- m_abis.append(Abi::abiFromTargetTriplet(QString::fromLatin1(target)));
+ // Get one of the available debugger matching the kit's toolchain.
+ const ToolChain *tc = ToolChainKitInformation::toolChain(k);
+ const Abi toolChainAbi = tc ? tc->targetAbi() : Abi::hostAbi();
+
+ // This can be anything (Id, binary path, "auto")
+ const QVariant rawId = k->value(DebuggerKitInformation::id());
+
+ enum {
+ NotDetected, DetectedAutomatically, DetectedByFile, DetectedById
+ } detection = NotDetected;
+ DebuggerEngineType autoEngine = NoEngineType;
+ FileName fileName;
+
+ // With 3.0 we have:
+ // <value type="QString" key="Debugger.Information">{75ecf347-f221-44c3-b613-ea1d29929cd4}</value>
+ // Before we had:
+ // <valuemap type="QVariantMap" key="Debugger.Information">
+ // <value type="QString" key="Binary">/data/dev/debugger/gdb-git/gdb/gdb</value>
+ // <value type="int" key="EngineType">1</value>
+ // </valuemap>
+ // Or for force auto-detected CDB
+ // <valuemap type="QVariantMap" key="Debugger.Information">
+ // <value type="QString" key="Binary">auto</value>
+ // <value type="int" key="EngineType">4</value>
+ // </valuemap>
+
+ if (rawId.isNull()) {
+ // Initial setup of a kit
+ detection = NotDetected;
+ } else if (rawId.type() == QVariant::String) {
+ detection = DetectedById;
+ } else {
+ QMap<QString, QVariant> map = rawId.toMap();
+ QString binary = map.value(QLatin1String("Binary")).toString();
+ if (binary == QLatin1String("auto")) {
+ detection = DetectedAutomatically;
+ autoEngine = DebuggerEngineType(map.value(QLatin1String("EngineType")).toInt());
} else {
- // Fallback.
- m_abis = Abi::abisOfBinary(m_command); // FIXME: Wrong.
+ detection = DetectedByFile;
+ fileName = FileName::fromUserInput(binary);
}
- return;
}
- if (ba.contains("lldb") || ba.startsWith("LLDB")) {
- m_engineType = LldbEngineType;
- m_abis = Abi::abisOfBinary(m_command);
- return;
+
+ const DebuggerItem *bestItem = 0;
+ DebuggerItem::MatchLevel bestLevel = DebuggerItem::DoesNotMatch;
+ foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) {
+ const DebuggerItem *goodItem = 0;
+ if (detection == DetectedById && item.id() == rawId)
+ goodItem = &item;
+ if (detection == DetectedByFile && item.command() == fileName)
+ goodItem = &item;
+ if (detection == DetectedAutomatically && item.engineType() == autoEngine)
+ goodItem = &item;
+
+ if (goodItem) {
+ DebuggerItem::MatchLevel level = goodItem->matchTarget(toolChainAbi);
+ if (level > bestLevel) {
+ bestLevel = level;
+ bestItem = goodItem;
+ }
+ }
}
- if (ba.startsWith("Python")) {
- m_engineType = PdbEngineType;
+
+ // If we have an existing debugger with matching id _and_
+ // matching target ABI we are fine.
+ if (bestItem) {
+ k->setValue(DebuggerKitInformation::id(), bestItem->id());
return;
}
- m_engineType = NoEngineType;
-}
-QString DebuggerItem::engineTypeName() const
-{
- switch (m_engineType) {
- case Debugger::NoEngineType:
- return DebuggerOptionsPage::tr("Not recognized");
- case Debugger::GdbEngineType:
- return QLatin1String("GDB");
- case Debugger::CdbEngineType:
- return QLatin1String("CDB");
- case Debugger::LldbEngineType:
- return QLatin1String("LLDB");
- default:
- return QString();
+ // We didn't find an existing debugger that matched by whatever
+ // data we found in the kit (i.e. no id, filename, "auto")
+ // (or what we found did not match ABI-wise)
+ // Let's try to pick one with matching ABI.
+ QVariant bestId;
+ bestLevel = DebuggerItem::DoesNotMatch;
+ foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) {
+ DebuggerItem::MatchLevel level = item.matchTarget(toolChainAbi);
+ if (level > bestLevel) {
+ bestLevel = level;
+ bestId = item.id();
+ }
}
-}
-QStringList DebuggerItem::abiNames() const
-{
- QStringList list;
- foreach (const Abi &abi, m_abis)
- list.append(abi.toString());
- return list;
+ k->setValue(DebuggerKitInformation::id(), bestId);
}
-QVariantMap DebuggerItem::toMap() const
+
+// This handles the upgrade path from 2.8 to 3.0
+void DebuggerKitInformation::fix(Kit *k)
{
- QVariantMap data;
- data.insert(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME), m_displayName);
- data.insert(QLatin1String(DEBUGGER_INFORMATION_ID), m_id);
- data.insert(QLatin1String(DEBUGGER_INFORMATION_COMMAND), m_command.toUserOutput());
- data.insert(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE), int(m_engineType));
- data.insert(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), m_isAutoDetected);
- data.insert(QLatin1String(DEBUGGER_INFORMATION_ABIS), abiNames());
- return data;
+ // This can be Id, binary path, but not "auto" anymore.
+ const QVariant rawId = k->value(DebuggerKitInformation::id());
+
+ if (rawId.isNull()) // No debugger set, that is fine.
+ return;
+
+ if (rawId.type() == QVariant::String) {
+ if (!DebuggerItemManager::findById(rawId)) {
+ qWarning("Unknown debugger id %s in kit %s",
+ qPrintable(rawId.toString()), qPrintable(k->displayName()));
+ k->setValue(DebuggerKitInformation::id(), QVariant());
+ }
+ return; // All fine (now).
+ }
+
+ QMap<QString, QVariant> map = rawId.toMap();
+ QString binary = map.value(QLatin1String("Binary")).toString();
+ if (binary == QLatin1String("auto")) {
+ // This should not happen as "auto" is handled by setup() already.
+ QTC_CHECK(false);
+ k->setValue(DebuggerKitInformation::id(), QVariant());
+ return;
+ }
+
+ FileName fileName = FileName::fromUserInput(binary);
+ const DebuggerItem *item = DebuggerItemManager::findByCommand(fileName);
+ if (!item) {
+ qWarning("Debugger command %s invalid in kit %s",
+ qPrintable(binary), qPrintable(k->displayName()));
+ k->setValue(DebuggerKitInformation::id(), QVariant());
+ return;
+ }
+
+ k->setValue(DebuggerKitInformation::id(), item->id());
}
-void DebuggerItem::setDisplayName(const QString &displayName)
+// Check the configuration errors and return a flag mask. Provide a quick check and
+// a verbose one with a list of errors.
+
+enum DebuggerConfigurationErrors {
+ NoDebugger = 0x1,
+ DebuggerNotFound = 0x2,
+ DebuggerNotExecutable = 0x4,
+ DebuggerNeedsAbsolutePath = 0x8
+};
+
+static unsigned debuggerConfigurationErrors(const Kit *k)
{
- m_displayName = displayName;
+ QTC_ASSERT(k, return NoDebugger);
+
+ const DebuggerItem *item = DebuggerKitInformation::debugger(k);
+ if (!item)
+ return NoDebugger;
+
+ if (item->command().isEmpty())
+ return NoDebugger;
+
+ unsigned result = 0;
+ const QFileInfo fi = item->command().toFileInfo();
+ if (!fi.exists() || fi.isDir())
+ result |= DebuggerNotFound;
+ else if (!fi.isExecutable())
+ result |= DebuggerNotExecutable;
+
+ if (!fi.exists() || fi.isDir()) {
+ if (item->engineType() == NoEngineType)
+ return NoDebugger;
+
+ // We need an absolute path to be able to locate Python on Windows.
+ if (item->engineType() == GdbEngineType)
+ if (const ToolChain *tc = ToolChainKitInformation::toolChain(k))
+ if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute())
+ result |= DebuggerNeedsAbsolutePath;
+ }
+ return result;
}
-void DebuggerItem::setEngineType(const DebuggerEngineType &engineType)
+const DebuggerItem *DebuggerKitInformation::debugger(const Kit *kit)
{
- m_engineType = engineType;
+ QTC_ASSERT(kit, return 0);
+ const QVariant id = kit->value(DebuggerKitInformation::id());
+ return DebuggerItemManager::findById(id);
}
-void DebuggerItem::setCommand(const Utils::FileName &command)
+bool DebuggerKitInformation::isValidDebugger(const Kit *k)
{
- m_command = command;
+ return debuggerConfigurationErrors(k) == 0;
}
-void DebuggerItem::setAutoDetected(bool isAutoDetected)
+QList<Task> DebuggerKitInformation::validateDebugger(const Kit *k)
{
- m_isAutoDetected = isAutoDetected;
+ QList<Task> result;
+
+ const unsigned errors = debuggerConfigurationErrors(k);
+ if (!errors)
+ return result;
+
+ QString path;
+ if (const DebuggerItem *item = debugger(k))
+ path = item->command().toUserOutput();
+
+ const Core::Id id = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM;
+ if (errors & NoDebugger)
+ result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id);
+
+ if (errors & DebuggerNotFound)
+ result << Task(Task::Error, tr("Debugger '%1' not found.").arg(path),
+ FileName(), -1, id);
+ if (errors & DebuggerNotExecutable)
+ result << Task(Task::Error, tr("Debugger '%1' not executable.").arg(path), FileName(), -1, id);
+
+ if (errors & DebuggerNeedsAbsolutePath) {
+ const QString message =
+ tr("The debugger location must be given as an "
+ "absolute path (%1).").arg(path);
+ result << Task(Task::Error, message, FileName(), -1, id);
+ }
+ return result;
}
-void DebuggerItem::setAbis(const QList<ProjectExplorer::Abi> &abis)
+KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const
{
- m_abis = abis;
+ return new Internal::DebuggerKitConfigWidget(k, this);
}
-void DebuggerItem::setAbi(const Abi &abi)
+KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const
{
- m_abis.clear();
- m_abis.append(abi);
+ return ItemList() << qMakePair(tr("Debugger"), displayString(k));
}
-static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &targetAbi)
+FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k)
{
- if (debuggerAbi.architecture() != Abi::UnknownArchitecture
- && debuggerAbi.architecture() != targetAbi.architecture())
- return DebuggerItem::DoesNotMatch;
-
- if (debuggerAbi.os() != Abi::UnknownOS
- && debuggerAbi.os() != targetAbi.os())
- return DebuggerItem::DoesNotMatch;
-
- if (debuggerAbi.binaryFormat() != Abi::UnknownFormat
- && debuggerAbi.binaryFormat() != targetAbi.binaryFormat())
- return DebuggerItem::DoesNotMatch;
-
- if (debuggerAbi.os() == Abi::WindowsOS) {
- if (debuggerAbi.osFlavor() == Abi::WindowsMSysFlavor && targetAbi.osFlavor() != Abi::WindowsMSysFlavor)
- return DebuggerItem::DoesNotMatch;
- if (debuggerAbi.osFlavor() != Abi::WindowsMSysFlavor && targetAbi.osFlavor() == Abi::WindowsMSysFlavor)
- return DebuggerItem::DoesNotMatch;
- }
-
- if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32)
- return DebuggerItem::MatchesSomewhat;
- if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth())
- return DebuggerItem::DoesNotMatch;
-
- return DebuggerItem::MatchesPerfectly;
+ const DebuggerItem *item = debugger(k);
+ QTC_ASSERT(item, return FileName());
+ return item->command();
}
-DebuggerItem::MatchLevel DebuggerItem::matchTarget(const Abi &targetAbi) const
+DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k)
{
- MatchLevel bestMatch = DoesNotMatch;
- foreach (const Abi &debuggerAbi, m_abis) {
- MatchLevel currentMatch = matchSingle(debuggerAbi, targetAbi);
- if (currentMatch > bestMatch)
- bestMatch = currentMatch;
- }
- return bestMatch;
+ const DebuggerItem *item = debugger(k);
+ QTC_ASSERT(item, return NoEngineType);
+ return item->engineType();
}
-bool Debugger::DebuggerItem::isValid() const
+QString DebuggerKitInformation::displayString(const Kit *k)
{
- return m_engineType != NoEngineType;
+ const DebuggerItem *item = debugger(k);
+ if (!item)
+ return tr("No Debugger");
+ QString binary = item->command().toUserOutput();
+ QString name = tr("%1 Engine").arg(item->engineTypeName());
+ return binary.isEmpty() ? tr("%1 <None>").arg(name) : tr("%1 using \"%2\"").arg(name, binary);
}
-} // namespace Debugger;
-
-#ifdef WITH_TESTS
-
-# include <QTest>
-# include "debuggerplugin.h"
-
-void Debugger::DebuggerPlugin::testDebuggerMatching_data()
+void DebuggerKitInformation::setDebugger(Kit *k, const QVariant &id)
{
- QTest::addColumn<QStringList>("debugger");
- QTest::addColumn<QString>("target");
- QTest::addColumn<int>("result");
-
- QTest::newRow("Invalid data")
- << QStringList()
- << QString()
- << int(DebuggerItem::DoesNotMatch);
- QTest::newRow("Invalid debugger")
- << QStringList()
- << QString::fromLatin1("x86-linux-generic-elf-32bit")
- << int(DebuggerItem::DoesNotMatch);
- QTest::newRow("Invalid target")
- << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
- << QString()
- << int(DebuggerItem::DoesNotMatch);
-
- QTest::newRow("Fuzzy match 1")
- << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit"))
- << QString::fromLatin1("x86-linux-generic-elf-32bit")
- << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior?
- QTest::newRow("Fuzzy match 2")
- << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit"))
- << QString::fromLatin1("arm-windows-msys-pe-64bit")
- << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior?
-
- QTest::newRow("Architecture mismatch")
- << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
- << QString::fromLatin1("arm-linux-generic-elf-32bit")
- << int(DebuggerItem::DoesNotMatch);
- QTest::newRow("OS mismatch")
- << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
- << QString::fromLatin1("x86-macosx-generic-elf-32bit")
- << int(DebuggerItem::DoesNotMatch);
- QTest::newRow("Format mismatch")
- << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
- << QString::fromLatin1("x86-linux-generic-pe-32bit")
- << int(DebuggerItem::DoesNotMatch);
-
- QTest::newRow("Linux perfect match")
- << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit"))
- << QString::fromLatin1("x86-linux-generic-elf-32bit")
- << int(DebuggerItem::MatchesPerfectly);
- QTest::newRow("Linux match")
- << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit"))
- << QString::fromLatin1("x86-linux-generic-elf-32bit")
- << int(DebuggerItem::MatchesSomewhat);
-
- QTest::newRow("Windows perfect match 1")
- << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
- << QString::fromLatin1("x86-windows-msvc2013-pe-64bit")
- << int(DebuggerItem::MatchesPerfectly);
- QTest::newRow("Windows perfect match 2")
- << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
- << QString::fromLatin1("x86-windows-msvc2012-pe-64bit")
- << int(DebuggerItem::MatchesPerfectly);
- QTest::newRow("Windows match 1")
- << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
- << QString::fromLatin1("x86-windows-msvc2013-pe-32bit")
- << int(DebuggerItem::MatchesSomewhat);
- QTest::newRow("Windows match 2")
- << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit"))
- << QString::fromLatin1("x86-windows-msvc2012-pe-32bit")
- << int(DebuggerItem::MatchesSomewhat);
- QTest::newRow("Windows mismatch on word size")
- << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit"))
- << QString::fromLatin1("x86-windows-msvc2013-pe-64bit")
- << int(DebuggerItem::DoesNotMatch);
- QTest::newRow("Windows mismatch on osflavor 1")
- << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit"))
- << QString::fromLatin1("x86-windows-msys-pe-64bit")
- << int(DebuggerItem::DoesNotMatch);
- QTest::newRow("Windows mismatch on osflavor 2")
- << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit"))
- << QString::fromLatin1("x86-windows-msvc2010-pe-64bit")
- << int(DebuggerItem::DoesNotMatch);
+ // Only register reasonably complete debuggers.
+ QTC_ASSERT(DebuggerItemManager::findById(id), return);
+ k->setValue(DebuggerKitInformation::id(), id);
}
-void Debugger::DebuggerPlugin::testDebuggerMatching()
+Core::Id DebuggerKitInformation::id()
{
- QFETCH(QStringList, debugger);
- QFETCH(QString, target);
- QFETCH(int, result);
-
- DebuggerItem::MatchLevel expectedLevel = static_cast<DebuggerItem::MatchLevel>(result);
-
- QList<Abi> debuggerAbis;
- foreach (const QString &abi, debugger)
- debuggerAbis << Abi(abi);
-
- DebuggerItem item;
- item.setAbis(debuggerAbis);
-
- DebuggerItem::MatchLevel level = item.matchTarget(Abi(target));
-
- QCOMPARE(expectedLevel, level);
+ return "Debugger.Information";
}
-#endif
+
+} // namespace Debugger
diff --git a/src/plugins/debugger/debuggerkitinformation.h b/src/plugins/debugger/debuggerkitinformation.h
index 4a185d79e3..3e03e19d2e 100644
--- a/src/plugins/debugger/debuggerkitinformation.h
+++ b/src/plugins/debugger/debuggerkitinformation.h
@@ -32,6 +32,7 @@
#include "debugger_global.h"
#include "debuggerconstants.h"
+#include "debuggeritem.h"
#include <projectexplorer/abi.h>
#include <projectexplorer/kitinformation.h>
@@ -40,102 +41,6 @@
namespace Debugger {
-namespace Internal { class DebuggerItemModel; }
-
-// -----------------------------------------------------------------------
-// DebuggerItem
-// -----------------------------------------------------------------------
-
-class DEBUGGER_EXPORT DebuggerItem
-{
-public:
- DebuggerItem();
- DebuggerItem(const QVariantMap &data);
-
- bool canClone() const { return true; }
- bool isValid() const;
- QString engineTypeName() const;
-
- QVariantMap toMap() const;
- void reinitializeFromFile();
-
- QVariant id() const { return m_id; }
-
- QString displayName() const { return m_displayName; }
- void setDisplayName(const QString &displayName);
-
- DebuggerEngineType engineType() const { return m_engineType; }
- void setEngineType(const DebuggerEngineType &engineType);
-
- Utils::FileName command() const { return m_command; }
- void setCommand(const Utils::FileName &command);
-
- bool isAutoDetected() const { return m_isAutoDetected; }
- void setAutoDetected(bool isAutoDetected);
-
- QList<ProjectExplorer::Abi> abis() const { return m_abis; }
- void setAbis(const QList<ProjectExplorer::Abi> &abis);
- void setAbi(const ProjectExplorer::Abi &abi);
-
- enum MatchLevel { DoesNotMatch, MatchesSomewhat, MatchesPerfectly };
- MatchLevel matchTarget(const ProjectExplorer::Abi &targetAbi) const;
-
- QStringList abiNames() const;
-
-private:
- QVariant m_id;
- QString m_displayName;
- DebuggerEngineType m_engineType;
- Utils::FileName m_command;
- bool m_isAutoDetected;
- QList<ProjectExplorer::Abi> m_abis;
-};
-
-// -----------------------------------------------------------------------
-// DebuggerItemManager
-// -----------------------------------------------------------------------
-
-class DEBUGGER_EXPORT DebuggerItemManager : public QObject
-{
- Q_OBJECT
-
-public:
- static QObject *instance();
- ~DebuggerItemManager();
-
- static QList<DebuggerItem> debuggers();
- static Debugger::Internal::DebuggerItemModel *model();
-
- static QVariant registerDebugger(const DebuggerItem &item);
- static void deregisterDebugger(const DebuggerItem &item);
-
- static const DebuggerItem *findByCommand(const Utils::FileName &command);
- static const DebuggerItem *findById(const QVariant &id);
-
- static void restoreDebuggers();
- static QString uniqueDisplayName(const QString &base);
- static void setItemData(const QVariant &id, const QString& displayName, const Utils::FileName &fileName);
-
- static void removeDebugger(const QVariant &id);
- static QVariant addDebugger(const DebuggerItem &item);
-
-public slots:
- void saveDebuggers();
-
-private:
- explicit DebuggerItemManager(QObject *parent = 0);
- static void autoDetectGdbOrLldbDebuggers();
- static void autoDetectCdbDebuggers();
- static void readLegacyDebuggers();
-
- static Utils::PersistentSettingsWriter *m_writer;
- static QList<DebuggerItem> m_debuggers;
- static Debugger::Internal::DebuggerItemModel *m_model;
-
- friend class Internal::DebuggerItemModel;
- friend class DebuggerPlugin; // Enable constrcutor for DebuggerPlugin
-};
-
class DEBUGGER_EXPORT DebuggerKitInformation : public ProjectExplorer::KitInformation
{
Q_OBJECT
diff --git a/src/plugins/debugger/debuggeroptionspage.cpp b/src/plugins/debugger/debuggeroptionspage.cpp
new file mode 100644
index 0000000000..893b28582b
--- /dev/null
+++ b/src/plugins/debugger/debuggeroptionspage.cpp
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "debuggeroptionspage.h"
+
+#include "debuggeritemmanager.h"
+#include "debuggeritemmodel.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <utils/detailswidget.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+
+#include <QFormLayout>
+#include <QHeaderView>
+#include <QLabel>
+#include <QLineEdit>
+#include <QObject>
+#include <QPushButton>
+#include <QTreeView>
+#include <QWidget>
+
+using namespace Utils;
+
+namespace Debugger {
+namespace Internal {
+
+static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging";
+
+// -----------------------------------------------------------------------
+// DebuggerItemConfigWidget
+// -----------------------------------------------------------------------
+
+class DebuggerItemConfigWidget : public QWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerItemConfigWidget)
+
+public:
+ explicit DebuggerItemConfigWidget();
+ void loadItem();
+ void saveItem();
+ void connectDirty();
+ void disconnectDirty();
+
+private:
+ QLineEdit *m_displayNameLineEdit;
+ QLabel *m_cdbLabel;
+ PathChooser *m_binaryChooser;
+ QLineEdit *m_abis;
+};
+
+DebuggerItemConfigWidget::DebuggerItemConfigWidget()
+{
+ m_displayNameLineEdit = new QLineEdit(this);
+
+ m_binaryChooser = new PathChooser(this);
+ m_binaryChooser->setExpectedKind(PathChooser::ExistingCommand);
+ m_binaryChooser->setMinimumWidth(400);
+
+ m_cdbLabel = new QLabel(this);
+ m_cdbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ m_cdbLabel->setOpenExternalLinks(true);
+
+ m_abis = new QLineEdit(this);
+ m_abis->setEnabled(false);
+
+ QFormLayout *formLayout = new QFormLayout(this);
+ formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit);
+// formLayout->addRow(new QLabel(tr("Type:")), m_engineTypeComboBox);
+ formLayout->addRow(m_cdbLabel);
+ formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser);
+ formLayout->addRow(new QLabel(tr("ABIs:")), m_abis);
+
+ connectDirty();
+}
+
+void DebuggerItemConfigWidget::connectDirty()
+{
+ DebuggerItemModel *model = DebuggerItemManager::model();
+ connect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
+ model, SLOT(markCurrentDirty()));
+ connect(m_binaryChooser, SIGNAL(changed(QString)),
+ model, SLOT(markCurrentDirty()));
+}
+
+void DebuggerItemConfigWidget::disconnectDirty()
+{
+ DebuggerItemModel *model = DebuggerItemManager::model();
+ disconnect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
+ model, SLOT(markCurrentDirty()));
+ disconnect(m_binaryChooser, SIGNAL(changed(QString)),
+ model, SLOT(markCurrentDirty()));
+}
+
+void DebuggerItemConfigWidget::loadItem()
+{
+ DebuggerItemModel *model = DebuggerItemManager::model();
+ const DebuggerItem *item = DebuggerItemManager::findById(model->currentDebugger());
+ if (!item)
+ return;
+
+ disconnectDirty();
+ m_displayNameLineEdit->setEnabled(!item->isAutoDetected());
+ m_displayNameLineEdit->setText(item->displayName());
+
+ m_binaryChooser->setEnabled(!item->isAutoDetected());
+ m_binaryChooser->setFileName(item->command());
+ connectDirty();
+
+ QString text;
+ QString versionCommand;
+ if (item->engineType() == CdbEngineType) {
+#ifdef Q_OS_WIN
+ const bool is64bit = winIs64BitSystem();
+#else
+ const bool is64bit = false;
+#endif
+ const QString versionString = is64bit ? tr("64-bit version") : tr("32-bit version");
+ //: Label text for path configuration. %2 is "x-bit version".
+ text = tr("<html><body><p>Specify the path to the "
+ "<a href=\"%1\">Windows Console Debugger executable</a>"
+ " (%2) here.</p>""</body></html>").
+ arg(QLatin1String(debuggingToolsWikiLinkC), versionString);
+ versionCommand = QLatin1String("-version");
+ } else {
+ versionCommand = QLatin1String("--version");
+ }
+
+ m_cdbLabel->setText(text);
+ m_cdbLabel->setVisible(!text.isEmpty());
+ m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand));
+
+ m_abis->setText(item->abiNames().join(QLatin1String(", ")));
+}
+
+void DebuggerItemConfigWidget::saveItem()
+{
+ DebuggerItemModel *model = DebuggerItemManager::model();
+ const DebuggerItem *item = DebuggerItemManager::findById(model->currentDebugger());
+ QTC_ASSERT(item, return);
+ DebuggerItemManager::setItemData(item->id(), m_displayNameLineEdit->text(),
+ m_binaryChooser->fileName());
+}
+
+// --------------------------------------------------------------------------
+// DebuggerOptionsPage
+// --------------------------------------------------------------------------
+
+DebuggerOptionsPage::DebuggerOptionsPage()
+{
+ m_model = 0;
+ m_debuggerView = 0;
+ m_container = 0;
+ m_addButton = 0;
+ m_cloneButton = 0;
+ m_delButton = 0;
+
+ setId(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID);
+ setDisplayName(tr("Debuggers"));
+ setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
+ setDisplayCategory(QCoreApplication::translate("ProjectExplorer",
+ ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY));
+ setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON));
+}
+
+QWidget *DebuggerOptionsPage::createPage(QWidget *parent)
+{
+ m_configWidget = new QWidget(parent);
+
+ m_addButton = new QPushButton(tr("Add"), m_configWidget);
+ m_cloneButton = new QPushButton(tr("Clone"), m_configWidget);
+ m_delButton = new QPushButton(tr("Remove"), m_configWidget);
+
+ m_container = new DetailsWidget(m_configWidget);
+ m_container->setState(DetailsWidget::NoSummary);
+ m_container->setVisible(false);
+
+ m_model = DebuggerItemManager::model();
+
+ m_debuggerView = new QTreeView(m_configWidget);
+ m_debuggerView->setModel(m_model);
+ m_debuggerView->setUniformRowHeights(true);
+ m_debuggerView->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_debuggerView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_debuggerView->expandAll();
+
+ QHeaderView *header = m_debuggerView->header();
+ header->setStretchLastSection(false);
+ header->setResizeMode(0, QHeaderView::ResizeToContents);
+ header->setResizeMode(1, QHeaderView::ResizeToContents);
+ header->setResizeMode(2, QHeaderView::Stretch);
+
+ QVBoxLayout *buttonLayout = new QVBoxLayout();
+ buttonLayout->setSpacing(6);
+ buttonLayout->setContentsMargins(0, 0, 0, 0);
+ buttonLayout->addWidget(m_addButton);
+ buttonLayout->addWidget(m_cloneButton);
+ buttonLayout->addWidget(m_delButton);
+ buttonLayout->addItem(new QSpacerItem(10, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
+
+ QVBoxLayout *verticalLayout = new QVBoxLayout();
+ verticalLayout->addWidget(m_debuggerView);
+ verticalLayout->addWidget(m_container);
+
+ QHBoxLayout *horizontalLayout = new QHBoxLayout(m_configWidget);
+ horizontalLayout->addLayout(verticalLayout);
+ horizontalLayout->addLayout(buttonLayout);
+
+ connect(m_debuggerView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(debuggerSelectionChanged()));
+
+ connect(m_addButton, SIGNAL(clicked()), this, SLOT(addDebugger()), Qt::QueuedConnection);
+ connect(m_cloneButton, SIGNAL(clicked()), this, SLOT(cloneDebugger()), Qt::QueuedConnection);
+ connect(m_delButton, SIGNAL(clicked()), this, SLOT(removeDebugger()), Qt::QueuedConnection);
+
+ m_searchKeywords = tr("Debuggers");
+
+ m_itemConfigWidget = new DebuggerItemConfigWidget;
+ m_container->setWidget(m_itemConfigWidget);
+
+ updateState();
+
+ return m_configWidget;
+}
+
+void DebuggerOptionsPage::apply()
+{
+ m_itemConfigWidget->saveItem();
+ debuggerModelChanged();
+}
+
+void DebuggerOptionsPage::cloneDebugger()
+{
+ const DebuggerItem *item = DebuggerItemManager::findById(m_model->currentDebugger());
+ QTC_ASSERT(item, return);
+ DebuggerItem newItem;
+ newItem.setCommand(item->command());
+ newItem.setEngineType(item->engineType());
+ newItem.setAbis(item->abis());
+ newItem.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("Clone of %1").arg(item->displayName())));
+ newItem.setAutoDetected(false);
+ DebuggerItemManager::addDebugger(newItem);
+ m_debuggerView->setCurrentIndex(m_model->lastIndex());
+}
+
+void DebuggerOptionsPage::addDebugger()
+{
+ DebuggerItem item;
+ item.setEngineType(NoEngineType);
+ item.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("New Debugger")));
+ item.setAutoDetected(false);
+ DebuggerItemManager::addDebugger(item);
+ m_debuggerView->setCurrentIndex(m_model->lastIndex());
+}
+
+void DebuggerOptionsPage::removeDebugger()
+{
+ QVariant id = m_model->currentDebugger();
+ DebuggerItemManager::removeDebugger(id);
+ m_debuggerView->setCurrentIndex(m_model->lastIndex());
+}
+
+void DebuggerOptionsPage::finish()
+{
+ // Deleted by settingsdialog.
+ m_configWidget = 0;
+
+ // Children of m_configWidget.
+ m_container = 0;
+ m_debuggerView = 0;
+ m_addButton = 0;
+ m_cloneButton = 0;
+ m_delButton = 0;
+}
+
+bool DebuggerOptionsPage::matches(const QString &s) const
+{
+ return m_searchKeywords.contains(s, Qt::CaseInsensitive);
+}
+
+void DebuggerOptionsPage::debuggerSelectionChanged()
+{
+ QTC_ASSERT(m_container, return);
+
+ QModelIndex mi = m_debuggerView->currentIndex();
+ mi = mi.sibling(mi.row(), 0);
+ m_model->setCurrentIndex(mi);
+
+ m_itemConfigWidget->loadItem();
+ m_container->setVisible(m_model->currentDebugger().isValid());
+ updateState();
+}
+
+void DebuggerOptionsPage::debuggerModelChanged()
+{
+ QTC_ASSERT(m_container, return);
+
+ m_itemConfigWidget->loadItem();
+ m_container->setVisible(m_model->currentDebugger().isValid());
+ m_debuggerView->setCurrentIndex(m_model->currentIndex());
+ updateState();
+}
+
+void DebuggerOptionsPage::updateState()
+{
+ if (!m_cloneButton)
+ return;
+
+ bool canCopy = false;
+ bool canDelete = false;
+
+ if (const DebuggerItem *item = DebuggerItemManager::findById(m_model->currentDebugger())) {
+ canCopy = item->isValid() && item->canClone();
+ canDelete = !item->isAutoDetected();
+ canDelete = true; // Do we want to remove auto-detected items?
+ }
+ m_cloneButton->setEnabled(canCopy);
+ m_delButton->setEnabled(canDelete);
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/debuggeroptionspage.h b/src/plugins/debugger/debuggeroptionspage.h
new file mode 100644
index 0000000000..fd1782f4b4
--- /dev/null
+++ b/src/plugins/debugger/debuggeroptionspage.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DEBUGGER_DEBUGGEROPTIONSPAGE_H
+#define DEBUGGER_DEBUGGEROPTIONSPAGE_H
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+class QTreeView;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Utils { class DetailsWidget; }
+
+namespace Debugger {
+namespace Internal {
+
+class DebuggerItemModel;
+class DebuggerItemConfigWidget;
+class DebuggerKitConfigWidget;
+
+// --------------------------------------------------------------------------
+// DebuggerOptionsPage
+// --------------------------------------------------------------------------
+
+class DebuggerOptionsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ DebuggerOptionsPage();
+
+ QWidget *createPage(QWidget *parent);
+ void apply();
+ void finish();
+ bool matches(const QString &) const;
+
+private slots:
+ void debuggerSelectionChanged();
+ void debuggerModelChanged();
+ void updateState();
+ void cloneDebugger();
+ void addDebugger();
+ void removeDebugger();
+
+private:
+ QWidget *m_configWidget;
+ QString m_searchKeywords;
+
+ DebuggerItemModel *m_model;
+ DebuggerItemConfigWidget *m_itemConfigWidget;
+ QTreeView *m_debuggerView;
+ Utils::DetailsWidget *m_container;
+ QPushButton *m_addButton;
+ QPushButton *m_cloneButton;
+ QPushButton *m_delButton;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_DEBUGGEROPTIONSPAGE_H
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index a01bdc9b63..67953afcfc 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -36,11 +36,13 @@
#include "debuggerkitconfigwidget.h"
#include "debuggerdialogs.h"
#include "debuggerengine.h"
+#include "debuggeritemmanager.h"
#include "debuggermainwindow.h"
#include "debuggerrunner.h"
#include "debuggerrunconfigurationaspect.h"
#include "debuggerruncontrolfactory.h"
#include "debuggerstringutils.h"
+#include "debuggeroptionspage.h"
#include "debuggerkitinformation.h"
#include "memoryagent.h"
#include "breakhandler.h"