From 3c88b11e5df33116580ac008e36092775df66135 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Fri, 13 Mar 2026 12:24:18 -0700 Subject: [WARP] Improved UX and API - Exposes WARP type objects directly - Adds processor API (for generating warp files directly) - Adds file and chunk API - Misc cleanup - Simplified the amount of commands - Replaced the "Create" commands with a purpose built processor dialog - Added a native QT viewer for WARP files - Simplified committing to a remote with a purpose built commit dialog --- .../warp/ui/shared/selectprojectfilesdialog.cpp | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 plugins/warp/ui/shared/selectprojectfilesdialog.cpp (limited to 'plugins/warp/ui/shared/selectprojectfilesdialog.cpp') diff --git a/plugins/warp/ui/shared/selectprojectfilesdialog.cpp b/plugins/warp/ui/shared/selectprojectfilesdialog.cpp new file mode 100644 index 00000000..e8454cff --- /dev/null +++ b/plugins/warp/ui/shared/selectprojectfilesdialog.cpp @@ -0,0 +1,141 @@ +#include "selectprojectfilesdialog.h" + +#include +#include +#include +#include +#include + +using namespace BinaryNinja; + +SelectProjectFilesDialog::SelectProjectFilesDialog(QWidget* parent) : QDialog(parent) +{ + setWindowTitle("Select Project Files"); + setMinimumSize(700, 400); + auto* layout = new QVBoxLayout(this); + + auto* topLayout = new QFormLayout(); + m_projectCombo = new QComboBox(this); + auto projects = Project::GetOpenProjects(); + for (auto& project : projects) + { + m_projectCombo->addItem(QString::fromStdString(project->GetName()), QVariant::fromValue(project)); + } + topLayout->addRow("Project:", m_projectCombo); + layout->addLayout(topLayout); + + m_searchBar = new QLineEdit(this); + m_searchBar->setPlaceholderText("Search files..."); + connect(m_searchBar, &QLineEdit::textChanged, this, &SelectProjectFilesDialog::filterLists); + layout->addWidget(m_searchBar); + + auto* listsLayout = new QHBoxLayout(); + + auto* notAddingBox = new QVBoxLayout(); + notAddingBox->addWidget(new QLabel("Available:")); + m_notAddingList = new QListWidget(this); + m_notAddingList->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_notAddingList->setTextElideMode(Qt::ElideLeft); + m_notAddingList->setStyleSheet("QListWidget::item { padding: 2px; }"); + notAddingBox->addWidget(m_notAddingList); + listsLayout->addLayout(notAddingBox); + + auto* middleButtons = new QVBoxLayout(); + middleButtons->addStretch(); + auto* addButton = new QPushButton(">>", this); + connect(addButton, &QPushButton::clicked, [this]() { moveSelected(m_notAddingList, m_addingList); }); + middleButtons->addWidget(addButton); + auto* removeButton = new QPushButton("<<", this); + connect(removeButton, &QPushButton::clicked, [this]() { moveSelected(m_addingList, m_notAddingList); }); + middleButtons->addWidget(removeButton); + middleButtons->addStretch(); + listsLayout->addLayout(middleButtons); + + auto* addingBox = new QVBoxLayout(); + addingBox->addWidget(new QLabel("Selected:")); + m_addingList = new QListWidget(this); + m_addingList->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_addingList->setTextElideMode(Qt::ElideLeft); + m_addingList->setStyleSheet("QListWidget::item { padding: 2px; }"); + addingBox->addWidget(m_addingList); + listsLayout->addLayout(addingBox); + + layout->addLayout(listsLayout); + + auto* buttons = new QHBoxLayout(this); + auto* ok = new QPushButton("Add", this); + connect(ok, &QPushButton::clicked, this, &QDialog::accept); + auto* cancel = new QPushButton("Cancel", this); + connect(cancel, &QPushButton::clicked, this, &QDialog::reject); + buttons->addStretch(); + buttons->addWidget(ok); + buttons->addWidget(cancel); + layout->addLayout(buttons); + + connect(m_projectCombo, QOverload::of(&QComboBox::currentIndexChanged), this, + &SelectProjectFilesDialog::updateFileList); + + connect(m_notAddingList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) { + m_addingList->addItem(m_notAddingList->takeItem(m_notAddingList->row(item))); + filterLists(); + }); + connect(m_addingList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) { + m_notAddingList->addItem(m_addingList->takeItem(m_addingList->row(item))); + filterLists(); + }); + + updateFileList(); +} + +void SelectProjectFilesDialog::updateFileList() +{ + m_notAddingList->clear(); + m_addingList->clear(); + m_currentProject = m_projectCombo->currentData().value>(); + if (m_currentProject) + { + for (auto& file : m_currentProject->GetFiles()) + { + auto* item = new QListWidgetItem(QString::fromStdString(file->GetPathInProject())); + item->setData(Qt::UserRole, QVariant::fromValue(file)); + m_notAddingList->addItem(item); + } + } + filterLists(); +} + +void SelectProjectFilesDialog::filterLists() +{ + QString filter = m_searchBar->text().toLower(); + for (int i = 0; i < m_notAddingList->count(); ++i) + { + auto* item = m_notAddingList->item(i); + item->setHidden(!item->text().toLower().contains(filter)); + } + for (int i = 0; i < m_addingList->count(); ++i) + { + auto* item = m_addingList->item(i); + item->setHidden(!item->text().toLower().contains(filter)); + } +} + +void SelectProjectFilesDialog::moveSelected(QListWidget* from, QListWidget* to) +{ + QList items = from->selectedItems(); + for (auto* item : items) + to->addItem(from->takeItem(from->row(item))); + filterLists(); +} + +std::vector> SelectProjectFilesDialog::getSelectedFiles() const +{ + std::vector> files; + for (int i = 0; i < m_addingList->count(); ++i) + files.push_back(m_addingList->item(i)->data(Qt::UserRole).value>()); + return files; +} + +Ref SelectProjectFilesDialog::getSelectedProject() const +{ + return m_currentProject; +} \ No newline at end of file -- cgit v1.3.1