2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2012-04-24 15:49:09 +02:00
|
|
|
**
|
2013-01-28 17:12:19 +01:00
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2012-04-24 15:49:09 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2012-04-24 15:49:09 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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.
|
2012-04-24 15:49:09 +02:00
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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
|
2012-04-24 15:49:09 +02:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2012-09-03 18:31:44 +02:00
|
|
|
#include "debuggerkitconfigwidget.h"
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2013-02-20 14:15:42 +01:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
2012-04-24 15:49:09 +02:00
|
|
|
#include <projectexplorer/abi.h>
|
2013-08-14 18:30:40 +02:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
|
#include <projectexplorer/toolchain.h>
|
|
|
|
|
#include <projectexplorer/toolchainmanager.h>
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2013-02-08 14:09:04 +01:00
|
|
|
#include <utils/elidinglabel.h>
|
2013-08-14 18:30:40 +02:00
|
|
|
#include <utils/environment.h>
|
|
|
|
|
#include <utils/pathchooser.h>
|
|
|
|
|
#include <utils/persistentsettings.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
2012-04-24 15:49:09 +02:00
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
#include <utils/winutils.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
#include <QApplication>
|
2012-09-05 14:56:08 +02:00
|
|
|
#include <QComboBox>
|
2013-08-14 18:30:40 +02:00
|
|
|
#include <QDirIterator>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QFormLayout>
|
|
|
|
|
#include <QHeaderView>
|
|
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QProcess>
|
2012-09-11 14:03:08 +02:00
|
|
|
#include <QPushButton>
|
2013-08-14 18:30:40 +02:00
|
|
|
#include <QStandardItem>
|
|
|
|
|
#include <QStandardItemModel>
|
|
|
|
|
#include <QTreeView>
|
|
|
|
|
#include <QUuid>
|
|
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
using namespace Debugger::Internal;
|
2012-04-24 15:49:09 +02:00
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
|
2012-12-17 13:42:52 +01:00
|
|
|
static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging";
|
2012-09-05 14:56:08 +02:00
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
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 DEFAULT_DEBUGGER_COUNT_KEY[] = "DefaultDebugger.Count";
|
|
|
|
|
static const char DEFAULT_DEBUGGER_ABI_KEY[] = "DefaultDebugger.Abi.";
|
|
|
|
|
static const char DEFAULT_DEBUGGER_PATH_KEY[] = "DefaultDebugger.Path.";
|
|
|
|
|
static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml";
|
2013-09-03 12:31:28 +02:00
|
|
|
static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml";
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
static const char DEBUGGER_INFORMATION_LEGACY[] = "Debugger.Information";
|
|
|
|
|
//static const char DEBUGGER_INFORMATION[] = "Debugger.InformationV3";
|
2013-08-14 18:30:40 +02:00
|
|
|
static const char DEBUGGER_INFORMATION[] = "Debugger.Information";
|
|
|
|
|
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";
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Helpers
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static DebuggerItemManager *theDebuggerItemManager()
|
|
|
|
|
{
|
|
|
|
|
static DebuggerItemManager *manager = new DebuggerItemManager(0);
|
|
|
|
|
return manager;
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerItem
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
class DebuggerItem
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
DebuggerItem();
|
|
|
|
|
|
|
|
|
|
bool canClone() const { return true; }
|
|
|
|
|
bool isValid() const { return engineType != NoEngineType; }
|
|
|
|
|
QString engineTypeName() const;
|
|
|
|
|
|
|
|
|
|
QVariantMap toMap() const;
|
|
|
|
|
void fromMap(const QVariantMap &data);
|
|
|
|
|
void reinitializeFromFile();
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
QVariant id;
|
|
|
|
|
QString displayName;
|
|
|
|
|
DebuggerEngineType engineType;
|
|
|
|
|
Utils::FileName command;
|
|
|
|
|
bool isAutoDetected;
|
|
|
|
|
QList<ProjectExplorer::Abi> abis;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
DebuggerItem::DebuggerItem()
|
2012-11-16 13:30:59 +01:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
engineType = NoEngineType;
|
|
|
|
|
isAutoDetected = false;
|
2012-11-16 13:30:59 +01:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
QString DebuggerItem::engineTypeName() const
|
|
|
|
|
{
|
|
|
|
|
switch (engineType) {
|
2013-09-02 14:59:49 +02:00
|
|
|
case Debugger::NoEngineType:
|
|
|
|
|
return DebuggerOptionsPage::tr("Not recognized");
|
2013-08-14 18:30:40 +02:00
|
|
|
case Debugger::GdbEngineType:
|
|
|
|
|
return QLatin1String("GDB");
|
|
|
|
|
case Debugger::CdbEngineType:
|
|
|
|
|
return QLatin1String("CDB");
|
|
|
|
|
case Debugger::LldbEngineType:
|
|
|
|
|
return QLatin1String("LLDB");
|
|
|
|
|
default:
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QStringList toList(const QList<Abi> &abis)
|
|
|
|
|
{
|
|
|
|
|
QStringList list;
|
|
|
|
|
foreach (const Abi &abi, abis)
|
|
|
|
|
list.append(abi.toString());
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariantMap DebuggerItem::toMap() const
|
|
|
|
|
{
|
|
|
|
|
QVariantMap data;
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME), displayName);
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_INFORMATION_ID), id);
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_INFORMATION_COMMAND), command.toUserOutput());
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE), int(engineType));
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), isAutoDetected);
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_INFORMATION_ABIS), toList(abis));
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItem::fromMap(const QVariantMap &data)
|
|
|
|
|
{
|
|
|
|
|
command = FileName::fromUserInput(data.value(QLatin1String(DEBUGGER_INFORMATION_COMMAND)).toString());
|
|
|
|
|
id = data.value(QLatin1String(DEBUGGER_INFORMATION_ID)).toString();
|
|
|
|
|
displayName = data.value(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME)).toString();
|
|
|
|
|
isAutoDetected = data.value(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED)).toBool();
|
|
|
|
|
engineType = DebuggerEngineType(data.value(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE)).toInt());
|
|
|
|
|
|
|
|
|
|
abis.clear();
|
|
|
|
|
foreach (const QString &a, data.value(QLatin1String(DEBUGGER_INFORMATION_ABIS)).toStringList()) {
|
|
|
|
|
Abi abi(a);
|
|
|
|
|
if (abi.isValid())
|
|
|
|
|
abis.append(abi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItem::reinitializeFromFile()
|
|
|
|
|
{
|
|
|
|
|
QProcess proc;
|
|
|
|
|
proc.start(command.toString(), QStringList() << QLatin1String("--version"));
|
|
|
|
|
proc.waitForStarted();
|
|
|
|
|
proc.waitForFinished();
|
|
|
|
|
QByteArray ba = proc.readAll();
|
|
|
|
|
if (ba.contains("gdb")) {
|
|
|
|
|
engineType = GdbEngineType;
|
|
|
|
|
// const char needle[] = "This GDB was configured as \"";
|
|
|
|
|
// int pos1 = ba.indexOf(needle);
|
|
|
|
|
// if (pos1 != -1) {
|
|
|
|
|
// pos1 += sizeof(needle);
|
|
|
|
|
// int pos2 = ba.indexOf('"', pos1 + 1);
|
|
|
|
|
// QByteArray target = ba.mid(pos1, pos2 - pos1);
|
|
|
|
|
// abis.append(Abi::abiFromTargetTriplet(target)); // FIXME: Doesn't exist yet.
|
|
|
|
|
// }
|
|
|
|
|
abis = Abi::abisOfBinary(command); // FIXME: Wrong.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ba.contains("lldb")) {
|
|
|
|
|
engineType = LldbEngineType;
|
|
|
|
|
abis = Abi::abisOfBinary(command);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ba.startsWith("Python")) {
|
|
|
|
|
engineType = PdbEngineType;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
engineType = NoEngineType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerKitInformation
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
DebuggerKitInformation::DebuggerKitInformation()
|
|
|
|
|
{
|
|
|
|
|
setObjectName(QLatin1String("DebuggerKitInformation"));
|
2013-08-28 18:57:25 +02:00
|
|
|
setDataId(DEBUGGER_INFORMATION);
|
|
|
|
|
setPriority(28000);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant DebuggerKitInformation::defaultValue(Kit *k) const
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
// This is only called from Kit::Kit()
|
|
|
|
|
// if (isValidDebugger(k)) {
|
|
|
|
|
// DebuggerItem *item = DebuggerItemManager::debuggerFromKit(k);
|
|
|
|
|
// QTC_ASSERT(item, return QVariant());
|
|
|
|
|
// return item->id;
|
|
|
|
|
// }
|
2013-08-14 18:30:40 +02:00
|
|
|
ToolChain *tc = ToolChainKitInformation::toolChain(k);
|
|
|
|
|
return theDebuggerItemManager()->defaultDebugger(tc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerKitInformation::setup(Kit *k)
|
|
|
|
|
{
|
|
|
|
|
k->setValue(DEBUGGER_INFORMATION, defaultValue(k));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
};
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
static QVariant debuggerPathOrId(const Kit *k)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(k, return QString());
|
|
|
|
|
QVariant id = k->value(DEBUGGER_INFORMATION);
|
|
|
|
|
if (!id.isValid())
|
|
|
|
|
return id; // Invalid.
|
|
|
|
|
|
|
|
|
|
// With 3.0 we have:
|
|
|
|
|
// <value type="QString" key="Debugger.Information">{75ecf347-f221-44c3-b613-ea1d29929cd4}</value>
|
|
|
|
|
if (id.type() == QVariant::String)
|
|
|
|
|
return id;
|
|
|
|
|
|
|
|
|
|
// 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>
|
|
|
|
|
return id.toMap().value(QLatin1String("Binary"));
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
static unsigned debuggerConfigurationErrors(const Kit *k)
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(k, return NoDebugger);
|
|
|
|
|
|
|
|
|
|
const DebuggerItem *item = DebuggerItemManager::debuggerFromKit(k);
|
|
|
|
|
if (!item)
|
|
|
|
|
return NoDebugger;
|
|
|
|
|
|
|
|
|
|
if (item->command.isEmpty())
|
2013-08-14 18:30:40 +02:00
|
|
|
return NoDebugger;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
unsigned result = 0;
|
|
|
|
|
const QFileInfo fi = item->command.toFileInfo();
|
2013-08-14 18:30:40 +02:00
|
|
|
if (!fi.exists() || fi.isDir())
|
|
|
|
|
result |= DebuggerNotFound;
|
|
|
|
|
else if (!fi.isExecutable())
|
|
|
|
|
result |= DebuggerNotExecutable;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
if (!fi.exists() || fi.isDir()) {
|
|
|
|
|
if (item->engineType == NoEngineType)
|
|
|
|
|
return NoDebugger;
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
// We need an absolute path to be able to locate Python on Windows.
|
2013-09-03 12:31:28 +02:00
|
|
|
if (item->engineType == GdbEngineType)
|
2013-08-14 18:30:40 +02:00
|
|
|
if (const ToolChain *tc = ToolChainKitInformation::toolChain(k))
|
|
|
|
|
if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute())
|
|
|
|
|
result |= DebuggerNeedsAbsolutePath;
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DebuggerKitInformation::isValidDebugger(const Kit *k)
|
|
|
|
|
{
|
|
|
|
|
return debuggerConfigurationErrors(k) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<Task> DebuggerKitInformation::validateDebugger(const Kit *k)
|
|
|
|
|
{
|
|
|
|
|
QList<Task> result;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
const unsigned errors = debuggerConfigurationErrors(k);
|
2013-08-14 18:30:40 +02:00
|
|
|
if (!errors)
|
|
|
|
|
return result;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
QString path;
|
|
|
|
|
if (const DebuggerItem *item = DebuggerItemManager::debuggerFromKit(k))
|
|
|
|
|
path = item->command.toUserOutput();
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
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, isSticky(k));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
return ItemList() << qMakePair(tr("Debugger"), displayString(k));
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *item = DebuggerItemManager::debuggerFromKit(k);
|
|
|
|
|
QTC_ASSERT(item, return FileName());
|
|
|
|
|
return item->command;
|
|
|
|
|
}
|
2013-08-30 11:19:55 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k)
|
|
|
|
|
{
|
|
|
|
|
const DebuggerItem *item = DebuggerItemManager::debuggerFromKit(k);
|
|
|
|
|
QTC_ASSERT(item, return NoEngineType);
|
|
|
|
|
return item->engineType;
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
QString DebuggerKitInformation::displayString(const Kit *k)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *item = DebuggerItemManager::debuggerFromKit(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);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerKitInformation::setDebugger(Kit *k,
|
|
|
|
|
DebuggerEngineType type, const FileName &command)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
theDebuggerItemManager()->setDebugger(k, type, command);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-02 15:38:31 +02:00
|
|
|
void DebuggerKitInformation::setSticky(Kit *k, bool b)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-02 15:38:31 +02:00
|
|
|
k->setSticky(DEBUGGER_INFORMATION, b);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
static FileName userSettingsFileName()
|
|
|
|
|
{
|
|
|
|
|
QFileInfo settingsLocation(Core::ICore::settings()->fileName());
|
|
|
|
|
return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME));
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
static QList<QStandardItem *> describeItem(const DebuggerItem &item)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
|
|
|
|
QList<QStandardItem *> row;
|
2013-09-03 12:31:28 +02:00
|
|
|
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);
|
2013-08-14 18:30:40 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerItemManager
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
DebuggerItemManager::DebuggerItemManager(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);
|
|
|
|
|
|
|
|
|
|
m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger"));
|
|
|
|
|
|
|
|
|
|
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
|
|
|
|
|
this, SLOT(saveDebuggers()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DebuggerItemManager::~DebuggerItemManager()
|
|
|
|
|
{
|
|
|
|
|
disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
|
|
|
|
|
this, SLOT(saveDebuggers()));
|
|
|
|
|
delete m_writer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant DebuggerItemManager::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();
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
QString DebuggerItemManager::uniqueDisplayName(const QString &base) const
|
|
|
|
|
{
|
|
|
|
|
foreach (const DebuggerItem &item, m_debuggers)
|
|
|
|
|
if (item.displayName == base)
|
|
|
|
|
return uniqueDisplayName(base + QLatin1String(" (1)"));
|
|
|
|
|
|
|
|
|
|
return base;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
void DebuggerItemManager::autoDetectCdbDebugger()
|
|
|
|
|
{
|
|
|
|
|
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) {
|
2013-09-03 12:31:28 +02:00
|
|
|
if (findByCommand(cdb))
|
|
|
|
|
continue;
|
2013-08-14 18:30:40 +02:00
|
|
|
DebuggerItem item;
|
|
|
|
|
item.isAutoDetected = true;
|
|
|
|
|
item.abis = Abi::abisOfBinary(cdb);
|
|
|
|
|
item.command = cdb;
|
|
|
|
|
item.engineType = CdbEngineType;
|
2013-09-03 12:31:28 +02:00
|
|
|
item.displayName = uniqueDisplayName(tr("Auto-detected CDB at %1").arg(cdb.toUserOutput()));
|
|
|
|
|
doAddDebugger(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::autoDetectDebuggers()
|
|
|
|
|
{
|
|
|
|
|
autoDetectCdbDebugger();
|
|
|
|
|
|
|
|
|
|
QStringList filters;
|
|
|
|
|
filters.append(QLatin1String("gdb-i686-pc-mingw32"));
|
|
|
|
|
filters.append(QLatin1String("gdb"));
|
|
|
|
|
filters.append(QLatin1String("lldb"));
|
|
|
|
|
filters.append(QLatin1String("lldb-*"));
|
|
|
|
|
|
|
|
|
|
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()) {
|
2013-09-03 12:31:28 +02:00
|
|
|
FileName command = FileName::fromString(fi.absoluteFilePath());
|
|
|
|
|
if (findByCommand(command))
|
|
|
|
|
continue;
|
2013-08-14 18:30:40 +02:00
|
|
|
DebuggerItem item;
|
2013-09-03 12:31:28 +02:00
|
|
|
item.command = command;
|
|
|
|
|
item.id = QUuid::createUuid().toString();
|
2013-08-14 18:30:40 +02:00
|
|
|
item.reinitializeFromFile();
|
|
|
|
|
item.displayName = tr("System %1 at %2")
|
|
|
|
|
.arg(item.engineTypeName()).arg(fi.absoluteFilePath());
|
|
|
|
|
item.isAutoDetected = true;
|
2013-09-03 12:31:28 +02:00
|
|
|
doAddDebugger(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerItemManager::readLegacyDebuggers()
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QFileInfo settingsLocation(Core::ICore::settings()->fileName());
|
|
|
|
|
FileName legacyKits = FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME));
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
PersistentSettingsReader reader;
|
|
|
|
|
if (!reader.load(legacyKits))
|
|
|
|
|
return;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
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(QLatin1String(DEBUGGER_INFORMATION));
|
|
|
|
|
QString fn;
|
|
|
|
|
if (v3.type() == QVariant::String)
|
|
|
|
|
fn = v3.toString();
|
|
|
|
|
else
|
|
|
|
|
fn = v3.toMap().value(QLatin1String(DEBUGGER_INFORMATION_COMMAND)).toString();
|
|
|
|
|
if (fn.isEmpty())
|
|
|
|
|
continue;
|
|
|
|
|
if (fn.startsWith(QLatin1Char('{')))
|
|
|
|
|
continue;
|
|
|
|
|
FileName command = FileName::fromUserInput(fn);
|
|
|
|
|
if (findByCommand(command))
|
|
|
|
|
continue;
|
|
|
|
|
DebuggerItem item;
|
|
|
|
|
item.command = command;
|
|
|
|
|
item.isAutoDetected = true;
|
|
|
|
|
item.reinitializeFromFile();
|
|
|
|
|
item.displayName = tr("Extracted from Kit %1").arg(kitName);
|
|
|
|
|
item.id = QUuid::createUuid().toString();
|
|
|
|
|
doAddDebugger(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant DebuggerItemManager::doAddDebugger(const DebuggerItem &item0)
|
|
|
|
|
{
|
|
|
|
|
DebuggerItem item = item0;
|
|
|
|
|
if (item.id.isNull()) {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
item.id = QUuid::createUuid().toString();
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
QList<QStandardItem *> row = describeItem(item);
|
2013-09-03 12:31:28 +02:00
|
|
|
(item.isAutoDetected ? m_autoRoot : m_manualRoot)->appendRow(row);
|
2013-08-14 18:30:40 +02:00
|
|
|
m_debuggers.append(item);
|
2013-09-03 12:31:28 +02:00
|
|
|
emit debuggerAdded(item.id, item.displayName);
|
|
|
|
|
return item.id;
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command)
|
|
|
|
|
{
|
|
|
|
|
foreach (const DebuggerItem &item, m_debuggers)
|
|
|
|
|
if (item.command == command)
|
|
|
|
|
return &item;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
return 0;
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *DebuggerItemManager::findById(const QVariant &id)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
foreach (const DebuggerItem &item, m_debuggers)
|
|
|
|
|
if (item.id == id)
|
|
|
|
|
return &item;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStandardItem *DebuggerItemManager::currentStandardItem() const
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) {
|
|
|
|
|
QStandardItem *sitem = m_autoRoot->child(i);
|
|
|
|
|
if (sitem->data() == m_currentDebugger)
|
|
|
|
|
return sitem;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) {
|
|
|
|
|
QStandardItem *sitem = m_manualRoot->child(i);
|
|
|
|
|
if (sitem->data() == m_currentDebugger)
|
|
|
|
|
return sitem;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
static QList<DebuggerItem> readDebuggers(const FileName &fileName)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QList<DebuggerItem> result;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
PersistentSettingsReader reader;
|
|
|
|
|
if (!reader.load(fileName))
|
|
|
|
|
return result;
|
|
|
|
|
QVariantMap data = reader.restoreValues();
|
|
|
|
|
|
|
|
|
|
// Check version
|
|
|
|
|
int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt();
|
|
|
|
|
if (version < 1)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
// Read default debugger settings (if any)
|
|
|
|
|
// int count = data.value(QLatin1String(DEFAULT_DEBUGGER_COUNT_KEY)).toInt();
|
|
|
|
|
// for (int i = 0; i < count; ++i) {
|
|
|
|
|
// const QString abiKey = QString::fromLatin1(DEFAULT_DEBUGGER_ABI_KEY) + QString::number(i);
|
|
|
|
|
// if (!data.contains(abiKey))
|
|
|
|
|
// continue;
|
|
|
|
|
// const QString pathKey = QString::fromLatin1(DEFAULT_DEBUGGER_PATH_KEY) + QString::number(i);
|
|
|
|
|
// if (!data.contains(pathKey))
|
|
|
|
|
// continue;
|
|
|
|
|
// m_abiToDebugger.insert(data.value(abiKey).toString(),
|
|
|
|
|
// FileName::fromString(data.value(pathKey).toString()));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// QList<DebuggerFactory *> factories = ExtensionSystem::PluginManager::getObjects<DebuggerFactory>();
|
|
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
break;
|
|
|
|
|
const QVariantMap dbMap = data.value(key).toMap();
|
2013-09-03 12:31:28 +02:00
|
|
|
DebuggerItem item;
|
|
|
|
|
item.fromMap(dbMap);
|
|
|
|
|
result.append(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::restoreDebuggers()
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QList<DebuggerItem> dbsToCheck;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
// Read debuggers from SDK
|
|
|
|
|
QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
|
2013-09-03 12:31:28 +02:00
|
|
|
QList<DebuggerItem> dbsToRegister =
|
2013-08-14 18:30:40 +02:00
|
|
|
readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)));
|
|
|
|
|
|
|
|
|
|
// These are autodetected.
|
2013-09-03 12:31:28 +02:00
|
|
|
for (int i = 0, n = dbsToRegister.size(); i != n; ++i)
|
|
|
|
|
dbsToRegister[i].isAutoDetected = true;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
// SDK debuggers are always considered to be up-to-date, so no need to recheck them.
|
|
|
|
|
|
|
|
|
|
// Read all debuggers from user file.
|
2013-09-03 12:31:28 +02:00
|
|
|
foreach (const DebuggerItem &item, readDebuggers(userSettingsFileName())) {
|
|
|
|
|
if (item.isAutoDetected)
|
2013-08-14 18:30:40 +02:00
|
|
|
dbsToCheck.append(item);
|
|
|
|
|
else
|
|
|
|
|
dbsToRegister.append(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove debuggers configured by the SDK.
|
2013-09-03 12:31:28 +02:00
|
|
|
// foreach (const DebuggerItem &item, dbsToRegister) {
|
|
|
|
|
// for (int i = dbsToCheck.count(); --i >= 0; ) {
|
|
|
|
|
// if (dbsToCheck.at(i).id == item.id)
|
|
|
|
|
// dbsToCheck.removeAt(i);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
// QList<DebuggerItem *> detectedDbs;
|
|
|
|
|
// QList<DebuggerFactory *> factories = ExtensionSystem::PluginManager::getObjects<DebuggerFactory>();
|
|
|
|
|
// foreach (DebuggerFactory *f, factories)
|
|
|
|
|
// detectedDbs.append(f->autoDetect());
|
|
|
|
|
|
|
|
|
|
// Find/update autodetected debuggers
|
|
|
|
|
// DebuggerItem *toStore = 0;
|
|
|
|
|
// foreach (DebuggerItem *currentDetected, detectedDbs) {
|
|
|
|
|
// toStore = currentDetected;
|
|
|
|
|
|
|
|
|
|
// // Check whether we had this debugger stored and prefer the old one with the old id:
|
|
|
|
|
// for (int i = 0; i < dbsToCheck.count(); ++i) {
|
|
|
|
|
// if (*(dbsToCheck.at(i)) == *currentDetected) {
|
|
|
|
|
// toStore = dbsToCheck.at(i);
|
|
|
|
|
// dbsToCheck.removeAt(i);
|
|
|
|
|
// delete currentDetected;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// dbsToRegister += toStore;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Keep debuggers that were not rediscovered but are still executable and delete the rest
|
2013-09-03 12:31:28 +02:00
|
|
|
foreach (const DebuggerItem &item, dbsToCheck) {
|
|
|
|
|
if (!item.isValid()) {
|
2013-08-14 18:30:40 +02:00
|
|
|
qWarning() << QString::fromLatin1("DebuggerItem \"%1\" (%2) dropped since it is not valid")
|
2013-09-03 12:31:28 +02:00
|
|
|
.arg(item.command.toString()).arg(item.id.toString());
|
2013-08-14 18:30:40 +02:00
|
|
|
} else {
|
2013-09-03 12:31:28 +02:00
|
|
|
dbsToRegister.append(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store manual debuggers
|
|
|
|
|
DebuggerItemManager *manager = theDebuggerItemManager();
|
2013-09-03 12:31:28 +02:00
|
|
|
for (int i = 0, n = dbsToRegister.size(); i != n; ++i) {
|
|
|
|
|
DebuggerItem item = dbsToRegister.at(i);
|
|
|
|
|
if (manager->findByCommand(item.command))
|
|
|
|
|
continue;
|
|
|
|
|
if (item.id.isNull())
|
|
|
|
|
item.id = QUuid::createUuid().toString();
|
|
|
|
|
manager->doAddDebugger(item);
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
// Auto detect current.
|
2013-08-14 18:30:40 +02:00
|
|
|
manager->autoDetectDebuggers();
|
2013-09-03 12:31:28 +02:00
|
|
|
|
|
|
|
|
// Add debuggers from pre-3.x profiles.xml
|
|
|
|
|
manager->readLegacyDebuggers();
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::saveDebuggers()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_writer, return);
|
|
|
|
|
QVariantMap data;
|
|
|
|
|
data.insert(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 1);
|
|
|
|
|
|
|
|
|
|
int count = 0;
|
2013-09-03 12:31:28 +02:00
|
|
|
foreach (const DebuggerItem &item, m_debuggers) {
|
|
|
|
|
if (item.isValid()) {
|
|
|
|
|
QVariantMap tmp = item.toMap();
|
2013-08-14 18:30:40 +02:00
|
|
|
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.
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *DebuggerItemManager::debuggerFromKit(const Kit *kit)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
if (!kit)
|
|
|
|
|
return 0;
|
|
|
|
|
QVariant pathOrId = debuggerPathOrId(kit);
|
|
|
|
|
foreach (const DebuggerItem &item, theDebuggerItemManager()->m_debuggers) {
|
|
|
|
|
if (item.id == pathOrId)
|
|
|
|
|
return &item;
|
|
|
|
|
if (item.command == FileName::fromUserInput(pathOrId.toString()))
|
|
|
|
|
return &item;
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerItemManager::setDebugger(Kit *kit, Debugger::DebuggerEngineType type, const FileName &command)
|
2013-08-30 11:19:55 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(kit, return);
|
|
|
|
|
// This should only operate on fresh kits.
|
|
|
|
|
//QVariant id = k->value(DEBUGGER_INFORMATION);
|
|
|
|
|
//QTC_CHECK(id.isNull());
|
|
|
|
|
if (!findByCommand(command)) {
|
|
|
|
|
DebuggerItem item;
|
|
|
|
|
item.engineType = type;
|
|
|
|
|
item.command = command;
|
|
|
|
|
item.id = QUuid::createUuid().toString();
|
|
|
|
|
item.displayName = uniqueDisplayName(tr("Created by tool chain."));
|
|
|
|
|
doAddDebugger(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DebuggerItem *it = findByCommand(command);
|
|
|
|
|
QTC_ASSERT(it, return);
|
|
|
|
|
QTC_ASSERT(it->id.isValid(), return);
|
|
|
|
|
kit->setValue(DEBUGGER_INFORMATION, it->id);
|
|
|
|
|
|
2013-08-30 11:19:55 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
QModelIndex DebuggerItemManager::currentIndex() const
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QStandardItem *current = currentStandardItem();
|
2013-08-14 18:30:40 +02:00
|
|
|
return current ? current->index() : QModelIndex();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::addDebugger()
|
|
|
|
|
{
|
|
|
|
|
DebuggerItem item;
|
|
|
|
|
item.engineType = NoEngineType;
|
2013-09-03 12:31:28 +02:00
|
|
|
item.id = QUuid::createUuid().toString();
|
|
|
|
|
item.displayName = uniqueDisplayName(tr("New Debugger"));
|
2013-08-14 18:30:40 +02:00
|
|
|
item.isAutoDetected = false;
|
2013-09-03 12:31:28 +02:00
|
|
|
doAddDebugger(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::cloneDebugger()
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *item = findById(m_currentDebugger);
|
|
|
|
|
QTC_ASSERT(item, return);
|
|
|
|
|
DebuggerItem newItem = *item;
|
|
|
|
|
newItem.id = QUuid::createUuid().toString();
|
|
|
|
|
newItem.displayName = uniqueDisplayName(tr("Clone of %1").arg(item->displayName));
|
|
|
|
|
newItem.isAutoDetected = false;
|
|
|
|
|
doAddDebugger(newItem);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::removeDebugger()
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(m_currentDebugger.isValid(), return);
|
|
|
|
|
QVariant id = m_currentDebugger;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
QTC_ASSERT(ok, return);
|
2013-09-03 12:31:28 +02:00
|
|
|
QStandardItem *sitem = currentStandardItem();
|
|
|
|
|
QTC_ASSERT(sitem, return);
|
|
|
|
|
QStandardItem *parent = sitem->parent();
|
2013-08-14 18:30:40 +02:00
|
|
|
QTC_ASSERT(parent, return);
|
|
|
|
|
// This will trigger a change of m_currentDebugger via changing the
|
2013-09-03 12:31:28 +02:00
|
|
|
// view selection.
|
|
|
|
|
parent->removeRow(sitem->row());
|
|
|
|
|
emit debuggerRemoved(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::markCurrentDirty()
|
|
|
|
|
{
|
|
|
|
|
QStandardItem *sitem = currentStandardItem();
|
|
|
|
|
QTC_ASSERT(sitem, return);
|
|
|
|
|
QFont font = sitem->font();
|
|
|
|
|
font.setBold(true);
|
|
|
|
|
sitem->setFont(font);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::setCurrentIndex(const QModelIndex &index)
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QStandardItem *sit = itemFromIndex(index);
|
|
|
|
|
m_currentDebugger = sit ? sit->data() : QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemManager::setCurrentData(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 == m_currentDebugger) {
|
|
|
|
|
item.displayName = displayName;
|
|
|
|
|
item.command = fileName;
|
|
|
|
|
item.reinitializeFromFile();
|
|
|
|
|
QStandardItem *sitem = currentStandardItem();
|
|
|
|
|
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(m_currentDebugger, displayName);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant DebuggerItemManager::defaultDebugger(ToolChain *tc)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(tc, return QVariant());
|
|
|
|
|
|
|
|
|
|
DebuggerItem result;
|
|
|
|
|
result.isAutoDetected = true;
|
|
|
|
|
result.displayName = tr("Auto-detected for Tool Chain %1").arg(tc->displayName());
|
|
|
|
|
|
|
|
|
|
Abi abi = Abi::hostAbi();
|
|
|
|
|
if (tc)
|
|
|
|
|
abi = tc->targetAbi();
|
|
|
|
|
|
|
|
|
|
// if (abis.first().wordWidth() == 32)
|
|
|
|
|
// result.first = cdb.toString();
|
|
|
|
|
// else if (abis.first().wordWidth() == 64)
|
|
|
|
|
// result.second = cdb.toString();
|
|
|
|
|
// // prefer 64bit debugger, even for 32bit binaries:
|
|
|
|
|
// if (!result.second.isEmpty())
|
|
|
|
|
// result.first = result.second;
|
|
|
|
|
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
foreach (const DebuggerItem &item, m_debuggers)
|
|
|
|
|
foreach (const Abi targetAbi, item.abis)
|
|
|
|
|
if (targetAbi.isCompatibleWith(abi))
|
|
|
|
|
return item.id;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// CDB for windows:
|
|
|
|
|
if (abi.os() == Abi::WindowsOS && abi.osFlavor() != Abi::WindowsMSysFlavor) {
|
|
|
|
|
QPair<QString, QString> cdbs = autoDetectCdbDebugger();
|
|
|
|
|
result.command = FileName::fromString(abi.wordWidth() == 32 ? cdbs.first : cdbs.second);
|
|
|
|
|
result.engineType = CdbEngineType;
|
|
|
|
|
return maybeAddDebugger(result, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default to GDB, system GDB
|
|
|
|
|
result.engineType = GdbEngineType;
|
|
|
|
|
QString gdb;
|
|
|
|
|
const QString systemGdb = QLatin1String("gdb");
|
|
|
|
|
// MinGW: Search for the python-enabled gdb first.
|
|
|
|
|
if (abi.os() == Abi::WindowsOS && abi.osFlavor() == Abi::WindowsMSysFlavor)
|
|
|
|
|
gdb = env.searchInPath(QLatin1String("gdb-i686-pc-mingw32"));
|
|
|
|
|
if (gdb.isEmpty())
|
|
|
|
|
gdb = env.searchInPath(systemGdb);
|
|
|
|
|
result.command = FileName::fromString(env.searchInPath(gdb.isEmpty() ? systemGdb : gdb));
|
|
|
|
|
return maybeAddDebugger(result, false);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// DebuggerKitConfigWidget
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
DebuggerKitConfigWidget::DebuggerKitConfigWidget(Kit *workingCopy, bool sticky)
|
|
|
|
|
: KitConfigWidget(workingCopy, sticky)
|
|
|
|
|
{
|
|
|
|
|
DebuggerItemManager *manager = theDebuggerItemManager();
|
|
|
|
|
QTC_CHECK(manager);
|
|
|
|
|
|
|
|
|
|
m_comboBox = new QComboBox;
|
|
|
|
|
m_comboBox->setEnabled(true);
|
|
|
|
|
m_comboBox->setToolTip(toolTip());
|
|
|
|
|
m_comboBox->addItem(tr("None"), QString());
|
2013-09-03 12:31:28 +02:00
|
|
|
foreach (const DebuggerItem &item, manager->m_debuggers)
|
|
|
|
|
m_comboBox->addItem(item.displayName, item.id);
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
refresh();
|
|
|
|
|
connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(currentDebuggerChanged(int)));
|
|
|
|
|
|
|
|
|
|
m_manageButton = new QPushButton(tr("Manage..."));
|
|
|
|
|
m_manageButton->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
connect(m_manageButton, SIGNAL(clicked()), this, SLOT(manageDebuggers()));
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
connect(manager, SIGNAL(debuggerAdded(QVariant,QString)),
|
|
|
|
|
this, SLOT(onDebuggerAdded(QVariant,QString)));
|
|
|
|
|
connect(manager, SIGNAL(debuggerUpdated(QVariant,QString)),
|
|
|
|
|
this, SLOT(onDebuggerUpdated(QVariant,QString)));
|
|
|
|
|
connect(manager, SIGNAL(debuggerRemoved(QVariant)),
|
|
|
|
|
this, SLOT(onDebuggerRemoved(QVariant)));
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString DebuggerKitConfigWidget::toolTip() const
|
2012-09-07 16:30:18 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
return tr("The debugger to use for this kit.");
|
2012-09-07 16:30:18 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-03 18:31:44 +02:00
|
|
|
QString DebuggerKitConfigWidget::displayName() const
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2012-08-28 11:33:49 +02:00
|
|
|
return tr("Debugger:");
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-03 18:31:44 +02:00
|
|
|
void DebuggerKitConfigWidget::makeReadOnly()
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
m_manageButton->setEnabled(false);
|
|
|
|
|
m_comboBox->setEnabled(false);
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-10 15:34:35 +02:00
|
|
|
void DebuggerKitConfigWidget::refresh()
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
const DebuggerItem *item = DebuggerItemManager::debuggerFromKit(m_kit);
|
|
|
|
|
updateComboBox(item ? item->id : QVariant());
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
QWidget *DebuggerKitConfigWidget::buttonWidget() const
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
return m_manageButton;
|
2012-09-11 14:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
QWidget *DebuggerKitConfigWidget::mainWidget() const
|
2012-09-11 14:03:08 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
return m_comboBox;
|
2012-09-05 14:56:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
void DebuggerKitConfigWidget::manageDebuggers()
|
|
|
|
|
{
|
|
|
|
|
Core::ICore::showOptionsDialog(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY,
|
|
|
|
|
ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID);
|
|
|
|
|
}
|
2012-09-11 14:03:08 +02:00
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
void DebuggerKitConfigWidget::currentDebuggerChanged(int)
|
2012-09-11 14:03:08 +02:00
|
|
|
{
|
2013-08-29 17:22:06 +02:00
|
|
|
m_kit->setValue(DEBUGGER_INFORMATION, m_comboBox->itemData(m_comboBox->currentIndex()));
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
2012-09-11 14:03:08 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerKitConfigWidget::onDebuggerAdded(const QVariant &id, const QString &displayName)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
|
|
|
|
m_comboBox->setEnabled(true);
|
2013-09-03 12:31:28 +02:00
|
|
|
m_comboBox->addItem(displayName, id);
|
2013-08-14 18:30:40 +02:00
|
|
|
updateComboBox(id);
|
|
|
|
|
}
|
2012-09-11 14:03:08 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerKitConfigWidget::onDebuggerUpdated(const QVariant &id, const QString &displayName)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
|
|
|
|
m_comboBox->setEnabled(true);
|
2013-09-03 12:31:28 +02:00
|
|
|
const int pos = indexOf(id);
|
2013-08-14 18:30:40 +02:00
|
|
|
if (pos < 0)
|
|
|
|
|
return;
|
2013-09-03 12:31:28 +02:00
|
|
|
m_comboBox->setItemText(pos, displayName);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
2012-09-11 14:03:08 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerKitConfigWidget::onDebuggerRemoved(const QVariant &id)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
if (const int pos = indexOf(id)) {
|
|
|
|
|
m_comboBox->removeItem(pos);
|
|
|
|
|
updateComboBox(id);
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
2012-09-11 14:03:08 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
int DebuggerKitConfigWidget::indexOf(const QVariant &id)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(id.isValid(), return -1);
|
2013-08-14 18:30:40 +02:00
|
|
|
for (int i = 0; i < m_comboBox->count(); ++i) {
|
|
|
|
|
if (id == m_comboBox->itemData(i))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
2012-09-11 14:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
QVariant DebuggerKitConfigWidget::currentId() const
|
2012-09-05 14:56:08 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
return m_comboBox->itemData(m_comboBox->currentIndex());
|
2012-09-05 14:56:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
void DebuggerKitConfigWidget::updateComboBox(const QVariant &id)
|
2012-09-05 14:56:08 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
for (int i = 0; i < m_comboBox->count(); ++i) {
|
|
|
|
|
if (id == m_comboBox->itemData(i)) {
|
2012-09-05 14:56:08 +02:00
|
|
|
m_comboBox->setCurrentIndex(i);
|
2013-08-14 18:30:40 +02:00
|
|
|
return;
|
2012-09-05 14:56:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
m_comboBox->setCurrentIndex(0);
|
2012-09-05 14:56:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// DebuggerItemConfigWidget
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
class DebuggerItemConfigWidget : public QWidget
|
2012-09-05 14:56:08 +02:00
|
|
|
{
|
2013-09-04 16:20:33 +02:00
|
|
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerItemConfigWidget)
|
2013-08-14 18:30:40 +02:00
|
|
|
public:
|
|
|
|
|
explicit DebuggerItemConfigWidget();
|
2013-09-03 12:31:28 +02:00
|
|
|
void loadItem();
|
|
|
|
|
void saveItem();
|
|
|
|
|
void connectDirty();
|
|
|
|
|
void disconnectDirty();
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
private:
|
|
|
|
|
QLineEdit *m_displayNameLineEdit;
|
|
|
|
|
QLabel *m_cdbLabel;
|
|
|
|
|
PathChooser *m_binaryChooser;
|
|
|
|
|
QLineEdit *m_abis;
|
|
|
|
|
};
|
2012-09-05 14:56:08 +02:00
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
DebuggerItemConfigWidget::DebuggerItemConfigWidget()
|
2012-09-05 14:56:08 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
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);
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
QFormLayout *formLayout = new QFormLayout(this);
|
2013-08-14 18:30:40 +02:00
|
|
|
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
2013-09-02 14:40:16 +02:00
|
|
|
formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit);
|
2013-08-14 18:30:40 +02:00
|
|
|
// 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);
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
connectDirty();
|
2012-09-05 14:56:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerItemConfigWidget::connectDirty()
|
2012-09-05 14:56:08 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
DebuggerItemManager *manager = theDebuggerItemManager();
|
|
|
|
|
connect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
|
|
|
|
|
manager, SLOT(markCurrentDirty()));
|
|
|
|
|
connect(m_binaryChooser, SIGNAL(changed(QString)),
|
|
|
|
|
manager, SLOT(markCurrentDirty()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemConfigWidget::disconnectDirty()
|
|
|
|
|
{
|
|
|
|
|
DebuggerItemManager *manager = theDebuggerItemManager();
|
|
|
|
|
disconnect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
|
|
|
|
|
manager, SLOT(markCurrentDirty()));
|
|
|
|
|
disconnect(m_binaryChooser, SIGNAL(changed(QString)),
|
|
|
|
|
manager, SLOT(markCurrentDirty()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemConfigWidget::loadItem()
|
|
|
|
|
{
|
|
|
|
|
DebuggerItemManager *manager = theDebuggerItemManager();
|
|
|
|
|
const DebuggerItem *item = manager->findById(manager->m_currentDebugger);
|
2013-08-14 18:30:40 +02:00
|
|
|
if (!item)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
disconnectDirty();
|
2013-08-14 18:30:40 +02:00
|
|
|
m_displayNameLineEdit->setEnabled(!item->isAutoDetected);
|
|
|
|
|
m_displayNameLineEdit->setText(item->displayName);
|
|
|
|
|
|
|
|
|
|
m_binaryChooser->setEnabled(!item->isAutoDetected);
|
|
|
|
|
m_binaryChooser->setFileName(item->command);
|
2013-09-03 12:31:28 +02:00
|
|
|
connectDirty();
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2012-09-05 14:56:08 +02:00
|
|
|
QString text;
|
2013-08-14 18:30:40 +02:00
|
|
|
QString versionCommand;
|
|
|
|
|
if (item->engineType == CdbEngineType) {
|
2012-09-05 14:56:08 +02:00
|
|
|
#ifdef Q_OS_WIN
|
2013-08-14 18:30:40 +02:00
|
|
|
const bool is64bit = winIs64BitSystem();
|
2012-09-05 14:56:08 +02:00
|
|
|
#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>"
|
2012-12-17 13:42:52 +01:00
|
|
|
" (%2) here.</p>""</body></html>").
|
|
|
|
|
arg(QLatin1String(debuggingToolsWikiLinkC), versionString);
|
2013-08-14 18:30:40 +02:00
|
|
|
versionCommand = QLatin1String("-version");
|
|
|
|
|
} else {
|
|
|
|
|
versionCommand = QLatin1String("--version");
|
2012-09-05 14:56:08 +02:00
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
m_cdbLabel->setText(text);
|
|
|
|
|
m_cdbLabel->setVisible(!text.isEmpty());
|
|
|
|
|
m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand));
|
|
|
|
|
|
|
|
|
|
m_abis->setText(toList(item->abis).join(QLatin1String(", ")));
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerItemConfigWidget::saveItem()
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
theDebuggerItemManager()->setCurrentData(m_displayNameLineEdit->text(), m_binaryChooser->fileName());
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerOptionsPage
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
DebuggerOptionsPage::DebuggerOptionsPage()
|
|
|
|
|
{
|
|
|
|
|
m_manager = 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_manager = theDebuggerItemManager();
|
|
|
|
|
|
|
|
|
|
m_debuggerView = new QTreeView(m_configWidget);
|
|
|
|
|
m_debuggerView->setModel(m_manager);
|
|
|
|
|
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()
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
m_itemConfigWidget->saveItem();
|
2013-08-14 18:30:40 +02:00
|
|
|
debuggerModelChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerOptionsPage::cloneDebugger()
|
|
|
|
|
{
|
|
|
|
|
m_manager->cloneDebugger();
|
|
|
|
|
debuggerModelChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerOptionsPage::addDebugger()
|
|
|
|
|
{
|
|
|
|
|
m_manager->addDebugger();
|
|
|
|
|
debuggerModelChanged();
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
void DebuggerOptionsPage::removeDebugger()
|
2012-09-11 14:03:08 +02:00
|
|
|
{
|
2013-08-14 18:30:40 +02:00
|
|
|
m_manager->removeDebugger();
|
|
|
|
|
debuggerModelChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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_manager->setCurrentIndex(mi);
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
m_itemConfigWidget->loadItem();
|
|
|
|
|
m_container->setVisible(m_manager->m_currentDebugger.isValid());
|
2013-08-14 18:30:40 +02:00
|
|
|
updateState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerOptionsPage::debuggerModelChanged()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_container, return);
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
m_itemConfigWidget->loadItem();
|
|
|
|
|
m_container->setVisible(m_manager->m_currentDebugger.isValid());
|
2013-08-14 18:30:40 +02:00
|
|
|
m_debuggerView->setCurrentIndex(m_manager->currentIndex());
|
|
|
|
|
updateState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerOptionsPage::updateState()
|
|
|
|
|
{
|
|
|
|
|
if (!m_cloneButton)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool canCopy = false;
|
|
|
|
|
bool canDelete = false;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
if (const DebuggerItem *item = m_manager->findById(m_manager->m_currentDebugger)) {
|
2013-08-14 18:30:40 +02:00
|
|
|
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);
|
2012-09-11 14:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2012-04-24 15:49:09 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|