summaryrefslogtreecommitdiff
path: root/view/sharedcache
diff options
context:
space:
mode:
authorAlexander Taylor <alex@vector35.com>2025-04-02 21:14:20 -0400
committerAlexander Taylor <alex@vector35.com>2025-04-02 21:21:53 -0400
commit67e5ac0aa51db4fd52da786a6227c8bc649814e5 (patch)
tree88971634c3dacc6da14b4b0b58f8bdb068df5e33 /view/sharedcache
parent1b32a95b3a88567b349e1d3a57dea2fea9f42961 (diff)
Add context menu for shared cache view.
Also addresses some lints that I thought were possibly worth it.
Diffstat (limited to 'view/sharedcache')
-rw-r--r--view/sharedcache/ui/dsctriage.cpp73
-rw-r--r--view/sharedcache/ui/dsctriage.h9
2 files changed, 75 insertions, 7 deletions
diff --git a/view/sharedcache/ui/dsctriage.cpp b/view/sharedcache/ui/dsctriage.cpp
index 91e1d24c..642fc5df 100644
--- a/view/sharedcache/ui/dsctriage.cpp
+++ b/view/sharedcache/ui/dsctriage.cpp
@@ -53,7 +53,7 @@ DSCTriageView::DSCTriageView(QWidget* parent, BinaryViewRef data) : QWidget(pare
QWidget* defaultWidget = nullptr;
- auto loadImagesWithAddr = [this](const std::vector<uint64_t>& addresses) {
+ auto loadImagesWithAddr = [this](const std::vector<uint64_t>& addresses, bool includeDependencies = false) {
auto controller = SharedCacheController::GetController(*this->m_data);
if (!controller)
return;
@@ -64,7 +64,24 @@ DSCTriageView::DSCTriageView(QWidget* parent, BinaryViewRef data) : QWidget(pare
auto image = controller->GetImageContaining(addr);
// Only try to load if we have not already.
if (image.has_value() && !controller->IsImageLoaded(*image))
+ {
images.insert({image->headerAddress, *image});
+
+ // TODO: We currently only add direct dependencies, may want to make the depth configurable?
+ if (includeDependencies)
+ {
+ auto dependencies = controller->GetImageDependencies(*image);
+ for (const auto& depName : dependencies)
+ {
+ auto depImage = controller->GetImageWithName(depName);
+ if (depImage.has_value() && !controller->IsImageLoaded(*depImage))
+ {
+ images.insert({depImage->headerAddress, *depImage});
+ }
+ }
+ }
+ }
+
}
// Don't create a worker action if we don't have any images.
@@ -94,14 +111,62 @@ DSCTriageView::DSCTriageView(QWidget* parent, BinaryViewRef data) : QWidget(pare
};
// Tab: Images
- auto loadImageTable = new FilterableTableView;
+ auto loadImageTable = new FilterableTableView(this);
{
m_imageModel = new QStandardItemModel(0, 3, loadImageTable);
m_imageModel->setHorizontalHeaderLabels({"Address", "Loaded", "Name"});
// Apply custom column styling
loadImageTable->setItemDelegateForColumn(0, new AddressColorDelegate(loadImageTable));
- loadImageTable->setItemDelegateForColumn(1, new LoadedDelegate());
+ loadImageTable->setItemDelegateForColumn(1, new LoadedDelegate(loadImageTable));
+
+ // Context menu
+ loadImageTable->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(loadImageTable, &QWidget::customContextMenuRequested, [loadImageTable, loadImagesWithAddr](const QPoint &pos) {
+ QMenu contextMenu(tr("Load Image Actions"), loadImageTable);
+
+ // Get number of selected images
+ auto selected = loadImageTable->selectionModel()->selectedRows();
+ int selectedCount = 0;
+ std::vector<uint64_t> addresses;
+ for (const auto& idx : selected)
+ {
+ // Skip rows hidden by the filter
+ if (loadImageTable->isRowHidden(idx.row()))
+ continue;
+ addresses.push_back(idx.data().toString().toULongLong(nullptr, 16));
+ selectedCount++;
+ }
+
+ QAction noSelectionAction("No Images Selected", loadImageTable);
+ QAction loadImagesAction("", loadImageTable);
+ QAction loadImagesWithDepsAction("", loadImageTable);
+ if (selectedCount == 0)
+ {
+ noSelectionAction.setEnabled(false);
+ contextMenu.addAction(&noSelectionAction);
+ }
+ else
+ {
+ // Format action text for loading selected images
+ QString loadActionText = (selectedCount == 1) ? "Load Selected Image" : QString("Load %1 Selected Images").arg(selectedCount);
+ loadImagesAction.setText(loadActionText);
+ connect(&loadImagesAction, &QAction::triggered, [loadImagesWithAddr, addresses]() {
+ loadImagesWithAddr(addresses, false);
+ });
+ contextMenu.addAction(&loadImagesAction);
+
+ // Format action text for loading selected images with dependencies
+ QString loadWithDepsActionText = (selectedCount == 1) ? "Load Selected Image and Dependencies" : QString("Load %1 Selected Images and Dependencies").arg(selectedCount);
+ loadImagesWithDepsAction.setText(loadWithDepsActionText);
+ connect(&loadImagesWithDepsAction, &QAction::triggered, [loadImagesWithAddr, addresses]() {
+ loadImagesWithAddr(addresses, true);
+ });
+ contextMenu.addAction(&loadImagesWithDepsAction);
+ }
+
+ contextMenu.exec(loadImageTable->viewport()->mapToGlobal(pos));
+ });
auto loadImageButton = new QPushButton();
connect(loadImageButton, &QPushButton::clicked,
@@ -110,7 +175,7 @@ DSCTriageView::DSCTriageView(QWidget* parent, BinaryViewRef data) : QWidget(pare
std::vector<uint64_t> addresses;
for (const auto& idx : selected)
{
- // Skip rows hidden by the filter.
+ // Skip rows hidden by the filter
if (loadImageTable->isRowHidden(idx.row()))
continue;
addresses.push_back(idx.data().toString().toULongLong(nullptr, 16));
diff --git a/view/sharedcache/ui/dsctriage.h b/view/sharedcache/ui/dsctriage.h
index edab8358..ae49bc8e 100644
--- a/view/sharedcache/ui/dsctriage.h
+++ b/view/sharedcache/ui/dsctriage.h
@@ -23,7 +23,7 @@ class AddressColorDelegate : public QStyledItemDelegate
{
public:
- AddressColorDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {}
+ explicit AddressColorDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {}
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
{
@@ -101,7 +101,7 @@ public:
bool eventFilter(QObject* obj, QEvent* event) override {
if (event->type() == QEvent::KeyPress) {
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+ auto* keyEvent = dynamic_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Escape) {
clearSelection();
return true;
@@ -161,7 +161,10 @@ public:
class LoadedDelegate : public QItemDelegate
{
Q_OBJECT
+
public:
+ explicit LoadedDelegate(QObject* parent = nullptr) : QItemDelegate(parent) {}
+
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override
{
@@ -202,7 +205,7 @@ public:
{
Q_UNUSED(option);
Q_UNUSED(index);
- return QSize(50, 24);
+ return {50, 24};
}
void setEditorData(QWidget *editor, const QModelIndex &index) const override