summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2026-02-16 23:56:13 -0500
committerJosh Ferrell <josh@vector35.com>2026-02-17 13:39:28 -0500
commite684f8294981aa4287f513dfb9e842177c99d428 (patch)
tree34f1424ac965934f28e16a0d5567cbb6a9463f39 /ui
parentc86c641c720fbcd4ae9c99eb084ff565a53659c5 (diff)
[Project Browser] Add table view, misc fixes and improvements
Diffstat (limited to 'ui')
-rw-r--r--ui/projectbrowser.h120
1 files changed, 108 insertions, 12 deletions
diff --git a/ui/projectbrowser.h b/ui/projectbrowser.h
index 348d5ff0..d0973806 100644
--- a/ui/projectbrowser.h
+++ b/ui/projectbrowser.h
@@ -1,11 +1,10 @@
#pragma once
-#include <QtWidgets/QLabel>
-#include <QtGui/QStandardItemModel>
#include <qabstractitemmodel.h>
#include <qboxlayout.h>
#include <qfileiconprovider.h>
#include <qfilesystemwatcher.h>
+#include <qlabel.h>
#include <qlineedit.h>
#include <qmimedatabase.h>
#include <qnamespace.h>
@@ -17,10 +16,12 @@
#include <qtextbrowser.h>
#include <qtmetamacros.h>
#include <qtoolbutton.h>
+#include <qtableview.h>
#include <qtreeview.h>
#include <qlistwidget.h>
#include <qwidget.h>
#include <qpushbutton.h>
+#include <qstackedwidget.h>
#include <globalarea.h>
#include <tabwidget.h>
#include <unordered_map>
@@ -140,7 +141,7 @@ private Q_SLOTS:
};
-class BINARYNINJAUIAPI SortFilterProjectItemModel: public QSortFilterProxyModel
+class BINARYNINJAUIAPI ProjectTreeFilterModel: public QSortFilterProxyModel
{
bool m_acceptAllFolders = false;
@@ -151,13 +152,93 @@ protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
public:
- SortFilterProjectItemModel(ProjectRef project, QObject* parent = nullptr): QSortFilterProxyModel(parent), m_project(project) {};
+ ProjectTreeFilterModel(ProjectRef project, QObject* parent = nullptr): QSortFilterProxyModel(parent), m_project(project) {};
void setAcceptAllFolders(bool accept) { m_acceptAllFolders = accept; }
bool acceptAllFolders() const { return m_acceptAllFolders; }
};
+class BINARYNINJAUIAPI ProjectTableItemModel: public QAbstractProxyModel
+{
+ Q_OBJECT
+
+ ProjectRef m_project;
+
+ QList<QPersistentModelIndex> m_sourceFileIndexes;
+ QHash<QPersistentModelIndex, int> m_sourceToProxyRow;
+ QList<int> m_pendingRemovals;
+
+ void rebuildMapping();
+ void collectFileIndexes(const QModelIndex& parent, QList<QModelIndex>& results) const;
+ QString folderPathForIndex(int row) const;
+
+ void sourceRowsInserted(const QModelIndex& parent, int first, int last);
+ void sourceRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last);
+ void sourceRowsRemoved();
+ void sourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QList<int>& roles);
+
+public:
+ ProjectTableItemModel(ProjectRef project, QObject* parent = nullptr);
+
+ enum {
+ COL_FOLDER = ProjectItemModel::COLUMN_COUNT,
+ COLUMN_COUNT,
+ };
+
+ void setSourceModel(QAbstractItemModel* sourceModel) override;
+
+ QModelIndex mapToSource(const QModelIndex& proxyIndex) const override;
+ QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override;
+
+ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex& child) const override;
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex& proxyIndex, int role = Qt::DisplayRole) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+
+ bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+};
+
+
+class BINARYNINJAUIAPI ProjectTableFilterModel: public QSortFilterProxyModel
+{
+ ProjectRef m_project;
+
+protected:
+ bool lessThan(const QModelIndex& sourceLeft, const QModelIndex& sourceRight) const override;
+ bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
+
+public:
+ ProjectTableFilterModel(ProjectRef project, QObject* parent = nullptr): QSortFilterProxyModel(parent), m_project(project) {};
+};
+
+
+class BINARYNINJAUIAPI ProjectTable: public QTableView, public FilterTarget
+{
+ Q_OBJECT
+
+ virtual void scrollToFirstItem() override;
+ virtual void scrollToCurrentItem() override;
+ virtual void ensureSelection() override;
+ virtual void activateSelection() override;
+ virtual void setFilter(const std::string& filter, FilterOptions options) override;
+
+protected:
+ void mousePressEvent(QMouseEvent* event) override;
+ void keyPressEvent(QKeyEvent* event) override;
+
+public:
+ ProjectTable(QWidget* parent = nullptr);
+
+Q_SIGNALS:
+ void filterChanged(const QString& filter, FilterOptions options);
+};
+
+
class BINARYNINJAUIAPI ProjectTreeStyle: public QProxyStyle
{
public:
@@ -173,9 +254,6 @@ class BINARYNINJAUIAPI ProjectTree: public QTreeView, public FilterTarget
QSet<QString> m_expandedIds;
- FilterOptions m_filterOptions;
- std::string m_filter;
-
virtual void scrollToFirstItem() override;
virtual void scrollToCurrentItem() override;
virtual void ensureSelection() override;
@@ -287,7 +365,7 @@ class BINARYNINJAUIAPI ProjectBrowser: public QWidget, public UIContextNotificat
ProjectRef m_project;
- FilterEdit* m_projectFilterEdit;
+ FilterEdit* m_treeFilterEdit;
FilteredView* m_filteredTreeView;
FilterEdit* m_recentsFilterEdit;
@@ -296,24 +374,38 @@ class BINARYNINJAUIAPI ProjectBrowser: public QWidget, public UIContextNotificat
DockableTabBar* m_tabBar;
ProjectItemModel* m_projectModel;
- SortFilterProjectItemModel* m_sortFilterProjectModel;
+ ProjectTreeFilterModel* m_sortFilterTreeModel;
+ ProjectTableItemModel* m_tableModel;
+ ProjectTableFilterModel* m_sortFilterTableModel;
QLabel* m_nameLabel;
QLabel* m_descriptionLabel;
ProjectTree* m_projectTree;
+ ProjectTable* m_projectTable;
InfoWidget* m_infoWidget;
QWidget* m_projectContainer;
+ QStackedWidget* m_viewStack;
+
+ FilterEdit* m_tableFilterEdit;
+ FilteredView* m_filteredTableView;
+
+ bool m_useTableView = false;
+ ClickableIcon* m_viewToggleButton;
RecentsList* m_recentFilesList;
ClickableIcon* m_refreshButton;
ClickableIcon* m_editDetailsButton;
- UIActionHandler m_projectActionHandler;
+ UIActionHandler* m_projectTreeActionHandler = nullptr;
+ UIActionHandler* m_projectTableActionHandler = nullptr;
ContextMenuManager* m_projectContextMenuManager = nullptr;
Menu m_projectMenu;
ProjectFolderRef GetFolderContainingIndex(const QModelIndex& index) const;
QModelIndex GetCurrentSelectedIndex() const;
+ QItemSelectionModel* activeSelectionModel() const;
+ UIActionHandler* activeUIActionHandler() const;
+ void setUseTableView(bool useTable);
virtual void OnAfterOpenProjectFile(UIContext* context, ProjectFileRef projectFile, ViewFrame* frame) override;
@@ -335,12 +427,16 @@ class BINARYNINJAUIAPI ProjectBrowser: public QWidget, public UIContextNotificat
std::vector<ProjectFileRef> GetSelectedFilesRecursive();
private slots:
- void itemDoubleClicked(const QModelIndex& index);
+ void treeItemDoubleClicked(const QModelIndex& index);
+ void fileDoubleClicked(ProjectFileRef file);
void openProjectFile(ProjectFileRef file, bool openWithOptions = false);
- void itemSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
+ void treeItemSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
void itemChanged(QStandardItem* item);
void handleItemsDropped(Qt::DropAction action, const QList<QString> fileIds, const QList<QString> folderIds, const QList<QUrl> newUrls, ProjectFolderRef newParentFolder);
void onTreeFilterChanged(const QString& filter, FilterOptions options);
+ void tableItemDoubleClicked(const QModelIndex& index);
+ void tableItemSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
+ void onTableFilterChanged(const QString& filter, FilterOptions options);
protected:
void SelectItems(std::vector<ProjectFileRef> files, std::vector<ProjectFolderRef> folders);