Commit 1afea78c authored by hjk's avatar hjk

debugger: convert register handler/window architecture

parent 702e9f3f
......@@ -31,26 +31,20 @@
#include "breakpointmarker.h"
#include "debuggeractions.h"
#include "debuggerengine.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
#include "threadshandler.h"
#include <utils/qtcassert.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
namespace Debugger {
namespace Internal {
static DebuggerPlugin *plugin() { return DebuggerPlugin::instance(); }
static Breakpoints m_bp;
// FIXME this is only static because it might map to bps in the above list
static QHash<quint64,BreakpointMarker*> m_markers;
//////////////////////////////////////////////////////////////////
//
// BreakHandler
......
......@@ -117,7 +117,7 @@ private:
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
void markerUpdated(BreakpointMarker *, int lineNumber);
void markerUpdated(BreakpointMarker *marker, int lineNumber);
void loadBreakpoints();
void saveBreakpoints();
void removeBreakpointHelper(int index);
......@@ -138,7 +138,8 @@ private:
mutable BreakpointData *m_lastFound;
mutable bool m_lastFoundQueried;
QList<BreakpointData *> m_bp;
Breakpoints m_bp;
QHash<quint64, BreakpointMarker *> m_markers;
};
} // namespace Internal
......
......@@ -239,14 +239,6 @@ enum ModelRoles
RequestAllSymbolsRole,
RequestOpenFileRole,
// Registers
RegisterNumberBaseRole, // Currently used number base
RegisterAddressRole, // Start value for opening memory view
RegisterChangedRole, // Used for painting changed values
RegisterBigNumberRole, // Register is a big integer that cannot be handled as quint64.
RequestSetRegisterRole,
RequestReloadRegistersRole,
// Snapshots
SnapshotCapabilityRole,
RequestCreateSnapshotRole,
......
......@@ -225,7 +225,7 @@ public:
m_targetState(DebuggerNotReady),
m_commandHandler(engine),
m_modulesHandler(engine),
m_registerHandler(engine),
m_registerHandler(),
m_sourceFilesHandler(engine),
m_stackHandler(engine),
m_threadsHandler(engine),
......@@ -534,9 +534,9 @@ void DebuggerEngine::handleCommand(int role, const QVariant &value)
reloadModules();
break;
case RequestReloadRegistersRole:
reloadRegisters();
break;
//case RequestReloadRegistersRole:
// reloadRegisters();
// break;
case RequestExecDetachRole:
detachDebugger();
......
......@@ -226,7 +226,7 @@
// * * +
// EngineShutdownRequested +
// + +
// (calls *Engine->shutdownEngine()) <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
// (calls *Engine->shutdownEngine()) <+-+-+-+-+-+-+-+-+-+-+-+-+-+'
// | |
// | |
// {notify- {notify-
......@@ -296,7 +296,7 @@ sg1: }
//
//
// GdbEngine::setupInferior()
// +
// +
// (calls *Adapter->prepareInferior())
// | |
// | `---> handlePrepareInferiorFailed()
......@@ -305,7 +305,7 @@ sg1: }
// |
// handleInferiorPrepared()
// +
// {notifyInferiorSetupOk}
// {notifyInferiorSetupOk}
......@@ -429,7 +429,7 @@ struct AttachRemoteParameters
quint64 attachPid;
QString attachTarget; // core file name or server:port
// Event handle for attaching to crashed Windows processes.
// Event handle for attaching to crashed Windows processes.
quint64 winCrashEvent;
};
......@@ -863,8 +863,12 @@ public slots:
{ if (on) notifyCurrentEngine(RequestReloadSourceFilesRole); }
void modulesDockToggled(bool on)
{ if (on) notifyCurrentEngine(RequestReloadModulesRole); }
void registerDockToggled(bool on)
{ if (on) notifyCurrentEngine(RequestReloadRegistersRole); }
{
if (on && m_currentEngine)
m_currentEngine->reloadRegisters();
}
void synchronizeBreakpoints()
{
......@@ -1767,7 +1771,7 @@ void DebuggerPluginPrivate::startExternalApplication()
void DebuggerPluginPrivate::notifyCurrentEngine(int role, const QVariant &value)
{
QTC_ASSERT(m_commandWindow, return);
if (m_commandWindow->model())
if (m_commandWindow->model())
m_commandWindow->model()->setData(QModelIndex(), value, role);
}
......@@ -2059,40 +2063,54 @@ void DebuggerPluginPrivate::startDebugger(RunControl *rc)
ProjectExplorerPlugin::instance()->startRunControl(rc, PE::DEBUGMODE);
}
class DummyEngine : public DebuggerEngine
{
Q_OBJECT
public:
DummyEngine() : DebuggerEngine(DebuggerStartParameters()) {}
virtual ~DummyEngine() {}
virtual void setupEngine() {}
virtual void setupInferior() {}
virtual void runEngine() {}
virtual void shutdownEngine() {}
virtual void shutdownInferior() {}
virtual void executeDebuggerCommand(const QString &) {}
virtual unsigned debuggerCapabilities() const { return 0; }
};
void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine, bool notify)
{
static Debugger::DummyEngine dummyEngine;
if (!engine)
engine = &dummyEngine;
if (m_currentEngine == engine)
return;
if (engine) {
if (notify)
notifyCurrentEngine(RequestActivationRole, false);
m_commandWindow->setModel(engine->commandModel());
m_localsWindow->setModel(engine->localsModel());
m_modulesWindow->setModel(engine->modulesModel());
m_registerWindow->setModel(engine->registerModel());
m_returnWindow->setModel(engine->returnModel());
m_sourceFilesWindow->setModel(engine->sourceFilesModel());
m_stackWindow->setModel(engine->stackModel());
m_threadsWindow->setModel(engine->threadsModel());
m_threadBox->setModel(engine->threadsModel());
m_threadBox->setModelColumn(ThreadData::NameColumn);
m_watchersWindow->setModel(engine->watchersModel());
if (notify)
notifyCurrentEngine(RequestActivationRole, true);
} else {
m_commandWindow->setModel(0);
m_localsWindow->setModel(0);
m_modulesWindow->setModel(0);
m_registerWindow->setModel(0);
m_returnWindow->setModel(0);
m_sourceFilesWindow->setModel(0);
m_stackWindow->setModel(0);
m_threadsWindow->setModel(0);
m_threadBox->setModel(0);
m_threadBox->setModelColumn(ThreadData::NameColumn);
m_watchersWindow->setModel(0);
}
m_currentEngine = engine;
if (notify)
notifyCurrentEngine(RequestActivationRole, false);
m_commandWindow->setModel(engine->commandModel());
m_localsWindow->setModel(engine->localsModel());
m_modulesWindow->setModel(engine->modulesModel());
m_registerWindow->setModel(engine->registerModel());
m_returnWindow->setModel(engine->returnModel());
m_sourceFilesWindow->setModel(engine->sourceFilesModel());
m_stackWindow->setModel(engine->stackModel());
m_threadsWindow->setModel(engine->threadsModel());
m_threadBox->setModel(engine->threadsModel());
m_threadBox->setModelColumn(ThreadData::NameColumn);
m_watchersWindow->setModel(engine->watchersModel());
if (notify)
notifyCurrentEngine(RequestActivationRole, true);
}
static void changeFontSize(QWidget *widget, qreal size)
......@@ -2542,7 +2560,7 @@ void DebuggerPluginPrivate::scriptExpressionEntered(const QString &expression)
}
void DebuggerPluginPrivate::openMemoryEditor()
{
{
AddressDialog dialog;
if (dialog.exec() != QDialog::Accepted)
return;
......@@ -2856,6 +2874,11 @@ Internal::BreakHandler *DebuggerPlugin::breakHandler() const
return d->m_breakHandler;
}
DebuggerEngine *DebuggerPlugin::currentEngine() const
{
return d->m_currentEngine;
}
void DebuggerPlugin::remoteCommand(const QStringList &options, const QStringList &)
{
if (options.isEmpty())
......
......@@ -91,6 +91,7 @@ public:
void openTextEditor(const QString &titlePattern, const QString &contents);
Internal::BreakHandler *breakHandler() const;
DebuggerEngine *currentEngine() const;
public slots:
void clearCppCodeModelSnapshot();
......
......@@ -28,24 +28,8 @@
**************************************************************************/
#include "registerhandler.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerconstants.h"
#include "debuggerengine.h"
#include "watchdelegatewidgets.h"
#include <utils/qtcassert.h>
#include <QtCore/QAbstractTableModel>
#include <QtCore/QDebug>
#include <QtGui/QColor>
using namespace Debugger;
using namespace Debugger::Internal;
using namespace Debugger::Constants;
//////////////////////////////////////////////////////////////////
//
......@@ -53,8 +37,11 @@ using namespace Debugger::Constants;
//
//////////////////////////////////////////////////////////////////
RegisterHandler::RegisterHandler(DebuggerEngine *engine)
: m_engine(engine), m_base(15)
namespace Debugger {
namespace Internal {
RegisterHandler::RegisterHandler()
: m_base(-1)
{
setNumberBase(16);
}
......@@ -70,53 +57,36 @@ int RegisterHandler::columnCount(const QModelIndex &parent) const
}
// Editor value: Preferably number, else string.
QVariant RegisterHandler::editValue(const Register &reg)
QVariant Register::editValue() const
{
bool ok = true;
// Try to convert to number?
const qulonglong value = reg.value.toULongLong(&ok, 0); // Autodetect format
const qulonglong v = value.toULongLong(&ok, 0); // Autodetect format
if (ok)
return QVariant(value);
return QVariant(reg.value);
return QVariant(v);
return QVariant(value);
}
// Editor value: Preferably padded number, else padded string.
inline QString RegisterHandler::displayValue(const Register &reg) const
QString Register::displayValue(int base, int strlen) const
{
const QVariant editV = RegisterHandler::editValue(reg);
const QVariant editV = editValue();
if (editV.type() == QVariant::ULongLong)
return QString::fromAscii("%1").arg(editV.toULongLong(), m_strlen, m_base);
return QString::fromAscii("%1").arg(editV.toULongLong(), strlen, base);
const QString stringValue = editV.toString();
if (stringValue.size() < m_strlen)
return QString(m_strlen - stringValue.size(), QLatin1Char(' ')) + reg.value;
if (stringValue.size() < strlen)
return QString(strlen - stringValue.size(), QLatin1Char(' ')) + value;
return stringValue;
}
QVariant RegisterHandler::data(const QModelIndex &index, int role) const
{
switch (role) {
case EngineStateRole:
return m_engine->state();
case EngineCapabilitiesRole:
return m_engine->debuggerCapabilities();
case EngineActionsEnabledRole:
return m_engine->debuggerActionsEnabled();
}
if (!index.isValid() || index.row() >= m_registers.size())
return QVariant();
const Register &reg = m_registers.at(index.row());
switch (role) {
case RegisterAddressRole: {
// Return some address associated with the register. Autodetect format
const QVariant editV = RegisterHandler::editValue(reg);
return editV.type() == QVariant::ULongLong ? editV : QVariant();
}
case Qt::DisplayRole:
switch (index.column()) {
case 0: {
......@@ -124,18 +94,12 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const
return QVariant(padding + reg.name + padding);
}
case 1: // Display: Pad value for alignment
return displayValue(reg);
return reg.displayValue(m_base, m_strlen);
} // switch column
case Qt::EditRole: // Edit: Unpadded for editing
return RegisterHandler::editValue(reg);
return reg.editValue();
case Qt::TextAlignmentRole:
return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant();
case RegisterChangedRole:
return QVariant(reg.changed);
case RegisterBigNumberRole: // Editor: Can it be handled as quint64?
return editValue(reg).type() != QVariant::ULongLong;
case RegisterNumberBaseRole: // Big integers are assumed to be hexadecimal
return editValue(reg).type() == QVariant::ULongLong ? m_base : 16;
default:
break;
}
......@@ -161,31 +125,12 @@ Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const
const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled;
// Can edit registers if they are hex numbers and not arrays.
if (idx.column() == 1 && IntegerWatchLineEdit::isUnsignedHexNumber(m_registers.at(idx.row()).value))
if (idx.column() == 1
&& IntegerWatchLineEdit::isUnsignedHexNumber(m_registers.at(idx.row()).value))
return notEditable | Qt::ItemIsEditable;
return notEditable;
}
bool RegisterHandler::setData(const QModelIndex &index, const QVariant &value, int role)
{
switch (role) {
case RequestSetRegisterRole:
m_engine->setRegisterValue(index.row(), value.toString());
return true;
case RequestReloadRegistersRole:
m_engine->reloadRegisters();
return true;
case RequestShowMemoryRole:
(void) new MemoryViewAgent(m_engine, value.toString());
return true;
default:
return QAbstractTableModel::setData(index, value, role);
}
}
void RegisterHandler::removeAll()
{
m_registers.clear();
......@@ -232,3 +177,6 @@ void RegisterHandler::setNumberBase(int base)
emit reset();
}
}
} // namespace Internal
} // namespace Debugger
......@@ -34,14 +34,16 @@
#include <QtCore/QVector>
namespace Debugger {
class DebuggerEngine;
namespace Internal {
class Register
{
public:
Register() : changed(true) {}
Register(QByteArray const &name_) : name(name_), changed(true) {}
Register(const QByteArray &name_) : name(name_), changed(true) {}
QVariant editValue() const;
QString displayValue(int base, int strlen) const;
public:
QByteArray name;
......@@ -60,7 +62,7 @@ class RegisterHandler : public QAbstractTableModel
Q_OBJECT
public:
explicit RegisterHandler(DebuggerEngine *engine);
RegisterHandler();
QAbstractItemModel *model() { return this; }
......@@ -68,22 +70,20 @@ public:
void setRegisters(const Registers &registers);
void setAndMarkRegisters(const Registers &registers);
Registers registers() const;
Register registerAt(int i) const { return m_registers.at(i); }
void removeAll();
Q_SLOT void setNumberBase(int base);
int numberBase() const { return m_base; }
private:
void calculateWidth();
inline QString displayValue(const Register &reg) const;
static QVariant editValue(const Register &reg);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &, int role);
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &idx) const;
DebuggerEngine *m_engine; // Not owned.
Registers m_registers;
int m_base;
int m_strlen; // approximate width of a value in chars.
......
......@@ -30,8 +30,11 @@
#include "registerwindow.h"
#include "debuggeractions.h"
#include "debuggerplugin.h"
#include "debuggeragents.h"
#include "debuggerconstants.h"
#include "debuggerengine.h"
#include "registerhandler.h"
#include "watchdelegatewidgets.h"
#include <utils/qtcassert.h>
......@@ -45,9 +48,22 @@
#include <QtGui/QPainter>
#include <QtGui/QResizeEvent>
namespace Debugger {
namespace Internal {
static DebuggerEngine *currentEngine()
{
return DebuggerPlugin::instance()->currentEngine();
}
static RegisterHandler *currentHandler()
{
DebuggerEngine *engine = currentEngine();
QTC_ASSERT(engine, return 0);
return engine->registerHandler();
}
///////////////////////////////////////////////////////////////////////
//
// RegisterDelegate
......@@ -57,18 +73,21 @@ namespace Internal {
class RegisterDelegate : public QItemDelegate
{
public:
RegisterDelegate(RegisterWindow *owner, QObject *parent)
: QItemDelegate(parent), m_owner(owner)
RegisterDelegate(QObject *parent)
: QItemDelegate(parent)
{}
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
const QModelIndex &index) const
{
Register reg = currentHandler()->registerAt(index.row());
IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent);
lineEdit->setBase(index.data(RegisterNumberBaseRole).toInt());
lineEdit->setBigInt(index.data(RegisterBigNumberRole).toBool());
const int base = currentHandler()->numberBase();
const bool big = reg.value.size() > 16;
// Big integers are assumed to be hexadecimal.
lineEdit->setBigInt(big);
lineEdit->setBase(big ? 16 : base);
lineEdit->setSigned(false);
lineEdit->setAlignment(Qt::AlignRight);
return lineEdit;
}
......@@ -80,13 +99,14 @@ public:
lineEdit->setModelData(index.data(Qt::EditRole));
}
void setModelData(QWidget *editor, QAbstractItemModel *, const QModelIndex &index) const
void setModelData(QWidget *editor, QAbstractItemModel *,
const QModelIndex &index) const
{
if (index.column() != 1)
return;
IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit*>(editor);
QTC_ASSERT(lineEdit, return);
m_owner->model()->setData(index, lineEdit->modelData(), RequestSetRegisterRole);
currentEngine()->setRegisterValue(index.row(), lineEdit->text());
}
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
......@@ -99,7 +119,7 @@ public:
const QModelIndex &index) const
{
if (index.column() == 1) {
bool paintRed = index.data(RegisterChangedRole).toBool();
bool paintRed = currentHandler()->registerAt(index.row()).changed;
QPen oldPen = painter->pen();
if (paintRed)
painter->setPen(QColor(200, 0, 0));
......@@ -125,9 +145,6 @@ public:
QItemDelegate::paint(painter, option, index);
}
}
private:
RegisterWindow *m_owner;
};
......@@ -146,10 +163,10 @@ RegisterWindow::RegisterWindow(QWidget *parent)
setAttribute(Qt::WA_MacShowFocusRect, false);
setAlternatingRowColors(act->isChecked());
setRootIsDecorated(false);
setItemDelegate(new RegisterDelegate(this, this));
setItemDelegate(new RegisterDelegate(this));
connect(act, SIGNAL(toggled(bool)),
this, SLOT(setAlternatingRowColorsHelper(bool)));
SLOT(setAlternatingRowColorsHelper(bool)));
}
void RegisterWindow::resizeEvent(QResizeEvent *ev)
......@@ -161,9 +178,12 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
{
QMenu menu;
const unsigned engineCapabilities = modelData(EngineCapabilitiesRole).toUInt();
const bool actionsEnabled = modelData(EngineActionsEnabledRole).toInt();
const int state = modelData(EngineStateRole).toInt();
DebuggerEngine *engine = currentEngine();
QTC_ASSERT(engine, return);
RegisterHandler *handler = currentHandler();
const unsigned engineCapabilities = engine->debuggerCapabilities();
const bool actionsEnabled = engine->debuggerActionsEnabled();
const int state = engine->state();
QAction *actReload = menu.addAction(tr("Reload Register Listing"));
actReload->setEnabled((engineCapabilities & RegisterCapability)
......@@ -172,7 +192,7 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
menu.addSeparator();
QModelIndex idx = indexAt(ev->pos());
QString address = modelData(RegisterAddressRole, idx).toString();
QString address = handler->registers().at(idx.row()).value;
QAction *actShowMemory = menu.addAction(QString());
if (address.isEmpty()) {
actShowMemory->setText(tr("Open Memory Editor"));
......@@ -184,7 +204,7 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
}
menu.addSeparator();
int base = modelData(RegisterNumberBaseRole).toInt();
const int base = handler->numberBase();
QAction *act16 = menu.addAction(tr("Hexadecimal"));
act16->setCheckable(true);
act16->setChecked(base == 16);
......@@ -215,13 +235,17 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
else if (act == actAlwaysAdjust)
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
else if (act == actReload)
setModelData(RequestReloadRegistersRole);
engine->reloadRegisters();
else if (act == actShowMemory)
setModelData(RequestShowMemoryRole, address);
else if (act) {
base = (act == act10 ? 10 : act == act8 ? 8 : act == act2 ? 2 : 16);
QMetaObject::invokeMethod(model(), "setNumberBase", Q_ARG(int, base));
}
(void) new MemoryViewAgent(engine, address);
else if (act == act16)
handler->setNumberBase(16);
else if (act == act10)
handler->setNumberBase(10);
else if (act == act8)
handler->setNumberBase(8);
else if (act == act2)
handler->setNumberBase(2);