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>
|
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 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-08-14 18:30:40 +02:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerKitInformation
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
DebuggerKitInformation::DebuggerKitInformation()
|
|
|
|
|
{
|
|
|
|
|
setObjectName(QLatin1String("DebuggerKitInformation"));
|
2013-09-09 17:10:41 +02:00
|
|
|
setId(DebuggerKitInformation::id());
|
2013-08-28 18:57:25 +02:00
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
ToolChain *tc = ToolChainKitInformation::toolChain(k);
|
2013-10-09 12:42:00 +02:00
|
|
|
return DebuggerItemManager::defaultDebugger(tc);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerKitInformation::setup(Kit *k)
|
|
|
|
|
{
|
2013-09-09 17:10:41 +02:00
|
|
|
k->setValue(DebuggerKitInformation::id(), defaultValue(k));
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(k, return NoDebugger);
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
const DebuggerItem *item = DebuggerKitInformation::debugger(k);
|
2013-09-03 12:31:28 +02:00
|
|
|
if (!item)
|
|
|
|
|
return NoDebugger;
|
|
|
|
|
|
2013-09-25 11:38:26 +02:00
|
|
|
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;
|
2013-09-25 11:38:26 +02:00
|
|
|
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()) {
|
2013-09-25 11:38:26 +02:00
|
|
|
if (item->engineType() == NoEngineType)
|
2013-09-03 12:31:28 +02:00
|
|
|
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-25 11:38:26 +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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
const DebuggerItem *DebuggerKitInformation::debugger(const Kit *kit)
|
|
|
|
|
{
|
|
|
|
|
if (!kit)
|
|
|
|
|
return 0;
|
2013-10-15 15:10:18 +02:00
|
|
|
|
|
|
|
|
const QVariant id = kit->value(DebuggerKitInformation::id());
|
|
|
|
|
|
|
|
|
|
enum Detection { NotDetected, DetectedAutomatically, DetectedByFile, DetectedById };
|
|
|
|
|
Detection 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 (id.type() == QVariant::String) {
|
|
|
|
|
detection = DetectedById;
|
|
|
|
|
} else {
|
|
|
|
|
QMap<QString, QVariant> map = id.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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTC_CHECK(detection != NotDetected);
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) {
|
2013-10-15 15:10:18 +02:00
|
|
|
if (detection == DetectedById && item.id() == id)
|
2013-10-09 12:42:00 +02:00
|
|
|
return &item;
|
2013-10-15 15:10:18 +02:00
|
|
|
if (detection == DetectedByFile && item.command() == fileName)
|
|
|
|
|
return &item;
|
|
|
|
|
if (detection == DetectedAutomatically && item.engineType() == autoEngine)
|
2013-10-09 12:42:00 +02:00
|
|
|
return &item;
|
|
|
|
|
}
|
2013-10-15 15:10:18 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
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;
|
2013-10-09 12:42:00 +02:00
|
|
|
if (const DebuggerItem *item = debugger(k))
|
2013-09-25 11:38:26 +02:00
|
|
|
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
|
|
|
|
|
{
|
2013-09-09 17:10:41 +02:00
|
|
|
return new Internal::DebuggerKitConfigWidget(k, this);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
const DebuggerItem *item = debugger(k);
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(item, return FileName());
|
2013-09-25 11:38:26 +02:00
|
|
|
return item->command();
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
2013-08-30 11:19:55 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k)
|
|
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
const DebuggerItem *item = debugger(k);
|
2013-09-03 12:31:28 +02:00
|
|
|
QTC_ASSERT(item, return NoEngineType);
|
2013-09-25 11:38:26 +02:00
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
const DebuggerItem *item = debugger(k);
|
2013-09-03 12:31:28 +02:00
|
|
|
if (!item)
|
|
|
|
|
return tr("No Debugger");
|
2013-09-25 11:38:26 +02:00
|
|
|
QString binary = item->command().toUserOutput();
|
2013-09-03 12:31:28 +02:00
|
|
|
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-25 11:38:26 +02:00
|
|
|
void DebuggerKitInformation::setDebugger(Kit *k, const DebuggerItem &item)
|
|
|
|
|
{
|
|
|
|
|
// Only register reasonably complete debuggers.
|
|
|
|
|
QTC_ASSERT(!item.id().isValid(), return);
|
|
|
|
|
QTC_ASSERT(!item.command().isEmpty(), return);
|
|
|
|
|
QTC_ASSERT(!item.displayName().isEmpty(), return);
|
|
|
|
|
QTC_ASSERT(item.engineType() != NoEngineType, return);
|
2013-10-09 12:42:00 +02:00
|
|
|
// Only set registered/existing debuggers
|
|
|
|
|
QTC_ASSERT(DebuggerItemManager::findByCommand(item.command()), return);
|
|
|
|
|
k->setValue(DebuggerKitInformation::id(), item.id());
|
2013-09-25 11:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-09 17:10:41 +02:00
|
|
|
Core::Id DebuggerKitInformation::id()
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-09 17:10:41 +02:00
|
|
|
return "Debugger.Information";
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerItemManager
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static DebuggerItemManager *m_instance = 0;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
static FileName userSettingsFileName()
|
|
|
|
|
{
|
|
|
|
|
QFileInfo settingsLocation(Core::ICore::settings()->fileName());
|
|
|
|
|
return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME));
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
static QList<DebuggerItem> readDebuggers(const FileName &fileName)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
QList<DebuggerItem> result;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
PersistentSettingsReader reader;
|
|
|
|
|
if (!reader.load(fileName))
|
|
|
|
|
return result;
|
|
|
|
|
QVariantMap data = reader.restoreValues();
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
// Check version
|
|
|
|
|
int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt();
|
|
|
|
|
if (version < 1)
|
|
|
|
|
return result;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
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();
|
|
|
|
|
DebuggerItem item;
|
|
|
|
|
item.fromMap(dbMap);
|
|
|
|
|
result.append(item);
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
QList<DebuggerItem> DebuggerItemManager::m_debuggers;
|
|
|
|
|
DebuggerItemModel* DebuggerItemManager::m_model = 0;
|
|
|
|
|
PersistentSettingsWriter * DebuggerItemManager::m_writer = 0;
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItemManager::DebuggerItemManager(QObject *parent)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
{
|
|
|
|
|
m_instance = this;
|
2013-08-14 18:30:40 +02:00
|
|
|
m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger"));
|
2013-10-09 12:42:00 +02:00
|
|
|
m_model = new Debugger::Internal::DebuggerItemModel(this);
|
2013-08-14 18:30:40 +02:00
|
|
|
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
|
|
|
|
|
this, SLOT(saveDebuggers()));
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
QObject *DebuggerItemManager::instance()
|
|
|
|
|
{
|
|
|
|
|
return m_instance;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
DebuggerItemManager::~DebuggerItemManager()
|
|
|
|
|
{
|
|
|
|
|
disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
|
|
|
|
|
this, SLOT(saveDebuggers()));
|
|
|
|
|
delete m_writer;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
QList<DebuggerItem> DebuggerItemManager::debuggers()
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
return m_debuggers;
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItemModel *DebuggerItemManager::model()
|
2013-09-03 12:31:28 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
return m_model;
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
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;
|
2013-09-25 11:38:26 +02:00
|
|
|
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())));
|
2013-10-09 12:42:00 +02:00
|
|
|
addDebugger(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-25 11:38:26 +02:00
|
|
|
item.setCommand(command);
|
2013-08-14 18:30:40 +02:00
|
|
|
item.reinitializeFromFile();
|
2013-10-08 17:45:40 +02:00
|
|
|
//: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path
|
2013-09-25 11:38:26 +02:00
|
|
|
item.setDisplayName(tr("System %1 at %2")
|
2013-10-08 17:45:40 +02:00
|
|
|
.arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath())));
|
2013-09-25 11:38:26 +02:00
|
|
|
item.setAutoDetected(true);
|
2013-10-09 12:42:00 +02:00
|
|
|
addDebugger(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();
|
2013-09-09 17:10:41 +02:00
|
|
|
QVariant v3 = data2.value(DebuggerKitInformation::id().toString());
|
2013-09-03 12:31:28 +02:00
|
|
|
QString fn;
|
|
|
|
|
if (v3.type() == QVariant::String)
|
|
|
|
|
fn = v3.toString();
|
|
|
|
|
else
|
2013-09-25 11:38:26 +02:00
|
|
|
fn = v3.toMap().value(QLatin1String("Binary")).toString();
|
2013-09-03 12:31:28 +02:00
|
|
|
if (fn.isEmpty())
|
|
|
|
|
continue;
|
|
|
|
|
if (fn.startsWith(QLatin1Char('{')))
|
|
|
|
|
continue;
|
2013-10-15 15:10:18 +02:00
|
|
|
if (fn == QLatin1String("auto"))
|
|
|
|
|
continue;
|
2013-09-03 12:31:28 +02:00
|
|
|
FileName command = FileName::fromUserInput(fn);
|
|
|
|
|
if (findByCommand(command))
|
|
|
|
|
continue;
|
|
|
|
|
DebuggerItem item;
|
2013-09-25 11:38:26 +02:00
|
|
|
item.setCommand(command);
|
|
|
|
|
item.setAutoDetected(true);
|
2013-09-03 12:31:28 +02:00
|
|
|
item.reinitializeFromFile();
|
2013-09-25 11:38:26 +02:00
|
|
|
item.setDisplayName(tr("Extracted from Kit %1").arg(kitName));
|
2013-10-09 12:42:00 +02:00
|
|
|
addDebugger(item);
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command)
|
|
|
|
|
{
|
|
|
|
|
foreach (const DebuggerItem &item, m_debuggers)
|
2013-09-25 11:38:26 +02:00
|
|
|
if (item.command() == command)
|
2013-09-03 12:31:28 +02:00
|
|
|
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)
|
2013-09-25 11:38:26 +02:00
|
|
|
if (item.id() == id)
|
2013-09-03 12:31:28 +02:00
|
|
|
return &item;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
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)
|
2013-09-25 11:38:26 +02:00
|
|
|
dbsToRegister[i].setAutoDetected(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())) {
|
2013-09-25 11:38:26 +02:00
|
|
|
if (item.isAutoDetected())
|
2013-08-14 18:30:40 +02:00
|
|
|
dbsToCheck.append(item);
|
|
|
|
|
else
|
|
|
|
|
dbsToRegister.append(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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-25 11:38:26 +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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
for (int i = 0, n = dbsToRegister.size(); i != n; ++i) {
|
|
|
|
|
DebuggerItem item = dbsToRegister.at(i);
|
2013-10-09 12:42:00 +02:00
|
|
|
if (findByCommand(item.command()))
|
2013-09-03 12:31:28 +02:00
|
|
|
continue;
|
2013-10-09 12:42:00 +02:00
|
|
|
addDebugger(item);
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
// Auto detect current.
|
2013-10-09 12:42:00 +02:00
|
|
|
autoDetectDebuggers();
|
2013-09-03 12:31:28 +02:00
|
|
|
|
|
|
|
|
// Add debuggers from pre-3.x profiles.xml
|
2013-10-09 12:42:00 +02:00
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
void DebuggerItemManager::registerDebugger(const DebuggerItem &item)
|
2013-08-30 11:19:55 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
if (findByCommand(item.command()))
|
|
|
|
|
return;
|
|
|
|
|
addDebugger(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
void DebuggerItemManager::deregisterDebugger(const DebuggerItem &item)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
if (findByCommand(item.command()))
|
|
|
|
|
removeDebugger(item.id());
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
void DebuggerItemManager::addDebugger(const DebuggerItem& item0)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItem item = item0;
|
|
|
|
|
if (item.id().isNull())
|
|
|
|
|
item.setId(QUuid::createUuid().toString());
|
|
|
|
|
m_debuggers.append(item);
|
2013-10-15 19:23:27 +02:00
|
|
|
m_model->addDebugger(item);
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-15 19:23:27 +02:00
|
|
|
void DebuggerItemManager::removeDebugger(const QVariant &id)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-09-03 12:31:28 +02:00
|
|
|
bool ok = false;
|
|
|
|
|
for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
|
2013-09-25 11:38:26 +02:00
|
|
|
if (m_debuggers.at(i).id() == id) {
|
2013-09-03 12:31:28 +02:00
|
|
|
m_debuggers.removeAt(i);
|
|
|
|
|
ok = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-09 12:42:00 +02:00
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
QTC_ASSERT(ok, return);
|
2013-10-15 19:23:27 +02:00
|
|
|
m_model->removeDebugger(id);
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
QString DebuggerItemManager::uniqueDisplayName(const QString &base)
|
2013-09-03 12:31:28 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
foreach (const DebuggerItem &item, m_debuggers)
|
|
|
|
|
if (item.displayName() == base)
|
|
|
|
|
return uniqueDisplayName(base + QLatin1String(" (1)"));
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
return base;
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName)
|
2013-09-03 12:31:28 +02:00
|
|
|
{
|
|
|
|
|
for (int i = 0, n = m_debuggers.size(); i != n; ++i) {
|
|
|
|
|
DebuggerItem &item = m_debuggers[i];
|
2013-10-09 12:42:00 +02:00
|
|
|
if (item.id() == id) {
|
2013-09-25 11:38:26 +02:00
|
|
|
item.setDisplayName(displayName);
|
|
|
|
|
item.setCommand(fileName);
|
2013-09-03 12:31:28 +02:00
|
|
|
item.reinitializeFromFile();
|
2013-10-15 19:23:27 +02:00
|
|
|
emit m_model->updateDebugger(item.id());
|
2013-10-09 12:42:00 +02:00
|
|
|
break;
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant DebuggerItemManager::defaultDebugger(ToolChain *tc)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(tc, return QVariant());
|
|
|
|
|
|
|
|
|
|
DebuggerItem result;
|
2013-09-25 11:38:26 +02:00
|
|
|
result.setAutoDetected(true);
|
|
|
|
|
result.setDisplayName(tr("Auto-detected for Tool Chain %1").arg(tc->displayName()));
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
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)
|
2013-09-25 11:38:26 +02:00
|
|
|
foreach (const Abi targetAbi, item.abis())
|
2013-09-03 12:31:28 +02:00
|
|
|
if (targetAbi.isCompatibleWith(abi))
|
2013-09-25 11:38:26 +02:00
|
|
|
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);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-15 19:23:27 +02:00
|
|
|
QModelIndex DebuggerItemModel::lastIndex() const
|
2013-10-09 12:42:00 +02:00
|
|
|
{
|
2013-10-15 19:23:27 +02:00
|
|
|
int n = m_manualRoot->rowCount();
|
|
|
|
|
QStandardItem *current = m_manualRoot->child(n - 1);
|
|
|
|
|
return current ? current->index() : QModelIndex();
|
2013-10-09 12:42:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemModel::markCurrentDirty()
|
|
|
|
|
{
|
|
|
|
|
QStandardItem *sitem = currentStandardItem();
|
|
|
|
|
QTC_ASSERT(sitem, return);
|
|
|
|
|
QFont font = sitem->font();
|
|
|
|
|
font.setBold(true);
|
|
|
|
|
sitem->setFont(font);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-15 19:23:27 +02:00
|
|
|
void DebuggerItemModel::addDebugger(const DebuggerItem &item0)
|
2013-10-09 12:42:00 +02:00
|
|
|
{
|
|
|
|
|
DebuggerItem item = item0;
|
|
|
|
|
if (item.id().isNull())
|
|
|
|
|
item.setId(QUuid::createUuid().toString());
|
|
|
|
|
QList<QStandardItem *> row = describeItem(item);
|
|
|
|
|
(item.isAutoDetected() ? m_autoRoot : m_manualRoot)->appendRow(row);
|
|
|
|
|
emit debuggerAdded(item.id(), item.displayName());
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-15 19:23:27 +02:00
|
|
|
void DebuggerItemModel::removeDebugger(const QVariant &id)
|
2013-10-09 12:42:00 +02:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-15 19:23:27 +02:00
|
|
|
void DebuggerItemModel::updateDebugger(const QVariant &id)
|
2013-10-09 12:42:00 +02:00
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 18:30:40 +02:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// DebuggerKitConfigWidget
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
2013-09-09 17:10:41 +02:00
|
|
|
DebuggerKitConfigWidget::DebuggerKitConfigWidget(Kit *workingCopy, const KitInformation *ki)
|
|
|
|
|
: KitConfigWidget(workingCopy, ki)
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItemModel *model = DebuggerItemManager::model();
|
|
|
|
|
QTC_CHECK(model);
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
m_comboBox = new QComboBox;
|
|
|
|
|
m_comboBox->setEnabled(true);
|
|
|
|
|
m_comboBox->setToolTip(toolTip());
|
|
|
|
|
m_comboBox->addItem(tr("None"), QString());
|
2013-10-09 12:42:00 +02:00
|
|
|
foreach (const DebuggerItem &item, DebuggerItemManager::debuggers())
|
2013-09-25 11:38:26 +02:00
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
connect(model, SIGNAL(debuggerAdded(QVariant,QString)),
|
2013-09-03 12:31:28 +02:00
|
|
|
this, SLOT(onDebuggerAdded(QVariant,QString)));
|
2013-10-09 12:42:00 +02:00
|
|
|
connect(model, SIGNAL(debuggerUpdated(QVariant,QString)),
|
2013-09-03 12:31:28 +02:00
|
|
|
this, SLOT(onDebuggerUpdated(QVariant,QString)));
|
2013-10-09 12:42:00 +02:00
|
|
|
connect(model, SIGNAL(debuggerRemoved(QVariant)),
|
2013-09-03 12:31:28 +02:00
|
|
|
this, SLOT(onDebuggerRemoved(QVariant)));
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-13 16:30:17 +02:00
|
|
|
DebuggerKitConfigWidget::~DebuggerKitConfigWidget()
|
|
|
|
|
{
|
|
|
|
|
delete m_comboBox;
|
|
|
|
|
delete m_manageButton;
|
|
|
|
|
}
|
|
|
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
const DebuggerItem *item = DebuggerKitInformation::debugger(m_kit);
|
2013-09-25 11:38:26 +02:00
|
|
|
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-09-09 17:10:41 +02:00
|
|
|
m_kit->setValue(DebuggerKitInformation::id(), 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);
|
2013-10-08 17:45:40 +02:00
|
|
|
formLayout->addRow(new QLabel(tr("ABIs:")), m_abis);
|
2013-08-14 18:30:40 +02:00
|
|
|
|
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-10-09 12:42:00 +02:00
|
|
|
DebuggerItemModel *model = DebuggerItemManager::model();
|
2013-09-03 12:31:28 +02:00
|
|
|
connect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
|
2013-10-09 12:42:00 +02:00
|
|
|
model, SLOT(markCurrentDirty()));
|
2013-09-03 12:31:28 +02:00
|
|
|
connect(m_binaryChooser, SIGNAL(changed(QString)),
|
2013-10-09 12:42:00 +02:00
|
|
|
model, SLOT(markCurrentDirty()));
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemConfigWidget::disconnectDirty()
|
|
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItemModel *model = DebuggerItemManager::model();
|
2013-09-03 12:31:28 +02:00
|
|
|
disconnect(m_displayNameLineEdit, SIGNAL(textChanged(QString)),
|
2013-10-09 12:42:00 +02:00
|
|
|
model, SLOT(markCurrentDirty()));
|
2013-09-03 12:31:28 +02:00
|
|
|
disconnect(m_binaryChooser, SIGNAL(changed(QString)),
|
2013-10-09 12:42:00 +02:00
|
|
|
model, SLOT(markCurrentDirty()));
|
2013-09-03 12:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerItemConfigWidget::loadItem()
|
|
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItemModel *model = DebuggerItemManager::model();
|
|
|
|
|
const DebuggerItem *item = DebuggerItemManager::findById(model->m_currentDebugger);
|
2013-08-14 18:30:40 +02:00
|
|
|
if (!item)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
disconnectDirty();
|
2013-09-25 11:38:26 +02:00
|
|
|
m_displayNameLineEdit->setEnabled(!item->isAutoDetected());
|
|
|
|
|
m_displayNameLineEdit->setText(item->displayName());
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-25 11:38:26 +02:00
|
|
|
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;
|
2013-09-25 11:38:26 +02:00
|
|
|
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));
|
|
|
|
|
|
2013-09-25 11:38:26 +02:00
|
|
|
m_abis->setText(item->abiNames().join(QLatin1String(", ")));
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
void DebuggerItemConfigWidget::saveItem()
|
2013-08-14 18:30:40 +02:00
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
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());
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// DebuggerOptionsPage
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
DebuggerOptionsPage::DebuggerOptionsPage()
|
|
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
m_model = 0;
|
2013-08-14 18:30:40 +02:00
|
|
|
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);
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
m_model = DebuggerItemManager::model();
|
2013-08-14 18:30:40 +02:00
|
|
|
|
|
|
|
|
m_debuggerView = new QTreeView(m_configWidget);
|
2013-10-09 12:42:00 +02:00
|
|
|
m_debuggerView->setModel(m_model);
|
2013-08-14 18:30:40 +02:00
|
|
|
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()
|
|
|
|
|
{
|
2013-10-15 19:23:27 +02:00
|
|
|
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());
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerOptionsPage::addDebugger()
|
|
|
|
|
{
|
2013-10-09 12:42:00 +02:00
|
|
|
DebuggerItem item;
|
|
|
|
|
item.setEngineType(NoEngineType);
|
|
|
|
|
item.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("New Debugger")));
|
|
|
|
|
item.setAutoDetected(false);
|
2013-10-15 19:23:27 +02:00
|
|
|
DebuggerItemManager::addDebugger(item);
|
|
|
|
|
m_debuggerView->setCurrentIndex(m_model->lastIndex());
|
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-10-15 19:23:27 +02:00
|
|
|
QVariant id = m_model->currentDebugger();
|
|
|
|
|
DebuggerItemManager::removeDebugger(id);
|
|
|
|
|
m_debuggerView->setCurrentIndex(m_model->lastIndex());
|
2013-08-14 18:30:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2013-10-09 12:42:00 +02:00
|
|
|
m_model->setCurrentIndex(mi);
|
2013-08-14 18:30:40 +02:00
|
|
|
|
2013-09-03 12:31:28 +02:00
|
|
|
m_itemConfigWidget->loadItem();
|
2013-10-09 12:42:00 +02:00
|
|
|
m_container->setVisible(m_model->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();
|
2013-10-09 12:42:00 +02:00
|
|
|
m_container->setVisible(m_model->m_currentDebugger.isValid());
|
|
|
|
|
m_debuggerView->setCurrentIndex(m_model->currentIndex());
|
2013-08-14 18:30:40 +02:00
|
|
|
updateState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DebuggerOptionsPage::updateState()
|
|
|
|
|
{
|
|
|
|
|
if (!m_cloneButton)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool canCopy = false;
|
|
|
|
|
bool canDelete = false;
|
|
|
|
|
|
2013-10-09 12:42:00 +02:00
|
|
|
if (const DebuggerItem *item = DebuggerItemManager::findById(m_model->m_currentDebugger)) {
|
2013-08-14 18:30:40 +02:00
|
|
|
canCopy = item->isValid() && item->canClone();
|
2013-09-25 11:38:26 +02:00
|
|
|
canDelete = !item->isAutoDetected();
|
2013-08-14 18:30:40 +02:00
|
|
|
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
|