@@ -17,6 +17,11 @@ limitations under the License.
1717#include < QPainter>
1818#include < QHeaderView>
1919#include < QFileInfo>
20+ #include < QClipboard>
21+ #include < QGuiApplication>
22+ #include < QKeyEvent>
23+ #include < QStringList>
24+ #include < algorithm>
2025#include " breakpointswidget.h"
2126#include " ui.h"
2227#include " menus.h"
@@ -229,12 +234,16 @@ QSize DebugBreakpointsItemDelegate::sizeHint(const QStyleOptionViewItem& option,
229234DebugBreakpointsWidget::DebugBreakpointsWidget (ViewFrame* view, BinaryViewRef data, Menu* menu):
230235 QTableView(view), m_view(view)
231236{
237+ setFocusPolicy (Qt::StrongFocus);
238+
232239 m_controller = DebuggerController::GetController (data);
233240 if (!m_controller)
234241 return ;
235242
236243 m_model = new DebugBreakpointsListModel (this , view);
237244 setModel (m_model);
245+ if (viewport ())
246+ viewport ()->setFocusPolicy (Qt::StrongFocus);
238247 setSelectionBehavior (QAbstractItemView::SelectItems);
239248 setSelectionMode (QAbstractItemView::ExtendedSelection);
240249
@@ -272,6 +281,10 @@ DebugBreakpointsWidget::DebugBreakpointsWidget(ViewFrame* view, BinaryViewRef da
272281 m_actionHandler.bindAction (
273282 jumpToBreakpointActionName, UIAction ([&]() { jump (); }, [&]() { return selectionNotEmpty (); }));
274283
284+ m_menu->addAction (" Copy" , " Options" , MENU_ORDER_NORMAL);
285+ m_actionHandler.bindAction (
286+ " Copy" , UIAction ([&]() { copySelection (); }, [&]() { return selectionNotEmpty (); }), HighActionPriority);
287+
275288 QString addBreakpointActionName = QString::fromStdString (" Add Breakpoint..." );
276289 UIAction::registerAction (addBreakpointActionName);
277290 m_menu->addAction (addBreakpointActionName, " Options" , MENU_ORDER_NORMAL);
@@ -305,13 +318,54 @@ void DebugBreakpointsWidget::contextMenuEvent(QContextMenuEvent* event)
305318}
306319
307320
321+ void DebugBreakpointsWidget::keyPressEvent (QKeyEvent* event)
322+ {
323+ if (event && event->matches (QKeySequence::Copy))
324+ {
325+ copySelection ();
326+ event->accept ();
327+ return ;
328+ }
329+
330+ QTableView::keyPressEvent (event);
331+ }
332+
333+
308334bool DebugBreakpointsWidget::selectionNotEmpty ()
309335{
310336 QModelIndexList sel = selectionModel ()->selectedIndexes ();
311337 return (!sel.empty ()) && sel[0 ].isValid ();
312338}
313339
314340
341+ void DebugBreakpointsWidget::copySelection ()
342+ {
343+ if (!model () || !selectionModel ())
344+ return ;
345+
346+ QModelIndexList rows = selectionModel ()->selectedRows ();
347+ if (rows.empty ())
348+ return ;
349+
350+ std::sort (rows.begin (), rows.end (), [](const QModelIndex& a, const QModelIndex& b) { return a.row () < b.row (); });
351+
352+ QStringList lines;
353+ for (const QModelIndex& rowIndex : rows)
354+ {
355+ QStringList cells;
356+ for (int column = 0 ; column < model ()->columnCount (); column++)
357+ {
358+ QModelIndex idx = model ()->index (rowIndex.row (), column);
359+ cells << model ()->data (idx, Qt::DisplayRole).toString ();
360+ }
361+ lines << cells.join (" \t " );
362+ }
363+
364+ if (QClipboard* clipboard = QGuiApplication::clipboard ())
365+ clipboard->setText (lines.join (" \n " ));
366+ }
367+
368+
315369void DebugBreakpointsWidget::jump ()
316370{
317371 QModelIndexList sel = selectionModel ()->selectedRows ();
0 commit comments