forked from qt-creator/qt-creator
debugger: merge attach to local and remote process dialogs
This also merges a larger part of the two code paths. Change-Id: I84a88c53ebc0073becac88ba04e63efd9a4a98b3 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@nokia.com> Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -41,7 +41,6 @@
|
||||
#include <projectexplorer/abi.h>
|
||||
#include <projectexplorer/profilechooser.h>
|
||||
#include <projectexplorer/profileinformation.h>
|
||||
#include <utils/filterlineedit.h>
|
||||
#include <utils/historycompleter.h>
|
||||
#include <utils/pathchooser.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -51,7 +50,6 @@
|
||||
#include <QApplication>
|
||||
#include <QButtonGroup>
|
||||
#include <QCheckBox>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -68,7 +66,6 @@
|
||||
#include <QRadioButton>
|
||||
#include <QRegExp>
|
||||
#include <QScrollArea>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSpinBox>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTreeView>
|
||||
@@ -79,301 +76,15 @@ using namespace Core;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
bool operator<(const ProcData &p1, const ProcData &p2)
|
||||
{
|
||||
return p1.name < p2.name;
|
||||
}
|
||||
|
||||
// A filterable process list model
|
||||
class ProcessListFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit ProcessListFilterModel(QObject *parent);
|
||||
QString processIdAt(const QModelIndex &index) const;
|
||||
QString executableForPid(const QString& pid) const;
|
||||
|
||||
void populate(QList<ProcData> processes, const QString &excludePid);
|
||||
|
||||
private:
|
||||
enum { ProcessImageRole = Qt::UserRole, ProcessNameRole };
|
||||
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
|
||||
QStandardItemModel *m_model;
|
||||
};
|
||||
|
||||
ProcessListFilterModel::ProcessListFilterModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent),
|
||||
m_model(new QStandardItemModel(this))
|
||||
{
|
||||
QStringList columns;
|
||||
columns << AttachExternalDialog::tr("Process ID")
|
||||
<< AttachExternalDialog::tr("Name")
|
||||
<< AttachExternalDialog::tr("State");
|
||||
m_model->setHorizontalHeaderLabels(columns);
|
||||
setSourceModel(m_model);
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
setFilterKeyColumn(1);
|
||||
}
|
||||
|
||||
bool ProcessListFilterModel::lessThan(const QModelIndex &left,
|
||||
const QModelIndex &right) const
|
||||
{
|
||||
const QString l = sourceModel()->data(left).toString();
|
||||
const QString r = sourceModel()->data(right).toString();
|
||||
if (left.column() == 0)
|
||||
return l.toInt() < r.toInt();
|
||||
return l < r;
|
||||
}
|
||||
|
||||
QString ProcessListFilterModel::processIdAt(const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid()) {
|
||||
const QModelIndex index0 = mapToSource(index);
|
||||
QModelIndex siblingIndex = index0.sibling(index0.row(), 0);
|
||||
if (const QStandardItem *item = m_model->itemFromIndex(siblingIndex))
|
||||
return item->text();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString ProcessListFilterModel::executableForPid(const QString &pid) const
|
||||
{
|
||||
const int rowCount = m_model->rowCount();
|
||||
for (int r = 0; r < rowCount; r++) {
|
||||
const QStandardItem *item = m_model->item(r, 0);
|
||||
if (item->text() == pid) {
|
||||
QString name = item->data(ProcessImageRole).toString();
|
||||
if (name.isEmpty())
|
||||
name = item->data(ProcessNameRole).toString();
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ProcessListFilterModel::populate
|
||||
(QList<ProcData> processes, const QString &excludePid)
|
||||
{
|
||||
qStableSort(processes);
|
||||
|
||||
if (const int rowCount = m_model->rowCount())
|
||||
m_model->removeRows(0, rowCount);
|
||||
|
||||
QStandardItem *root = m_model->invisibleRootItem();
|
||||
foreach (const ProcData &proc, processes) {
|
||||
QList<QStandardItem *> row;
|
||||
row.append(new QStandardItem(proc.ppid));
|
||||
QString name = proc.image.isEmpty() ? proc.name : proc.image;
|
||||
row.back()->setData(name, ProcessImageRole);
|
||||
row.append(new QStandardItem(proc.name));
|
||||
row.back()->setToolTip(proc.image);
|
||||
row.append(new QStandardItem(proc.state));
|
||||
|
||||
if (proc.ppid == excludePid)
|
||||
foreach (QStandardItem *item, row)
|
||||
item->setEnabled(false);
|
||||
root->appendRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AttachExternalDialog
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AttachExternalDialogPrivate
|
||||
{
|
||||
public:
|
||||
QLineEdit *pidLineEdit;
|
||||
FilterLineEdit *filterWidget;
|
||||
ProfileChooser *profileComboBox;
|
||||
QTreeView *procView;
|
||||
QDialogButtonBox *buttonBox;
|
||||
|
||||
QString selfPid;
|
||||
ProcessListFilterModel *model;
|
||||
};
|
||||
|
||||
AttachExternalDialog::AttachExternalDialog(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
d(new AttachExternalDialogPrivate)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowTitle(tr("Start Debugger"));
|
||||
setMinimumHeight(500);
|
||||
|
||||
d->selfPid = QString::number(QCoreApplication::applicationPid());
|
||||
|
||||
d->model = new ProcessListFilterModel(this);
|
||||
|
||||
d->pidLineEdit = new QLineEdit(this);
|
||||
|
||||
d->filterWidget = new FilterLineEdit(this);
|
||||
d->filterWidget->setFocus(Qt::TabFocusReason);
|
||||
|
||||
d->profileComboBox = new ProfileChooser(this, ProfileChooser::LocalDebugging);
|
||||
|
||||
d->procView = new QTreeView(this);
|
||||
d->procView->setAlternatingRowColors(true);
|
||||
d->procView->setRootIsDecorated(false);
|
||||
d->procView->setUniformRowHeights(true);
|
||||
d->procView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
d->procView->setModel(d->model);
|
||||
d->procView->setSortingEnabled(true);
|
||||
d->procView->sortByColumn(1, Qt::AscendingOrder);
|
||||
|
||||
QPushButton *refreshButton = new QPushButton(tr("Refresh"));
|
||||
|
||||
d->buttonBox = new QDialogButtonBox(this);
|
||||
d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
d->buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
|
||||
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||
formLayout->addRow(tr("Attach to &process ID:"), d->pidLineEdit);
|
||||
formLayout->addRow(tr("&Target:"), d->profileComboBox);
|
||||
formLayout->addRow(d->filterWidget);
|
||||
|
||||
QVBoxLayout *vboxLayout = new QVBoxLayout(this);
|
||||
vboxLayout->addLayout(formLayout);
|
||||
vboxLayout->addWidget(d->procView);
|
||||
vboxLayout->addWidget(line);
|
||||
vboxLayout->addWidget(d->buttonBox);
|
||||
|
||||
okButton()->setDefault(true);
|
||||
okButton()->setEnabled(false);
|
||||
|
||||
connect(refreshButton, SIGNAL(clicked()), SLOT(rebuildProcessList()));
|
||||
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
|
||||
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
|
||||
// Do not use activated, will be single click in Oxygen
|
||||
connect(d->procView, SIGNAL(doubleClicked(QModelIndex)),
|
||||
SLOT(procSelected(QModelIndex)));
|
||||
connect(d->procView, SIGNAL(clicked(QModelIndex)),
|
||||
SLOT(procClicked(QModelIndex)));
|
||||
connect(d->pidLineEdit, SIGNAL(textChanged(QString)),
|
||||
SLOT(pidChanged(QString)));
|
||||
connect(d->filterWidget, SIGNAL(filterChanged(QString)),
|
||||
SLOT(setFilterString(QString)));
|
||||
|
||||
rebuildProcessList();
|
||||
}
|
||||
|
||||
AttachExternalDialog::~AttachExternalDialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void AttachExternalDialog::setFilterString(const QString &filter)
|
||||
{
|
||||
d->model->setFilterFixedString(filter);
|
||||
// Activate the line edit if there's a unique filtered process.
|
||||
QString processId;
|
||||
if (d->model->rowCount(QModelIndex()) == 1)
|
||||
processId = d->model->processIdAt(d->model->index(0, 0, QModelIndex()));
|
||||
d->pidLineEdit->setText(processId);
|
||||
pidChanged(processId);
|
||||
}
|
||||
|
||||
QPushButton *AttachExternalDialog::okButton() const
|
||||
{
|
||||
return d->buttonBox->button(QDialogButtonBox::Ok);
|
||||
}
|
||||
|
||||
void AttachExternalDialog::rebuildProcessList()
|
||||
{
|
||||
d->model->populate(hostProcessList(), d->selfPid);
|
||||
d->procView->expandAll();
|
||||
d->procView->resizeColumnToContents(0);
|
||||
d->procView->resizeColumnToContents(1);
|
||||
}
|
||||
|
||||
void AttachExternalDialog::procSelected(const QModelIndex &proxyIndex)
|
||||
{
|
||||
const QString processId = d->model->processIdAt(proxyIndex);
|
||||
if (!processId.isEmpty()) {
|
||||
d->pidLineEdit->setText(processId);
|
||||
if (okButton()->isEnabled())
|
||||
okButton()->animateClick();
|
||||
}
|
||||
}
|
||||
|
||||
void AttachExternalDialog::procClicked(const QModelIndex &proxyIndex)
|
||||
{
|
||||
const QString processId = d->model->processIdAt(proxyIndex);
|
||||
if (!processId.isEmpty())
|
||||
d->pidLineEdit->setText(processId);
|
||||
}
|
||||
|
||||
QString AttachExternalDialog::attachPIDText() const
|
||||
{
|
||||
return d->pidLineEdit->text().trimmed();
|
||||
}
|
||||
|
||||
qint64 AttachExternalDialog::attachPID() const
|
||||
{
|
||||
return attachPIDText().toLongLong();
|
||||
}
|
||||
|
||||
QString AttachExternalDialog::executable() const
|
||||
{
|
||||
// Search pid in model in case the user typed in the PID.
|
||||
return d->model->executableForPid(attachPIDText());
|
||||
}
|
||||
|
||||
Id AttachExternalDialog::profileId() const
|
||||
{
|
||||
return d->profileComboBox->currentProfileId();
|
||||
}
|
||||
|
||||
void AttachExternalDialog::setProfileIndex(int i)
|
||||
{
|
||||
if (i >= 0 && i < d->profileComboBox->count())
|
||||
d->profileComboBox->setCurrentIndex(i);
|
||||
}
|
||||
|
||||
int AttachExternalDialog::profileIndex() const
|
||||
{
|
||||
return d->profileComboBox->currentIndex();
|
||||
}
|
||||
|
||||
void AttachExternalDialog::pidChanged(const QString &pid)
|
||||
{
|
||||
const bool enabled = !pid.isEmpty() && pid != QLatin1String("0") && pid != d->selfPid
|
||||
&& d->profileComboBox->currentIndex() >= 0;
|
||||
okButton()->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void AttachExternalDialog::accept()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
const qint64 pid = attachPID();
|
||||
if (pid && isWinProcessBeingDebugged(pid)) {
|
||||
QMessageBox::warning(this, tr("Process Already Under Debugger Control"),
|
||||
tr("The process %1 is already under the control of a debugger.\n"
|
||||
"Qt Creator cannot attach to it.").arg(pid));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// StartExternalDialog
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class StartExternalParameters
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -52,7 +52,6 @@ class DebuggerStartParameters;
|
||||
namespace Internal {
|
||||
|
||||
class AttachCoreDialogPrivate;
|
||||
class AttachExternalDialogPrivate;
|
||||
class AttachToQmlPortDialogPrivate;
|
||||
class ProcessListFilterModel;
|
||||
class StartExternalDialogPrivate;
|
||||
@@ -61,37 +60,6 @@ class StartRemoteDialogPrivate;
|
||||
class StartRemoteEngineDialogPrivate;
|
||||
class StartRemoteParameters;
|
||||
|
||||
class AttachExternalDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AttachExternalDialog(QWidget *parent);
|
||||
~AttachExternalDialog();
|
||||
|
||||
qint64 attachPID() const;
|
||||
QString executable() const;
|
||||
|
||||
int profileIndex() const;
|
||||
void setProfileIndex(int);
|
||||
Core::Id profileId() const;
|
||||
|
||||
void accept();
|
||||
|
||||
private slots:
|
||||
void rebuildProcessList();
|
||||
void procSelected(const QModelIndex &index);
|
||||
void procClicked(const QModelIndex &index);
|
||||
void pidChanged(const QString &index);
|
||||
void setFilterString(const QString &filter);
|
||||
|
||||
private:
|
||||
inline QPushButton *okButton() const;
|
||||
inline QString attachPIDText() const;
|
||||
|
||||
AttachExternalDialogPrivate *d;
|
||||
};
|
||||
|
||||
class StartExternalDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include "debuggertooltipmanager.h"
|
||||
#include "localsandexpressionswindow.h"
|
||||
#include "loadcoredialog.h"
|
||||
#include "hostutils.h"
|
||||
|
||||
#include "snapshothandler.h"
|
||||
#include "threadshandler.h"
|
||||
@@ -94,11 +95,13 @@
|
||||
#include <projectexplorer/abi.h>
|
||||
#include <projectexplorer/applicationrunconfiguration.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorersettings.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <projectexplorer/profilechooser.h>
|
||||
#include <projectexplorer/profileinformation.h>
|
||||
#include <projectexplorer/profilemanager.h>
|
||||
#include <projectexplorer/target.h>
|
||||
@@ -776,13 +779,12 @@ public slots:
|
||||
void startRemoteCdbSession();
|
||||
void startRemoteProcess();
|
||||
void startRemoteServer();
|
||||
//bool queryRemoteParameters(DebuggerStartParameters &sp, bool useScript);
|
||||
void attachToRemoteServer();
|
||||
void attachToProcess(bool startServerOnly);
|
||||
void attachToRunningApplication();
|
||||
void attachToQmlPort();
|
||||
void startRemoteEngine();
|
||||
void attachExternalApplication();
|
||||
Q_SLOT void attachExternalApplication(ProjectExplorer::RunControl *rc);
|
||||
//Q_SLOT void attachToLocalProcess(ProjectExplorer::RunControl *rc);
|
||||
void runScheduled();
|
||||
void attachCore();
|
||||
|
||||
@@ -1122,7 +1124,6 @@ public:
|
||||
QAction *m_attachToRemoteServerAction;
|
||||
QAction *m_startRemoteCdbAction;
|
||||
QAction *m_startRemoteLldbAction;
|
||||
QAction *m_attachToLocalProcessAction;
|
||||
QAction *m_attachToCoreAction;
|
||||
QAction *m_detachAction;
|
||||
QAction *m_continueAction;
|
||||
@@ -1245,7 +1246,6 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
|
||||
m_attachToQmlPortAction = 0;
|
||||
m_startRemoteCdbAction = 0;
|
||||
m_startRemoteLldbAction = 0;
|
||||
m_attachToLocalProcessAction = 0;
|
||||
m_attachToCoreAction = 0;
|
||||
m_detachAction = 0;
|
||||
|
||||
@@ -1520,44 +1520,44 @@ void DebuggerPluginPrivate::startExternalApplication()
|
||||
startDebugger(rc);
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::attachExternalApplication()
|
||||
{
|
||||
AttachExternalDialog dlg(mainWindow());
|
||||
dlg.setProfileIndex(configValue(_("LastAttachExternalProfileIndex")).toInt());
|
||||
//void DebuggerPluginPrivate::attachToLocalProcessHelper()
|
||||
//{
|
||||
// AttachExternalDialog dlg(mainWindow());
|
||||
// dlg.setProfileIndex(configValue(_("LastAttachExternalProfileIndex")).toInt());
|
||||
|
||||
if (dlg.exec() != QDialog::Accepted)
|
||||
return;
|
||||
// if (dlg.exec() != QDialog::Accepted)
|
||||
// return;
|
||||
|
||||
if (dlg.attachPID() == 0) {
|
||||
QMessageBox::warning(mainWindow(), tr("Warning"),
|
||||
tr("Cannot attach to process with PID 0"));
|
||||
return;
|
||||
}
|
||||
// if (dlg.attachPID() == 0) {
|
||||
// QMessageBox::warning(mainWindow(), tr("Warning"),
|
||||
// tr("Cannot attach to process with PID 0"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
setConfigValue(_("LastAttachExternalProfileIndex"), QVariant(dlg.profileIndex()));
|
||||
// setConfigValue(_("LastAttachExternalProfileIndex"), QVariant(dlg.profileIndex()));
|
||||
|
||||
DebuggerStartParameters sp;
|
||||
fillParameters(&sp, dlg.profileId());
|
||||
sp.attachPID = dlg.attachPID();
|
||||
sp.displayName = tr("Process %1").arg(dlg.attachPID());
|
||||
sp.executable = dlg.executable();
|
||||
sp.startMode = AttachExternal;
|
||||
sp.closeMode = DetachAtClose;
|
||||
if (DebuggerRunControl *rc = createDebugger(sp))
|
||||
startDebugger(rc);
|
||||
}
|
||||
// DebuggerStartParameters sp;
|
||||
// fillParameters(&sp, dlg.profileId());
|
||||
// sp.attachPID = dlg.attachPID();
|
||||
// sp.displayName = tr("Process %1").arg(dlg.attachPID());
|
||||
// sp.executable = dlg.executable();
|
||||
// sp.startMode = AttachExternal;
|
||||
// sp.closeMode = DetachAtClose;
|
||||
// if (DebuggerRunControl *rc = createDebugger(sp))
|
||||
// startDebugger(rc);
|
||||
//}
|
||||
|
||||
void DebuggerPluginPrivate::attachExternalApplication(RunControl *rc)
|
||||
{
|
||||
DebuggerStartParameters sp;
|
||||
fillParameters(&sp, ProfileManager::instance()->defaultProfile()->id()); // FIXME: Extract from rc.
|
||||
sp.attachPID = rc->applicationProcessHandle().pid();
|
||||
sp.displayName = tr("Debugger attached to %1").arg(rc->displayName());
|
||||
sp.startMode = AttachExternal;
|
||||
sp.closeMode = DetachAtClose;
|
||||
if (DebuggerRunControl *rc = createDebugger(sp))
|
||||
startDebugger(rc);
|
||||
}
|
||||
//void DebuggerPluginPrivate::attachToLocalProcess(RunControl *rc)
|
||||
//{
|
||||
// DebuggerStartParameters sp;
|
||||
// fillParameters(&sp, ProfileManager::instance()->defaultProfile()->id()); // FIXME: Extract from rc.
|
||||
// sp.attachPID = rc->applicationProcessHandle().pid();
|
||||
// sp.displayName = tr("Debugger attached to %1").arg(rc->displayName());
|
||||
// sp.startMode = AttachExternal;
|
||||
// sp.closeMode = DetachAtClose;
|
||||
// if (DebuggerRunControl *rc = createDebugger(sp))
|
||||
// startDebugger(rc);
|
||||
//}
|
||||
|
||||
void DebuggerPluginPrivate::attachCore()
|
||||
{
|
||||
@@ -1637,11 +1637,6 @@ void DebuggerPluginPrivate::startRemoteCdbSession()
|
||||
startDebugger(rc);
|
||||
}
|
||||
|
||||
//bool DebuggerPluginPrivate::queryRemoteParameters(DebuggerStartParameters &sp, bool useScript)
|
||||
//{
|
||||
// return StartRemoteDialog::run(mainWindow(), m_coreSettings, useScript, &sp);
|
||||
//}
|
||||
|
||||
void DebuggerPluginPrivate::startRemoteProcess()
|
||||
{
|
||||
DebuggerStartParameters sp;
|
||||
@@ -1665,16 +1660,68 @@ void DebuggerPluginPrivate::attachToRemoteServer()
|
||||
}
|
||||
}
|
||||
|
||||
//const char LastProfile[] = "Debugger/LastProfile";
|
||||
//const char LastDevice[] = "Debugger/LastDevice";
|
||||
//const char LastProcessName[] = "Debugger/LastProcessName";
|
||||
//const char LastLocalExecutable[] = "Debugger/LastLocalExecutable";
|
||||
|
||||
void DebuggerPluginPrivate::startRemoteServer()
|
||||
{
|
||||
StartGdbServerDialog dlg(mainWindow());
|
||||
dlg.startGdbServer();
|
||||
attachToProcess(true);
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::attachToRunningApplication()
|
||||
{
|
||||
StartGdbServerDialog dlg(mainWindow());
|
||||
dlg.attachToRemoteProcess();
|
||||
attachToProcess(false);
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::attachToProcess(bool startServerOnly)
|
||||
{
|
||||
DeviceProcessesDialog *dlg = new DeviceProcessesDialog(mainWindow());
|
||||
dlg->showAllDevices();
|
||||
if (dlg->exec() == QDialog::Rejected) {
|
||||
delete dlg;
|
||||
return;
|
||||
}
|
||||
|
||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
ProfileChooser *profileChooser = dlg->profileChooser();
|
||||
Profile *profile = profileChooser->currentProfile();
|
||||
QTC_ASSERT(profile, return);
|
||||
IDevice::ConstPtr device = DeviceProfileInformation::device(profile);
|
||||
QTC_ASSERT(device, return);
|
||||
DeviceProcess process = dlg->currentProcess();
|
||||
if (process.pid == 0) {
|
||||
QMessageBox::warning(mainWindow(), tr("Warning"),
|
||||
tr("Cannot attach to process with PID 0"));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (isWinProcessBeingDebugged(process.pid)) {
|
||||
QMessageBox::warning(ICore::mainWindow(), tr("Process Already Under Debugger Control"),
|
||||
tr("The process %1 is already under the control of a debugger.\n"
|
||||
"Qt Creator cannot attach to it.").arg(process.pid));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
//setConfigValue(_("LastAttachExternalProfileIndex"), QVariant(dlg->profileChooser()->currentProfileId()));
|
||||
|
||||
if (device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
|
||||
DebuggerStartParameters sp;
|
||||
fillParameters(&sp, profile->id());
|
||||
sp.attachPID = process.pid;
|
||||
sp.displayName = tr("Process %1").arg(process.pid);
|
||||
sp.executable = process.exe;
|
||||
sp.startMode = AttachExternal;
|
||||
sp.closeMode = DetachAtClose;
|
||||
if (DebuggerRunControl *rc = createDebugger(sp))
|
||||
startDebugger(rc);
|
||||
} else {
|
||||
GdbServerStarter *starter = new GdbServerStarter(dlg, startServerOnly);
|
||||
starter->run();
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::attachToQmlPort()
|
||||
@@ -2137,7 +2184,6 @@ void DebuggerPluginPrivate::setInitialState()
|
||||
m_toolTipManager->closeAllToolTips();
|
||||
|
||||
m_startLocalProcessAction->setEnabled(true);
|
||||
m_attachToLocalProcessAction->setEnabled(true);
|
||||
m_attachToQmlPortAction->setEnabled(true);
|
||||
m_attachToCoreAction->setEnabled(true);
|
||||
m_startRemoteProcessAction->setEnabled(true);
|
||||
@@ -2264,7 +2310,6 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
|
||||
|
||||
m_startLocalProcessAction->setEnabled(true);
|
||||
m_attachToQmlPortAction->setEnabled(true);
|
||||
m_attachToLocalProcessAction->setEnabled(true);
|
||||
m_attachToCoreAction->setEnabled(true);
|
||||
m_startRemoteProcessAction->setEnabled(true);
|
||||
m_attachToRemoteServerAction->setEnabled(true);
|
||||
@@ -2962,10 +3007,6 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
connect(act, SIGNAL(triggered()), SLOT(startRemoteEngine()));
|
||||
#endif
|
||||
|
||||
act = m_attachToLocalProcessAction = new QAction(this);
|
||||
act->setText(tr("Attach to Running Local Application..."));
|
||||
connect(act, SIGNAL(triggered()), SLOT(attachExternalApplication()));
|
||||
|
||||
act = m_attachToCoreAction = new QAction(this);
|
||||
act->setText(tr("Load Core File..."));
|
||||
connect(act, SIGNAL(triggered()), SLOT(attachCore()));
|
||||
@@ -3065,11 +3106,6 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
cmd->setDescription(tr("Start Gdbserver"));
|
||||
mstart->addAction(cmd, Constants::G_MANUAL_REMOTE);
|
||||
|
||||
cmd = ActionManager::registerAction(m_attachToLocalProcessAction,
|
||||
"Debugger.AttachToLocalProcess", globalcontext);
|
||||
cmd->setAttribute(Command::CA_Hide);
|
||||
mstart->addAction(cmd, Constants::G_MANUAL_REMOTE);
|
||||
|
||||
#ifdef WITH_LLDB
|
||||
cmd = ActionManager::registerAction(m_startRemoteLldbAction,
|
||||
"Debugger.RemoteLldb", globalcontext);
|
||||
|
||||
@@ -49,36 +49,13 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QSettings>
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFormLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSpacerItem>
|
||||
#include <QTextBrowser>
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace Core;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace QSsh;
|
||||
using namespace Utils;
|
||||
|
||||
const char LastProfile[] = "Debugger/LastProfile";
|
||||
const char LastDevice[] = "Debugger/LastDevice";
|
||||
const char LastProcessName[] = "Debugger/LastProcessName";
|
||||
//const char LastLocalExecutable[] = "Debugger/LastLocalExecutable";
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
@@ -86,257 +63,92 @@ namespace Internal {
|
||||
class StartGdbServerDialogPrivate
|
||||
{
|
||||
public:
|
||||
StartGdbServerDialogPrivate(StartGdbServerDialog *q);
|
||||
|
||||
IDevice::ConstPtr currentDevice() const
|
||||
{
|
||||
Profile *profile = profileChooser->currentProfile();
|
||||
return DeviceProfileInformation::device(profile);
|
||||
}
|
||||
StartGdbServerDialogPrivate() {}
|
||||
|
||||
DeviceProcessesDialog *dialog;
|
||||
bool startServerOnly;
|
||||
DeviceProcessList *processList;
|
||||
QSortFilterProxyModel proxyModel;
|
||||
|
||||
QLineEdit *processFilterLineEdit;
|
||||
QTreeView *processView;
|
||||
QPushButton *attachProcessButton;
|
||||
QTextBrowser *textBrowser;
|
||||
QPushButton *closeButton;
|
||||
ProfileChooser *profileChooser;
|
||||
DeviceProcess process;
|
||||
Profile *profile;
|
||||
IDevice::ConstPtr device;
|
||||
|
||||
DeviceUsedPortsGatherer gatherer;
|
||||
SshRemoteProcessRunner runner;
|
||||
QString remoteCommandLine;
|
||||
QString remoteExecutable;
|
||||
};
|
||||
|
||||
StartGdbServerDialogPrivate::StartGdbServerDialogPrivate(StartGdbServerDialog *q)
|
||||
: startServerOnly(true), processList(0)
|
||||
GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool startServerOnly)
|
||||
: QObject(dlg)
|
||||
{
|
||||
QSettings *settings = ICore::settings();
|
||||
|
||||
profileChooser = new ProfileChooser(q, ProfileChooser::RemoteDebugging);
|
||||
|
||||
//executablePathChooser = new PathChooser(q);
|
||||
//executablePathChooser->setExpectedKind(PathChooser::File);
|
||||
//executablePathChooser->setPromptDialogTitle(StartGdbServerDialog::tr("Select Executable"));
|
||||
//executablePathChooser->setPath(settings->value(LastLocalExecutable).toString());
|
||||
|
||||
processFilterLineEdit = new QLineEdit(q);
|
||||
processFilterLineEdit->setText(settings->value(LastProcessName).toString());
|
||||
processFilterLineEdit->selectAll();
|
||||
|
||||
processView = new QTreeView(q);
|
||||
processView->setSortingEnabled(true);
|
||||
processView->header()->setDefaultSectionSize(100);
|
||||
processView->header()->setStretchLastSection(true);
|
||||
processView->setAlternatingRowColors(true);
|
||||
processView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
processView->setRootIsDecorated(false);
|
||||
|
||||
attachProcessButton = new QPushButton(q);
|
||||
attachProcessButton->setText(StartGdbServerDialog::tr("&Attach to Selected Process"));
|
||||
|
||||
closeButton = new QPushButton(q);
|
||||
closeButton->setText(StartGdbServerDialog::tr("Close"));
|
||||
|
||||
textBrowser = new QTextBrowser(q);
|
||||
textBrowser->setEnabled(false);
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(StartGdbServerDialog::tr("Target:"), profileChooser);
|
||||
formLayout->addRow(StartGdbServerDialog::tr("&Filter entries:"), processFilterLineEdit);
|
||||
|
||||
QHBoxLayout *horizontalLayout2 = new QHBoxLayout();
|
||||
horizontalLayout2->addStretch(1);
|
||||
horizontalLayout2->addWidget(attachProcessButton);
|
||||
horizontalLayout2->addWidget(closeButton);
|
||||
|
||||
formLayout->addRow(processView);
|
||||
formLayout->addRow(textBrowser);
|
||||
formLayout->addRow(horizontalLayout2);
|
||||
q->setLayout(formLayout);
|
||||
d = new StartGdbServerDialogPrivate;
|
||||
d->dialog = dlg;
|
||||
d->profile = dlg->profileChooser()->currentProfile();
|
||||
d->process = dlg->currentProcess();
|
||||
d->device = DeviceProfileInformation::device(d->profile);
|
||||
d->startServerOnly = startServerOnly;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
|
||||
StartGdbServerDialog::StartGdbServerDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
d(new Internal::StartGdbServerDialogPrivate(this))
|
||||
GdbServerStarter::~GdbServerStarter()
|
||||
{
|
||||
setWindowTitle(tr("List of Remote Processes"));
|
||||
|
||||
QObject::connect(d->closeButton, SIGNAL(clicked()), this, SLOT(reject()));
|
||||
|
||||
connect(&d->gatherer, SIGNAL(error(QString)), SLOT(portGathererError(QString)));
|
||||
connect(&d->gatherer, SIGNAL(portListReady()), SLOT(portListReady()));
|
||||
|
||||
d->processView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
d->proxyModel.setDynamicSortFilter(true);
|
||||
d->proxyModel.setFilterKeyColumn(-1);
|
||||
d->processView->setModel(&d->proxyModel);
|
||||
connect(d->processFilterLineEdit, SIGNAL(textChanged(QString)),
|
||||
&d->proxyModel, SLOT(setFilterRegExp(QString)));
|
||||
|
||||
connect(d->processView->selectionModel(),
|
||||
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
SLOT(updateButtons()));
|
||||
connect(d->profileChooser, SIGNAL(activated(int)),
|
||||
SLOT(updateButtons()));
|
||||
//connect(d->updateListButton, SIGNAL(clicked()),
|
||||
// SLOT(updateProcessList()));
|
||||
connect(d->attachProcessButton, SIGNAL(clicked()), SLOT(attachToProcess()));
|
||||
connect(&d->proxyModel, SIGNAL(layoutChanged()),
|
||||
SLOT(handleProcessListUpdated()));
|
||||
connect(d->profileChooser, SIGNAL(currentIndexChanged(int)),
|
||||
SLOT(attachToDevice()));
|
||||
updateButtons();
|
||||
attachToDevice();
|
||||
}
|
||||
|
||||
StartGdbServerDialog::~StartGdbServerDialog()
|
||||
{
|
||||
delete d->processList;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::attachToDevice()
|
||||
void GdbServerStarter::handleRemoteError(const QString &errorMsg)
|
||||
{
|
||||
IDevice::ConstPtr device = d->currentDevice();
|
||||
// TODO: display error on non-matching device.
|
||||
if (!device || !device->canCreateProcessModel())
|
||||
return;
|
||||
delete d->processList;
|
||||
d->processList = device->createProcessListModel();
|
||||
d->proxyModel.setSourceModel(d->processList);
|
||||
connect(d->processList, SIGNAL(error(QString)),
|
||||
SLOT(handleRemoteError(QString)));
|
||||
connect(d->processList, SIGNAL(modelReset()),
|
||||
SLOT(handleProcessListUpdated()));
|
||||
connect(d->processList, SIGNAL(processKilled()),
|
||||
SLOT(handleProcessKilled()), Qt::QueuedConnection);
|
||||
updateProcessList();
|
||||
QMessageBox::critical(0, tr("Remote Error"), errorMsg);
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleRemoteError(const QString &errorMsg)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Remote Error"), errorMsg);
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleProcessListUpdated()
|
||||
{
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::updateProcessList()
|
||||
{
|
||||
d->attachProcessButton->setEnabled(false);
|
||||
d->processList->update();
|
||||
d->proxyModel.setFilterRegExp(QString());
|
||||
d->proxyModel.setFilterRegExp(d->processFilterLineEdit->text());
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::attachToProcess()
|
||||
{
|
||||
const QModelIndexList indexes =
|
||||
d->processView->selectionModel()->selectedIndexes();
|
||||
if (indexes.empty())
|
||||
return;
|
||||
d->attachProcessButton->setEnabled(false);
|
||||
|
||||
IDevice::ConstPtr device = d->currentDevice();
|
||||
if (!device)
|
||||
return;
|
||||
PortList ports = device->freePorts();
|
||||
const int port = d->gatherer.getNextFreePort(&ports);
|
||||
const int row = d->proxyModel.mapToSource(indexes.first()).row();
|
||||
QTC_ASSERT(row >= 0, return);
|
||||
DeviceProcess process = d->processList->at(row);
|
||||
d->remoteCommandLine = process.cmdLine;
|
||||
d->remoteExecutable = process.exe;
|
||||
if (port == -1) {
|
||||
reportFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
QSettings *settings = ICore::settings();
|
||||
settings->setValue(LastProfile, d->profileChooser->currentProfileId().toString());
|
||||
settings->setValue(LastProcessName, d->processFilterLineEdit->text());
|
||||
|
||||
startGdbServerOnPort(port, process.pid);
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::reportFailure()
|
||||
{
|
||||
QTC_ASSERT(false, /**/);
|
||||
logMessage(tr("Process aborted"));
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::logMessage(const QString &line)
|
||||
{
|
||||
d->textBrowser->append(line);
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleProcessKilled()
|
||||
{
|
||||
updateProcessList();
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::updateButtons()
|
||||
{
|
||||
d->attachProcessButton->setEnabled(d->processView->selectionModel()->hasSelection()
|
||||
|| d->proxyModel.rowCount() == 1);
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::portGathererError(const QString &text)
|
||||
void GdbServerStarter::portGathererError(const QString &text)
|
||||
{
|
||||
logMessage(tr("Could not retrieve list of free ports:"));
|
||||
logMessage(text);
|
||||
reportFailure();
|
||||
logMessage(tr("Process aborted"));
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::portListReady()
|
||||
void GdbServerStarter::run()
|
||||
{
|
||||
updateButtons();
|
||||
QTC_ASSERT(d->device, return);
|
||||
connect(&d->gatherer, SIGNAL(error(QString)), SLOT(portGathererError(QString)));
|
||||
connect(&d->gatherer, SIGNAL(portListReady()), SLOT(portListReady()));
|
||||
d->gatherer.start(d->device);
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::startGdbServer()
|
||||
void GdbServerStarter::portListReady()
|
||||
{
|
||||
d->startServerOnly = true;
|
||||
if (exec() == QDialog::Rejected)
|
||||
PortList ports = d->device->freePorts();
|
||||
const int port = d->gatherer.getNextFreePort(&ports);
|
||||
if (port == -1) {
|
||||
QTC_ASSERT(false, /**/);
|
||||
emit logMessage(tr("Process aborted"));
|
||||
return;
|
||||
d->gatherer.start(d->currentDevice());
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::attachToRemoteProcess()
|
||||
{
|
||||
d->startServerOnly = false;
|
||||
if (exec() == QDialog::Rejected)
|
||||
return;
|
||||
d->gatherer.start(d->currentDevice());
|
||||
connect(&d->runner, SIGNAL(connectionError()), SLOT(handleConnectionError()));
|
||||
connect(&d->runner, SIGNAL(processStarted()), SLOT(handleProcessStarted()));
|
||||
connect(&d->runner, SIGNAL(readyReadStandardOutput()), SLOT(handleProcessOutputAvailable()));
|
||||
connect(&d->runner, SIGNAL(readyReadStandardError()), SLOT(handleProcessErrorOutput()));
|
||||
connect(&d->runner, SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int)));
|
||||
|
||||
QByteArray cmd = "/usr/bin/gdbserver --attach :"
|
||||
+ QByteArray::number(port) + " " + QByteArray::number(d->process.pid);
|
||||
logMessage(tr("Running command: %1").arg(QString::fromLatin1(cmd)));
|
||||
d->runner.run(cmd, d->device->sshParameters());
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleConnectionError()
|
||||
void GdbServerStarter::handleConnectionError()
|
||||
{
|
||||
logMessage(tr("Connection error: %1").arg(d->runner.lastConnectionErrorString()));
|
||||
emit processAborted();
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleProcessStarted()
|
||||
void GdbServerStarter::handleProcessStarted()
|
||||
{
|
||||
logMessage(tr("Starting gdbserver..."));
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleProcessOutputAvailable()
|
||||
void GdbServerStarter::handleProcessOutputAvailable()
|
||||
{
|
||||
logMessage(QString::fromUtf8(d->runner.readAllStandardOutput().trimmed()));
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleProcessErrorOutput()
|
||||
void GdbServerStarter::handleProcessErrorOutput()
|
||||
{
|
||||
const QByteArray ba = d->runner.readAllStandardError();
|
||||
logMessage(QString::fromUtf8(ba.trimmed()));
|
||||
@@ -345,33 +157,25 @@ void StartGdbServerDialog::handleProcessErrorOutput()
|
||||
foreach (const QByteArray &line, ba.split('\n')) {
|
||||
if (line.startsWith("Listening on port")) {
|
||||
const int port = line.mid(18).trimmed().toInt();
|
||||
reportOpenPort(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::reportOpenPort(int port)
|
||||
{
|
||||
close();
|
||||
logMessage(tr("Port %1 is now accessible.").arg(port));
|
||||
IDevice::ConstPtr device = d->currentDevice();
|
||||
QString channel = QString("%1:%2").arg(device->sshParameters().host).arg(port);
|
||||
logMessage(tr("Server started on %1").arg(channel));
|
||||
logMessage(tr("Server started on %1:%2")
|
||||
.arg(d->device->sshParameters().host).arg(port));
|
||||
if (!d->startServerOnly)
|
||||
attach(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Profile *profile = d->profileChooser->currentProfile();
|
||||
QTC_ASSERT(profile, return);
|
||||
|
||||
if (d->startServerOnly) {
|
||||
//showStatusMessage(tr("gdbserver is now listening at %1").arg(channel));
|
||||
} else {
|
||||
QString sysroot = SysRootProfileInformation::sysRoot(profile).toString();
|
||||
void GdbServerStarter::attach(int port)
|
||||
{
|
||||
QString sysroot = SysRootProfileInformation::sysRoot(d->profile).toString();
|
||||
QString binary;
|
||||
QString localExecutable;
|
||||
QString candidate = sysroot + d->remoteExecutable;
|
||||
QString candidate = sysroot + d->process.exe;
|
||||
if (QFileInfo(candidate).exists())
|
||||
localExecutable = candidate;
|
||||
if (localExecutable.isEmpty()) {
|
||||
binary = d->remoteCommandLine.section(QLatin1Char(' '), 0, 0);
|
||||
binary = d->process.cmdLine.section(QLatin1Char(' '), 0, 0);
|
||||
candidate = sysroot + QLatin1Char('/') + binary;
|
||||
if (QFileInfo(candidate).exists())
|
||||
localExecutable = candidate;
|
||||
@@ -389,7 +193,7 @@ void StartGdbServerDialog::reportOpenPort(int port)
|
||||
if (localExecutable.isEmpty()) {
|
||||
QMessageBox::warning(DebuggerPlugin::mainWindow(), tr("Warning"),
|
||||
tr("Cannot find local executable for remote process \"%1\".")
|
||||
.arg(d->remoteCommandLine));
|
||||
.arg(d->process.exe));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -397,10 +201,12 @@ void StartGdbServerDialog::reportOpenPort(int port)
|
||||
if (abis.isEmpty()) {
|
||||
QMessageBox::warning(DebuggerPlugin::mainWindow(), tr("Warning"),
|
||||
tr("Cannot find ABI for remote process \"%1\".")
|
||||
.arg(d->remoteCommandLine));
|
||||
.arg(d->process.exe));
|
||||
return;
|
||||
}
|
||||
|
||||
QString channel = QString("%1:%2").arg(d->device->sshParameters().host).arg(port);
|
||||
|
||||
DebuggerStartParameters sp;
|
||||
sp.displayName = tr("Remote: \"%1\"").arg(channel);
|
||||
sp.remoteChannel = channel;
|
||||
@@ -410,35 +216,25 @@ void StartGdbServerDialog::reportOpenPort(int port)
|
||||
sp.overrideStartScript.clear();
|
||||
sp.useServerStartScript = false;
|
||||
sp.serverStartScript.clear();
|
||||
sp.sysRoot = SysRootProfileInformation::sysRoot(profile).toString();
|
||||
sp.debuggerCommand = DebuggerProfileInformation::debuggerCommand(profile).toString();
|
||||
sp.connParams = device->sshParameters();
|
||||
if (ToolChain *tc = ToolChainProfileInformation::toolChain(profile))
|
||||
sp.sysRoot = SysRootProfileInformation::sysRoot(d->profile).toString();
|
||||
sp.debuggerCommand = DebuggerProfileInformation::debuggerCommand(d->profile).toString();
|
||||
sp.connParams = d->device->sshParameters();
|
||||
if (ToolChain *tc = ToolChainProfileInformation::toolChain(d->profile))
|
||||
sp.toolChainAbi = tc->targetAbi();
|
||||
|
||||
if (RunControl *rc = DebuggerPlugin::createDebugger(sp))
|
||||
DebuggerPlugin::startDebugger(rc);
|
||||
}
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::handleProcessClosed(int status)
|
||||
void GdbServerStarter::handleProcessClosed(int status)
|
||||
{
|
||||
logMessage(tr("Process gdbserver finished. Status: %1").arg(status));
|
||||
}
|
||||
|
||||
void StartGdbServerDialog::startGdbServerOnPort(int port, int pid)
|
||||
void GdbServerStarter::logMessage(const QString &line)
|
||||
{
|
||||
IDevice::ConstPtr device = d->currentDevice();
|
||||
connect(&d->runner, SIGNAL(connectionError()), SLOT(handleConnectionError()));
|
||||
connect(&d->runner, SIGNAL(processStarted()), SLOT(handleProcessStarted()));
|
||||
connect(&d->runner, SIGNAL(readyReadStandardOutput()), SLOT(handleProcessOutputAvailable()));
|
||||
connect(&d->runner, SIGNAL(readyReadStandardError()), SLOT(handleProcessErrorOutput()));
|
||||
connect(&d->runner, SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int)));
|
||||
|
||||
QByteArray cmd = "/usr/bin/gdbserver --attach :"
|
||||
+ QByteArray::number(port) + " " + QByteArray::number(pid);
|
||||
logMessage(tr("Running command: %1").arg(QString::fromLatin1(cmd)));
|
||||
d->runner.run(cmd, device->sshParameters());
|
||||
d->dialog->logMessage(line);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
@@ -32,35 +32,26 @@
|
||||
#define STARTGDBSERVERDIALOG_H
|
||||
|
||||
#include "debugger_global.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <projectexplorer/profile.h>
|
||||
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
namespace Internal { class StartGdbServerDialogPrivate; }
|
||||
class StartGdbServerDialogPrivate;
|
||||
|
||||
class DEBUGGER_EXPORT StartGdbServerDialog : public QDialog
|
||||
class GdbServerStarter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StartGdbServerDialog(QWidget *parent);
|
||||
~StartGdbServerDialog();
|
||||
GdbServerStarter(ProjectExplorer::DeviceProcessesDialog *dlg, bool startServerOnly);
|
||||
~GdbServerStarter();
|
||||
|
||||
void startGdbServer();
|
||||
void attachToRemoteProcess();
|
||||
|
||||
signals:
|
||||
void processAborted();
|
||||
void run();
|
||||
|
||||
private slots:
|
||||
void attachToDevice();
|
||||
void handleRemoteError(const QString &errorMessage);
|
||||
void handleProcessListUpdated();
|
||||
void updateProcessList();
|
||||
void attachToProcess();
|
||||
void handleProcessKilled();
|
||||
void updateButtons();
|
||||
void portGathererError(const QString &errorMessage);
|
||||
void portListReady();
|
||||
|
||||
@@ -71,13 +62,12 @@ private slots:
|
||||
void handleConnectionError();
|
||||
|
||||
private:
|
||||
void startGdbServerOnPort(int port, int pid);
|
||||
void reportOpenPort(int port);
|
||||
void reportFailure();
|
||||
void attach(int port);
|
||||
void logMessage(const QString &line);
|
||||
Internal::StartGdbServerDialogPrivate *d;
|
||||
StartGdbServerDialogPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
#endif // STARTGDBSERVERDIALOG_H
|
||||
|
||||
@@ -29,106 +29,299 @@
|
||||
|
||||
#include "devicesupport/deviceprocessesdialog.h"
|
||||
#include "devicesupport/deviceprocesslist.h"
|
||||
#include "ui_deviceprocessesdialog.h"
|
||||
#include "profilechooser.h"
|
||||
#include "profileinformation.h"
|
||||
|
||||
#include <utils/filterlineedit.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFormLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSpacerItem>
|
||||
#include <QTextBrowser>
|
||||
#include <QTextDocument>
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
class DeviceProcessesDialogPrivate
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ProcessListFilterModel
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ProcessListFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
DeviceProcessesDialogPrivate(DeviceProcessList *processList)
|
||||
: processList(processList)
|
||||
{
|
||||
}
|
||||
|
||||
Ui::DeviceProcessesDialog ui;
|
||||
DeviceProcessList * const processList;
|
||||
QSortFilterProxyModel proxyModel;
|
||||
ProcessListFilterModel();
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
};
|
||||
|
||||
|
||||
DeviceProcessesDialog::DeviceProcessesDialog(DeviceProcessList *processList, QWidget *parent)
|
||||
: QDialog(parent), d(new DeviceProcessesDialogPrivate(processList))
|
||||
ProcessListFilterModel::ProcessListFilterModel()
|
||||
{
|
||||
processList->setParent(this);
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
setDynamicSortFilter(true);
|
||||
setFilterKeyColumn(-1);
|
||||
}
|
||||
|
||||
d->ui.setupUi(this);
|
||||
d->proxyModel.setSourceModel(d->processList);
|
||||
d->proxyModel.setDynamicSortFilter(true);
|
||||
d->proxyModel.setFilterKeyColumn(-1);
|
||||
d->ui.treeView->setModel(&d->proxyModel);
|
||||
d->ui.treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
d->ui.treeView->setUniformRowHeights(true);
|
||||
connect(d->ui.processFilterLineEdit, SIGNAL(textChanged(QString)),
|
||||
&d->proxyModel, SLOT(setFilterRegExp(QString)));
|
||||
bool ProcessListFilterModel::lessThan(const QModelIndex &left,
|
||||
const QModelIndex &right) const
|
||||
{
|
||||
const QString l = sourceModel()->data(left).toString();
|
||||
const QString r = sourceModel()->data(right).toString();
|
||||
if (left.column() == 0)
|
||||
return l.toInt() < r.toInt();
|
||||
return l < r;
|
||||
}
|
||||
|
||||
connect(d->ui.treeView->selectionModel(),
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DeviceProcessesDialogPrivate
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DeviceProcessesDialogPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeviceProcessesDialogPrivate(QWidget *parent);
|
||||
|
||||
public slots:
|
||||
void setDevice(const IDevice::ConstPtr &device);
|
||||
void updateProcessList();
|
||||
void updateDevice();
|
||||
void killProcess();
|
||||
void handleRemoteError(const QString &errorMsg);
|
||||
void handleProcessListUpdated();
|
||||
void handleProcessKilled();
|
||||
void updateButtons();
|
||||
DeviceProcess selectedProcess() const;
|
||||
|
||||
public:
|
||||
QWidget *q;
|
||||
DeviceProcessList *processList;
|
||||
ProcessListFilterModel proxyModel;
|
||||
ProfileChooser *profileChooser;
|
||||
|
||||
QTreeView *procView;
|
||||
QTextBrowser *errorText;
|
||||
FilterLineEdit *processFilterLineEdit;
|
||||
QPushButton *updateListButton;
|
||||
QPushButton *killProcessButton;
|
||||
QPushButton *attachProcessButton;
|
||||
};
|
||||
|
||||
DeviceProcessesDialogPrivate::DeviceProcessesDialogPrivate(QWidget *parent)
|
||||
: q(parent)
|
||||
{
|
||||
processList = 0;
|
||||
|
||||
processFilterLineEdit = new FilterLineEdit(q);
|
||||
processFilterLineEdit->setPlaceholderText(DeviceProcessesDialog::tr("Filter"));
|
||||
processFilterLineEdit->setFocus(Qt::TabFocusReason);
|
||||
|
||||
profileChooser = new ProfileChooser(q);
|
||||
|
||||
procView = new QTreeView(q);
|
||||
procView->setModel(&proxyModel);
|
||||
procView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
procView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
procView->setUniformRowHeights(true);
|
||||
procView->setRootIsDecorated(false);
|
||||
procView->setAlternatingRowColors(true);
|
||||
procView->setSortingEnabled(true);
|
||||
procView->header()->setDefaultSectionSize(100);
|
||||
procView->header()->setStretchLastSection(true);
|
||||
procView->sortByColumn(1, Qt::AscendingOrder);
|
||||
|
||||
errorText = new QTextBrowser(q);
|
||||
|
||||
updateListButton = new QPushButton(DeviceProcessesDialog::tr("&Update List"), q);
|
||||
killProcessButton = new QPushButton(DeviceProcessesDialog::tr("&Kill Process"), q);
|
||||
attachProcessButton = new QPushButton(DeviceProcessesDialog::tr("&Attach to Process"), q);
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(q);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Close);
|
||||
buttonBox->addButton(updateListButton, QDialogButtonBox::ActionRole);
|
||||
buttonBox->addButton(killProcessButton, QDialogButtonBox::ActionRole);
|
||||
buttonBox->addButton(attachProcessButton, QDialogButtonBox::AcceptRole);
|
||||
|
||||
QFormLayout *leftColumn = new QFormLayout();
|
||||
leftColumn->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||
leftColumn->addRow(DeviceProcessesDialog::tr("Target:"), profileChooser);
|
||||
leftColumn->addRow(DeviceProcessesDialog::tr("&Filter:"), processFilterLineEdit);
|
||||
|
||||
// QVBoxLayout *rightColumn = new QVBoxLayout();
|
||||
// rightColumn->addWidget(updateListButton);
|
||||
// rightColumn->addWidget(killProcessButton);
|
||||
// rightColumn->addStretch();
|
||||
|
||||
// QHBoxLayout *horizontalLayout = new QHBoxLayout();
|
||||
// horizontalLayout->addLayout(leftColumn);
|
||||
// horizontalLayout->addLayout(rightColumn);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(q);
|
||||
mainLayout->addLayout(leftColumn);
|
||||
mainLayout->addWidget(procView);
|
||||
mainLayout->addWidget(errorText);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
|
||||
// QFrame *line = new QFrame(this);
|
||||
// line->setFrameShape(QFrame::HLine);
|
||||
// line->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
connect(processFilterLineEdit, SIGNAL(textChanged(QString)),
|
||||
&proxyModel, SLOT(setFilterRegExp(QString)));
|
||||
connect(procView->selectionModel(),
|
||||
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
SLOT(handleSelectionChanged()));
|
||||
connect(d->ui.updateListButton, SIGNAL(clicked()),
|
||||
SLOT(updateProcessList()));
|
||||
connect(d->ui.killProcessButton, SIGNAL(clicked()), SLOT(killProcess()));
|
||||
connect(d->processList, SIGNAL(error(QString)),
|
||||
SLOT(updateButtons()));
|
||||
connect(updateListButton, SIGNAL(clicked()), SLOT(updateProcessList()));
|
||||
connect(profileChooser, SIGNAL(currentIndexChanged(int)), SLOT(updateDevice()));
|
||||
connect(killProcessButton, SIGNAL(clicked()), SLOT(killProcess()));
|
||||
connect(&proxyModel, SIGNAL(layoutChanged()), SLOT(handleProcessListUpdated()));
|
||||
connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
|
||||
connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::setDevice(const IDevice::ConstPtr &device)
|
||||
{
|
||||
delete processList;
|
||||
|
||||
processList = device->createProcessListModel();
|
||||
QTC_ASSERT(processList, return);
|
||||
proxyModel.setSourceModel(processList);
|
||||
|
||||
connect(processList, SIGNAL(error(QString)),
|
||||
SLOT(handleRemoteError(QString)));
|
||||
connect(d->processList, SIGNAL(processListUpdated()),
|
||||
connect(processList, SIGNAL(processListUpdated()),
|
||||
SLOT(handleProcessListUpdated()));
|
||||
connect(d->processList, SIGNAL(processKilled()),
|
||||
connect(processList, SIGNAL(processKilled()),
|
||||
SLOT(handleProcessKilled()), Qt::QueuedConnection);
|
||||
connect(&d->proxyModel, SIGNAL(layoutChanged()),
|
||||
SLOT(handleProcessListUpdated()));
|
||||
handleSelectionChanged();
|
||||
|
||||
updateButtons();
|
||||
updateProcessList();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::handleRemoteError(const QString &errorMsg)
|
||||
{
|
||||
QMessageBox::critical(q, tr("Remote Error"), errorMsg);
|
||||
updateListButton->setEnabled(true);
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::handleProcessListUpdated()
|
||||
{
|
||||
updateListButton->setEnabled(true);
|
||||
procView->resizeColumnToContents(0);
|
||||
procView->resizeColumnToContents(1);
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::updateProcessList()
|
||||
{
|
||||
updateListButton->setEnabled(false);
|
||||
killProcessButton->setEnabled(false);
|
||||
if (processList)
|
||||
processList->update();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::killProcess()
|
||||
{
|
||||
const QModelIndexList indexes = procView->selectionModel()->selectedIndexes();
|
||||
if (indexes.empty())
|
||||
return;
|
||||
updateListButton->setEnabled(false);
|
||||
killProcessButton->setEnabled(false);
|
||||
processList->killProcess(proxyModel.mapToSource(indexes.first()).row());
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::updateDevice()
|
||||
{
|
||||
setDevice(DeviceProfileInformation::device(profileChooser->currentProfile()));
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::handleProcessKilled()
|
||||
{
|
||||
updateProcessList();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialogPrivate::updateButtons()
|
||||
{
|
||||
bool hasSelection = procView->selectionModel()->hasSelection();
|
||||
attachProcessButton->setEnabled(hasSelection);
|
||||
killProcessButton->setEnabled(hasSelection);
|
||||
errorText->setVisible(!errorText->document()->isEmpty());
|
||||
}
|
||||
|
||||
DeviceProcess DeviceProcessesDialogPrivate::selectedProcess() const
|
||||
{
|
||||
const QModelIndexList indexes = procView->selectionModel()->selectedIndexes();
|
||||
if (indexes.empty())
|
||||
return DeviceProcess();
|
||||
return processList->at(proxyModel.mapToSource(indexes.first()).row());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DeviceProcessesDialog
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
DeviceProcessesDialog::DeviceProcessesDialog(QWidget *parent)
|
||||
: QDialog(parent), d(new Internal::DeviceProcessesDialogPrivate(this))
|
||||
{
|
||||
setWindowTitle(tr("List of Processes"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setMinimumHeight(500);
|
||||
}
|
||||
|
||||
DeviceProcessesDialog::~DeviceProcessesDialog()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void DeviceProcessesDialog::handleRemoteError(const QString &errorMsg)
|
||||
void DeviceProcessesDialog::setDevice(const IDevice::ConstPtr &device)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Remote Error"), errorMsg);
|
||||
d->ui.updateListButton->setEnabled(true);
|
||||
handleSelectionChanged();
|
||||
d->profileChooser->hide();
|
||||
d->setDevice(device);
|
||||
}
|
||||
|
||||
void DeviceProcessesDialog::handleProcessListUpdated()
|
||||
void DeviceProcessesDialog::showAllDevices()
|
||||
{
|
||||
d->ui.updateListButton->setEnabled(true);
|
||||
handleSelectionChanged();
|
||||
d->profileChooser->show();
|
||||
d->updateDevice();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialog::updateProcessList()
|
||||
DeviceProcess DeviceProcessesDialog::currentProcess() const
|
||||
{
|
||||
d->ui.updateListButton->setEnabled(false);
|
||||
d->ui.killProcessButton->setEnabled(false);
|
||||
d->processList->update();
|
||||
return d->selectedProcess();
|
||||
}
|
||||
|
||||
void DeviceProcessesDialog::killProcess()
|
||||
ProfileChooser *DeviceProcessesDialog::profileChooser() const
|
||||
{
|
||||
const QModelIndexList &indexes
|
||||
= d->ui.treeView->selectionModel()->selectedIndexes();
|
||||
if (indexes.empty())
|
||||
return;
|
||||
d->ui.updateListButton->setEnabled(false);
|
||||
d->ui.killProcessButton->setEnabled(false);
|
||||
d->processList->killProcess(d->proxyModel.mapToSource(indexes.first()).row());
|
||||
return d->profileChooser;
|
||||
}
|
||||
|
||||
void DeviceProcessesDialog::handleProcessKilled()
|
||||
void DeviceProcessesDialog::logMessage(const QString &line)
|
||||
{
|
||||
updateProcessList();
|
||||
d->errorText->setVisible(true);
|
||||
d->errorText->append(line);
|
||||
}
|
||||
|
||||
void DeviceProcessesDialog::handleSelectionChanged()
|
||||
{
|
||||
d->ui.killProcessButton->setEnabled(d->ui.treeView->selectionModel()->hasSelection());
|
||||
}
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace RemoteLinux
|
||||
#include "deviceprocessesdialog.moc"
|
||||
|
||||
@@ -32,37 +32,36 @@
|
||||
|
||||
#include "../projectexplorer_export.h"
|
||||
|
||||
#include <projectexplorer/profile.h>
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <projectexplorer/devicesupport/deviceprocesslist.h>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
class DeviceProcessList;
|
||||
class ProfileChooser;
|
||||
|
||||
namespace Internal {
|
||||
class DeviceProcessesDialogPrivate;
|
||||
namespace Internal { class DeviceProcessesDialogPrivate; }
|
||||
|
||||
class DeviceProcessesDialog : public QDialog
|
||||
class PROJECTEXPLORER_EXPORT DeviceProcessesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Note: The dialog takes ownership of processList.
|
||||
explicit DeviceProcessesDialog(DeviceProcessList *processList, QWidget *parent = 0);
|
||||
explicit DeviceProcessesDialog(QWidget *parent = 0);
|
||||
~DeviceProcessesDialog();
|
||||
|
||||
private slots:
|
||||
void updateProcessList();
|
||||
void killProcess();
|
||||
void handleRemoteError(const QString &errorMsg);
|
||||
void handleProcessListUpdated();
|
||||
void handleProcessKilled();
|
||||
void handleSelectionChanged();
|
||||
void setDevice(const IDevice::ConstPtr &device);
|
||||
void showAllDevices();
|
||||
DeviceProcess currentProcess() const;
|
||||
ProfileChooser *profileChooser() const;
|
||||
void logMessage(const QString &line);
|
||||
|
||||
private:
|
||||
Internal::DeviceProcessesDialogPrivate * const d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace RemoteLinux
|
||||
|
||||
#endif // REMOTELINUXPROCESSESDIALOG_H
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProjectExplorer::Internal::DeviceProcessesDialog</class>
|
||||
<widget class="QDialog" name="ProjectExplorer::Internal::DeviceProcessesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>766</width>
|
||||
<height>684</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>List of Remote Processes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="filterLabel">
|
||||
<property name="text">
|
||||
<string>&Filter entries:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>processFilterLineEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="processFilterLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeView"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="updateListButton">
|
||||
<property name="text">
|
||||
<string>&Update List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="killProcessButton">
|
||||
<property name="text">
|
||||
<string>&Kill Selected Process</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ProjectExplorer::Internal::DeviceProcessesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>257</x>
|
||||
<y>290</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ProjectExplorer::Internal::DeviceProcessesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -134,7 +134,10 @@ int DeviceProcessList::rowCount(const QModelIndex &parent) const
|
||||
return parent.isValid() ? 0 : d->remoteProcesses.count();
|
||||
}
|
||||
|
||||
int DeviceProcessList::columnCount(const QModelIndex &) const { return 2; }
|
||||
int DeviceProcessList::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
QVariant DeviceProcessList::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const
|
||||
@@ -142,7 +145,7 @@ QVariant DeviceProcessList::headerData(int section, Qt::Orientation orientation,
|
||||
if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0
|
||||
|| section >= columnCount())
|
||||
return QVariant();
|
||||
return section == 0? tr("PID") : tr("Command Line");
|
||||
return section == 0? tr("Process ID") : tr("Command Line");
|
||||
}
|
||||
|
||||
QVariant DeviceProcessList::data(const QModelIndex &index, int role) const
|
||||
|
||||
@@ -248,7 +248,7 @@ int DeviceSettingsWidget::currentIndex() const
|
||||
return m_ui->configurationComboBox->currentIndex();
|
||||
}
|
||||
|
||||
QSharedPointer<const IDevice> DeviceSettingsWidget::currentDevice() const
|
||||
IDevice::ConstPtr DeviceSettingsWidget::currentDevice() const
|
||||
{
|
||||
Q_ASSERT(currentIndex() != -1);
|
||||
return m_deviceManagerModel->device(currentIndex());
|
||||
@@ -335,8 +335,9 @@ void DeviceSettingsWidget::handleAdditionalActionRequest(int actionId)
|
||||
void DeviceSettingsWidget::handleProcessListRequested()
|
||||
{
|
||||
QTC_ASSERT(currentDevice()->canCreateProcessModel(), return);
|
||||
DeviceProcessesDialog d(currentDevice()->createProcessListModel());
|
||||
d.exec();
|
||||
DeviceProcessesDialog dlg;
|
||||
dlg.setDevice(currentDevice());
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#ifndef DEVICESETTINGSWIDGET_H
|
||||
#define DEVICESETTINGSWIDGET_H
|
||||
|
||||
#include "devicesupport/idevice.h"
|
||||
#include <coreplugin/id.h>
|
||||
|
||||
#include <QList>
|
||||
@@ -75,7 +76,7 @@ private:
|
||||
void initGui();
|
||||
void displayCurrent();
|
||||
void setDeviceInfoWidgetsEnabled(bool enable);
|
||||
QSharedPointer<const IDevice> currentDevice() const;
|
||||
IDevice::ConstPtr currentDevice() const;
|
||||
int currentIndex() const;
|
||||
void clearDetails();
|
||||
QString parseTestOutput();
|
||||
|
||||
@@ -174,7 +174,7 @@ void LocalProcessList::handleWindowsUpdate()
|
||||
CloseHandle(snapshot);
|
||||
|
||||
reportProcessListUpdated(processes);
|
||||
#endif //Q_OS_WIN
|
||||
#endif
|
||||
}
|
||||
|
||||
void LocalProcessList::handlePsError()
|
||||
|
||||
@@ -245,7 +245,6 @@ FORMS += processstep.ui \
|
||||
publishing/publishingwizardselectiondialog.ui \
|
||||
codestylesettingspropertiespage.ui \
|
||||
devicesupport/devicefactoryselectiondialog.ui \
|
||||
devicesupport/deviceprocessesdialog.ui \
|
||||
devicesupport/devicesettingswidget.ui
|
||||
|
||||
WINSOURCES += \
|
||||
|
||||
@@ -302,7 +302,6 @@ QtcPlugin {
|
||||
"devicesupport/sshdeviceprocesslist.h",
|
||||
"devicesupport/deviceprocessesdialog.cpp",
|
||||
"devicesupport/deviceprocessesdialog.h",
|
||||
"devicesupport/deviceprocessesdialog.ui",
|
||||
"devicesupport/devicesettingswidget.cpp",
|
||||
"devicesupport/devicesettingswidget.h",
|
||||
"devicesupport/devicesettingswidget.ui",
|
||||
|
||||
Reference in New Issue
Block a user