Commit ed8dd0b0 authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger: Actually pass the debugger command from ToolChain.

Do not retrieve debugger command from ABI as that causes mismatches
when several toolchains of the same ABI are present.
Use indexes in the debugger dialogs.
Polish tooltip.
parent 88f33326
......@@ -24,7 +24,6 @@ HEADERS += breakhandler.h \
consolewindow.h \
debugger_global.h \
debuggeractions.h \
debuggerchooserwidget.h \
debuggercore.h \
debuggerconstants.h \
debuggerdialogs.h \
......@@ -72,7 +71,6 @@ SOURCES += breakhandler.cpp \
commonoptionspage.cpp \
consolewindow.cpp \
debuggeractions.cpp \
debuggerchooserwidget.cpp \
debuggerdialogs.cpp \
debuggerengine.cpp \
debuggermainwindow.cpp \
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "debuggerchooserwidget.h"
#include <coreplugin/coreconstants.h>
#include <projectexplorer/toolchain.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>
#include <QtCore/QSet>
#include <QtGui/QCheckBox>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QFormLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QHBoxLayout>
#include <QtGui/QIcon>
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>
#include <QtGui/QStandardItem>
#include <QtGui/QStandardItemModel>
#include <QtGui/QToolButton>
#include <QtGui/QTreeView>
#include <QtGui/QVBoxLayout>
enum Columns { abiColumn, binaryColumn, ColumnCount };
typedef QList<QStandardItem *> StandardItemList;
namespace Debugger {
namespace Internal {
// -----------------------------------------------
// Obtain a tooltip for a debugger binary by running --version
static QString debuggerToolTip(const QString &binary)
{
if (binary.isEmpty())
return QString();
if (!QFileInfo(binary).exists())
return DebuggerChooserWidget::tr("File not found.");
QProcess process;
process.start(binary, QStringList(QLatin1String("--version")));
process.closeWriteChannel();
if (!process.waitForStarted())
return DebuggerChooserWidget::tr("Unable to run '%1': %2")
.arg(binary, process.errorString());
process.waitForFinished(); // That should never fail
QString rc = QDir::toNativeSeparators(binary);
rc += QLatin1String("\n\n");
rc += QString::fromLocal8Bit(process.readAllStandardOutput());
rc.remove(QLatin1Char('\r'));
return rc;
}
// DebuggerBinaryModel: Show toolchains and associated debugger binaries.
// Provides a delayed tooltip listing the debugger version as
// obtained by running it. Provides conveniences for getting/setting the maps and
// for listing the toolchains used and the ones still available.
class DebuggerBinaryModel : public QStandardItemModel
{
public:
explicit DebuggerBinaryModel(QObject *parent = 0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
// get / set data as map.
QMap<QString, QString> debuggerMapping() const;
void setDebuggerMapping(const QMap<QString, QString> &m);
QString binary(int row) const;
QString abi(int row) const;
void append(const QString &abi, const QString &binary);
bool isDirty() const;
static void setAbiItem(QStandardItem *item, const QString &abi);
static void setBinaryItem(QStandardItem *item, const QString &binary);
};
DebuggerBinaryModel::DebuggerBinaryModel(QObject *parent) :
QStandardItemModel(0, ColumnCount, parent)
{
QStringList headers;
headers.append(DebuggerChooserWidget::tr("ABI"));
headers.append(DebuggerChooserWidget::tr("Debugger"));
setHorizontalHeaderLabels(headers);
}
QVariant DebuggerBinaryModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && role == Qt::ToolTipRole) {
// Is there a tooltip set?
const QString itemToolTip = itemFromIndex(index)->toolTip();
if (!itemToolTip.isEmpty())
return QVariant(itemToolTip);
// Run the debugger and obtain the tooltip
const QString tooltip = debuggerToolTip(binary(index.row()));
// Set on the whole row
item(index.row(), abiColumn)->setToolTip(tooltip);
item(index.row(), binaryColumn)->setToolTip(tooltip);
return QVariant(tooltip);
}
return QStandardItemModel::data(index, role);
}
bool DebuggerBinaryModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
Q_ASSERT(index.column() == binaryColumn);
item(index.row(), abiColumn)->setToolTip(QString());
item(index.row(), binaryColumn)->setToolTip(QString());
item(index.row(), binaryColumn)->setData(true);
QFont f(item(index.row(), binaryColumn)->font());
f.setBold(true);
item(index.row(), binaryColumn)->setFont(f);
}
return QStandardItemModel::setData(index, value, role);
}
QMap<QString, QString> DebuggerBinaryModel::debuggerMapping() const
{
QMap<QString, QString> rc;
const int binaryCount = rowCount();
for (int r = 0; r < binaryCount; ++r)
rc.insert(abi(r), binary(r));
return rc;
}
void DebuggerBinaryModel::setDebuggerMapping(const QMap<QString, QString> &m)
{
removeRows(0, rowCount());
for (QMap<QString, QString>::const_iterator i = m.constBegin(); i != m.constEnd(); ++i)
append(i.key(), i.value());
}
QString DebuggerBinaryModel::binary(int row) const
{
return QDir::fromNativeSeparators(
item(row, binaryColumn)->data(Qt::DisplayRole).toString());
}
QString DebuggerBinaryModel::abi(int row) const
{
return item(row, abiColumn)->data(Qt::DisplayRole).toString();
}
void DebuggerBinaryModel::setBinaryItem(QStandardItem *item, const QString &binary)
{
item->setText(binary.isEmpty() ? QString() : QDir::toNativeSeparators(binary));
item->setToolTip(QString());; // clean out delayed tooltip
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable);
item->setData(false);
}
void DebuggerBinaryModel::setAbiItem(QStandardItem *item, const QString &abi)
{
item->setText(abi);
item->setToolTip(QString()); // clean out delayed tooltip
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
}
void DebuggerBinaryModel::append(const QString &abi, const QString &binary)
{
QStandardItem *binaryItem = new QStandardItem;
QStandardItem *abiItem = new QStandardItem;
DebuggerBinaryModel::setAbiItem(abiItem, abi);
DebuggerBinaryModel::setBinaryItem(binaryItem, binary);
StandardItemList row;
row << abiItem << binaryItem;
appendRow(row);
}
bool DebuggerBinaryModel::isDirty() const
{
for (int i = 0; i < rowCount(); ++i) {
if (item(i, binaryColumn)->data().toBool())
return true;
}
return false;
}
// ----------- DebuggerChooserWidget
DebuggerChooserWidget::DebuggerChooserWidget(QWidget *parent) :
QWidget(parent),
m_treeView(new QTreeView),
m_model(new DebuggerBinaryModel(m_treeView))
{
QVBoxLayout *layout = new QVBoxLayout(this);
m_treeView->setRootIsDecorated(false);
m_treeView->setModel(m_model);
m_treeView->setUniformRowHeights(true);
m_treeView->setAllColumnsShowFocus(true);
m_treeView->setSelectionMode(QAbstractItemView::SingleSelection);
layout->addWidget(m_treeView);
}
QMap<QString, QString> DebuggerChooserWidget::debuggerMapping() const
{
return m_model->debuggerMapping();
}
void DebuggerChooserWidget::setDebuggerMapping(const QMap<QString, QString> &m)
{
m_model->setDebuggerMapping(m);
for (int c = 0; c < ColumnCount; c++)
m_treeView->resizeColumnToContents(c);
}
bool DebuggerChooserWidget::isDirty() const
{
return m_model->isDirty();
}
} // namespace Internal
} // namespace Debugger
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef DEGUBBER_DEBUGGERCHOOSERWIDGET_H
#define DEGUBBER_DEBUGGERCHOOSERWIDGET_H
#include <QtCore/QMultiMap>
#include <QtGui/QDialog>
QT_BEGIN_NAMESPACE
class QTreeView;
class QToolButton;
class QModelIndex;
class QStandardItem;
class QComboBox;
class QDialogButtonBox;
class QFormLayout;
class QCheckBox;
QT_END_NAMESPACE
namespace Utils {
class PathChooser;
}
namespace Debugger {
namespace Internal {
class DebuggerBinaryModel;
/* DebuggerChooserWidget: Shows a list of toolchains and associated debugger
* binaries together with 'add' and 'remove' buttons.
* Provides delayed tooltip showing version information. */
class DebuggerChooserWidget : public QWidget
{
Q_OBJECT
public:
explicit DebuggerChooserWidget(QWidget *parent = 0);
QMap<QString, QString> debuggerMapping() const;
void setDebuggerMapping(const QMap<QString, QString> &m);
bool isDirty() const;
private:
void removeItem(QStandardItem *item);
QToolButton *createAddToolMenuButton();
QTreeView *m_treeView;
DebuggerBinaryModel *m_model;
};
} // namespace Internal
} // namespace Debugger
#endif // DEGUBBER_DEBUGGERCHOOSERWIDGET_H
......@@ -232,9 +232,20 @@ ProjectExplorer::Abi AttachCoreDialog::abi() const
return m_ui->toolchainComboBox->abi();
}
void AttachCoreDialog::setAbi(const ProjectExplorer::Abi &abi)
void AttachCoreDialog::setAbiIndex(int i)
{
m_ui->toolchainComboBox->setAbi(abi);
if (i >= 0 && i < m_ui->toolchainComboBox->count())
m_ui->toolchainComboBox->setCurrentIndex(i);
}
int AttachCoreDialog::abiIndex() const
{
return m_ui->toolchainComboBox->currentIndex();
}
QString AttachCoreDialog::debuggerCommand()
{
return m_ui->toolchainComboBox->debuggerCommand();
}
bool AttachCoreDialog::isValid() const
......@@ -464,9 +475,20 @@ ProjectExplorer::Abi AttachExternalDialog::abi() const
return m_ui->toolchainComboBox->abi();
}
void AttachExternalDialog::setAbi(const ProjectExplorer::Abi &abi)
void AttachExternalDialog::setAbiIndex(int i)
{
if (i >= 0 && i < m_ui->toolchainComboBox->count())
m_ui->toolchainComboBox->setCurrentIndex(i);
}
int AttachExternalDialog::abiIndex() const
{
m_ui->toolchainComboBox->setAbi(abi);
return m_ui->toolchainComboBox->currentIndex();
}
QString AttachExternalDialog::debuggerCommand()
{
return m_ui->toolchainComboBox->debuggerCommand();
}
void AttachExternalDialog::pidChanged(const QString &pid)
......@@ -657,9 +679,20 @@ ProjectExplorer::Abi StartExternalDialog::abi() const
return m_ui->toolChainComboBox->abi();
}
void StartExternalDialog::setAbi(const ProjectExplorer::Abi &abi)
void StartExternalDialog::setAbiIndex(int i)
{
if (i >= 0 && i < m_ui->toolChainComboBox->count())
m_ui->toolChainComboBox->setCurrentIndex(i);
}
int StartExternalDialog::abiIndex() const
{
return m_ui->toolChainComboBox->currentIndex();
}
QString StartExternalDialog::debuggerCommand()
{
m_ui->toolChainComboBox->setAbi(abi);
return m_ui->toolChainComboBox->debuggerCommand();
}
bool StartExternalDialog::isValid() const
......
......@@ -85,8 +85,10 @@ public:
QString executableFile() const;
QString coreFile() const;
int abiIndex() const;
void setAbiIndex(int);
ProjectExplorer::Abi abi() const;
void setAbi(const ProjectExplorer::Abi &);
QString debuggerCommand();
private slots:
void changed();
......@@ -108,8 +110,10 @@ public:
qint64 attachPID() const;
QString executable() const;
int abiIndex() const;
void setAbiIndex(int);
ProjectExplorer::Abi abi() const;
void setAbi(const ProjectExplorer::Abi &);
QString debuggerCommand();
virtual void accept();
......@@ -173,8 +177,10 @@ public:
QString workingDirectory() const;
void setWorkingDirectory(const QString &str);
int abiIndex() const;
void setAbiIndex(int);
ProjectExplorer::Abi abi() const;
void setAbi(const ProjectExplorer::Abi &);
QString debuggerCommand();
bool breakAtMain() const;
......
......@@ -697,10 +697,13 @@ public slots:
void startRemoteEngine();
void attachExternalApplication();
void attachExternalApplication(qint64 pid, const QString &binary,
const ProjectExplorer::Abi &abi = ProjectExplorer::Abi());
const ProjectExplorer::Abi &abi = ProjectExplorer::Abi(),
const QString &debuggerCommand = QString());
void runScheduled();
void attachCore();
void attachCore(const QString &core, const QString &exeFileName, const ProjectExplorer::Abi &abi = ProjectExplorer::Abi());
void attachCore(const QString &core, const QString &exeFileName,
const ProjectExplorer::Abi &abi = ProjectExplorer::Abi(),
const QString &debuggerCommand = QString());
void attachRemote(const QString &spec);
void attachRemoteTcf();
......@@ -1342,9 +1345,7 @@ void DebuggerPluginPrivate::startExternalApplication()
configValue(_("LastExternalExecutableArguments")).toString());
dlg.setWorkingDirectory(
configValue(_("LastExternalWorkingDirectory")).toString());
const QString abiString = configValue(_("LastExternalAbi")).toString();
if (!abiString.isEmpty())
dlg.setAbi(ProjectExplorer::Abi(abiString));
dlg.setAbiIndex(configValue(_("LastExternalAbiIndex")).toInt());
if (dlg.exec() != QDialog::Accepted)
return;
......@@ -1355,12 +1356,12 @@ void DebuggerPluginPrivate::startExternalApplication()
dlg.executableArguments());
setConfigValue(_("LastExternalWorkingDirectory"),
dlg.workingDirectory());
setConfigValue(_("LastExternalAbi"),
dlg.abi().toString());
setConfigValue(_("LastExternalAbiIndex"), QVariant(dlg.abiIndex()));
sp.executable = dlg.executableFile();
sp.startMode = StartExternal;
sp.toolChainAbi = dlg.abi();
sp.debuggerCommand = dlg.debuggerCommand();
sp.workingDirectory = dlg.workingDirectory();
if (!dlg.executableArguments().isEmpty())
sp.processArgs = dlg.executableArguments();
......@@ -1385,20 +1386,18 @@ void DebuggerPluginPrivate::startExternalApplication()
void DebuggerPluginPrivate::attachExternalApplication()
{
AttachExternalDialog dlg(mainWindow());
const QString abiString = configValue(_("LastAttachExternalAbi")).toString();
if (!abiString.isEmpty())
dlg.setAbi(ProjectExplorer::Abi(abiString));
dlg.setAbiIndex(configValue(_("LastAttachExternalAbiIndex")).toInt());
if (dlg.exec() != QDialog::Accepted)
return;
setConfigValue(_("LastAttachExternalAbi"), dlg.abi().toString());
attachExternalApplication(dlg.attachPID(), dlg.executable(), dlg.abi());
setConfigValue(_("LastAttachExternalAbiIndex"), QVariant(dlg.abiIndex()));
attachExternalApplication(dlg.attachPID(), dlg.executable(), dlg.abi(), dlg.debuggerCommand());
}
void DebuggerPluginPrivate::attachExternalApplication
(qint64 pid, const QString &binary, const ProjectExplorer::Abi &abi)
void DebuggerPluginPrivate::attachExternalApplication(qint64 pid, const QString &binary,
const ProjectExplorer::Abi &abi,
const QString &debuggerCommand)
{
if (pid == 0) {
QMessageBox::warning(mainWindow(), tr("Warning"),
......@@ -1411,6 +1410,7 @@ void DebuggerPluginPrivate::attachExternalApplication
sp.executable = binary;
sp.startMode = AttachExternal;
sp.toolChainAbi = abi.isValid() ? abi : abiOfBinary(sp.executable);
sp.debuggerCommand = debuggerCommand;
if (DebuggerRunControl *rc = createDebugger(sp))
startDebugger(rc);
}
......@@ -1420,26 +1420,28 @@ void DebuggerPluginPrivate::attachCore()
AttachCoreDialog dlg(mainWindow());
dlg.setExecutableFile(configValue(_("LastExternalExecutableFile")).toString());
dlg.setCoreFile(configValue(_("LastExternalCoreFile")).toString());
const QString abiString = configValue(_("LastExternalCoreAbi")).toString();
if (!abiString.isEmpty())
dlg.setAbi(ProjectExplorer::Abi(abiString));
dlg.setAbiIndex(configValue(_("LastExternalCoreAbiIndex")).toInt());
if (dlg.exec() != QDialog::Accepted)
return;
setConfigValue(_("LastExternalExecutableFile"), dlg.executableFile());
setConfigValue(_("LastExternalCoreFile"), dlg.coreFile());
setConfigValue(_("LastExternalCoreAbi"), dlg.abi().toString());
setConfigValue(_("LastExternalCoreAbiIndex"), QVariant(dlg.abiIndex()));
attachCore(dlg.coreFile(), dlg.executableFile(), dlg.abi());
}
void DebuggerPluginPrivate::attachCore(const QString &core, const QString &exe, const ProjectExplorer::Abi &abi)
void DebuggerPluginPrivate::attachCore(const QString &core,
const QString &exe,
const ProjectExplorer::Abi &abi,
const QString &debuggerCommand)
{
DebuggerStartParameters sp;
sp.executable = exe;
sp.coreFile = core;
sp.displayName = tr("Core file \"%1\"").arg(core);
sp.startMode = AttachCore;
sp.debuggerCommand = debuggerCommand;
sp.toolChainAbi = abi.isValid() ? abi : abiOfBinary(sp.coreFile);
if (DebuggerRunControl *rc = createDebugger(sp))
startDebugger(rc);
......@@ -2378,7 +2380,7 @@ static QString formatStartParameters(DebuggerStartParameters &sp)
if (!sp.projectDir.isEmpty()) {
str << "Project: " << QDir::toNativeSeparators(sp.projectDir);
if (!sp.projectBuildDir.isEmpty())
str << " (built: " << QDir::toNativeSeparators(sp.projectBuildDir);
str << " (built: " << QDir::toNativeSeparators(sp.projectBuildDir) << ')';
str << '\n';
}
if (!sp.qmlServerAddress.isEmpty())
......
......@@ -56,6 +56,7 @@
#include <projectexplorer/target.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/outputformat.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
#include <utils/synchronousprocess.h>
......@@ -660,19 +661,26 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu
sp.dumperLibrary = rc->dumperLibrary();
sp.dumperLibraryLocations = rc->dumperLibraryLocations();
if (const ProjectExplorer::Target *target = runConfiguration->target()) {
if (const ProjectExplorer::Project *project = target->project()) {
sp.projectDir = project->projectDirectory();
if (const ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration()) {
sp.projectBuildDir = buildConfig->buildDirectory();