1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
#include "matched.h"
#include <QGridLayout>
#include "theme.h"
const char* WARP_APPLY_ACTIVITY = "analysis.warp.apply";
WarpMatchedWidget::WarpMatchedWidget(BinaryViewRef current)
{
m_current = current;
// Create the QT stuff
QGridLayout* layout = new QGridLayout(this);
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(2);
auto newPalette = palette();
newPalette.setColor(QPalette::Window, getThemeColor(SidebarWidgetBackgroundColor));
setAutoFillBackground(true);
setPalette(newPalette);
// TODO: Split horizontally if the widget is displayed in a sidebar that is vertically challenged.
m_splitter = new QSplitter(Qt::Vertical);
m_splitter->setContentsMargins(0, 0, 0, 0);
// Add a widget to display the matches.
m_tableWidget = new WarpFunctionTableWidget(this);
m_tableWidget->setContentsMargins(0, 0, 0, 0);
m_splitter->addWidget(m_tableWidget);
// Removes the match for the function, this is irreversible currently, and the user must run the matcher again.
// TODO: We previously were trying to instead toggle the application of the match, but because the symbols are applied
// TODO: when applying the match metadata we would persist that regardless.
m_tableWidget->RegisterContextMenuAction(
"Remove Match", [this](WarpFunctionItem*, std::optional<uint64_t> address) {
if (!address.has_value())
return;
for (const auto& func : m_current->GetAnalysisFunctionsForAddress(*address))
{
WarpRemoveMatchDialog dlg(this, func);
if (dlg.execute())
Update();
}
});
layout->addWidget(m_splitter, 1, 0, 1, 5);
setLayout(layout);
Update();
connect(m_tableWidget->GetTableView(), &QTableView::doubleClicked, this, [this](const QModelIndex& index) {
if (m_current == nullptr)
return;
if (!index.isValid())
return;
const QModelIndex sourceIndex = m_tableWidget->GetProxyModel()->mapToSource(index);
if (!sourceIndex.isValid())
return;
auto selectedItem = m_tableWidget->GetModel()->GetAddress(sourceIndex);
if (!selectedItem.has_value())
return;
// Navigate to the address in the view, so the user feels like they are doing something.
auto currentView = m_current->GetCurrentView();
// TODO: Navigate unconditionally steals focus, need to figure out how to prevent the loss of focus.
m_current->Navigate(currentView, selectedItem.value());
});
}
void WarpMatchedWidget::Update()
{
m_tableWidget->GetTableView()->setSortingEnabled(false);
m_tableWidget->GetTableView()->setEnabled(false);
m_tableWidget->GetProxyModel()->setDynamicSortFilter(false);
m_tableWidget->GetTableView()->setUpdatesEnabled(false);
m_tableWidget->GetTableView()->setModel(nullptr);
m_tableWidget->GetProxyModel()->setSourceModel(nullptr);
for (const auto& analysisFunction : m_current->GetAnalysisFunctionList())
{
if (const auto& matchedFunction = Warp::Function::GetMatched(*analysisFunction))
m_tableWidget->InsertFunction(analysisFunction->GetStart(), new WarpFunctionItem(matchedFunction, analysisFunction));
else
m_tableWidget->RemoveFunction(analysisFunction->GetStart());
}
m_tableWidget->GetTableView()->setModel(m_tableWidget->GetProxyModel());
m_tableWidget->GetProxyModel()->setSourceModel(m_tableWidget->GetModel());
m_tableWidget->GetProxyModel()->setDynamicSortFilter(true);
m_tableWidget->GetTableView()->setEnabled(true);
m_tableWidget->GetTableView()->setSortingEnabled(true);
m_tableWidget->GetTableView()->setUpdatesEnabled(true);
}
|