From 7e8b58ec538b7293710bcbe64496b7da78bd69e8 Mon Sep 17 00:00:00 2001 From: Aaron Barany Date: Fri, 4 Feb 2022 16:37:59 -0800 Subject: [PATCH] Debugger: Use queued connection for menu actions Pass the parent calling object to the addAction() functions and use a queued connection. This prevents the following sequence of events: 1. The menu is dismissed when selecting a menu item. 2. The deletion gets queued via deleteLater(). 2. The onTriggered action gets invoked and opens a dialog box. 3. The dialog box triggers the events to be processed. 4. The menu is deleted when processing the events, while still in the event function to handle the dismissal. This only affected the watch menu since the others were leaked. Added cleanup handlers for the other debugger menus to avoid leaking them. Task-number: QTCREATORBUG-26989 Change-Id: Ifa2c52d7bea884c55d43fa545e3e2870301e4052 --- src/plugins/debugger/breakhandler.cpp | 28 ++++---- src/plugins/debugger/debuggercore.h | 9 +-- src/plugins/debugger/debuggerplugin.cpp | 27 +++++--- src/plugins/debugger/moduleshandler.cpp | 19 +++--- .../debugger/peripheralregisterhandler.cpp | 17 ++--- src/plugins/debugger/registerhandler.cpp | 18 ++--- src/plugins/debugger/stackhandler.cpp | 19 +++--- src/plugins/debugger/watchhandler.cpp | 66 +++++++++---------- 8 files changed, 110 insertions(+), 93 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 35b1c30449..0b577eb6e5 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1615,9 +1615,9 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); + addAction(this, menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); - addAction(menu, tr("Delete Selected Breakpoints"), + addAction(this, menu, tr("Delete Selected Breakpoints"), !selectedBreakpoints.isEmpty(), [selectedBreakpoints] { for (Breakpoint bp : selectedBreakpoints) { @@ -1629,7 +1629,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Edit Selected Breakpoints..."), + addAction(this, menu, tr("Edit Selected Breakpoints..."), !selectedBreakpoints.isEmpty(), [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); }); @@ -1645,7 +1645,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) // bp.setThreadSpec(threadId); // }); - addAction(menu, + addAction(this, menu, selectedBreakpoints.size() > 1 ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"), @@ -1659,7 +1659,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) } ); - addAction(menu, + addAction(this, menu, selectedLocations.size() > 1 ? locationsEnabled ? tr("Disable Selected Locations") : tr("Enable Selected Locations") : locationsEnabled ? tr("Disable Location") : tr("Enable Location"), @@ -1672,7 +1672,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); - addAction(menu, tr("Delete All Breakpoints"), + addAction(this, menu, tr("Delete All Breakpoints"), rowCount() > 0, &BreakpointManager::executeDeleteAllBreakpointsDialog); @@ -1687,7 +1687,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) breakpointsInFile.append(findBreakpointByIndex(index)); } } - addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file), + addAction(this, menu, tr("Delete Breakpoints of \"%1\"").arg(file), tr("Delete Breakpoints of File"), breakpointsInFile.size() > 1, [breakpointsInFile] { @@ -1700,6 +1700,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; @@ -2640,20 +2641,20 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); + addAction(this, menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); - addAction(menu, tr("Delete Selected Breakpoints"), + addAction(this, menu, tr("Delete Selected Breakpoints"), !selectedBreakpoints.isEmpty(), [selectedBreakpoints] { for (GlobalBreakpoint gbp : selectedBreakpoints) gbp->deleteBreakpoint(); }); - addAction(menu, tr("Edit Selected Breakpoints..."), + addAction(this, menu, tr("Edit Selected Breakpoints..."), !selectedBreakpoints.isEmpty(), [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); }); - addAction(menu, + addAction(this, menu, selectedBreakpoints.size() > 1 ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"), @@ -2666,7 +2667,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); - addAction(menu, tr("Delete All Breakpoints"), + addAction(this, menu, tr("Delete All Breakpoints"), rowCount() > 0, &BreakpointManager::executeDeleteAllBreakpointsDialog); @@ -2682,7 +2683,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) }); } } - addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file.toUserOutput()), + addAction(this, menu, tr("Delete Breakpoints of \"%1\"").arg(file.toUserOutput()), tr("Delete Breakpoints of File"), breakpointsInFile.size() > 1, [breakpointsInFile] { @@ -2695,6 +2696,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index bd228b2560..e4123d3cdd 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -32,6 +32,7 @@ #include QT_BEGIN_NAMESPACE +class QObject; class QWidget; class QMenu; class QAction; @@ -53,12 +54,12 @@ void openTextEditor(const QString &titlePattern, const QString &contents); bool isTestRun(); -QAction *addAction(QMenu *menu, const QString &display, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered = {}); -QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &d1, const QString &d2, bool on, const std::function &onTriggered); -QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked, - const std::function &onTriggered); +QAction *addCheckableAction(const QObject *parent, QMenu *menu, const QString &display, bool on, + bool checked, const std::function &onTriggered); // Qt's various build paths for unpatched versions QStringList qtBuildPaths(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ae727383d2..cec08760aa 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -428,25 +428,33 @@ static QIcon interruptIcon(bool toolBarStyle) return toolBarStyle ? iconToolBar : icon; } -QAction *addAction(QMenu *menu, const QString &display, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered) { QAction *act = menu->addAction(display); act->setEnabled(on); - QObject::connect(act, &QAction::triggered, onTriggered); + // Always queue the connection to prevent the following sequence of events if the menu cleans + // itself up on dismissal: + // 1. The menu is dismissed when selecting a menu item. + // 2. The deletion gets queued via deleteLater(). + // 2. The onTriggered action gets invoked and opens a dialog box. + // 3. The dialog box triggers the events to be processed. + // 4. The menu is deleted when processing the events, while still in the event function to + // handle the dismissal. + QObject::connect(act, &QAction::triggered, parent, onTriggered, Qt::QueuedConnection); return act; }; -QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &d1, const QString &d2, bool on, const std::function &onTriggered) { - return on ? addAction(menu, d1, true, onTriggered) : addAction(menu, d2, false); + return on ? addAction(parent, menu, d1, true, onTriggered) : addAction(parent, menu, d2, false); }; -QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked, - const std::function &onTriggered) +QAction *addCheckableAction(const QObject *parent, QMenu *menu, const QString &display, bool on, + bool checked, const std::function &onTriggered) { - QAction *act = addAction(menu, display, on, onTriggered); + QAction *act = addAction(parent, menu, display, on, onTriggered); act->setCheckable(true); act->setChecked(checked); return act; @@ -1186,8 +1194,9 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, &DebuggerPluginPrivate::updateBreakMenuItem); // Application interaction - connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered, - [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); + // Use a queued connection so the dialog isn't triggered in the same event. + connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered, this, + [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }, Qt::QueuedConnection); m_perspective.useSubPerspectiveSwitcher(EngineManager::engineChooser()); m_perspective.addToolBarAction(&m_startAction); diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index e894042c2d..a040c7f1fe 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -179,51 +179,52 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Update Module List"), + addAction(this, menu, tr("Update Module List"), enabled && canReload, [this] { engine->reloadModules(); }); - addAction(menu, tr("Show Source Files for Module \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Source Files for Module \"%1\"").arg(moduleName), tr("Show Source Files for Module"), moduleNameValid && enabled && canReload, [this, modulePath] { engine->loadSymbols(modulePath); }); // FIXME: Dependencies only available on Windows, when "depends" is installed. - addAction(menu, tr("Show Dependencies of \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Dependencies of \"%1\"").arg(moduleName), tr("Show Dependencies"), moduleNameValid && !moduleName.isEmpty() && HostOsInfo::isWindowsHost(), [modulePath] { QtcProcess::startDetached({{"depends"}, {modulePath}}); }); - addAction(menu, tr("Load Symbols for All Modules"), + addAction(this, menu, tr("Load Symbols for All Modules"), enabled && canLoadSymbols, [this] { engine->loadAllSymbols(); }); - addAction(menu, tr("Examine All Modules"), + addAction(this, menu, tr("Examine All Modules"), enabled && canLoadSymbols, [this] { engine->examineModules(); }); - addAction(menu, tr("Load Symbols for Module \"%1\"").arg(moduleName), + addAction(this, menu, tr("Load Symbols for Module \"%1\"").arg(moduleName), tr("Load Symbols for Module"), moduleNameValid && canLoadSymbols, [this, modulePath] { engine->loadSymbols(modulePath); }); - addAction(menu, tr("Edit File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Edit File \"%1\"").arg(moduleName), tr("Edit File"), moduleNameValid, [this, modulePath] { engine->gotoLocation(FilePath::fromString(modulePath)); }); - addAction(menu, tr("Show Symbols in File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Symbols in File \"%1\"").arg(moduleName), tr("Show Symbols"), canShowSymbols && moduleNameValid, [this, modulePath] { engine->requestModuleSymbols(modulePath); }); - addAction(menu, tr("Show Sections in File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Sections in File \"%1\"").arg(moduleName), tr("Show Sections"), canShowSymbols && moduleNameValid, [this, modulePath] { engine->requestModuleSections(modulePath); }); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/peripheralregisterhandler.cpp b/src/plugins/debugger/peripheralregisterhandler.cpp index 3f466ab180..2cdf51c977 100644 --- a/src/plugins/debugger/peripheralregisterhandler.cpp +++ b/src/plugins/debugger/peripheralregisterhandler.cpp @@ -799,6 +799,7 @@ bool PeripheralRegisterHandler::contextMenuEvent(const ItemViewEvent &ev) } menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } @@ -841,7 +842,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Hexadecimal action. const auto hexAct = addCheckableAction( - fmtMenu, tr("Hexadecimal"), on, + this, fmtMenu, tr("Hexadecimal"), on, fmt == PeripheralRegisterFormat::Hexadecimal, [item] { item->m_reg.format = PeripheralRegisterFormat::Hexadecimal; @@ -851,7 +852,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Decimal action. const auto decAct = addCheckableAction( - fmtMenu, tr("Decimal"), on, + this, fmtMenu, tr("Decimal"), on, fmt == PeripheralRegisterFormat::Decimal, [item] { item->m_reg.format = PeripheralRegisterFormat::Decimal; @@ -861,7 +862,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Octal action. const auto octAct = addCheckableAction( - fmtMenu, tr("Octal"), on, + this, fmtMenu, tr("Octal"), on, fmt == PeripheralRegisterFormat::Octal, [item] { item->m_reg.format = PeripheralRegisterFormat::Octal; @@ -871,7 +872,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Binary action. const auto binAct = addCheckableAction( - fmtMenu, tr("Binary"), on, + this, fmtMenu, tr("Binary"), on, fmt == PeripheralRegisterFormat::Binary, [item] { item->m_reg.format = PeripheralRegisterFormat::Binary; @@ -895,7 +896,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Hexadecimal action. const auto hexAct = addCheckableAction( - fmtMenu, tr("Hexadecimal"), on, + this, fmtMenu, tr("Hexadecimal"), on, fmt == PeripheralRegisterFormat::Hexadecimal, [item] { item->m_fld.format = PeripheralRegisterFormat::Hexadecimal; @@ -905,7 +906,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Decimal action. const auto decAct = addCheckableAction( - fmtMenu, tr("Decimal"), on, + this, fmtMenu, tr("Decimal"), on, fmt == PeripheralRegisterFormat::Decimal, [item] { item->m_fld.format = PeripheralRegisterFormat::Decimal; @@ -915,7 +916,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Octal action. const auto octAct = addCheckableAction( - fmtMenu, tr("Octal"), on, + this, fmtMenu, tr("Octal"), on, fmt == PeripheralRegisterFormat::Octal, [item] { item->m_fld.format = PeripheralRegisterFormat::Octal; @@ -925,7 +926,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Binary action. const auto binAct = addCheckableAction( - fmtMenu, tr("Binary"), on, + this, fmtMenu, tr("Binary"), on, fmt == PeripheralRegisterFormat::Binary, [item] { item->m_fld.format = PeripheralRegisterFormat::Binary; diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 7ed8af6300..1dbafd23f3 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -764,14 +764,14 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Reload Register Listing"), + addAction(this, menu, tr("Reload Register Listing"), m_engine->hasCapability(RegisterCapability) && (state == InferiorStopOk || state == InferiorUnrunnable), [this] { m_engine->reloadRegisters(); }); menu->addSeparator(); - addAction(menu, tr("Open Memory View at Value of Register %1 0x%2") + addAction(this, menu, tr("Open Memory View at Value of Register %1 0x%2") .arg(registerName).arg(address, 0, 16), tr("Open Memory View at Value of Register"), address, @@ -784,7 +784,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openMemoryView(data); }); - addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), tr("Open Memory Editor"), address && actionsEnabled && m_engine->hasCapability(ShowMemoryCapability), [this, registerName, address] { @@ -796,12 +796,12 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openMemoryView(data); }); - addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), tr("Open Disassembler"), address && m_engine->hasCapability(DisassemblerCapability), [this, address] { m_engine->openDisassemblerView(Location(address)); }); - addAction(menu, tr("Open Disassembler..."), + addAction(this, menu, tr("Open Disassembler..."), m_engine->hasCapability(DisassemblerCapability), [this, address] { AddressDialog dialog; @@ -820,9 +820,10 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) : HexadecimalFormat; auto addFormatAction = - [menu, currentFormat, registerItem](const QString &display, RegisterFormat format) { - addCheckableAction(menu, display, registerItem, currentFormat == format, - [registerItem, format] { + [this, menu, currentFormat, registerItem]( + const QString &display, RegisterFormat format) { + addCheckableAction(this, menu, display, registerItem, currentFormat == format, + [registerItem, format] { registerItem->m_format = format; registerItem->update(); }); @@ -834,6 +835,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) addFormatAction(tr("Binary"), BinaryFormat); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 488c6649b1..c42c196b09 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -457,24 +457,24 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->expandStack.action()); - addAction(menu, tr("Copy Contents to Clipboard"), true, [ev] { + addAction(this, menu, tr("Copy Contents to Clipboard"), true, [ev] { copyTextToClipboard(selectedText(ev.view(), true)); }); - addAction(menu, tr("Copy Selection to Clipboard"), true, [ev] { + addAction(this, menu, tr("Copy Selection to Clipboard"), true, [ev] { copyTextToClipboard(selectedText(ev.view(), false)); }); - addAction(menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); + addAction(this, menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); if (m_engine->hasCapability(CreateFullBacktraceCapability)) menu->addAction(debuggerSettings()->createFullBacktrace.action()); if (m_engine->hasCapability(AdditionalQmlStackCapability)) - addAction(menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); }); + addAction(this, menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); }); if (m_engine->hasCapability(ShowMemoryCapability)) - addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), tr("Open Memory Editor"), address, [this, row, frame, address] { @@ -488,12 +488,12 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) }); if (m_engine->hasCapability(DisassemblerCapability)) { - addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), tr("Open Disassembler"), address, [this, frame] { m_engine->openDisassemblerView(frame); }); - addAction(menu, tr("Open Disassembler at Address..."), true, + addAction(this, menu, tr("Open Disassembler at Address..."), true, [this, address] { AddressDialog dialog; if (address) @@ -502,7 +502,7 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openDisassemblerView(Location(dialog.address())); }); - addAction(menu, tr("Disassemble Function..."), true, + addAction(this, menu, tr("Disassemble Function..."), true, [this] { const StackFrame frame = inputFunctionForDisassembly(); if (!frame.function.isEmpty()) @@ -511,13 +511,14 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) } if (m_engine->hasCapability(ShowModuleSymbolsCapability)) { - addAction(menu, tr("Try to Load Unknown Symbols"), true, + addAction(this, menu, tr("Try to Load Unknown Symbols"), true, [this] { m_engine->loadSymbolsForStack(); }); } menu->addSeparator(); menu->addAction(debuggerSettings()->useToolTipsInStackView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index bc1e57206c..8818ceb4fd 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1720,24 +1720,24 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add New Expression Evaluator..."), + addAction(this, menu, tr("Add New Expression Evaluator..."), canHandleWatches && canInsertWatches, [this] { inputNewExpression(); }); - addAction(menu, addWatchActionText(exp), + addAction(this, menu, addWatchActionText(exp), // Suppress for top-level watchers. canHandleWatches && !exp.isEmpty() && item && !(item->level() == 2 && item->isWatcher()), [this, exp, name] { m_handler->watchExpression(exp, name); }); - addAction(menu, removeWatchActionText(exp), + addAction(this, menu, removeWatchActionText(exp), canRemoveWatches && !exp.isEmpty() && item && item->isWatcher(), [this, item] { removeWatchItem(item); }); - addAction(menu, tr("Remove All Expression Evaluators"), + addAction(this, menu, tr("Remove All Expression Evaluators"), canRemoveWatches && !WatchHandler::watchedExpressions().isEmpty(), [this] { clearWatches(); }); - addAction(menu, tr("Select Widget to Add into Expression Evaluator"), + addAction(this, menu, tr("Select Widget to Add into Expression Evaluator"), state == InferiorRunOk && m_engine->hasCapability(WatchWidgetsCapability), [this] { grabWidget(); }); @@ -1757,7 +1757,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) menu->addMenu(createBreakpointMenu(item, menu)); menu->addSeparator(); - addAction(menu, tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { + addAction(this, menu, tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { m_expandedINames.insert(name); if (auto item = findItem(name)) { item->forFirstLevelChildren( @@ -1766,7 +1766,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Collapse All Children"), item, [this, name = item ? item->iname : QString()] { + addAction(this, menu, tr("Collapse All Children"), item, [this, name = item ? item->iname : QString()] { if (auto item = findItem(name)) { item->forFirstLevelChildren( [this](WatchItem *child) { m_expandedINames.remove(child->iname); }); @@ -1774,15 +1774,15 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Close Editor Tooltips"), + addAction(this, menu, tr("Close Editor Tooltips"), m_engine->toolTipManager()->hasToolTips(), [this] { m_engine->toolTipManager()->closeAllToolTips(); }); - addAction(menu, tr("Copy View Contents to Clipboard"), + addAction(this, menu, tr("Copy View Contents to Clipboard"), true, [this] { copyToClipboard(editorContents()); }); - addAction(menu, + addAction(this, menu, tr("Copy Current Value to Clipboard"), item, [this, name = item ? item->iname : QString()] { @@ -1794,7 +1794,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) // selectionModel()->hasSelection(), // [this] { copyToClipboard(editorContents(selectionModel()->selectedRows())); }); - addAction(menu, tr("Open View Contents in Editor"), + addAction(this, menu, tr("Open View Contents in Editor"), m_engine->debuggerActionsEnabled(), [this] { Internal::openTextEditor(tr("Locals & Expressions"), editorContents()); }); @@ -1827,7 +1827,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) const bool canSetWatchpoint = m_engine->hasCapability(WatchpointByAddressCapability); const bool createPointerActions = item->origaddr && item->origaddr != item->address; - act = addAction(menu, tr("Add Data Breakpoint at Object's Address (0x%1)").arg(item->address, 0, 16), + act = addAction(this, menu, tr("Add Data Breakpoint at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Add Data Breakpoint"), canSetWatchpoint && item->address, [bh, item] { bh->setWatchpointAtAddress(item->address, item->size); }); @@ -1836,7 +1836,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) act->setChecked(bh->findWatchpoint(bp)); act->setToolTip(tr("Stop the program when the data at the address is modified.")); - act = addAction(menu, tr("Add Data Breakpoint at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + act = addAction(this, menu, tr("Add Data Breakpoint at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Add Data Breakpoint at Pointer's Address"), canSetWatchpoint && item->address && createPointerActions, // FIXME: an approximation. This should be target's sizeof(void) @@ -1847,7 +1847,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) act->setChecked(bh->findWatchpoint(bp)); } - act = addAction(menu, tr("Add Data Breakpoint at Expression \"%1\"").arg(item->name), + act = addAction(this, menu, tr("Add Data Breakpoint at Expression \"%1\"").arg(item->name), tr("Add Data Breakpoint at Expression"), m_engine->hasCapability(WatchpointByExpressionCapability) && !item->name.isEmpty(), [bh, item] { bh->setWatchpointAtExpression(item->name); }); @@ -1869,37 +1869,37 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) QPoint pos = QPoint(100, 100); // ev->globalPos - addAction(menu, tr("Open Memory View at Object's Address (0x%1)").arg(item->address, 0, 16), + addAction(this, menu, tr("Open Memory View at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Open Memory View at Object's Address"), item->address, [this, item, pos] { addVariableMemoryView(true, item, false, pos); }); - addAction(menu, tr("Open Memory View at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + addAction(this, menu, tr("Open Memory View at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Open Memory View at Pointer's Address"), createPointerActions, [this, item, pos] { addVariableMemoryView(true, item, true, pos); }); - addAction(menu, tr("Open Memory View Showing Stack Layout"), + addAction(this, menu, tr("Open Memory View Showing Stack Layout"), true, [this, pos] { addStackLayoutMemoryView(true, pos); }); menu->addSeparator(); - addAction(menu, tr("Open Memory Editor at Object's Address (0x%1)").arg(item->address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Open Memory Editor at Object's Address"), item->address, [this, item, pos] { addVariableMemoryView(false, item, false, pos); }); - addAction(menu, tr("Open Memory Editor at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + addAction(this, menu, tr("Open Memory Editor at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Open Memory Editor at Pointer's Address"), createPointerActions, [this, item, pos] { addVariableMemoryView(false, item, true, pos); }); - addAction(menu, tr("Open Memory Editor Showing Stack Layout"), + addAction(this, menu, tr("Open Memory Editor Showing Stack Layout"), true, [this, pos] { addStackLayoutMemoryView(false, pos); }); - addAction(menu, tr("Open Memory Editor..."), + addAction(this, menu, tr("Open Memory Editor..."), true, [this, item] { AddressDialog dialog; @@ -1918,7 +1918,7 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) void WatchModel::addCharsPrintableMenu(QMenu *menu) { auto addBaseChangeAction = [this, menu](const QString &text, int base) { - addCheckableAction(menu, text, true, theUnprintableBase == base, [this, base] { + addCheckableAction(this, menu, text, true, theUnprintableBase == base, [this, base] { theUnprintableBase = base; emit layoutChanged(); // FIXME }); @@ -1954,13 +1954,13 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) const QString spacer = " "; menu->addSeparator(); - addAction(menu, tr("Change Display for Object Named \"%1\":").arg(iname), false); + addAction(this, menu, tr("Change Display for Object Named \"%1\":").arg(iname), false); QString msg = (individualFormat == AutomaticFormat && typeFormat != AutomaticFormat) ? tr("Use Format for Type (Currently %1)").arg(nameForFormat(typeFormat)) : QString(tr("Use Display Format Based on Type") + ' '); - addCheckableAction(menu, spacer + msg, true, individualFormat == AutomaticFormat, + addCheckableAction(this, menu, spacer + msg, true, individualFormat == AutomaticFormat, [this, iname] { // FIXME: Extend to multi-selection. //const QModelIndexList active = activeRows(); @@ -1971,23 +1971,23 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) }); for (int format : alternativeFormats) { - addCheckableAction(menu, spacer + nameForFormat(format), true, format == individualFormat, + addCheckableAction(this, menu, spacer + nameForFormat(format), true, format == individualFormat, [this, format, iname] { setIndividualFormat(iname, format); m_engine->updateLocals(); }); } - addAction(menu, tr("Reset All Individual Formats"), true, [this]() { + addAction(this, menu, tr("Reset All Individual Formats"), true, [this]() { theIndividualFormats.clear(); saveFormats(); m_engine->updateLocals(); }); menu->addSeparator(); - addAction(menu, tr("Change Display for Type \"%1\":").arg(item->type), false); + addAction(this, menu, tr("Change Display for Type \"%1\":").arg(item->type), false); - addCheckableAction(menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat, + addCheckableAction(this, menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat, [this, item] { //const QModelIndexList active = activeRows(); //for (const QModelIndex &idx : active) @@ -1997,14 +1997,14 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) }); for (int format : alternativeFormats) { - addCheckableAction(menu, spacer + nameForFormat(format), true, format == typeFormat, + addCheckableAction(this, menu, spacer + nameForFormat(format), true, format == typeFormat, [this, format, item] { setTypeFormat(item->type, format); m_engine->updateLocals(); }); } - addAction(menu, tr("Reset All Formats for Types"), true, [this]() { + addAction(this, menu, tr("Reset All Formats for Types"), true, [this]() { theTypeFormats.clear(); saveFormats(); m_engine->updateLocals(); @@ -2046,9 +2046,9 @@ QMenu *WatchModel::createFormatMenuForManySelected(const WatchItemSet &items, QW const QString spacer = " "; menu->addSeparator(); - addAction(menu, tr("Change Display for Objects"), false); + addAction(this, menu, tr("Change Display for Objects"), false); QString msg = QString(tr("Use Display Format Based on Type")); - addCheckableAction(menu, spacer + msg, true, false, + addCheckableAction(this, menu, spacer + msg, true, false, [this, items] { setItemsFormat(items, AutomaticFormat); m_engine->updateLocals(); @@ -2061,7 +2061,7 @@ QMenu *WatchModel::createFormatMenuForManySelected(const WatchItemSet &items, QW if (formatName.isEmpty()) continue; - addCheckableAction(menu, spacer + formatName, + addCheckableAction(this, menu, spacer + formatName, it.value() == countOfSelectItems, false, [this, format, items] { -- 2.35.1