diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 8bb1ce5045793dd6db0ea0a318272375c322e2f1..6bed777cfc6af09766413f5d41c0b4976f507e3c 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -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: diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index 3b8ba8084a95e23a293ed21ac2a2b47cd1bb84ac..d38d92f968fb6774b61951b5e1a8b3b534f86d20 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -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 diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index bdd8e249071cc61faa851c2b1a666f54f048f18f..74fc0958482f3647591a074d197c6021d9054107 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -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()); - - if (dlg.exec() != QDialog::Accepted) - return; - - if (dlg.attachPID() == 0) { - QMessageBox::warning(mainWindow(), tr("Warning"), - tr("Cannot attach to process with PID 0")); - return; - } - - 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); -} +//void DebuggerPluginPrivate::attachToLocalProcessHelper() +//{ +// AttachExternalDialog dlg(mainWindow()); +// dlg.setProfileIndex(configValue(_("LastAttachExternalProfileIndex")).toInt()); + +// if (dlg.exec() != QDialog::Accepted) +// return; + +// if (dlg.attachPID() == 0) { +// QMessageBox::warning(mainWindow(), tr("Warning"), +// tr("Cannot attach to process with PID 0")); +// return; +// } + +// 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); +//} -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); diff --git a/src/plugins/debugger/gdb/startgdbserverdialog.cpp b/src/plugins/debugger/gdb/startgdbserverdialog.cpp index 1da5e1cf607cb10f7bb42b27980e27660791f76e..a1f30194801cc3eed0b3c8afbdc76c22d73d7af1 100644 --- a/src/plugins/debugger/gdb/startgdbserverdialog.cpp +++ b/src/plugins/debugger/gdb/startgdbserverdialog.cpp @@ -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) -{ - 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); -} - -} // namespace Internal - - -StartGdbServerDialog::StartGdbServerDialog(QWidget *parent) : - QDialog(parent), - d(new Internal::StartGdbServerDialogPrivate(this)) +GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool startServerOnly) + : QObject(dlg) { - 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(); + d = new StartGdbServerDialogPrivate; + d->dialog = dlg; + d->profile = dlg->profileChooser()->currentProfile(); + d->process = dlg->currentProcess(); + d->device = DeviceProfileInformation::device(d->profile); + d->startServerOnly = startServerOnly; } -StartGdbServerDialog::~StartGdbServerDialog() +GdbServerStarter::~GdbServerStarter() { - 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(); -} - -void StartGdbServerDialog::handleRemoteError(const QString &errorMsg) -{ - QMessageBox::critical(this, tr("Remote Error"), errorMsg); - updateButtons(); + QMessageBox::critical(0, tr("Remote Error"), errorMsg); } -void StartGdbServerDialog::handleProcessListUpdated() +void GdbServerStarter::portGathererError(const QString &text) { - updateButtons(); + logMessage(tr("Could not retrieve list of free ports:")); + logMessage(text); + logMessage(tr("Process aborted")); } -void StartGdbServerDialog::updateProcessList() +void GdbServerStarter::run() { - d->attachProcessButton->setEnabled(false); - d->processList->update(); - d->proxyModel.setFilterRegExp(QString()); - d->proxyModel.setFilterRegExp(d->processFilterLineEdit->text()); - 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::attachToProcess() +void GdbServerStarter::portListReady() { - 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(); + PortList ports = d->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(); + QTC_ASSERT(false, /**/); + emit logMessage(tr("Process aborted")); 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) -{ - logMessage(tr("Could not retrieve list of free ports:")); - logMessage(text); - reportFailure(); -} - -void StartGdbServerDialog::portListReady() -{ - updateButtons(); -} - -void StartGdbServerDialog::startGdbServer() -{ - d->startServerOnly = true; - 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))); -void StartGdbServerDialog::attachToRemoteProcess() -{ - d->startServerOnly = false; - if (exec() == QDialog::Rejected) - return; - d->gatherer.start(d->currentDevice()); + 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,100 +157,84 @@ 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); + logMessage(tr("Port %1 is now accessible.").arg(port)); + logMessage(tr("Server started on %1:%2") + .arg(d->device->sshParameters().host).arg(port)); + if (!d->startServerOnly) + attach(port); } } } -void StartGdbServerDialog::reportOpenPort(int port) +void GdbServerStarter::attach(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)); - - 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(); - QString binary; - QString localExecutable; - QString candidate = sysroot + d->remoteExecutable; + QString sysroot = SysRootProfileInformation::sysRoot(d->profile).toString(); + QString binary; + QString localExecutable; + QString candidate = sysroot + d->process.exe; + if (QFileInfo(candidate).exists()) + localExecutable = candidate; + if (localExecutable.isEmpty()) { + binary = d->process.cmdLine.section(QLatin1Char(' '), 0, 0); + candidate = sysroot + QLatin1Char('/') + binary; if (QFileInfo(candidate).exists()) localExecutable = candidate; - if (localExecutable.isEmpty()) { - binary = d->remoteCommandLine.section(QLatin1Char(' '), 0, 0); - candidate = sysroot + QLatin1Char('/') + binary; - if (QFileInfo(candidate).exists()) - localExecutable = candidate; - } - if (localExecutable.isEmpty()) { - candidate = sysroot + QLatin1String("/usr/bin/") + binary; - if (QFileInfo(candidate).exists()) - localExecutable = candidate; - } - if (localExecutable.isEmpty()) { - candidate = sysroot + QLatin1String("/bin/") + binary; - if (QFileInfo(candidate).exists()) - localExecutable = candidate; - } - if (localExecutable.isEmpty()) { - QMessageBox::warning(DebuggerPlugin::mainWindow(), tr("Warning"), - tr("Cannot find local executable for remote process \"%1\".") - .arg(d->remoteCommandLine)); - return; - } + } + if (localExecutable.isEmpty()) { + candidate = sysroot + QLatin1String("/usr/bin/") + binary; + if (QFileInfo(candidate).exists()) + localExecutable = candidate; + } + if (localExecutable.isEmpty()) { + candidate = sysroot + QLatin1String("/bin/") + binary; + if (QFileInfo(candidate).exists()) + localExecutable = candidate; + } + if (localExecutable.isEmpty()) { + QMessageBox::warning(DebuggerPlugin::mainWindow(), tr("Warning"), + tr("Cannot find local executable for remote process \"%1\".") + .arg(d->process.exe)); + return; + } - QList<Abi> abis = Abi::abisOfBinary(Utils::FileName::fromString(localExecutable)); - if (abis.isEmpty()) { - QMessageBox::warning(DebuggerPlugin::mainWindow(), tr("Warning"), - tr("Cannot find ABI for remote process \"%1\".") - .arg(d->remoteCommandLine)); - return; - } + QList<Abi> abis = Abi::abisOfBinary(Utils::FileName::fromString(localExecutable)); + if (abis.isEmpty()) { + QMessageBox::warning(DebuggerPlugin::mainWindow(), tr("Warning"), + tr("Cannot find ABI for remote process \"%1\".") + .arg(d->process.exe)); + return; + } - DebuggerStartParameters sp; - sp.displayName = tr("Remote: \"%1\"").arg(channel); - sp.remoteChannel = channel; - sp.executable = localExecutable; - sp.startMode = AttachToRemoteServer; - sp.closeMode = KillAtClose; - 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.toolChainAbi = tc->targetAbi(); + QString channel = QString("%1:%2").arg(d->device->sshParameters().host).arg(port); - if (RunControl *rc = DebuggerPlugin::createDebugger(sp)) - DebuggerPlugin::startDebugger(rc); - } + DebuggerStartParameters sp; + sp.displayName = tr("Remote: \"%1\"").arg(channel); + sp.remoteChannel = channel; + sp.executable = localExecutable; + sp.startMode = AttachToRemoteServer; + sp.closeMode = KillAtClose; + sp.overrideStartScript.clear(); + sp.useServerStartScript = false; + sp.serverStartScript.clear(); + 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 diff --git a/src/plugins/debugger/gdb/startgdbserverdialog.h b/src/plugins/debugger/gdb/startgdbserverdialog.h index 74dd0231bcecb9446d3da6c1b5e156198b88d30f..285848996ecb09fc11eea2200b9cd90874c03832 100644 --- a/src/plugins/debugger/gdb/startgdbserverdialog.h +++ b/src/plugins/debugger/gdb/startgdbserverdialog.h @@ -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(); - - void startGdbServer(); - void attachToRemoteProcess(); + GdbServerStarter(ProjectExplorer::DeviceProcessesDialog *dlg, bool startServerOnly); + ~GdbServerStarter(); -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 diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp index eb525845818bc27dcec89701454901af5dfaa5e1..df44ccf51a8abd2fc5b38cd004afafb0b0abb508 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp @@ -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; }; +ProcessListFilterModel::ProcessListFilterModel() +{ + setFilterCaseSensitivity(Qt::CaseInsensitive); + setDynamicSortFilter(true); + 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; +} + +/////////////////////////////////////////////////////////////////////// +// +// 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; +}; -DeviceProcessesDialog::DeviceProcessesDialog(DeviceProcessList *processList, QWidget *parent) - : QDialog(parent), d(new DeviceProcessesDialogPrivate(processList)) +DeviceProcessesDialogPrivate::DeviceProcessesDialogPrivate(QWidget *parent) + : q(parent) { - processList->setParent(this); + processList = 0; - 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))); + processFilterLineEdit = new FilterLineEdit(q); + processFilterLineEdit->setPlaceholderText(DeviceProcessesDialog::tr("Filter")); + processFilterLineEdit->setFocus(Qt::TabFocusReason); - connect(d->ui.treeView->selectionModel(), + 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(); } -DeviceProcessesDialog::~DeviceProcessesDialog() +void DeviceProcessesDialogPrivate::handleRemoteError(const QString &errorMsg) { - delete d; + QMessageBox::critical(q, tr("Remote Error"), errorMsg); + updateListButton->setEnabled(true); + updateButtons(); } -void DeviceProcessesDialog::handleRemoteError(const QString &errorMsg) +void DeviceProcessesDialogPrivate::handleProcessListUpdated() { - QMessageBox::critical(this, tr("Remote Error"), errorMsg); - d->ui.updateListButton->setEnabled(true); - handleSelectionChanged(); + updateListButton->setEnabled(true); + procView->resizeColumnToContents(0); + procView->resizeColumnToContents(1); + updateButtons(); } -void DeviceProcessesDialog::handleProcessListUpdated() +void DeviceProcessesDialogPrivate::updateProcessList() { - d->ui.updateListButton->setEnabled(true); - handleSelectionChanged(); + updateListButton->setEnabled(false); + killProcessButton->setEnabled(false); + if (processList) + processList->update(); } -void DeviceProcessesDialog::updateProcessList() +void DeviceProcessesDialogPrivate::killProcess() { - d->ui.updateListButton->setEnabled(false); - d->ui.killProcessButton->setEnabled(false); - d->processList->update(); + const QModelIndexList indexes = procView->selectionModel()->selectedIndexes(); + if (indexes.empty()) + return; + updateListButton->setEnabled(false); + killProcessButton->setEnabled(false); + processList->killProcess(proxyModel.mapToSource(indexes.first()).row()); } -void DeviceProcessesDialog::killProcess() +void DeviceProcessesDialogPrivate::updateDevice() { - 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()); + setDevice(DeviceProfileInformation::device(profileChooser->currentProfile())); } -void DeviceProcessesDialog::handleProcessKilled() +void DeviceProcessesDialogPrivate::handleProcessKilled() { updateProcessList(); } -void DeviceProcessesDialog::handleSelectionChanged() +void DeviceProcessesDialogPrivate::updateButtons() { - d->ui.killProcessButton->setEnabled(d->ui.treeView->selectionModel()->hasSelection()); + 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 -} // namespace RemoteLinux + +/////////////////////////////////////////////////////////////////////// +// +// 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::setDevice(const IDevice::ConstPtr &device) +{ + d->profileChooser->hide(); + d->setDevice(device); +} + +void DeviceProcessesDialog::showAllDevices() +{ + d->profileChooser->show(); + d->updateDevice(); +} + +DeviceProcess DeviceProcessesDialog::currentProcess() const +{ + return d->selectedProcess(); +} + +ProfileChooser *DeviceProcessesDialog::profileChooser() const +{ + return d->profileChooser; +} + +void DeviceProcessesDialog::logMessage(const QString &line) +{ + d->errorText->setVisible(true); + d->errorText->append(line); +} + +} // namespace ProjectExplorer + +#include "deviceprocessesdialog.moc" diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.h b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.h index 6b1f3f63d2eefc986f433d3b024efa635b6fc066..9d11ad974df1a578bc6b1ceadf181f1a3a8840b5 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.h +++ b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.h @@ -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 diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.ui b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.ui deleted file mode 100644 index 1e3e5cd906c17093189bfc9c75332834a48b4f9b..0000000000000000000000000000000000000000 --- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.ui +++ /dev/null @@ -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> diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp index ad3f689163c8f2307d701725cf2343dca91a20e8..20c068ba98b77ffa3cf995d421d90a4bf585f803 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp @@ -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 diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index be079bf2acf2928859405355f6278fbe014d9951..08c628c8258636ba2c136df5f4f01523b2c1cb04 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -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 diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h index ed8768e35097b6d8261ffc29c22ea9bf3aec3eca..177315a959fc77cade86fb46ca25ab758dea4ca6 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h @@ -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(); diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp index e1896e897ed810fa7f46845753261820961324ba..8b757c1c617ef6f1ff254a05b31474cb2a3ead9b 100644 --- a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp +++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp @@ -174,7 +174,7 @@ void LocalProcessList::handleWindowsUpdate() CloseHandle(snapshot); reportProcessListUpdated(processes); -#endif //Q_OS_WIN +#endif } void LocalProcessList::handlePsError() diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index e60c11a5d0b70eb6f39ae099bc8fa4af1f89fb2f..8e5bcfc560814331623ccaeca7590879caf1f7fb 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -245,7 +245,6 @@ FORMS += processstep.ui \ publishing/publishingwizardselectiondialog.ui \ codestylesettingspropertiespage.ui \ devicesupport/devicefactoryselectiondialog.ui \ - devicesupport/deviceprocessesdialog.ui \ devicesupport/devicesettingswidget.ui WINSOURCES += \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index ec786ce819ad6fc17606d328604ddaf0f94e7497..79597beab305f14bf6af98cda7442a5f6f60e6a0 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -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",