diff options
Diffstat (limited to 'ui/commandpalette.h')
| -rw-r--r-- | ui/commandpalette.h | 215 |
1 files changed, 197 insertions, 18 deletions
diff --git a/ui/commandpalette.h b/ui/commandpalette.h index fcb27b31..8fb20cd6 100644 --- a/ui/commandpalette.h +++ b/ui/commandpalette.h @@ -5,6 +5,7 @@ #include <QtWidgets/QLineEdit> #include <QtWidgets/QFrame> #include <QtCore/QPointer> +#include <QtCore/QThread> #include <QtWidgets/QStyledItemDelegate> #include <vector> #include "action.h" @@ -21,14 +22,132 @@ */ struct BINARYNINJAUIAPI CommandListItem { + enum CommandListItemType + { + // Index is serialized so only to add to the end + Help, + UIAction, + OpenTab, + NavigationHistory, + RecentFile, + RecentProject, + ProjectFile, + Expression, + RecentExpression, + Function, + Symbol, + Type, + String, + DerivedString, + LastItemType + }; + + CommandListItemType type; QString name; + QString secondary; QString shortcut; - QString action; + QString extraSearchableText; + QVariant action; + Qt::TextElideMode secondaryElide = Qt::ElideRight; + bool addToRecents = true; + bool includeUnfiltered = true; + int score = 0; +}; + + +/*! + + \ingroup commandpalette +*/ +struct BINARYNINJAUIAPI CommandListItemSearchInfo +{ + std::unordered_set<CommandListItem::CommandListItemType> types; + QString name; + QString searchName; + std::string prefix; + QKeySequence shortcut; + + static std::vector<CommandListItemSearchInfo> GetSearchTypes(); }; + class CommandPalette; class CommandListFilter; +class CommandListGenerateWorker : public QObject +{ + Q_OBJECT + + BinaryViewRef m_view; + bool m_aborted; + int m_request; + std::shared_ptr<std::atomic_int> m_latestRequest; + + bool m_pending; + std::vector<CommandListItem> m_pendingItems; + std::mutex m_pendingItemsMutex; + +public: + explicit CommandListGenerateWorker(QObject* parent, std::shared_ptr<std::atomic_int> request, const UIActionContext& context); + virtual ~CommandListGenerateWorker(); + +Q_SIGNALS: + void dataFetched(int request, const std::vector<CommandListItem>& items); + void noMoreDataToFetch(int request); + void workFinished(int request); + +public Q_SLOTS: + void fetchMore(); + void start(); + void abort(); +}; + + +class CommandListScoreWorker : public QObject +{ +public: + enum OrderStrategy + { + DefaultOrder, + ScoreOrder + }; + +private: + Q_OBJECT + + bool m_aborted; + int m_request; + std::shared_ptr<std::atomic_int> m_latestRequest; + QString m_filter; + std::shared_ptr<std::vector<CommandListItem>> m_items; + std::vector<int> m_oldItemScores; + OrderStrategy m_strategy; + + bool m_pending; + std::vector<std::pair<CommandListItem*, int>> m_pendingItems; + std::mutex m_pendingItemsMutex; + +public: + explicit CommandListScoreWorker( + QObject* parent, + std::shared_ptr<std::atomic_int> request, + QString filter, + std::shared_ptr<std::vector<CommandListItem>> items, + OrderStrategy orderStrategy + ); + virtual ~CommandListScoreWorker(); + +Q_SIGNALS: + void dataFetched(int request, const std::vector<std::pair<CommandListItem*, int>>& items); + void noMoreDataToFetch(int request); + void workFinished(int request); + +public Q_SLOTS: + void fetchMore(); + void start(); + void abort(); +}; + /*! @@ -54,17 +173,40 @@ class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel { Q_OBJECT - std::vector<CommandListItem> m_items; - std::vector<CommandListItem> m_allItems; + UIActionHandler* m_handler; + UIActionContext m_context; + + std::shared_ptr<std::vector<CommandListItem>> m_allItems; + std::vector<CommandListItem*> m_displayItems; // pointers into m_allItems + QString m_filterText; + bool m_updatesPaused; - std::vector<QString> m_recentItems; - size_t m_maxRecentItems; + std::vector<CommandListItem> m_recentItems; - bool isFilterMatch(const QString& name, const QString& filter); - int getFilterMatchScore(const QString& name, const QString& filter); + QThread m_generateWorkerThread; + CommandListGenerateWorker* m_generateWorker; + std::shared_ptr<std::atomic_int> m_generateWorkerRequest; + QTimer m_generateFetchTimer; + bool m_generateMoreToFetch; - public: - CommandListModel(QWidget* parent, const std::vector<CommandListItem>& items); + QTimer m_scoreTimer; + QMetaObject::Connection m_scoreTimerConnection; + + QThread m_scoreWorkerThread; + CommandListScoreWorker* m_scoreWorker; + std::shared_ptr<std::atomic_int> m_scoreWorkerRequest; + QTimer m_scoreFetchTimer; + bool m_scoreMoreToFetch; + + void loadRecentItems(); + std::vector<CommandListItem> generateFastCommandList(); + void sortCommandList(std::vector<CommandListItem>& list); + void mergeCommandList(std::vector<CommandListItem>& output, std::vector<CommandListItem>&& input); + void startScoreListThread(); + +public: + CommandListModel(QWidget* parent); + ~CommandListModel(); virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override; virtual QModelIndex parent(const QModelIndex& i) const override; @@ -73,10 +215,33 @@ class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel virtual int columnCount(const QModelIndex& parent) const override; virtual QVariant data(const QModelIndex& i, int role) const override; - QString getActionForItem(int row); + CommandListItem getItem(int row); void setFilterText(const QString& text); - size_t getRecentPosition(const QString& name) const; - void addRecentItem(const QString& name); + size_t getRecentPosition(const CommandListItem& item) const; + void addRecentItem(const CommandListItem& item); + + void clearCommandList(); + void generateCommandList(UIActionHandler* handler, const UIActionContext& context); + void cancelGenerateCommandList(); + + void scoreCommandList(CommandListScoreWorker::OrderStrategy strategy); + void cancelScoreCommandList(); + + void pauseCommandListUpdates(); + void unpauseCommandListUpdates(); + + void updateDisplayedItems(); + +private Q_SLOTS: + void generateFetch(); + void itemsGenerated(int request, const std::vector<CommandListItem>& items); + void itemsFinishedGenerating(int request); + void generateWorkFinished(int request); + + void scoreFetch(); + void itemsScored(int request, const std::vector<std::pair<CommandListItem*, int>>& items); + void itemsFinishedScoring(int request); + void scoreWorkFinished(int request); }; /*! @@ -92,14 +257,21 @@ class BINARYNINJAUIAPI CommandList : public QListView CommandListFilter* m_filter; public: - CommandList(CommandPalette* parent, const std::vector<CommandListItem>& items); + CommandList(CommandPalette* parent); void setFilter(CommandListFilter* filter) { m_filter = filter; } void setFilterText(const QString& text); - QString getActionForItem(int row); + CommandListItem getItem(int row); QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const; - void addRecentItem(const QString& name); + void addRecentItem(const CommandListItem& item); + + void clearCommandList(); + void generateCommandList(UIActionHandler* handler, const UIActionContext& context); + void cancelGenerateCommandList(); + + void pauseCommandListUpdates(); + void unpauseCommandListUpdates(); protected: virtual void keyPressEvent(QKeyEvent* event) override; @@ -126,7 +298,9 @@ class BINARYNINJAUIAPI CommandListFilter : public QLineEdit protected: bool event(QEvent* event) override; virtual void keyPressEvent(QKeyEvent* event) override; + virtual void focusInEvent(QFocusEvent* event) override; virtual void focusOutEvent(QFocusEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; }; /*! @@ -139,26 +313,31 @@ class BINARYNINJAUIAPI CommandPalette : public QFrame UIActionHandler* m_handler; UIActionContext m_context; + QPointer<QWidget> m_previousWidget; CommandListFilter* m_filter; CommandList* m_list; + std::optional<CommandListItem> m_savedTop; bool m_executing; - std::vector<CommandListItem> getCommandList(); void init(); public: - CommandPalette(QWidget* parent, UIActionHandler* handler); - CommandPalette(QWidget* parent, UIActionHandler* handler, const UIActionContext& context); + CommandPalette(QWidget* parent); + void openWithInput(const QString& text); void focusInput(); + void clearCommandList(); + void generateCommandList(UIActionHandler* handler, const UIActionContext& context); + //! Activate the focused item, or topmost item if there is no selection. void activateFocusedItem(); void selectFirstItem(); void close(bool restoreFocus = true); + void activateItem(const CommandListItem& item); private Q_SLOTS: void itemClicked(const QModelIndex& idx); |
