forked from qt-creator/qt-creator
Fixes: Error logging, polish attach remote dialog
This commit is contained in:
committed by
unknown
parent
cb2cce5139
commit
355f44fe8f
@@ -1,7 +1,8 @@
|
|||||||
<ui version="4.0" >
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
<class>AttachRemoteDialog</class>
|
<class>AttachRemoteDialog</class>
|
||||||
<widget class="QDialog" name="AttachRemoteDialog" >
|
<widget class="QDialog" name="AttachRemoteDialog">
|
||||||
<property name="geometry" >
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
@@ -9,50 +10,76 @@
|
|||||||
<height>866</height>
|
<height>866</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle">
|
||||||
<string>Start Debugger</string>
|
<string>Start Debugger</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout">
|
||||||
<property name="spacing" >
|
<property name="spacing">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="margin" >
|
<property name="margin">
|
||||||
<number>9</number>
|
<number>9</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" >
|
<layout class="QFormLayout" name="formLayout">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="pidLabel" >
|
<widget class="QLabel" name="pidLabel">
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string>Attach to Process ID:</string>
|
<string>Attach to Process ID:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<widget class="QLineEdit" name="pidLineEdit" />
|
<widget class="QLineEdit" name="pidLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Filter:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QWidget" name="filterWidget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="filterLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="filterClearToolButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeView" name="procView" >
|
<widget class="QTreeView" name="procView">
|
||||||
<property name="editTriggers" >
|
<property name="editTriggers">
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line" >
|
<widget class="Line" name="line">
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons" >
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "debuggermanager.h"
|
#include "debuggermanager.h"
|
||||||
#include "breakhandler.h"
|
#include "breakhandler.h"
|
||||||
#include "stackhandler.h"
|
#include "stackhandler.h"
|
||||||
|
#include "watchhandler.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/winutils.h>
|
#include <utils/winutils.h>
|
||||||
@@ -50,11 +51,13 @@
|
|||||||
static const char *dbgEngineDllC = "dbgeng";
|
static const char *dbgEngineDllC = "dbgeng";
|
||||||
static const char *debugCreateFuncC = "DebugCreate";
|
static const char *debugCreateFuncC = "DebugCreate";
|
||||||
|
|
||||||
static QString debugEngineComError(HRESULT hr)
|
static QString msgDebugEngineComResult(HRESULT hr)
|
||||||
{
|
{
|
||||||
if (!FAILED(hr))
|
|
||||||
return QLatin1String("S_OK");
|
|
||||||
switch (hr) {
|
switch (hr) {
|
||||||
|
case S_OK:
|
||||||
|
return QLatin1String("S_OK");
|
||||||
|
case S_FALSE:
|
||||||
|
return QLatin1String("S_FALSE");
|
||||||
case E_FAIL:
|
case E_FAIL:
|
||||||
break;
|
break;
|
||||||
case E_INVALIDARG:
|
case E_INVALIDARG:
|
||||||
@@ -207,6 +210,7 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
|
m_d->m_bIgnoreNextDebugEvent = false;
|
||||||
switch (m_d->m_debuggerManager->startMode()) {
|
switch (m_d->m_debuggerManager->startMode()) {
|
||||||
case AttachExternal:
|
case AttachExternal:
|
||||||
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
||||||
@@ -235,7 +239,7 @@ bool CdbDebugEngine::startAttachDebugger(unsigned long pid, QString *errorMessag
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << "Attaching to " << pid << " returns " << hr;
|
qDebug() << "Attaching to " << pid << " returns " << hr;
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = tr("AttachProcess failed for pid %1: %2").arg(pid).arg(debugEngineComError(hr));
|
*errorMessage = tr("AttachProcess failed for pid %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -276,7 +280,7 @@ bool CdbDebugEngine::startDebuggerWithExecutable(QString *errorMessage)
|
|||||||
m_d->m_debuggerManager->m_workingDir.utf16(),
|
m_d->m_debuggerManager->m_workingDir.utf16(),
|
||||||
env);
|
env);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd).arg(debugEngineComError(hr));
|
*errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd).arg(msgDebugEngineComResult(hr));
|
||||||
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -295,6 +299,9 @@ void CdbDebugEngine::exitDebugger()
|
|||||||
|
|
||||||
void CdbDebugEngine::updateWatchModel()
|
void CdbDebugEngine::updateWatchModel()
|
||||||
{
|
{
|
||||||
|
const QList<WatchData> incomplete = m_d->m_debuggerManagerAccess->watchHandler()->takeCurrentIncompletes();
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << incomplete.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::stepExec()
|
void CdbDebugEngine::stepExec()
|
||||||
@@ -357,9 +364,12 @@ void CdbDebugEngine::nextExec()
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
HRESULT hr;
|
const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
|
||||||
hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
|
if (SUCCEEDED(hr)) {
|
||||||
startWatchTimer();
|
startWatchTimer();
|
||||||
|
} else {
|
||||||
|
qWarning("%s failed: %s", Q_FUNC_INFO, qPrintable(msgDebugEngineComResult(hr)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::stepIExec()
|
void CdbDebugEngine::stepIExec()
|
||||||
@@ -372,8 +382,12 @@ void CdbDebugEngine::nextIExec()
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
|
const HRESULT hr = m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
|
||||||
startWatchTimer();
|
if (SUCCEEDED(hr)) {
|
||||||
|
startWatchTimer();
|
||||||
|
} else {
|
||||||
|
qWarning("%s failed: %s", Q_FUNC_INFO, qPrintable(msgDebugEngineComResult(hr)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::continueInferior()
|
void CdbDebugEngine::continueInferior()
|
||||||
@@ -386,26 +400,30 @@ void CdbDebugEngine::continueInferior()
|
|||||||
|
|
||||||
ULONG executionStatus;
|
ULONG executionStatus;
|
||||||
HRESULT hr = m_d->m_pDebugControl->GetExecutionStatus(&executionStatus);
|
HRESULT hr = m_d->m_pDebugControl->GetExecutionStatus(&executionStatus);
|
||||||
if (SUCCEEDED(hr) && executionStatus != DEBUG_STATUS_GO)
|
if (SUCCEEDED(hr) && executionStatus != DEBUG_STATUS_GO) {
|
||||||
m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO);
|
hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
startWatchTimer();
|
startWatchTimer();
|
||||||
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
||||||
|
} else {
|
||||||
|
qWarning("%s failed: %s", Q_FUNC_INFO, qPrintable(msgDebugEngineComResult(hr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::interruptInferior()
|
void CdbDebugEngine::interruptInferior()
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO << m_d->m_hDebuggeeProcess;
|
||||||
|
|
||||||
//TODO: better use IDebugControl::SetInterrupt?
|
//TODO: better use IDebugControl::SetInterrupt?
|
||||||
if (!m_d->m_hDebuggeeProcess)
|
if (!m_d->m_hDebuggeeProcess)
|
||||||
return;
|
return;
|
||||||
if (!DebugBreakProcess(m_d->m_hDebuggeeProcess)) {
|
if (DebugBreakProcess(m_d->m_hDebuggeeProcess)) {
|
||||||
qWarning("DebugBreakProcess failed.");
|
m_d->m_debuggerManagerAccess->notifyInferiorStopped();
|
||||||
return;
|
} else {
|
||||||
|
qWarning("DebugBreakProcess failed: %s", Core::Utils::winErrorMessage(GetLastError()));
|
||||||
}
|
}
|
||||||
m_d->m_debuggerManagerAccess->notifyInferiorStopped();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
|
void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
|
||||||
@@ -571,43 +589,30 @@ void CdbDebugEngine::timerEvent(QTimerEvent* te)
|
|||||||
if (te->timerId() != m_d->m_watchTimer)
|
if (te->timerId() != m_d->m_watchTimer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (debugCDB > 1)
|
const HRESULT hr = m_d->m_pDebugControl->WaitForEvent(0, 1);
|
||||||
qDebug() << Q_FUNC_INFO;
|
if (debugCDB)
|
||||||
|
if (debugCDB > 1 || hr != S_FALSE)
|
||||||
|
qDebug() << Q_FUNC_INFO << "WaitForEvent" << msgDebugEngineComResult(hr);
|
||||||
|
|
||||||
HRESULT hr;
|
|
||||||
hr = m_d->m_pDebugControl->WaitForEvent(0, 1);
|
|
||||||
switch (hr) {
|
switch (hr) {
|
||||||
case S_OK:
|
case S_OK:
|
||||||
if (debugCDB > 1)
|
|
||||||
qDebug() << "WaitForEvent S_OK";
|
|
||||||
|
|
||||||
killWatchTimer();
|
killWatchTimer();
|
||||||
m_d->handleDebugEvent();
|
m_d->handleDebugEvent();
|
||||||
break;
|
break;
|
||||||
case S_FALSE:
|
case S_FALSE:
|
||||||
if (debugCDB > 1)
|
|
||||||
qDebug() << "WaitForEvent S_FALSE";
|
|
||||||
break;
|
|
||||||
case E_PENDING:
|
case E_PENDING:
|
||||||
if (debugCDB > 1)
|
case E_FAIL:
|
||||||
qDebug() << "WaitForEvent E_PENDING";
|
|
||||||
break;
|
break;
|
||||||
case E_UNEXPECTED:
|
case E_UNEXPECTED:
|
||||||
if (debugCDB > 1)
|
|
||||||
qDebug() << "WaitForEvent E_UNEXPECTED";
|
|
||||||
killWatchTimer();
|
killWatchTimer();
|
||||||
break;
|
break;
|
||||||
case E_FAIL:
|
|
||||||
if (debugCDB > 1)
|
|
||||||
qDebug() << "WaitForEvent E_FAIL";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::handleDebugEvent()
|
void CdbDebugEnginePrivate::handleDebugEvent()
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
||||||
|
|
||||||
if (m_bIgnoreNextDebugEvent) {
|
if (m_bIgnoreNextDebugEvent) {
|
||||||
m_engine->startWatchTimer();
|
m_engine->startWatchTimer();
|
||||||
@@ -630,10 +635,18 @@ void CdbDebugEnginePrivate::handleDebugEvent()
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CdbDebugEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread)
|
||||||
|
{
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << hDebuggeeProcess << hDebuggeeThread;
|
||||||
|
m_hDebuggeeProcess = hDebuggeeProcess;
|
||||||
|
m_hDebuggeeThread = hDebuggeeThread;
|
||||||
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::updateThreadList()
|
void CdbDebugEnginePrivate::updateThreadList()
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
||||||
|
|
||||||
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
|
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
|
||||||
QList<ThreadData> threads;
|
QList<ThreadData> threads;
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ struct CdbDebugEnginePrivate
|
|||||||
explicit CdbDebugEnginePrivate(const DebuggerEngineLibrary &lib, DebuggerManager *parent, CdbDebugEngine* engine);
|
explicit CdbDebugEnginePrivate(const DebuggerEngineLibrary &lib, DebuggerManager *parent, CdbDebugEngine* engine);
|
||||||
~CdbDebugEnginePrivate();
|
~CdbDebugEnginePrivate();
|
||||||
|
|
||||||
|
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
||||||
|
|
||||||
bool isDebuggeeRunning() const { return m_watchTimer != -1; }
|
bool isDebuggeeRunning() const { return m_watchTimer != -1; }
|
||||||
void handleDebugEvent();
|
void handleDebugEvent();
|
||||||
void updateThreadList();
|
void updateThreadList();
|
||||||
|
|||||||
@@ -91,6 +91,13 @@ STDMETHODIMP CdbDebugEventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT Bp)
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline QString msgException(const EXCEPTION_RECORD64 *Exception, ULONG FirstChance)
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("An exception occurred: Code=0x%1 FirstChance=%2").
|
||||||
|
arg(QString::number(Exception->ExceptionCode, 16)).
|
||||||
|
arg(FirstChance);
|
||||||
|
}
|
||||||
|
|
||||||
STDMETHODIMP CdbDebugEventCallback::Exception(
|
STDMETHODIMP CdbDebugEventCallback::Exception(
|
||||||
THIS_
|
THIS_
|
||||||
__in PEXCEPTION_RECORD64 Exception,
|
__in PEXCEPTION_RECORD64 Exception,
|
||||||
@@ -99,7 +106,11 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
|
|||||||
{
|
{
|
||||||
Q_UNUSED(Exception)
|
Q_UNUSED(Exception)
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << FirstChance;
|
qDebug() << Q_FUNC_INFO << msgException(Exception, FirstChance);
|
||||||
|
|
||||||
|
// First chance are harmless
|
||||||
|
if (!FirstChance)
|
||||||
|
qWarning("%s", qPrintable(msgException(Exception, FirstChance)));
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +172,7 @@ STDMETHODIMP CdbDebugEventCallback::CreateProcess(
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << ModuleName;
|
qDebug() << Q_FUNC_INFO << ModuleName;
|
||||||
|
|
||||||
m_pEngine->m_d->m_hDebuggeeProcess = (HANDLE)Handle;
|
m_pEngine->m_d->setDebuggeeHandles(reinterpret_cast<HANDLE>(Handle), reinterpret_cast<HANDLE>(InitialThreadHandle));
|
||||||
m_pEngine->m_d->m_hDebuggeeThread = (HANDLE)InitialThreadHandle;
|
|
||||||
m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
||||||
|
|
||||||
ULONG currentThreadId;
|
ULONG currentThreadId;
|
||||||
@@ -183,8 +193,7 @@ STDMETHODIMP CdbDebugEventCallback::ExitProcess(
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << ExitCode;
|
qDebug() << Q_FUNC_INFO << ExitCode;
|
||||||
|
|
||||||
m_pEngine->m_d->m_hDebuggeeProcess = 0;
|
m_pEngine->m_d->setDebuggeeHandles(0, 0);
|
||||||
m_pEngine->m_d->m_hDebuggeeThread = 0;
|
|
||||||
m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,72 @@
|
|||||||
#include <QtGui/QProxyModel>
|
#include <QtGui/QProxyModel>
|
||||||
#include <QtGui/QSortFilterProxyModel>
|
#include <QtGui/QSortFilterProxyModel>
|
||||||
|
|
||||||
using namespace Debugger::Internal;
|
|
||||||
|
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;
|
||||||
|
void populate(QList<ProcData> processes, const QString &excludePid = QString());
|
||||||
|
|
||||||
|
private:
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ProcessListFilterModel::processIdAt(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
const QModelIndex index0 = mapToSource(index);
|
||||||
|
QModelIndex index = index0.sibling(index0.row(), 0);
|
||||||
|
if (const QStandardItem *item = m_model->itemFromIndex(index))
|
||||||
|
return item->text();
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
row.append(new QStandardItem(proc.name));
|
||||||
|
if (!proc.image.isEmpty())
|
||||||
|
row.back()->setToolTip(proc.image);
|
||||||
|
row.append(new QStandardItem(proc.state));
|
||||||
|
if (proc.ppid == excludePid)
|
||||||
|
foreach(QStandardItem *i, row)
|
||||||
|
i->setEnabled(false);
|
||||||
|
root->appendRow(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -105,17 +170,6 @@ void AttachCoreDialog::setCoreFile(const QString &fileName)
|
|||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static QStandardItemModel *createProcessModel(QObject *parent)
|
|
||||||
{
|
|
||||||
QStandardItemModel *rc = new QStandardItemModel(parent);
|
|
||||||
QStringList columns;
|
|
||||||
columns << AttachExternalDialog::tr("Process ID")
|
|
||||||
<< AttachExternalDialog::tr("Name")
|
|
||||||
<< AttachExternalDialog::tr("State");
|
|
||||||
rc->setHorizontalHeaderLabels(columns);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isUnixProcessId(const QString &procname)
|
static bool isUnixProcessId(const QString &procname)
|
||||||
{
|
{
|
||||||
for (int i = 0; i != procname.size(); ++i)
|
for (int i = 0; i != procname.size(); ++i)
|
||||||
@@ -124,13 +178,6 @@ static bool isUnixProcessId(const QString &procname)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
bool operator<(const ProcData &p1, const ProcData &p2)
|
|
||||||
{
|
|
||||||
return p1.name < p2.name;
|
|
||||||
}
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
// Determine UNIX processes by reading "/proc"
|
// Determine UNIX processes by reading "/proc"
|
||||||
static QList<ProcData> unixProcessList()
|
static QList<ProcData> unixProcessList()
|
||||||
{
|
{
|
||||||
@@ -162,40 +209,13 @@ static QList<ProcData> unixProcessList()
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QStandardItem *createStandardItem(const QString &text,
|
static QList<ProcData> processList()
|
||||||
bool enabled)
|
|
||||||
{
|
|
||||||
QStandardItem *rc = new QStandardItem(text);
|
|
||||||
rc->setEnabled(enabled);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate a standard item model with a list
|
|
||||||
// of processes and gray out the excludePid.
|
|
||||||
static void populateProcessModel(QStandardItemModel *model,
|
|
||||||
const QString &excludePid = QString())
|
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QList<ProcData> processes = winProcessList();
|
return winProcessList();
|
||||||
#else
|
#else
|
||||||
QList<ProcData> processes = unixProcessList();
|
return unixProcessList();
|
||||||
#endif
|
#endif
|
||||||
qStableSort(processes);
|
|
||||||
|
|
||||||
if (const int rowCount = model->rowCount())
|
|
||||||
model->removeRows(0, rowCount);
|
|
||||||
|
|
||||||
QStandardItem *root = model->invisibleRootItem();
|
|
||||||
foreach(const ProcData &proc, processes) {
|
|
||||||
const bool enabled = proc.ppid != excludePid;
|
|
||||||
QList<QStandardItem *> row;
|
|
||||||
row.append(createStandardItem(proc.ppid, enabled));
|
|
||||||
row.append(createStandardItem(proc.name, enabled));
|
|
||||||
if (!proc.image.isEmpty())
|
|
||||||
row.back()->setToolTip(proc.image);
|
|
||||||
row.append(createStandardItem(proc.state, enabled));
|
|
||||||
root->appendRow(row);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
@@ -208,17 +228,13 @@ AttachExternalDialog::AttachExternalDialog(QWidget *parent) :
|
|||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
m_selfPid(QString::number(QCoreApplication::applicationPid())),
|
m_selfPid(QString::number(QCoreApplication::applicationPid())),
|
||||||
m_ui(new Ui::AttachExternalDialog),
|
m_ui(new Ui::AttachExternalDialog),
|
||||||
m_proxyModel(new QSortFilterProxyModel(this)),
|
m_model(new ProcessListFilterModel(this))
|
||||||
m_model(createProcessModel(this))
|
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
okButton()->setDefault(true);
|
okButton()->setDefault(true);
|
||||||
okButton()->setEnabled(false);
|
okButton()->setEnabled(false);
|
||||||
|
|
||||||
m_proxyModel->setSourceModel(m_model);
|
m_ui->procView->setModel(m_model);
|
||||||
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
||||||
m_proxyModel->setFilterKeyColumn(1);
|
|
||||||
m_ui->procView->setModel(m_proxyModel);
|
|
||||||
m_ui->procView->setSortingEnabled(true);
|
m_ui->procView->setSortingEnabled(true);
|
||||||
|
|
||||||
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||||
@@ -227,7 +243,8 @@ AttachExternalDialog::AttachExternalDialog(QWidget *parent) :
|
|||||||
connect(refreshButton, SIGNAL(clicked()), this, SLOT(rebuildProcessList()));
|
connect(refreshButton, SIGNAL(clicked()), this, SLOT(rebuildProcessList()));
|
||||||
m_ui->buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
|
m_ui->buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
|
||||||
|
|
||||||
connect(m_ui->procView, SIGNAL(activated(QModelIndex)),
|
// Do not use activated, will be single click in Oxygen
|
||||||
|
connect(m_ui->procView, SIGNAL(doubleClicked(QModelIndex)),
|
||||||
this, SLOT(procSelected(QModelIndex)));
|
this, SLOT(procSelected(QModelIndex)));
|
||||||
connect(m_ui->pidLineEdit, SIGNAL(textChanged(QString)),
|
connect(m_ui->pidLineEdit, SIGNAL(textChanged(QString)),
|
||||||
this, SLOT(pidChanged(QString)));
|
this, SLOT(pidChanged(QString)));
|
||||||
@@ -235,7 +252,7 @@ AttachExternalDialog::AttachExternalDialog(QWidget *parent) :
|
|||||||
connect(m_ui->filterClearToolButton, SIGNAL(clicked()),
|
connect(m_ui->filterClearToolButton, SIGNAL(clicked()),
|
||||||
m_ui->filterLineEdit, SLOT(clear()));
|
m_ui->filterLineEdit, SLOT(clear()));
|
||||||
connect(m_ui->filterLineEdit, SIGNAL(textChanged(QString)),
|
connect(m_ui->filterLineEdit, SIGNAL(textChanged(QString)),
|
||||||
m_proxyModel, SLOT(setFilterFixedString(QString)));
|
m_model, SLOT(setFilterFixedString(QString)));
|
||||||
|
|
||||||
rebuildProcessList();
|
rebuildProcessList();
|
||||||
}
|
}
|
||||||
@@ -252,7 +269,7 @@ QPushButton *AttachExternalDialog::okButton() const
|
|||||||
|
|
||||||
void AttachExternalDialog::rebuildProcessList()
|
void AttachExternalDialog::rebuildProcessList()
|
||||||
{
|
{
|
||||||
populateProcessModel(m_model, m_selfPid);
|
m_model->populate(processList(), m_selfPid);
|
||||||
m_ui->procView->expandAll();
|
m_ui->procView->expandAll();
|
||||||
m_ui->procView->resizeColumnToContents(0);
|
m_ui->procView->resizeColumnToContents(0);
|
||||||
m_ui->procView->resizeColumnToContents(1);
|
m_ui->procView->resizeColumnToContents(1);
|
||||||
@@ -260,10 +277,9 @@ void AttachExternalDialog::rebuildProcessList()
|
|||||||
|
|
||||||
void AttachExternalDialog::procSelected(const QModelIndex &proxyIndex)
|
void AttachExternalDialog::procSelected(const QModelIndex &proxyIndex)
|
||||||
{
|
{
|
||||||
const QModelIndex index0 = m_proxyModel->mapToSource(proxyIndex);
|
const QString proccessId = m_model->processIdAt(proxyIndex);
|
||||||
QModelIndex index = index0.sibling(index0.row(), 0);
|
if (!proccessId.isEmpty()) {
|
||||||
if (const QStandardItem *item = m_model->itemFromIndex(index)) {
|
m_ui->pidLineEdit->setText(proccessId);
|
||||||
m_ui->pidLineEdit->setText(item->text());
|
|
||||||
if (okButton()->isEnabled())
|
if (okButton()->isEnabled())
|
||||||
okButton()->animateClick();
|
okButton()->animateClick();
|
||||||
}
|
}
|
||||||
@@ -276,7 +292,7 @@ int AttachExternalDialog::attachPID() const
|
|||||||
|
|
||||||
void AttachExternalDialog::pidChanged(const QString &pid)
|
void AttachExternalDialog::pidChanged(const QString &pid)
|
||||||
{
|
{
|
||||||
okButton()->setEnabled(!pid.isEmpty() && pid != m_selfPid);
|
okButton()->setEnabled(!pid.isEmpty() && pid != QLatin1String("0") && pid != m_selfPid);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
@@ -288,7 +304,7 @@ void AttachExternalDialog::pidChanged(const QString &pid)
|
|||||||
AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid) :
|
AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
m_ui(new Ui::AttachRemoteDialog),
|
m_ui(new Ui::AttachRemoteDialog),
|
||||||
m_model(createProcessModel(this))
|
m_model(new ProcessListFilterModel(this))
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
|
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
|
||||||
@@ -300,9 +316,22 @@ AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid) :
|
|||||||
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||||
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||||
|
|
||||||
connect(m_ui->procView, SIGNAL(activated(QModelIndex)),
|
// Do not use activated, will be single click in Oxygen
|
||||||
|
connect(m_ui->procView, SIGNAL(doubleClicked(QModelIndex)),
|
||||||
this, SLOT(procSelected(QModelIndex)));
|
this, SLOT(procSelected(QModelIndex)));
|
||||||
|
|
||||||
|
QPushButton *refreshButton = new QPushButton(tr("Refresh"));
|
||||||
|
connect(refreshButton, SIGNAL(clicked()), this, SLOT(rebuildProcessList()));
|
||||||
|
m_ui->buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
|
||||||
|
|
||||||
|
connect(m_ui->pidLineEdit, SIGNAL(textChanged(QString)),
|
||||||
|
this, SLOT(pidChanged(QString)));
|
||||||
|
|
||||||
|
connect(m_ui->filterClearToolButton, SIGNAL(clicked()),
|
||||||
|
m_ui->filterLineEdit, SLOT(clear()));
|
||||||
|
connect(m_ui->filterLineEdit, SIGNAL(textChanged(QString)),
|
||||||
|
m_model, SLOT(setFilterFixedString(QString)));
|
||||||
|
|
||||||
m_ui->pidLineEdit->setText(m_defaultPID);
|
m_ui->pidLineEdit->setText(m_defaultPID);
|
||||||
rebuildProcessList();
|
rebuildProcessList();
|
||||||
}
|
}
|
||||||
@@ -312,22 +341,27 @@ AttachRemoteDialog::~AttachRemoteDialog()
|
|||||||
delete m_ui;
|
delete m_ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton *AttachRemoteDialog::okButton() const
|
||||||
|
{
|
||||||
|
return m_ui->buttonBox->button(QDialogButtonBox::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
void AttachRemoteDialog::rebuildProcessList()
|
void AttachRemoteDialog::rebuildProcessList()
|
||||||
{
|
{
|
||||||
populateProcessModel(m_model);
|
m_model->populate(processList());
|
||||||
m_ui->procView->expandAll();
|
m_ui->procView->expandAll();
|
||||||
m_ui->procView->resizeColumnToContents(0);
|
m_ui->procView->resizeColumnToContents(0);
|
||||||
m_ui->procView->resizeColumnToContents(1);
|
m_ui->procView->resizeColumnToContents(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachRemoteDialog::procSelected(const QModelIndex &index0)
|
void AttachRemoteDialog::procSelected(const QModelIndex &index0)
|
||||||
{
|
{
|
||||||
QModelIndex index = index0.sibling(index0.row(), 0);
|
const QString proccessId = m_model->processIdAt(index0);
|
||||||
QStandardItem *item = m_model->itemFromIndex(index);
|
if (!proccessId.isEmpty()) {
|
||||||
if (!item)
|
m_ui->pidLineEdit->setText(proccessId);
|
||||||
return;
|
if (okButton()->isEnabled())
|
||||||
m_ui->pidLineEdit->setText(item->text());
|
okButton()->animateClick();
|
||||||
accept();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AttachRemoteDialog::attachPID() const
|
int AttachRemoteDialog::attachPID() const
|
||||||
@@ -335,6 +369,12 @@ int AttachRemoteDialog::attachPID() const
|
|||||||
return m_ui->pidLineEdit->text().toInt();
|
return m_ui->pidLineEdit->text().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AttachRemoteDialog::pidChanged(const QString &pid)
|
||||||
|
{
|
||||||
|
okButton()->setEnabled(!pid.isEmpty() && pid != QLatin1String("0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// StartExternalDialog
|
// StartExternalDialog
|
||||||
@@ -385,3 +425,6 @@ QString StartExternalDialog::executableArguments() const
|
|||||||
{
|
{
|
||||||
return m_ui->argsEdit->text();
|
return m_ui->argsEdit->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,8 +35,6 @@
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
class QStandardItemModel;
|
|
||||||
class QSortFilterProxyModel;
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@@ -52,6 +50,8 @@ QT_END_NAMESPACE
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class ProcessListFilterModel;
|
||||||
|
|
||||||
struct ProcData
|
struct ProcData
|
||||||
{
|
{
|
||||||
QString ppid;
|
QString ppid;
|
||||||
@@ -98,8 +98,7 @@ private:
|
|||||||
const QString m_selfPid;
|
const QString m_selfPid;
|
||||||
|
|
||||||
Ui::AttachExternalDialog *m_ui;
|
Ui::AttachExternalDialog *m_ui;
|
||||||
QStandardItemModel *m_model;
|
ProcessListFilterModel *m_model;
|
||||||
QSortFilterProxyModel *m_proxyModel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -116,11 +115,13 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void rebuildProcessList();
|
void rebuildProcessList();
|
||||||
void procSelected(const QModelIndex &);
|
void procSelected(const QModelIndex &);
|
||||||
|
void pidChanged(const QString &);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
inline QPushButton *okButton() const;
|
||||||
Ui::AttachRemoteDialog *m_ui;
|
Ui::AttachRemoteDialog *m_ui;
|
||||||
QString m_defaultPID;
|
QString m_defaultPID;
|
||||||
QStandardItemModel *m_model;
|
ProcessListFilterModel *m_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user