diff options
author | hjk <hjk@theqtcompany.com> | 2016-07-18 12:36:31 +0200 |
---|---|---|
committer | hjk <hjk@qt.io> | 2016-07-18 11:17:53 +0000 |
commit | 2d79bdc29c242a04aad3519858ad64712be4de8e (patch) | |
tree | a910e2daeaeca5ce943f33d569f2e88b8a477ad4 /src/plugins/debugger/watchwindow.cpp | |
parent | 84f1466b01e9098ae983c1f53e376e977921dad9 (diff) |
Debugger: Remove some uses of semi-global currentEngine()
Make use of recent TreeModel improvements in various
tool views, push more operations into the engine-
owned data models, specifically context menu creation.
Change-Id: I479c97102b9fb81611c6461c6df1cec59295179a
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins/debugger/watchwindow.cpp')
-rw-r--r-- | src/plugins/debugger/watchwindow.cpp | 961 |
1 files changed, 3 insertions, 958 deletions
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index fd14bef0ac..a0aceb9000 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -25,413 +25,28 @@ #include "watchwindow.h" -#include "breakhandler.h" -#include "registerhandler.h" #include "debuggeractions.h" #include "debuggerinternalconstants.h" #include "debuggercore.h" -#include "debuggerdialogs.h" -#include "debuggerengine.h" -#include "watchdelegatewidgets.h" #include "watchhandler.h" -#include "debuggertooltipmanager.h" -#include "memoryagent.h" -#include <texteditor/syntaxhighlighter.h> - -#include <coreplugin/messagebox.h> - -#include <utils/fancylineedit.h> #include <utils/qtcassert.h> #include <utils/savedaction.h> -#include <utils/treemodel.h> -#include <QApplication> -#include <QClipboard> -#include <QDebug> #include <QHeaderView> -#include <QInputDialog> -#include <QItemDelegate> -#include <QMenu> -#include <QMetaProperty> -#include <QMimeData> #include <QScrollBar> #include <QTimer> -#include <QTextStream> - -// For InputDialog, move to Utils? -#include <coreplugin/helpmanager.h> -#include <QLabel> -#include <QVBoxLayout> -#include <QButtonGroup> -#include <QDialogButtonBox> - -///////////////////////////////////////////////////////////////////// -// -// WatchDelegate -// -///////////////////////////////////////////////////////////////////// namespace Debugger { namespace Internal { -class WatchDelegate : public QItemDelegate -{ -public: - explicit WatchDelegate(QObject *parent) - : QItemDelegate(parent) - {} - - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, - const QModelIndex &index) const - { - // Value column: Custom editor. Apply integer-specific settings. - if (index.column() == 1) { - const QVariant::Type type = - static_cast<QVariant::Type>(index.data(LocalsEditTypeRole).toInt()); - switch (type) { - case QVariant::Bool: - return new BooleanComboBox(parent); - default: - break; - } - WatchLineEdit *edit = WatchLineEdit::create(type, parent); - edit->setFrame(false); - IntegerWatchLineEdit *intEdit - = qobject_cast<IntegerWatchLineEdit *>(edit); - if (intEdit) - intEdit->setBase(index.data(LocalsIntegerBaseRole).toInt()); - return edit; - } - - // Standard line edits for the rest. - Utils::FancyLineEdit *lineEdit = new Utils::FancyLineEdit(parent); - lineEdit->setFrame(false); - lineEdit->setHistoryCompleter(QLatin1String("WatchItems")); - return lineEdit; - } - - void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, - const QModelIndex &) const - { - editor->setGeometry(option.rect); - } -}; - -// Watch model query helpers. -static inline quint64 addressOf(const QModelIndex &m) -{ - return m.data(LocalsObjectAddressRole).toULongLong(); -} - -static inline quint64 pointerAddressOf(const QModelIndex &m) -{ - return m.data(LocalsPointerAddressRole).toULongLong(); -} - -static inline QString nameOf(const QModelIndex &m) -{ - return m.data().toString(); -} - -static inline QString typeOf(const QModelIndex &m) -{ - return m.data(LocalsTypeRole).toString(); -} - -static inline uint sizeOf(const QModelIndex &m) -{ - return m.data(LocalsSizeRole).toUInt(); -} - -// Helper functionality to indicate the area of a member variable in -// a vector representing the memory area by a unique color -// number and tooltip. Parts of it will be overwritten when recursing -// over the children. - -typedef QPair<int, QString> ColorNumberToolTip; -typedef QVector<ColorNumberToolTip> ColorNumberToolTips; - -static QString variableToolTip(const QString &name, const QString &type, - quint64 offset) -{ - return offset ? - //: HTML tooltip of a variable in the memory editor - WatchTreeView::tr("<i>%1</i> %2 at #%3"). - arg(type, name).arg(offset) : - //: HTML tooltip of a variable in the memory editor - WatchTreeView::tr("<i>%1</i> %2").arg(type, name); -} - -static int memberVariableRecursion(const QAbstractItemModel *model, - const QModelIndex &modelIndex, - const QString &name, - quint64 start, quint64 end, - int *colorNumberIn, - ColorNumberToolTips *cnmv) -{ - int childCount = 0; - QTC_ASSERT(modelIndex.isValid(), return childCount ); - const int rowCount = model->rowCount(modelIndex); - if (!rowCount) - return childCount; - const QString nameRoot = name.isEmpty() ? name : name + QLatin1Char('.'); - for (int r = 0; r < rowCount; r++) { - const QModelIndex childIndex = modelIndex.child(r, 0); - const quint64 childAddress = addressOf(childIndex); - const uint childSize = sizeOf(childIndex); - if (childAddress && childAddress >= start - && (childAddress + childSize) <= end) { // Non-static, within area? - const QString childName = nameRoot + nameOf(childIndex); - const quint64 childOffset = childAddress - start; - const QString toolTip - = variableToolTip(childName, typeOf(childIndex), childOffset); - const ColorNumberToolTip colorNumberNamePair((*colorNumberIn)++, toolTip); - const ColorNumberToolTips::iterator begin = cnmv->begin() + childOffset; - qFill(begin, begin + childSize, colorNumberNamePair); - childCount++; - childCount += memberVariableRecursion(model, childIndex, - childName, start, end, colorNumberIn, cnmv); - } - } - return childCount; -} - -typedef QList<MemoryMarkup> MemoryMarkupList; - -/*! - Creates markup for a variable in the memory view. - - Marks the visible children with alternating colors in the parent, that is, for - \code - struct Foo { - char c1 - char c2 - int x2; - QPair<int, int> pair - } - \endcode - create something like: - \code - 0 memberColor1 - 1 memberColor2 - 2 base color (padding area of parent) - 3 base color - 4 member color1 - ... - 8 memberColor2 (pair.first) - ... - 12 memberColor1 (pair.second) - \endcode - - In addition, registers pointing into the area are shown as 1 byte-markers. - - Fixme: When dereferencing a pointer, the size of the pointee is not - known, currently. So, we take an area of 1024 and fill the background - with the default color so that just the members are shown - (sizeIsEstimate=true). This could be fixed by passing the pointee size - as well from the debugger, but would require expensive type manipulation. - - \note To recurse over the top level items of the model, pass an invalid model - index. - - \sa Debugger::Internal::MemoryViewWidget -*/ -static MemoryMarkupList - variableMemoryMarkup(const QAbstractItemModel *model, - const QModelIndex &modelIndex, - const QString &rootName, - const QString &rootToolTip, - quint64 address, quint64 size, - const RegisterMap ®isterMap, - bool sizeIsEstimate, - const QColor &defaultBackground) -{ - enum { debug = 0 }; - enum { registerColorNumber = 0x3453 }; - - if (debug) - qDebug() << address << ' ' << size << rootName << rootToolTip; - // Starting out from base, create an array representing the area - // filled with base color. Fill children with some unique color numbers, - // leaving the padding areas of the parent colored with the base color. - MemoryMarkupList result; - int colorNumber = 0; - ColorNumberToolTips ranges(size, ColorNumberToolTip(colorNumber, rootToolTip)); - colorNumber++; - const int childCount = memberVariableRecursion(model, modelIndex, - rootName, address, address + size, - &colorNumber, &ranges); - if (sizeIsEstimate && !childCount) - return result; // Fixme: Exact size not known, no point in filling if no children. - // Punch in registers as 1-byte markers on top. - for (auto it = registerMap.constBegin(), end = registerMap.constEnd(); it != end; ++it) { - if (it.key() >= address) { - const quint64 offset = it.key() - address; - if (offset < size) { - ranges[offset] = ColorNumberToolTip(registerColorNumber, - WatchTreeView::tr("Register <i>%1</i>").arg(it.value())); - } else { - break; // Sorted. - } - } - } // for registers. - if (debug) { - QDebug dbg = qDebug().nospace(); - dbg << rootToolTip << ' ' << address << ' ' << size << '\n'; - QString name; - for (unsigned i = 0; i < size; ++i) - if (name != ranges.at(i).second) { - dbg << ",[" << i << ' ' << ranges.at(i).first << ' ' - << ranges.at(i).second << ']'; - name = ranges.at(i).second; - } - } - - // Assign colors from a list, use base color for 0 (contrast to black text). - // Overwrite the first color (which is usually very bright) by the base color. - QList<QColor> colors = TextEditor::SyntaxHighlighter::generateColors(colorNumber + 2, - QColor(Qt::black)); - colors[0] = sizeIsEstimate ? defaultBackground : Qt::lightGray; - const QColor registerColor = Qt::green; - int lastColorNumber = 0; - for (unsigned i = 0; i < size; ++i) { - const ColorNumberToolTip &range = ranges.at(i); - if (result.isEmpty() || lastColorNumber != range.first) { - lastColorNumber = range.first; - const QColor color = range.first == registerColorNumber ? - registerColor : colors.at(range.first); - result.push_back(MemoryMarkup(address + i, 1, color, range.second)); - } else { - result.back().length++; - } - } - - if (debug) { - QDebug dbg = qDebug().nospace(); - dbg << rootName << ' ' << address << ' ' << size << '\n'; - QString name; - for (unsigned i = 0; i < size; ++i) - if (name != ranges.at(i).second) { - dbg << ',' << i << ' ' << ranges.at(i).first << ' ' - << ranges.at(i).second; - name = ranges.at(i).second; - } - dbg << '\n'; - foreach (const MemoryMarkup &m, result) - dbg << m.address << ' ' << m.length << ' ' << m.toolTip << '\n'; - } - - return result; -} - -// Convenience to create a memory view of a variable. -static void addVariableMemoryView(DebuggerEngine *engine, bool separateView, - const QModelIndex &m, bool atPointerAddress, - const QPoint &p, QWidget *parent) -{ - const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base); - MemoryViewSetupData data; - data.startAddress = atPointerAddress ? pointerAddressOf(m) : addressOf(m); - if (!data.startAddress) - return; - // Fixme: Get the size of pointee (see variableMemoryMarkup())? - const QString rootToolTip = variableToolTip(nameOf(m), typeOf(m), 0); - const quint64 typeSize = sizeOf(m); - const bool sizeIsEstimate = atPointerAddress || !typeSize; - const quint64 size = sizeIsEstimate ? 1024 : typeSize; - data.markup = variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip, - data.startAddress, size, - engine->registerHandler()->registerMap(), - sizeIsEstimate, background); - data.flags = separateView ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0; - QString pat = atPointerAddress - ? WatchTreeView::tr("Memory at Pointer's Address \"%1\" (0x%2)") - : WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)"); - data.title = pat.arg(nameOf(m)).arg(data.startAddress, 0, 16); - data.pos = p; - data.parent = parent; - engine->openMemoryView(data); -} - -// Add a memory view of the stack layout showing local variables -// and registers. -static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView, - const QAbstractItemModel *m, const QPoint &p, QWidget *parent) -{ - QTC_ASSERT(engine && m, return); - - // Determine suitable address range from locals. - quint64 start = Q_UINT64_C(0xFFFFFFFFFFFFFFFF); - quint64 end = 0; - const QModelIndex localsIndex = m->index(0, 0); - QTC_ASSERT(localsIndex.data(LocalsINameRole).toString() == QLatin1String("local"), return); - const int localsItemCount = m->rowCount(localsIndex); - // Note: Unsorted by default. Exclude 'Automatically dereferenced - // pointer' items as they are outside the address range. - for (int r = 0; r < localsItemCount; r++) { - const QModelIndex idx = localsIndex.child(r, 0); - const quint64 pointerAddress = pointerAddressOf(idx); - if (pointerAddress == 0) { - const quint64 address = addressOf(idx); - if (address) { - if (address < start) - start = address; - const uint size = qMax(1u, sizeOf(idx)); - if (address + size > end) - end = address + size; - } - } - } - if (const quint64 remainder = end % 8) - end += 8 - remainder; - // Anything found and everything in a sensible range (static data in-between)? - if (end <= start || end - start > 100 * 1024) { - Core::AsynchronousMessageBox::information( - WatchTreeView::tr("Cannot Display Stack Layout"), - WatchTreeView::tr("Could not determine a suitable address range.")); - return; - } - // Take a look at the register values. Extend the range a bit if suitable - // to show stack/stack frame pointers. - const RegisterMap regMap = engine->registerHandler()->registerMap(); - for (auto it = regMap.constBegin(), cend = regMap.constEnd(); it != cend; ++it) { - const quint64 value = it.key(); - if (value < start && start - value < 512) - start = value; - else if (value > end && value - end < 512) - end = value + 1; - } - // Indicate all variables. - MemoryViewSetupData data; - const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base); - data.startAddress = start; - data.markup = variableMemoryMarkup(m, localsIndex, QString(), - QString(), start, end - start, - regMap, true, background); - data.flags = separateView - ? (DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly) : 0; - data.title = WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16); - data.pos = p; - data.parent = parent; - engine->openMemoryView(data); -} - -///////////////////////////////////////////////////////////////////// -// -// WatchWindow -// -///////////////////////////////////////////////////////////////////// - WatchTreeView::WatchTreeView(WatchType type) : m_type(type), m_sliderPosition(0) { - setObjectName(QLatin1String("WatchWindow")); - m_grabbing = false; + setObjectName("WatchWindow"); setWindowTitle(tr("Locals and Expressions")); setIndentation(indentation() * 9/10); setUniformRowHeights(true); - setItemDelegate(new WatchDelegate(this)); setDragEnabled(true); setAcceptDrops(true); setDropIndicatorShown(true); @@ -442,480 +57,12 @@ WatchTreeView::WatchTreeView(WatchType type) void WatchTreeView::expandNode(const QModelIndex &idx) { - setModelData(LocalsExpandedRole, true, idx); + model()->setData(idx, true, LocalsExpandedRole); } void WatchTreeView::collapseNode(const QModelIndex &idx) { - setModelData(LocalsExpandedRole, false, idx); -} - -void WatchTreeView::keyPressEvent(QKeyEvent *ev) -{ - if (ev->key() == Qt::Key_Delete && m_type == WatchersType) { - WatchHandler *handler = currentEngine()->watchHandler(); - foreach (const QModelIndex &idx, activeRows()) - handler->removeItemByIName(idx.data(LocalsINameRole).toString()); - } else if (ev->key() == Qt::Key_Return - && ev->modifiers() == Qt::ControlModifier - && m_type == LocalsType) { - QModelIndex idx = currentIndex(); - QModelIndex idx1 = idx.sibling(idx.row(), 0); - QString exp = model()->data(idx1).toString(); - watchExpression(exp); - } - BaseTreeView::keyPressEvent(ev); -} - -void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev) -{ - //BaseTreeView::dragEnterEvent(ev); - if (ev->mimeData()->hasText()) { - ev->setDropAction(Qt::CopyAction); - ev->accept(); - } -} - -void WatchTreeView::dragMoveEvent(QDragMoveEvent *ev) -{ - //BaseTreeView::dragMoveEvent(ev); - if (ev->mimeData()->hasText()) { - ev->setDropAction(Qt::CopyAction); - ev->accept(); - } -} - -void WatchTreeView::dropEvent(QDropEvent *ev) -{ - if (ev->mimeData()->hasText()) { - QString exp; - QString data = ev->mimeData()->text(); - foreach (const QChar c, data) - exp.append(c.isPrint() ? c : QChar(QLatin1Char(' '))); - currentEngine()->watchHandler()->watchVariable(exp); - //ev->acceptProposedAction(); - ev->setDropAction(Qt::CopyAction); - ev->accept(); - } - //BaseTreeView::dropEvent(ev); -} - -void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev) -{ - const QModelIndex idx = indexAt(ev->pos()); - if (!idx.isValid()) { - inputNewExpression(); - return; - } - BaseTreeView::mouseDoubleClickEvent(ev); -} - -// Text for add watch action with truncated expression. -static QString addWatchActionText(QString exp) -{ - if (exp.isEmpty()) - return WatchTreeView::tr("Add Expression Evaluator"); - if (exp.size() > 30) { - exp.truncate(30); - exp.append(QLatin1String("...")); - } - return WatchTreeView::tr("Add Expression Evaluator for \"%1\"").arg(exp); -} - -// Text for add watch action with truncated expression. -static QString removeWatchActionText(QString exp) -{ - if (exp.isEmpty()) - return WatchTreeView::tr("Remove Expression Evaluator"); - if (exp.size() > 30) { - exp.truncate(30); - exp.append(QLatin1String("...")); - } - return WatchTreeView::tr("Remove Expression Evaluator for \"%1\"") - .arg(exp.replace(QLatin1Char('&'), QLatin1String("&&"))); -} - -static void copyToClipboard(const QString &clipboardText) -{ - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(clipboardText, QClipboard::Selection); - clipboard->setText(clipboardText, QClipboard::Clipboard); -} - -void WatchTreeView::fillFormatMenu(QMenu *formatMenu, const QModelIndex &mi) -{ - QTC_CHECK(mi.isValid()); - - const QModelIndex mi2 = mi.sibling(mi.row(), 2); - const QString type = mi2.data().toString(); - - const DisplayFormats alternativeFormats = - mi.data(LocalsTypeFormatListRole).value<DisplayFormats>(); - const int typeFormat = mi.data(LocalsTypeFormatRole).toInt(); - const int individualFormat = mi.data(LocalsIndividualFormatRole).toInt(); - const int unprintableBase = WatchHandler::unprintableBase(); - - QAction *showUnprintableUnicode = 0; - QAction *showUnprintableEscape = 0; - QAction *showUnprintableOctal = 0; - QAction *showUnprintableHexadecimal = 0; - showUnprintableUnicode = - formatMenu->addAction(tr("Treat All Characters as Printable")); - showUnprintableUnicode->setCheckable(true); - showUnprintableUnicode->setChecked(unprintableBase == 0); - showUnprintableEscape = - formatMenu->addAction(tr("Show Unprintable Characters as Escape Sequences")); - showUnprintableEscape->setCheckable(true); - showUnprintableEscape->setChecked(unprintableBase == -1); - showUnprintableOctal = - formatMenu->addAction(tr("Show Unprintable Characters as Octal")); - showUnprintableOctal->setCheckable(true); - showUnprintableOctal->setChecked(unprintableBase == 8); - showUnprintableHexadecimal = - formatMenu->addAction(tr("Show Unprintable Characters as Hexadecimal")); - showUnprintableHexadecimal->setCheckable(true); - showUnprintableHexadecimal->setChecked(unprintableBase == 16); - - connect(showUnprintableUnicode, &QAction::triggered, [this] { showUnprintable(0); }); - connect(showUnprintableEscape, &QAction::triggered, [this] { showUnprintable(-1); }); - connect(showUnprintableOctal, &QAction::triggered, [this] { showUnprintable(8); }); - connect(showUnprintableHexadecimal, &QAction::triggered, [this] { showUnprintable(16); }); - - const QString spacer = QLatin1String(" "); - formatMenu->addSeparator(); - QAction *dummy = formatMenu->addAction( - tr("Change Display for Object Named \"%1\":").arg(mi.data().toString())); - dummy->setEnabled(false); - QString msg = (individualFormat == AutomaticFormat && typeFormat != AutomaticFormat) - ? tr("Use Format for Type (Currently %1)") - .arg(WatchHandler::nameForFormat(typeFormat)) - : QString(tr("Use Display Format Based on Type") + QLatin1Char(' ')); - - QAction *clearIndividualFormatAction = formatMenu->addAction(spacer + msg); - clearIndividualFormatAction->setCheckable(true); - clearIndividualFormatAction->setChecked(individualFormat == AutomaticFormat); - connect(clearIndividualFormatAction, &QAction::triggered, [this] { - const QModelIndexList active = activeRows(); - foreach (const QModelIndex &idx, active) - setModelData(LocalsIndividualFormatRole, AutomaticFormat, idx); - }); - - for (int i = 0; i != alternativeFormats.size(); ++i) { - const int format = alternativeFormats.at(i); - const QString display = spacer + WatchHandler::nameForFormat(format); - QAction *act = new QAction(display, formatMenu); - act->setCheckable(true); - act->setChecked(format == individualFormat); - formatMenu->addAction(act); - connect(act, &QAction::triggered, [this, act, format, mi] { - setModelData(LocalsIndividualFormatRole, format, mi); - }); - } - - formatMenu->addSeparator(); - dummy = formatMenu->addAction(tr("Change Display for Type \"%1\":").arg(type)); - dummy->setEnabled(false); - - QAction *clearTypeFormatAction = formatMenu->addAction(spacer + tr("Automatic")); - clearTypeFormatAction->setCheckable(true); - clearTypeFormatAction->setChecked(typeFormat == AutomaticFormat); - connect(clearTypeFormatAction, &QAction::triggered, [this] { - const QModelIndexList active = activeRows(); - foreach (const QModelIndex &idx, active) - setModelData(LocalsTypeFormatRole, AutomaticFormat, idx); - }); - - for (int i = 0; i != alternativeFormats.size(); ++i) { - const int format = alternativeFormats.at(i); - const QString display = spacer + WatchHandler::nameForFormat(format); - QAction *act = new QAction(display, formatMenu); - act->setCheckable(true); - act->setChecked(format == typeFormat); - formatMenu->addAction(act); - connect(act, &QAction::triggered, [this, act, format, mi] { - setModelData(LocalsTypeFormatRole, format, mi); - }); - } -} - -void WatchTreeView::showUnprintable(int base) -{ - DebuggerEngine *engine = currentEngine(); - WatchHandler *handler = engine->watchHandler(); - handler->setUnprintableBase(base); -} - -void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) -{ - DebuggerEngine *engine = currentEngine(); - WatchHandler *handler = engine->watchHandler(); - - const QModelIndex idx = indexAt(ev->pos()); - const QModelIndex mi0 = idx.sibling(idx.row(), 0); - const QModelIndex mi1 = idx.sibling(idx.row(), 1); - const quint64 address = addressOf(mi0); - const uint size = sizeOf(mi0); - const quint64 pointerAddress = pointerAddressOf(mi0); - const QString exp = mi0.data(LocalsExpressionRole).toString(); - const QString name = mi0.data(LocalsNameRole).toString(); - - // Offer to open address pointed to or variable address. - const bool createPointerActions = pointerAddress && pointerAddress != address; - - const bool actionsEnabled = engine->debuggerActionsEnabled(); - const bool canHandleWatches = engine->hasCapability(AddWatcherCapability); - const DebuggerState state = engine->state(); - const bool canInsertWatches = state == InferiorStopOk - || state == DebuggerNotReady - || state == InferiorUnrunnable - || (state == InferiorRunOk && engine->hasCapability(AddWatcherWhileRunningCapability)); - - QAction actSetWatchpointAtObjectAddress(0); - QAction actSetWatchpointAtPointerAddress(0); - actSetWatchpointAtPointerAddress.setText(tr("Add Data Breakpoint at Pointer's Address")); - actSetWatchpointAtPointerAddress.setEnabled(false); - const bool canSetWatchpoint = engine->hasCapability(WatchpointByAddressCapability); - if (canSetWatchpoint && address) { - actSetWatchpointAtObjectAddress - .setText(tr("Add Data Breakpoint at Object's Address (0x%1)").arg(address, 0, 16)); - actSetWatchpointAtObjectAddress - .setChecked(mi0.data(LocalsIsWatchpointAtObjectAddressRole).toBool()); - if (createPointerActions) { - actSetWatchpointAtPointerAddress - .setText(tr("Add Data Breakpoint at Pointer's Address (0x%1)") - .arg(pointerAddress, 0, 16)); - actSetWatchpointAtPointerAddress - .setChecked(mi0.data(LocalsIsWatchpointAtPointerAddressRole).toBool()); - actSetWatchpointAtPointerAddress.setEnabled(true); - } - } else { - actSetWatchpointAtObjectAddress.setText(tr("Add Data Breakpoint")); - actSetWatchpointAtObjectAddress.setEnabled(false); - } - actSetWatchpointAtObjectAddress.setToolTip( - tr("Setting a data breakpoint on an address will cause the program " - "to stop when the data at the address is modified.")); - - QAction actSetWatchpointAtExpression(0); - const bool canSetWatchpointAtExpression = engine->hasCapability(WatchpointByExpressionCapability); - if (name.isEmpty() || !canSetWatchpointAtExpression) { - actSetWatchpointAtExpression.setText(tr("Add Data Breakpoint at Expression")); - actSetWatchpointAtExpression.setEnabled(false); - } else { - actSetWatchpointAtExpression.setText(tr("Add Data Breakpoint at Expression \"%1\"").arg(name)); - } - actSetWatchpointAtExpression.setToolTip( - tr("Setting a data breakpoint on an expression will cause the program " - "to stop when the data at the address given by the expression " - "is modified.")); - - QAction actInsertNewWatchItem(tr("Add New Expression Evaluator..."), 0); - actInsertNewWatchItem.setEnabled(canHandleWatches && canInsertWatches); - - QAction actSelectWidgetToWatch(tr("Select Widget to Add into Expression Evaluator"), 0); - actSelectWidgetToWatch.setEnabled(canHandleWatches && canInsertWatches - && engine->hasCapability(WatchWidgetsCapability)); - - bool canAddWatches = canHandleWatches && !exp.isEmpty(); - // Suppress for top-level watchers. - if (m_type == WatchersType && mi0.parent().isValid() && !mi0.parent().parent().isValid()) - canAddWatches = false; - QAction actWatchExpression(addWatchActionText(exp), 0); - actWatchExpression.setEnabled(canAddWatches); - - // Can remove watch if engine can handle it or session engine. - QModelIndex p = mi0; - while (true) { - QModelIndex pp = p.parent(); - if (!pp.isValid() || !pp.parent().isValid()) - break; - p = pp; - } - - bool canRemoveWatches = ((canHandleWatches && canInsertWatches) || state == DebuggerNotReady) - && m_type == WatchersType; - - QString removeExp = p.data(LocalsExpressionRole).toString(); - QAction actRemoveWatchExpression(removeWatchActionText(removeExp), 0); - actRemoveWatchExpression.setEnabled(canRemoveWatches && !exp.isEmpty()); - - QAction actRemoveAllWatchExpression(tr("Remove All Expression Evaluators"), 0); - actRemoveAllWatchExpression.setEnabled(canRemoveWatches - && !handler->watchedExpressions().isEmpty()); - - QMenu formatMenu(tr("Change Value Display Format")); - if (mi0.isValid()) - fillFormatMenu(&formatMenu, mi0); - else - formatMenu.setEnabled(false); - - QMenu memoryMenu(tr("Open Memory Editor")); - QAction actOpenMemoryEditAtObjectAddress(0); - QAction actOpenMemoryEditAtPointerAddress(0); - QAction actOpenMemoryEditor(0); - QAction actOpenMemoryEditorStackLayout(0); - QAction actOpenMemoryViewAtObjectAddress(0); - QAction actOpenMemoryViewAtPointerAddress(0); - if (engine->hasCapability(ShowMemoryCapability)) { - actOpenMemoryEditor.setText(tr("Open Memory Editor...")); - if (address) { - actOpenMemoryEditAtObjectAddress.setText( - tr("Open Memory Editor at Object's Address (0x%1)") - .arg(address, 0, 16)); - actOpenMemoryViewAtObjectAddress.setText( - tr("Open Memory View at Object's Address (0x%1)") - .arg(address, 0, 16)); - } else { - actOpenMemoryEditAtObjectAddress.setText( - tr("Open Memory Editor at Object's Address")); - actOpenMemoryEditAtObjectAddress.setEnabled(false); - actOpenMemoryViewAtObjectAddress.setText( - tr("Open Memory View at Object's Address")); - actOpenMemoryViewAtObjectAddress.setEnabled(false); - } - if (createPointerActions) { - actOpenMemoryEditAtPointerAddress.setText( - tr("Open Memory Editor at Pointer's Address (0x%1)") - .arg(pointerAddress, 0, 16)); - actOpenMemoryViewAtPointerAddress.setText( - tr("Open Memory View at Pointer's Address (0x%1)") - .arg(pointerAddress, 0, 16)); - } else { - actOpenMemoryEditAtPointerAddress.setText( - tr("Open Memory Editor at Pointer's Address")); - actOpenMemoryEditAtPointerAddress.setEnabled(false); - actOpenMemoryViewAtPointerAddress.setText( - tr("Open Memory View at Pointer's Address")); - actOpenMemoryViewAtPointerAddress.setEnabled(false); - } - actOpenMemoryEditorStackLayout.setText( - tr("Open Memory Editor Showing Stack Layout")); - actOpenMemoryEditorStackLayout.setEnabled(m_type == LocalsType); - memoryMenu.addAction(&actOpenMemoryViewAtObjectAddress); - memoryMenu.addAction(&actOpenMemoryViewAtPointerAddress); - memoryMenu.addAction(&actOpenMemoryEditAtObjectAddress); - memoryMenu.addAction(&actOpenMemoryEditAtPointerAddress); - memoryMenu.addAction(&actOpenMemoryEditorStackLayout); - memoryMenu.addAction(&actOpenMemoryEditor); - } else { - memoryMenu.setEnabled(false); - } - - QMenu breakpointMenu; - breakpointMenu.setTitle(tr("Add Data Breakpoint")); - breakpointMenu.addAction(&actSetWatchpointAtObjectAddress); - breakpointMenu.addAction(&actSetWatchpointAtPointerAddress); - breakpointMenu.addAction(&actSetWatchpointAtExpression); - breakpointMenu.setEnabled(actSetWatchpointAtObjectAddress.isEnabled() - || actSetWatchpointAtPointerAddress.isEnabled() - || actSetWatchpointAtExpression.isEnabled()); - - QAction actCopy(tr("Copy View Contents to Clipboard"), 0); - QAction actCopyValue(tr("Copy Current Value to Clipboard"), 0); - actCopyValue.setEnabled(idx.isValid()); - QAction actCopySelected(tr("Copy Selected Rows to Clipboard"), 0); - actCopySelected.setEnabled(selectionModel()->hasSelection()); - - QAction actShowInEditor(tr("Open View Contents in Editor"), 0); - actShowInEditor.setEnabled(actionsEnabled); - QAction actCloseEditorToolTips(tr("Close Editor Tooltips"), 0); - actCloseEditorToolTips.setEnabled(DebuggerToolTipManager::hasToolTips()); - - QMenu menu; - menu.addAction(&actInsertNewWatchItem); - menu.addAction(&actWatchExpression); - menu.addAction(&actRemoveWatchExpression); - menu.addAction(&actRemoveAllWatchExpression); - menu.addAction(&actSelectWidgetToWatch); - menu.addSeparator(); - - menu.addMenu(&formatMenu); - menu.addMenu(&memoryMenu); - menu.addMenu(&breakpointMenu); - menu.addSeparator(); - - menu.addAction(&actCloseEditorToolTips); - menu.addAction(&actCopy); - menu.addAction(&actCopyValue); - menu.addAction(&actCopySelected); - menu.addAction(&actShowInEditor); - menu.addSeparator(); - - menu.addAction(action(UseDebuggingHelpers)); - menu.addAction(action(UseToolTipsInLocalsView)); - menu.addAction(action(AutoDerefPointers)); - menu.addAction(action(SortStructMembers)); - menu.addAction(action(UseDynamicType)); - menu.addAction(action(SettingsDialog)); - - menu.addSeparator(); - menu.addAction(action(SettingsDialog)); - - QAction *act = menu.exec(ev->globalPos()); - - if (!act) { - ; - } else if (act == &actInsertNewWatchItem) { - inputNewExpression(); - } else if (act == &actOpenMemoryEditAtObjectAddress) { - addVariableMemoryView(currentEngine(), false, mi0, false, ev->globalPos(), this); - } else if (act == &actOpenMemoryEditAtPointerAddress) { - addVariableMemoryView(currentEngine(), false, mi0, true, ev->globalPos(), this); - } else if (act == &actOpenMemoryEditor) { - AddressDialog dialog; - if (address) - dialog.setAddress(address); - if (dialog.exec() == QDialog::Accepted) { - MemoryViewSetupData data; - data.startAddress = dialog.address(); - currentEngine()->openMemoryView(data); - } - } else if (act == &actOpenMemoryViewAtObjectAddress) { - addVariableMemoryView(currentEngine(), true, mi0, false, ev->globalPos(), this); - } else if (act == &actOpenMemoryViewAtPointerAddress) { - addVariableMemoryView(currentEngine(), true, mi0, true, ev->globalPos(), this); - } else if (act == &actOpenMemoryEditorStackLayout) { - addStackLayoutMemoryView(currentEngine(), false, model(), ev->globalPos(), this); - } else if (act == &actSetWatchpointAtObjectAddress) { - breakHandler()->setWatchpointAtAddress(address, size); - } else if (act == &actSetWatchpointAtPointerAddress) { - breakHandler()->setWatchpointAtAddress(pointerAddress, sizeof(void *)); // FIXME: an approximation.. - } else if (act == &actSetWatchpointAtExpression) { - breakHandler()->setWatchpointAtExpression(name); - } else if (act == &actSelectWidgetToWatch) { - grabMouse(Qt::CrossCursor); - m_grabbing = true; - } else if (act == &actWatchExpression) { - watchExpression(exp, name); - } else if (act == &actRemoveWatchExpression) { - handler->removeItemByIName(p.data(LocalsINameRole).toString()); - } else if (act == &actRemoveAllWatchExpression) { - handler->clearWatches(); - } else if (act == &actCopy) { - QString contents = handler->editorContents(); - copyToClipboard(contents); - } else if (act == &actCopySelected) { - QString contents = handler->editorContents(selectionModel()->selectedRows()); - copyToClipboard(contents); - } else if (act == &actCopyValue) { - copyToClipboard(mi1.data().toString()); - } else if (act == &actShowInEditor) { - QString contents = handler->editorContents(); - Internal::openTextEditor(tr("Locals & Expressions"), contents); - } else if (act == &actCloseEditorToolTips) { - DebuggerToolTipManager::closeAllToolTips(); - } -} - -bool WatchTreeView::event(QEvent *ev) -{ - if (m_grabbing && ev->type() == QEvent::MouseButtonPress) { - QMouseEvent *mev = static_cast<QMouseEvent *>(ev); - m_grabbing = false; - releaseMouse(); - currentEngine()->watchPoint(mapToGlobal(mev->pos())); - } - return BaseTreeView::event(ev); + model()->setData(idx, false, LocalsExpandedRole); } void WatchTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) @@ -924,11 +71,6 @@ void WatchTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex BaseTreeView::currentChanged(current, previous); } -void WatchTreeView::editItem(const QModelIndex &idx) -{ - Q_UNUSED(idx) // FIXME -} - void WatchTreeView::setModel(QAbstractItemModel *model) { BaseTreeView::setModel(model); @@ -956,11 +98,6 @@ void WatchTreeView::setModel(QAbstractItemModel *model) } } -void WatchTreeView::rowActivated(const QModelIndex &index) -{ - currentEngine()->selectWatchData(index.data(LocalsINameRole).toString()); -} - void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx) { bool on = idx.data(LocalsExpandedRole).toBool(); @@ -1020,97 +157,5 @@ void WatchTreeView::adjustSlider() } } -void WatchTreeView::watchExpression(const QString &exp) -{ - watchExpression(exp, QString()); -} - -void WatchTreeView::watchExpression(const QString &exp, const QString &name) -{ - currentEngine()->watchHandler()->watchExpression(exp, name); -} - -void WatchTreeView::setModelData - (int role, const QVariant &value, const QModelIndex &index) -{ - QTC_ASSERT(model(), return); - model()->setData(index, value, role); -} - - -// FIXME: Move to Utils? -class InputDialog : public QDialog -{ -public: - InputDialog() - { - m_label = new QLabel(this); - m_hint = new QLabel(this); - m_lineEdit = new Utils::FancyLineEdit(this); - m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, - Qt::Horizontal, this); - - auto layout = new QVBoxLayout(this); - layout->addWidget(m_label, Qt::AlignLeft); - layout->addWidget(m_hint, Qt::AlignLeft); - layout->addWidget(m_lineEdit); - layout->addSpacing(10); - layout->addWidget(m_buttons); - setLayout(layout); - - connect(m_buttons, &QDialogButtonBox::accepted, - m_lineEdit, &Utils::FancyLineEdit::onEditingFinished); - connect(m_buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(m_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(m_hint, &QLabel::linkActivated, [](const QString &link) { - Core::HelpManager::handleHelpRequest(link); - }); - } - - void setLabelText(const QString &text) - { - m_label->setText(text); - } - - void setHintText(const QString &text) - { - m_hint->setText(QString::fromLatin1("<html>%1</html>").arg(text)); - } - - void setHistoryCompleter(const QString &key) - { - m_lineEdit->setHistoryCompleter(key); - m_lineEdit->clear(); // Undo "convenient" population with history item. - } - - QString text() const - { - return m_lineEdit->text(); - } - -public: - QLabel *m_label; - QLabel *m_hint; - Utils::FancyLineEdit *m_lineEdit; - QDialogButtonBox *m_buttons; -}; - -void WatchTreeView::inputNewExpression() -{ - InputDialog dlg; - dlg.setWindowTitle(tr("New Evaluated Expression")); - dlg.setLabelText(tr("Enter an expression to evaluate.")); - dlg.setHintText(tr("Note: Evaluators will be re-evaluated after each step. " - "For details check the <a href=\"" - "qthelp://org.qt-project.qtcreator/doc/creator-debug-mode.html#locals-and-expressions" - "\">documentation</a>.")); - dlg.setHistoryCompleter(QLatin1String("WatchItems")); - if (dlg.exec() == QDialog::Accepted) { - const QString exp = dlg.text().trimmed(); - if (!exp.isEmpty()) - watchExpression(exp, exp); - } -} - } // namespace Internal } // namespace Debugger |