diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java index 9b3317474..69d75bbb2 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java @@ -43,6 +43,8 @@ public class JadxProject { private static final int CURRENT_PROJECT_VERSION = 1; public static final String PROJECT_EXTENSION = "jadx"; + private static final int SEARCH_HISTORY_LIMIT = 30; + private final transient MainWindow mainWindow; private transient String name = "New Project"; @@ -195,6 +197,27 @@ public class JadxProject { } } + public List getSearchHistory() { + return data.getSearchHistory(); + } + + public void addToSearchHistory(String str) { + if (str == null || str.isEmpty()) { + return; + } + List list = data.getSearchHistory(); + if (!list.isEmpty() && list.get(0).equals(str)) { + return; + } + list.remove(str); + list.add(0, str); + if (list.size() > SEARCH_HISTORY_LIMIT) { + list.remove(list.size() - 1); + } + data.setSearchHistory(list); + changed(); + } + private void changed() { JadxSettings settings = mainWindow.getSettings(); if (settings != null && settings.isAutoSaveProject()) { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/data/ProjectData.java b/jadx-gui/src/main/java/jadx/gui/settings/data/ProjectData.java index 536d3b0bf..7256dca32 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/data/ProjectData.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/data/ProjectData.java @@ -20,6 +20,7 @@ public class ProjectData { private int activeTab = -1; private @Nullable Path cacheDir; private boolean enableLiveReload = false; + private List searchHistory = new ArrayList<>(); public List getFiles() { return files; @@ -103,4 +104,12 @@ public class ProjectData { public void setEnableLiveReload(boolean enableLiveReload) { this.enableLiveReload = enableLiveReload; } + + public List getSearchHistory() { + return searchHistory; + } + + public void setSearchHistory(List searchHistory) { + this.searchHistory = searchHistory; + } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/SearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/SearchDialog.java index c927aea53..d79e10f81 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/SearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/SearchDialog.java @@ -20,7 +20,9 @@ import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; +import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JTextField; import javax.swing.WindowConstants; import javax.swing.event.ChangeListener; @@ -29,6 +31,9 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.icons.FlatSearchWithHistoryIcon; + import io.reactivex.BackpressureStrategy; import io.reactivex.Emitter; import io.reactivex.Flowable; @@ -207,6 +212,8 @@ public class SearchDialog extends CommonSearchDialog { searchFieldDefaultBgColor = searchField.getBackground(); searchField.setAlignmentX(LEFT_ALIGNMENT); TextStandardActions.attach(searchField); + addSearchHistoryButton(); + searchField.putClientProperty(FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true); boolean autoSearch = mainWindow.getSettings().isUseAutoSearch(); JButton searchBtn = new JButton(NLS.str("search_dialog.search_button")); @@ -286,6 +293,25 @@ public class SearchDialog extends CommonSearchDialog { setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } + private void addSearchHistoryButton() { + JButton searchHistoryButton = new JButton(new FlatSearchWithHistoryIcon(true)); + searchHistoryButton.setToolTipText(NLS.str("search_dialog.search_history")); + searchHistoryButton.addActionListener(e -> { + JPopupMenu popupMenu = new JPopupMenu(); + List searchHistory = mainWindow.getProject().getSearchHistory(); + if (searchHistory.isEmpty()) { + popupMenu.add("(empty)"); + } else { + for (String str : searchHistory) { + JMenuItem item = popupMenu.add(str); + item.addActionListener(ev -> searchField.setText(str)); + } + } + popupMenu.show(searchHistoryButton, 0, searchHistoryButton.getHeight()); + }); + searchField.putClientProperty(FlatClientProperties.TEXT_FIELD_LEADING_COMPONENT, searchHistoryButton); + } + protected void addResultsActions(JPanel resultsActionsPanel) { loadAllButton = new JButton(NLS.str("search_dialog.load_all")); loadAllButton.addActionListener(e -> loadMoreResults(true)); @@ -463,6 +489,15 @@ public class SearchDialog extends CommonSearchDialog { return true; } + @Override + protected void openItem(JNode node) { + if (mainWindow.getSettings().isUseAutoSearch()) { + // for auto search save only searches which leads to node opening + mainWindow.getProject().addToSearchHistory(searchField.getText()); + } + super.openItem(node); + } + private void pauseSearch() { stopBtn.setEnabled(false); searchBackgroundExecutor.execute(() -> { @@ -539,6 +574,9 @@ public class SearchDialog extends CommonSearchDialog { updateHighlightContext(text, !options.contains(IGNORE_CASE), options.contains(USE_REGEX)); cache.setLastSearch(text); cache.getLastSearchOptions().put(searchPreset, options); + if (!mainWindow.getSettings().isUseAutoSearch()) { + mainWindow.getProject().addToSearchHistory(text); + } } private void updateProgress(ITaskProgress progress) { diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index db6a43c25..665121178 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -97,6 +97,7 @@ search_dialog.open=Öffnen search_dialog.cancel=Beenden search_dialog.open_by_name=Nach Text suchen: #search_dialog.search_button=Search +#search_dialog.search_history=Search history #search_dialog.auto_search=Auto search search_dialog.search_in=Suche in Definitionen von: search_dialog.class=Klassen diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 80a61221a..d6419f7d3 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -97,6 +97,7 @@ search_dialog.open=Open search_dialog.cancel=Cancel search_dialog.open_by_name=Search for text: search_dialog.search_button=Search +search_dialog.search_history=Search history search_dialog.auto_search=Auto search search_dialog.search_in=Search definitions of: search_dialog.class=Class diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index 6179ae9ed..343ab3564 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -97,6 +97,7 @@ search_dialog.open=Abrir search_dialog.cancel=Cancelar search_dialog.open_by_name=Buscar texto: #search_dialog.search_button=Search +#search_dialog.search_history=Search history #search_dialog.auto_search=Auto search search_dialog.search_in=Buscar definiciones de: search_dialog.class=Clase diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index 223b5b6be..40e908c7f 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -97,6 +97,7 @@ search_dialog.open=열기 search_dialog.cancel=취소 search_dialog.open_by_name=텍스트 검색 : #search_dialog.search_button=Search +#search_dialog.search_history=Search history #search_dialog.auto_search=Auto search search_dialog.search_in=정의 검색 : search_dialog.class=클래스 diff --git a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties index a189e6d44..d560c40ea 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties @@ -97,6 +97,7 @@ search_dialog.open=Abrir search_dialog.cancel=Cancelar search_dialog.open_by_name=Buscar por text: #search_dialog.search_button=Search +#search_dialog.search_history=Search history #search_dialog.auto_search=Auto search search_dialog.search_in=Buscar definições de: search_dialog.class=Classe diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index 22b68f970..a9331d8d5 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -97,6 +97,7 @@ search_dialog.open=转到 search_dialog.cancel=取消 search_dialog.open_by_name=搜索文本: #search_dialog.search_button=Search +#search_dialog.search_history=Search history #search_dialog.auto_search=Auto search search_dialog.search_in=在以下位置搜索: search_dialog.class=类名 diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties index 1643daa25..c8190b9a2 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties @@ -97,6 +97,7 @@ search_dialog.open=開啟 search_dialog.cancel=取消 search_dialog.open_by_name=搜尋文字: #search_dialog.search_button=Search +#search_dialog.search_history=Search history #search_dialog.auto_search=Auto search search_dialog.search_in=搜尋定義: search_dialog.class=類別