Skip to content

Commit bcefd84

Browse files
Copilotxusheng6
andcommitted
Add copy functionality to stack trace widget
Co-authored-by: xusheng6 <94503187+xusheng6@users.noreply.github.com>
1 parent efe58d0 commit bcefd84

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

ui/stackwidget.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ limitations under the License.
1717
#include <QPainter>
1818
#include <QHeaderView>
1919
#include <QLineEdit>
20+
#include <QGuiApplication>
21+
#include <QMimeData>
22+
#include <QClipboard>
2023
#include "stackwidget.h"
2124
#include "fmt/format.h"
2225

@@ -409,6 +412,18 @@ DebugStackWidget::DebugStackWidget(const QString& name, ViewFrame* view, BinaryV
409412
layout->addWidget(m_table);
410413
setLayout(layout);
411414

415+
m_actionHandler.setupActionHandler(this);
416+
m_contextMenuManager = new ContextMenuManager(this);
417+
m_menu = new Menu();
418+
419+
m_menu->addAction("Copy", "Options", MENU_ORDER_NORMAL);
420+
m_actionHandler.bindAction("Copy", UIAction([&]() { copy(); }, [&]() { return selectionNotEmpty(); }));
421+
422+
QString actionName = QString::fromStdString("Copy All Stack Entries");
423+
UIAction::registerAction(actionName);
424+
m_menu->addAction(actionName, "Options", MENU_ORDER_NORMAL);
425+
m_actionHandler.bindAction(actionName, UIAction([this]() { copyAll(); }));
426+
412427
updateContent();
413428
}
414429

@@ -421,6 +436,101 @@ void DebugStackWidget::notifyStackChanged(std::vector<DebugStackItem> stackItems
421436
}
422437

423438

439+
void DebugStackWidget::contextMenuEvent(QContextMenuEvent* event)
440+
{
441+
showContextMenu();
442+
}
443+
444+
445+
void DebugStackWidget::showContextMenu()
446+
{
447+
m_contextMenuManager->show(m_menu, &m_actionHandler);
448+
}
449+
450+
451+
bool DebugStackWidget::selectionNotEmpty()
452+
{
453+
QModelIndexList sel = m_table->selectionModel()->selectedRows();
454+
return !sel.empty();
455+
}
456+
457+
458+
void DebugStackWidget::copy()
459+
{
460+
QModelIndexList sel = m_table->selectionModel()->selectedRows();
461+
if (sel.empty())
462+
return;
463+
464+
QString text;
465+
for (int i = 0; i < sel.size(); i++)
466+
{
467+
if (i > 0)
468+
text += "\n";
469+
470+
int row = sel[i].row();
471+
if (row < 0 || row >= m_model->rowCount())
472+
continue;
473+
474+
DebugStackItem item = m_model->getRow(row);
475+
476+
// Format: Offset Address Value Hint
477+
QString offsetStr;
478+
ptrdiff_t offset = item.offset();
479+
if (offset < 0)
480+
offsetStr = QString::asprintf("-0x%" PRIx64, (uint64_t)-offset);
481+
else
482+
offsetStr = QString::asprintf("0x%" PRIx64, (uint64_t)offset);
483+
484+
text += QString::asprintf("%s 0x%" PRIx64 " 0x%" PRIx64 " %s",
485+
offsetStr.toStdString().c_str(),
486+
item.address(),
487+
item.value(),
488+
item.hint().c_str());
489+
}
490+
491+
auto* clipboard = QGuiApplication::clipboard();
492+
clipboard->clear();
493+
auto* mime = new QMimeData();
494+
mime->setText(text);
495+
clipboard->setMimeData(mime);
496+
}
497+
498+
499+
void DebugStackWidget::copyAll()
500+
{
501+
QString text;
502+
int rowCount = m_model->rowCount();
503+
504+
for (int row = 0; row < rowCount; row++)
505+
{
506+
if (row > 0)
507+
text += "\n";
508+
509+
DebugStackItem item = m_model->getRow(row);
510+
511+
// Format: Offset Address Value Hint
512+
QString offsetStr;
513+
ptrdiff_t offset = item.offset();
514+
if (offset < 0)
515+
offsetStr = QString::asprintf("-0x%" PRIx64, (uint64_t)-offset);
516+
else
517+
offsetStr = QString::asprintf("0x%" PRIx64, (uint64_t)offset);
518+
519+
text += QString::asprintf("%s 0x%" PRIx64 " 0x%" PRIx64 " %s",
520+
offsetStr.toStdString().c_str(),
521+
item.address(),
522+
item.value(),
523+
item.hint().c_str());
524+
}
525+
526+
auto* clipboard = QGuiApplication::clipboard();
527+
clipboard->clear();
528+
auto* mime = new QMimeData();
529+
mime->setText(text);
530+
clipboard->setMimeData(mime);
531+
}
532+
533+
424534
//void DebugStackWidget::notifyFontChanged()
425535
//{
426536
// m_delegate->updateFonts();

ui/stackwidget.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ limitations under the License.
2121
#include <QModelIndex>
2222
#include <QTableView>
2323
#include <QStyledItemDelegate>
24+
#include <QGuiApplication>
25+
#include <QMimeData>
26+
#include <QClipboard>
2427
#include "inttypes.h"
2528
#include "binaryninjaapi.h"
2629
#include "viewframe.h"
2730
#include "fontsettings.h"
2831
#include "theme.h"
2932
#include "debuggerapi.h"
33+
#include "menus.h"
3034

3135
using namespace BinaryNinjaDebuggerAPI;
3236

@@ -138,6 +142,13 @@ class DebugStackWidget : public QWidget
138142
DebugStackListModel* m_model;
139143
DebugStackItemDelegate* m_delegate;
140144

145+
UIActionHandler m_actionHandler;
146+
ContextMenuManager* m_contextMenuManager;
147+
Menu* m_menu;
148+
149+
virtual void contextMenuEvent(QContextMenuEvent* event) override;
150+
bool selectionNotEmpty();
151+
141152
//void shouldBeVisible()
142153

143154
//virtual void notifyFontChanged() override;
@@ -147,6 +158,11 @@ class DebugStackWidget : public QWidget
147158
DebugStackWidget(const QString& name, ViewFrame* view, BinaryViewRef data);
148159
void notifyStackChanged(std::vector<DebugStackItem> stackItems);
149160

161+
private slots:
162+
void copy();
163+
void copyAll();
164+
150165
public slots:
151166
void updateContent();
167+
void showContextMenu();
152168
};

0 commit comments

Comments
 (0)