From 715dd78287934c2dcb6de54b0a9be48b2237f9e6 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Wed, 30 Apr 2025 21:16:54 -0400 Subject: Make Triage Summary tables multi-select + copyable. Closes #6562. --- examples/triage/strings.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'examples/triage/strings.cpp') diff --git a/examples/triage/strings.cpp b/examples/triage/strings.cpp index f7fe5989..b84f6b62 100644 --- a/examples/triage/strings.cpp +++ b/examples/triage/strings.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include "strings.h" #include "view.h" #include "fontsettings.h" @@ -193,12 +196,53 @@ StringsTreeView::StringsTreeView(StringsWidget* parent, TriageView* view, Binary setRootIsDecorated(false); setUniformRowHeights(true); setSortingEnabled(true); + setSelectionMode(QAbstractItemView::ExtendedSelection); + setSelectionBehavior(QAbstractItemView::SelectRows); + setAllColumnsShowFocus(true); sortByColumn(0, Qt::AscendingOrder); setFont(getMonospaceFont(this)); connect(selectionModel(), &QItemSelectionModel::currentChanged, this, &StringsTreeView::stringSelected); connect(this, &QTreeView::doubleClicked, this, &StringsTreeView::stringDoubleClicked); + + m_actionHandler.bindAction("Copy", UIAction([this]() { copySelection(); }, [this]() { return canCopySelection(); })); +} + +void StringsTreeView::copySelection() +{ + if (!model() || !selectionModel()) + return; + + QModelIndexList rows = selectionModel()->selectedRows(); + if (rows.isEmpty()) + return; + + std::sort(rows.begin(), rows.end(), [](const QModelIndex& a, const QModelIndex& b) { return a.row() < b.row(); }); + + QStringList lines; + for (const QModelIndex& rowIndex : rows) + { + QStringList cells; + for (int column = 0; column < m_model->columnCount(QModelIndex()); column++) + { + if (isColumnHidden(column)) + continue; + + QModelIndex idx = m_model->index(rowIndex.row(), column, QModelIndex()); + cells << m_model->data(idx, Qt::DisplayRole).toString(); + } + lines << cells.join("\t"); + } + + if (QClipboard* clipboard = QGuiApplication::clipboard()) + clipboard->setText(lines.join("\n")); +} + + +bool StringsTreeView::canCopySelection() const +{ + return !selectionModel()->selectedRows().isEmpty(); } @@ -275,6 +319,12 @@ void StringsTreeView::keyPressEvent(QKeyEvent* event) if (sel.size() != 0) stringDoubleClicked(sel[0]); } + else if (event->matches(QKeySequence::Copy)) + { + copySelection(); + event->accept(); + return; + } QTreeView::keyPressEvent(event); } @@ -295,4 +345,4 @@ StringsWidget::StringsWidget(QWidget* parent, TriageView* view, BinaryViewRef da void StringsWidget::showFilter(const QString& filter) { m_filter->showFilter(filter); -} \ No newline at end of file +} -- cgit v1.3.1