55#include < QtWidgets/QLineEdit>
66#include < QtWidgets/QFrame>
77#include < QtCore/QPointer>
8+ #include < QtCore/QThread>
89#include < QtWidgets/QStyledItemDelegate>
910#include < vector>
1011#include " action.h"
2122*/
2223struct BINARYNINJAUIAPI CommandListItem
2324{
25+ enum CommandListItemType
26+ {
27+ // Index is serialized so only to add to the end
28+ Help,
29+ UIAction,
30+ OpenTab,
31+ NavigationHistory,
32+ RecentFile,
33+ RecentProject,
34+ ProjectFile,
35+ Expression,
36+ RecentExpression,
37+ Function,
38+ Symbol,
39+ Type,
40+ String,
41+ DerivedString,
42+ LastItemType
43+ };
44+
45+ CommandListItemType type;
2446 QString name;
47+ QString secondary;
2548 QString shortcut;
26- QString action;
49+ QString extraSearchableText;
50+ QVariant action;
51+ Qt::TextElideMode secondaryElide = Qt::ElideRight;
52+ bool addToRecents = true ;
53+ bool includeUnfiltered = true ;
54+ int score = 0 ;
2755};
2856
57+
58+ /* !
59+
60+ \ingroup commandpalette
61+ */
62+ struct BINARYNINJAUIAPI CommandListItemSearchInfo
63+ {
64+ std::unordered_set<CommandListItem::CommandListItemType> types;
65+ QString name;
66+ QString searchName;
67+ std::string prefix;
68+ QKeySequence shortcut;
69+
70+ static std::vector<CommandListItemSearchInfo> GetSearchTypes ();
71+ };
72+
73+
2974class CommandPalette ;
3075class CommandListFilter ;
3176
77+ class CommandListGenerateWorker : public QObject
78+ {
79+ Q_OBJECT
80+
81+ BinaryViewRef m_view;
82+ bool m_aborted;
83+ int m_request;
84+ std::shared_ptr<std::atomic_int> m_latestRequest;
85+
86+ bool m_pending;
87+ std::vector<CommandListItem> m_pendingItems;
88+ std::mutex m_pendingItemsMutex;
89+
90+ public:
91+ explicit CommandListGenerateWorker (QObject* parent, std::shared_ptr<std::atomic_int> request, const UIActionContext& context);
92+ virtual ~CommandListGenerateWorker ();
93+
94+ Q_SIGNALS:
95+ void dataFetched (int request, const std::vector<CommandListItem>& items);
96+ void noMoreDataToFetch (int request);
97+ void workFinished (int request);
98+
99+ public Q_SLOTS:
100+ void fetchMore ();
101+ void start ();
102+ void abort ();
103+ };
104+
105+
106+ class CommandListScoreWorker : public QObject
107+ {
108+ public:
109+ enum OrderStrategy
110+ {
111+ DefaultOrder,
112+ ScoreOrder
113+ };
114+
115+ private:
116+ Q_OBJECT
117+
118+ bool m_aborted;
119+ int m_request;
120+ std::shared_ptr<std::atomic_int> m_latestRequest;
121+ QString m_filter;
122+ std::shared_ptr<std::vector<CommandListItem>> m_items;
123+ std::vector<int > m_oldItemScores;
124+ OrderStrategy m_strategy;
125+
126+ bool m_pending;
127+ std::vector<std::pair<CommandListItem*, int >> m_pendingItems;
128+ std::mutex m_pendingItemsMutex;
129+
130+ public:
131+ explicit CommandListScoreWorker (
132+ QObject* parent,
133+ std::shared_ptr<std::atomic_int> request,
134+ QString filter,
135+ std::shared_ptr<std::vector<CommandListItem>> items,
136+ OrderStrategy orderStrategy
137+ );
138+ virtual ~CommandListScoreWorker ();
139+
140+ Q_SIGNALS:
141+ void dataFetched (int request, const std::vector<std::pair<CommandListItem*, int >>& items);
142+ void noMoreDataToFetch (int request);
143+ void workFinished (int request);
144+
145+ public Q_SLOTS:
146+ void fetchMore ();
147+ void start ();
148+ void abort ();
149+ };
150+
32151
33152/* !
34153
@@ -54,17 +173,40 @@ class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel
54173{
55174 Q_OBJECT
56175
57- std::vector<CommandListItem> m_items ;
58- std::vector<CommandListItem> m_allItems ;
176+ UIActionHandler* m_handler ;
177+ UIActionContext m_context ;
59178
60- std::vector<QString> m_recentItems;
61- size_t m_maxRecentItems;
179+ std::shared_ptr<std::vector<CommandListItem>> m_allItems;
180+ std::vector<CommandListItem*> m_displayItems; // pointers into m_allItems
181+ QString m_filterText;
182+ bool m_updatesPaused;
62183
63- bool isFilterMatch (const QString& name, const QString& filter);
64- int getFilterMatchScore (const QString& name, const QString& filter);
184+ std::vector<CommandListItem> m_recentItems;
65185
66- public:
67- CommandListModel (QWidget* parent, const std::vector<CommandListItem>& items);
186+ QThread m_generateWorkerThread;
187+ CommandListGenerateWorker* m_generateWorker;
188+ std::shared_ptr<std::atomic_int> m_generateWorkerRequest;
189+ QTimer m_generateFetchTimer;
190+ bool m_generateMoreToFetch;
191+
192+ QTimer m_scoreTimer;
193+ QMetaObject::Connection m_scoreTimerConnection;
194+
195+ QThread m_scoreWorkerThread;
196+ CommandListScoreWorker* m_scoreWorker;
197+ std::shared_ptr<std::atomic_int> m_scoreWorkerRequest;
198+ QTimer m_scoreFetchTimer;
199+ bool m_scoreMoreToFetch;
200+
201+ void loadRecentItems ();
202+ std::vector<CommandListItem> generateFastCommandList ();
203+ void sortCommandList (std::vector<CommandListItem>& list);
204+ void mergeCommandList (std::vector<CommandListItem>& output, std::vector<CommandListItem>&& input);
205+ void startScoreListThread ();
206+
207+ public:
208+ CommandListModel (QWidget* parent);
209+ ~CommandListModel ();
68210
69211 virtual QModelIndex index (int row, int col, const QModelIndex& parent) const override ;
70212 virtual QModelIndex parent (const QModelIndex& i) const override ;
@@ -73,10 +215,33 @@ class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel
73215 virtual int columnCount (const QModelIndex& parent) const override ;
74216 virtual QVariant data (const QModelIndex& i, int role) const override ;
75217
76- QString getActionForItem (int row);
218+ CommandListItem getItem (int row);
77219 void setFilterText (const QString& text);
78- size_t getRecentPosition (const QString& name) const ;
79- void addRecentItem (const QString& name);
220+ size_t getRecentPosition (const CommandListItem& item) const ;
221+ void addRecentItem (const CommandListItem& item);
222+
223+ void clearCommandList ();
224+ void generateCommandList (UIActionHandler* handler, const UIActionContext& context);
225+ void cancelGenerateCommandList ();
226+
227+ void scoreCommandList (CommandListScoreWorker::OrderStrategy strategy);
228+ void cancelScoreCommandList ();
229+
230+ void pauseCommandListUpdates ();
231+ void unpauseCommandListUpdates ();
232+
233+ void updateDisplayedItems ();
234+
235+ private Q_SLOTS:
236+ void generateFetch ();
237+ void itemsGenerated (int request, const std::vector<CommandListItem>& items);
238+ void itemsFinishedGenerating (int request);
239+ void generateWorkFinished (int request);
240+
241+ void scoreFetch ();
242+ void itemsScored (int request, const std::vector<std::pair<CommandListItem*, int >>& items);
243+ void itemsFinishedScoring (int request);
244+ void scoreWorkFinished (int request);
80245};
81246
82247/* !
@@ -92,14 +257,21 @@ class BINARYNINJAUIAPI CommandList : public QListView
92257 CommandListFilter* m_filter;
93258
94259 public:
95- CommandList (CommandPalette* parent, const std::vector<CommandListItem>& items );
260+ CommandList (CommandPalette* parent);
96261 void setFilter (CommandListFilter* filter) { m_filter = filter; }
97262 void setFilterText (const QString& text);
98263
99- QString getActionForItem (int row);
264+ CommandListItem getItem (int row);
100265
101266 QModelIndex index (int row, int col, const QModelIndex& parent = QModelIndex()) const ;
102- void addRecentItem (const QString& name);
267+ void addRecentItem (const CommandListItem& item);
268+
269+ void clearCommandList ();
270+ void generateCommandList (UIActionHandler* handler, const UIActionContext& context);
271+ void cancelGenerateCommandList ();
272+
273+ void pauseCommandListUpdates ();
274+ void unpauseCommandListUpdates ();
103275
104276 protected:
105277 virtual void keyPressEvent (QKeyEvent* event) override ;
@@ -126,7 +298,9 @@ class BINARYNINJAUIAPI CommandListFilter : public QLineEdit
126298 protected:
127299 bool event (QEvent* event) override ;
128300 virtual void keyPressEvent (QKeyEvent* event) override ;
301+ virtual void focusInEvent (QFocusEvent* event) override ;
129302 virtual void focusOutEvent (QFocusEvent* event) override ;
303+ virtual void paintEvent (QPaintEvent* event) override ;
130304};
131305
132306/* !
@@ -139,26 +313,31 @@ class BINARYNINJAUIAPI CommandPalette : public QFrame
139313
140314 UIActionHandler* m_handler;
141315 UIActionContext m_context;
316+
142317 QPointer<QWidget> m_previousWidget;
143318
144319 CommandListFilter* m_filter;
145320 CommandList* m_list;
321+ std::optional<CommandListItem> m_savedTop;
146322
147323 bool m_executing;
148324
149- std::vector<CommandListItem> getCommandList ();
150325 void init ();
151326
152327 public:
153- CommandPalette (QWidget* parent, UIActionHandler* handler);
154- CommandPalette (QWidget* parent, UIActionHandler* handler, const UIActionContext& context);
328+ CommandPalette (QWidget* parent);
155329
330+ void openWithInput (const QString& text);
156331 void focusInput ();
157332
333+ void clearCommandList ();
334+ void generateCommandList (UIActionHandler* handler, const UIActionContext& context);
335+
158336 // ! Activate the focused item, or topmost item if there is no selection.
159337 void activateFocusedItem ();
160338 void selectFirstItem ();
161339 void close (bool restoreFocus = true );
340+ void activateItem (const CommandListItem& item);
162341
163342 private Q_SLOTS:
164343 void itemClicked (const QModelIndex& idx);
0 commit comments