diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 3de9f3495..0e41f909b 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -7,6 +7,7 @@ import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JResource; import jadx.gui.treemodel.JRoot; +import jadx.gui.ui.SearchDialog.SearchOptions; import jadx.gui.update.JadxUpdate; import jadx.gui.update.JadxUpdate.IUpdateCallback; import jadx.gui.update.data.Release; @@ -16,9 +17,10 @@ import jadx.gui.utils.NLS; import jadx.gui.utils.Position; import jadx.gui.utils.Utils; +import javax.swing.AbstractAction; +import javax.swing.Action; import javax.swing.Box; import javax.swing.ImageIcon; -import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -60,10 +62,13 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.Arrays; +import java.util.EnumSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static javax.swing.KeyStroke.getKeyStroke; + @SuppressWarnings("serial") public class MainWindow extends JFrame { private static final Logger LOG = LoggerFactory.getLogger(MainWindow.class); @@ -181,7 +186,7 @@ public class MainWindow extends JFrame { } } - private void saveAllAction() { + private void saveAll() { JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileChooser.setToolTipText(NLS.str("file.save_all_msg")); @@ -273,137 +278,150 @@ public class MainWindow extends JFrame { TreePath path = new TreePath(pathNodes); tree.setSelectionPath(path); tree.makeVisible(path); - } - - private void toggleFind() { - ContentPanel contentPanel = tabbedPane.getSelectedCodePanel(); - if (contentPanel != null) { - contentPanel.getSearchBar().toggle(); - } + tree.requestFocus(); } private void initMenuAndToolbar() { - JMenuBar menuBar = new JMenuBar(); - - JMenu file = new JMenu(NLS.str("menu.file")); - file.setMnemonic(KeyEvent.VK_F); - - JMenuItem exit = new JMenuItem(NLS.str("file.exit"), ICON_CLOSE); - exit.setMnemonic(KeyEvent.VK_E); - exit.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - dispose(); - } - }); - - JMenuItem open = new JMenuItem(NLS.str("file.open"), ICON_OPEN); - open.setMnemonic(KeyEvent.VK_O); - open.addActionListener(new OpenListener()); - - JMenuItem saveAll = new JMenuItem(NLS.str("file.save_all"), ICON_SAVE_ALL); - saveAll.setMnemonic(KeyEvent.VK_S); - saveAll.addActionListener(new ActionListener() { + Action openAction = new AbstractAction(NLS.str("file.open"), ICON_OPEN) { @Override public void actionPerformed(ActionEvent e) { - saveAllAction(); + openFile(); } - }); + }; + openAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.open")); + openAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK)); + + Action saveAllAction = new AbstractAction(NLS.str("file.save_all"), ICON_SAVE_ALL) { + @Override + public void actionPerformed(ActionEvent e) { + saveAll(); + } + }; + saveAllAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.save_all")); + saveAllAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK)); JMenu recentFiles = new JMenu(NLS.str("menu.recent_files")); recentFiles.addMenuListener(new RecentFilesMenuListener(recentFiles)); - JMenuItem preferences = new JMenuItem(NLS.str("menu.preferences"), ICON_PREF); - ActionListener prefAction = new ActionListener() { - public void actionPerformed(ActionEvent event) { - final JadxSettingsWindow dialog = new JadxSettingsWindow(MainWindow.this, settings); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }); + Action prefsAction = new AbstractAction(NLS.str("menu.preferences"), ICON_PREF) { + @Override + public void actionPerformed(ActionEvent e) { + new JadxSettingsWindow(MainWindow.this, settings).setVisible(true); } }; - preferences.addActionListener(prefAction); + prefsAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.preferences")); + prefsAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_P, + KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); - file.add(open); - file.add(saveAll); - file.addSeparator(); - file.add(recentFiles); - file.addSeparator(); - file.add(preferences); - file.addSeparator(); - file.add(exit); - - JMenu view = new JMenu(NLS.str("menu.view")); - view.setMnemonic(KeyEvent.VK_V); + Action exitAction = new AbstractAction(NLS.str("file.exit"), ICON_CLOSE) { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }; isFlattenPackage = settings.isFlattenPackage(); - flatPkgMenuItem = new JCheckBoxMenuItem(NLS.str("menu.flatten"), ICON_FLAT_PKG); - view.add(flatPkgMenuItem); flatPkgMenuItem.setState(isFlattenPackage); - JMenuItem syncItem = new JMenuItem(NLS.str("menu.sync"), ICON_SYNC); - view.add(syncItem); - syncItem.addActionListener(new ActionListener() { + Action syncAction = new AbstractAction(NLS.str("menu.sync"), ICON_SYNC) { @Override public void actionPerformed(ActionEvent e) { syncWithEditor(); } - }); - - JMenu nav = new JMenu(NLS.str("menu.navigation")); - nav.setMnemonic(KeyEvent.VK_N); - - JMenuItem search = new JMenuItem(NLS.str("menu.search"), ICON_SEARCH); - nav.add(search); - ActionListener searchAction = new ActionListener() { - public void actionPerformed(ActionEvent event) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - SearchDialog dialog = new SearchDialog(MainWindow.this, tabbedPane, wrapper); - dialog.setVisible(true); - } - }); - } }; - search.addActionListener(searchAction); + syncAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.sync")); + syncAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK)); - JMenuItem find = new JMenuItem(NLS.str("menu.find_in_file"), ICON_FIND); - nav.add(find); - ActionListener findAction = new ActionListener() { + Action textSearchAction = new AbstractAction(NLS.str("menu.text_search"), ICON_SEARCH) { @Override public void actionPerformed(ActionEvent e) { - toggleFind(); + new SearchDialog(MainWindow.this, EnumSet.of(SearchOptions.CODE)).setVisible(true); } }; - find.addActionListener(findAction); + textSearchAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.text_search")); + textSearchAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_F, + KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); - JMenu tools = new JMenu(NLS.str("menu.tools")); - tools.setMnemonic(KeyEvent.VK_T); + Action clsSearchAction = new AbstractAction(NLS.str("menu.class_search"), ICON_FIND) { + @Override + public void actionPerformed(ActionEvent e) { + new SearchDialog(MainWindow.this, EnumSet.of(SearchOptions.CLASS)).setVisible(true); + } + }; + clsSearchAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.class_search")); + clsSearchAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK)); - JMenuItem logItem = new JMenuItem(NLS.str("menu.log"), ICON_LOG); - ActionListener logAction = new ActionListener() { + Action logAction = new AbstractAction(NLS.str("menu.log"), ICON_LOG) { @Override public void actionPerformed(ActionEvent e) { new LogViewer().setVisible(true); } }; - logItem.addActionListener(logAction); - tools.add(logItem); + logAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.log")); + logAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_L, + KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK)); + + Action aboutAction = new AbstractAction(NLS.str("menu.about")) { + @Override + public void actionPerformed(ActionEvent e) { + new AboutDialog().setVisible(true); + } + }; + + Action backAction = new AbstractAction(NLS.str("nav.back"), ICON_BACK) { + @Override + public void actionPerformed(ActionEvent e) { + tabbedPane.navBack(); + } + }; + backAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("nav.back")); + backAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_LEFT, + KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); + + Action forwardAction = new AbstractAction(NLS.str("nav.forward"), ICON_FORWARD) { + @Override + public void actionPerformed(ActionEvent e) { + tabbedPane.navForward(); + } + }; + forwardAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("nav.forward")); + forwardAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_RIGHT, + KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)); + + JMenu file = new JMenu(NLS.str("menu.file")); + file.setMnemonic(KeyEvent.VK_F); + file.add(openAction); + file.add(saveAllAction); + file.addSeparator(); + file.add(recentFiles); + file.addSeparator(); + file.add(prefsAction); + file.addSeparator(); + file.add(exitAction); + + JMenu view = new JMenu(NLS.str("menu.view")); + view.setMnemonic(KeyEvent.VK_V); + view.add(flatPkgMenuItem); + view.add(syncAction); + + JMenu nav = new JMenu(NLS.str("menu.navigation")); + nav.setMnemonic(KeyEvent.VK_N); + nav.add(textSearchAction); + nav.add(clsSearchAction); + nav.addSeparator(); + nav.add(backAction); + nav.add(forwardAction); + + JMenu tools = new JMenu(NLS.str("menu.tools")); + tools.setMnemonic(KeyEvent.VK_T); + tools.add(logAction); JMenu help = new JMenu(NLS.str("menu.help")); help.setMnemonic(KeyEvent.VK_H); + help.add(aboutAction); - JMenuItem about = new JMenuItem(NLS.str("menu.about")); - help.add(about); - about.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - AboutDialog ad = new AboutDialog(); - ad.setVisible(true); - } - }); - + JMenuBar menuBar = new JMenuBar(); menuBar.add(file); menuBar.add(view); menuBar.add(nav); @@ -411,28 +429,6 @@ public class MainWindow extends JFrame { menuBar.add(help); setJMenuBar(menuBar); - final JButton openButton = new JButton(ICON_OPEN); - openButton.addActionListener(new OpenListener()); - openButton.setToolTipText(NLS.str("file.open")); - - final JButton saveAllButton = new JButton(ICON_SAVE_ALL); - saveAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - saveAllAction(); - } - }); - saveAllButton.setToolTipText(NLS.str("file.save_all")); - - final JButton syncButton = new JButton(ICON_SYNC); - syncButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - syncWithEditor(); - } - }); - syncButton.setToolTipText(NLS.str("menu.sync")); - flatPkgButton = new JToggleButton(ICON_FLAT_PKG); flatPkgButton.setSelected(isFlattenPackage); ActionListener flatPkgAction = new ActionListener() { @@ -441,41 +437,10 @@ public class MainWindow extends JFrame { toggleFlattenPackage(); } }; - flatPkgButton.addActionListener(flatPkgAction); flatPkgMenuItem.addActionListener(flatPkgAction); - + flatPkgButton.addActionListener(flatPkgAction); flatPkgButton.setToolTipText(NLS.str("menu.flatten")); - final JButton searchButton = new JButton(ICON_SEARCH); - searchButton.addActionListener(searchAction); - searchButton.setToolTipText(NLS.str("menu.search")); - - final JButton findButton = new JButton(ICON_FIND); - findButton.addActionListener(findAction); - findButton.setToolTipText(NLS.str("menu.find_in_file")); - - final JButton backButton = new JButton(ICON_BACK); - backButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - tabbedPane.navBack(); - } - }); - backButton.setToolTipText(NLS.str("nav.back")); - - final JButton forwardButton = new JButton(ICON_FORWARD); - forwardButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - tabbedPane.navForward(); - } - }); - forwardButton.setToolTipText(NLS.str("nav.forward")); - - final JButton prefButton = new JButton(ICON_PREF); - prefButton.addActionListener(prefAction); - prefButton.setToolTipText(NLS.str("menu.preferences")); - deobfToggleBtn = new JToggleButton(ICON_DEOBF); deobfToggleBtn.setSelected(settings.isDeobfuscationOn()); deobfToggleBtn.setToolTipText(NLS.str("preferences.deobfuscation")); @@ -488,41 +453,29 @@ public class MainWindow extends JFrame { } }); - JButton logBtn = new JButton(ICON_LOG); - logBtn.setToolTipText(NLS.str("menu.log")); - logBtn.addActionListener(logAction); - updateLink = new Link("", JadxUpdate.JADX_RELEASES_URL); updateLink.setVisible(false); JToolBar toolbar = new JToolBar(); toolbar.setFloatable(false); - - toolbar.add(openButton); - toolbar.add(saveAllButton); + toolbar.add(openAction); + toolbar.add(saveAllAction); toolbar.addSeparator(); - - toolbar.add(syncButton); + toolbar.add(syncAction); toolbar.add(flatPkgButton); toolbar.addSeparator(); - - toolbar.add(searchButton); - toolbar.add(findButton); + toolbar.add(textSearchAction); + toolbar.add(clsSearchAction); toolbar.addSeparator(); - - toolbar.add(backButton); - toolbar.add(forwardButton); + toolbar.add(backAction); + toolbar.add(forwardAction); toolbar.addSeparator(); - toolbar.add(deobfToggleBtn); toolbar.addSeparator(); - - toolbar.add(logBtn); + toolbar.add(logAction); toolbar.addSeparator(); - - toolbar.add(prefButton); + toolbar.add(prefsAction); toolbar.addSeparator(); - toolbar.add(Box.createHorizontalGlue()); toolbar.add(updateLink); @@ -605,6 +558,14 @@ public class MainWindow extends JFrame { tabbedPane.loadSettings(); } + public JadxWrapper getWrapper() { + return wrapper; + } + + public TabbedPane getTabbedPane() { + return tabbedPane; + } + public JadxSettings getSettings() { return settings; } @@ -613,12 +574,6 @@ public class MainWindow extends JFrame { return cacheObject; } - private class OpenListener implements ActionListener { - public void actionPerformed(ActionEvent event) { - openFile(); - } - } - private class RecentFilesMenuListener implements MenuListener { private final JMenu recentFiles; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java index f6237b598..4f0a959ed 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java @@ -16,6 +16,7 @@ import javax.swing.BoxLayout; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; +import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; @@ -23,6 +24,7 @@ import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextField; +import javax.swing.KeyStroke; import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -61,14 +63,14 @@ public class SearchDialog extends JDialog { private static final Logger LOG = LoggerFactory.getLogger(SearchDialog.class); private static final int MAX_RESULTS_COUNT = 500; - private enum SearchOptions { + enum SearchOptions { CLASS, METHOD, FIELD, CODE } - private static final Set OPTIONS = EnumSet.allOf(SearchOptions.class); + private Set options = EnumSet.allOf(SearchOptions.class); private final TabbedPane tabbedPane; private final JadxWrapper wrapper; @@ -79,11 +81,12 @@ public class SearchDialog extends JDialog { private JList resultsList; private JProgressBar busyBar; - public SearchDialog(MainWindow mainWindow, TabbedPane tabbedPane, JadxWrapper wrapper) { + public SearchDialog(MainWindow mainWindow, Set options) { super(mainWindow); - this.tabbedPane = tabbedPane; - this.wrapper = wrapper; + this.tabbedPane = mainWindow.getTabbedPane(); + this.wrapper = mainWindow.getWrapper(); this.cache = mainWindow.getCacheObject(); + this.options = options; initUI(); addWindowListener(new WindowAdapter() { @@ -93,6 +96,7 @@ public class SearchDialog extends JDialog { @Override public void run() { prepare(); + searchField.requestFocus(); } }); } @@ -126,23 +130,23 @@ public class SearchDialog extends JDialog { private synchronized void performSearch() { resultsModel.removeAllElements(); String text = searchField.getText(); - if (text == null || text.isEmpty() || OPTIONS.isEmpty()) { + if (text == null || text.isEmpty() || options.isEmpty()) { return; } TextSearchIndex index = cache.getTextIndex(); if (index == null) { return; } - if (OPTIONS.contains(SearchOptions.CLASS)) { + if (options.contains(SearchOptions.CLASS)) { resultsModel.addAll(index.searchClsName(text)); } - if (OPTIONS.contains(SearchOptions.METHOD)) { + if (options.contains(SearchOptions.METHOD)) { resultsModel.addAll(index.searchMthName(text)); } - if (OPTIONS.contains(SearchOptions.FIELD)) { + if (options.contains(SearchOptions.FIELD)) { resultsModel.addAll(index.searchFldName(text)); } - if (OPTIONS.contains(SearchOptions.CODE)) { + if (options.contains(SearchOptions.CODE)) { resultsModel.addAll(index.searchCode(text)); } LOG.info("Search returned {} results", resultsModel.size()); @@ -321,7 +325,7 @@ public class SearchDialog extends JDialog { buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); buttonPane.add(cancelButton); - final Container contentPane = getContentPane(); + Container contentPane = getContentPane(); contentPane.add(searchPane, BorderLayout.PAGE_START); contentPane.add(listPane, BorderLayout.CENTER); contentPane.add(buttonPane, BorderLayout.PAGE_END); @@ -339,7 +343,15 @@ public class SearchDialog extends JDialog { } }); - setTitle(NLS.str("menu.search")); + KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); + getRootPane().registerKeyboardAction(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW); + + setTitle(NLS.str("menu.text_search")); pack(); setSize(700, 500); setLocationRelativeTo(null); @@ -350,13 +362,13 @@ public class SearchDialog extends JDialog { private JCheckBox makeOptionsCheckBox(String name, final SearchOptions opt) { final JCheckBox chBox = new JCheckBox(name); chBox.setAlignmentX(LEFT_ALIGNMENT); - chBox.setSelected(OPTIONS.contains(opt)); + chBox.setSelected(options.contains(opt)); chBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (chBox.isSelected()) { - OPTIONS.add(opt); + options.add(opt); } else { - OPTIONS.remove(opt); + options.remove(opt); } performSearch(); } 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 dcb29b10d..f76419885 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -6,8 +6,8 @@ menu.preferences=Preferences menu.sync=Sync with editor menu.flatten=Show flatten packages menu.navigation=Navigation -menu.search=Search ... -menu.find_in_file=Find in ... +menu.text_search=Text search +menu.class_search=Class search menu.tools=Tools menu.log=Log Viewer menu.help=Help @@ -15,7 +15,6 @@ menu.about=About menu.update_label=New version %s available! file.open=Open file -file.save=Save file file.save_all=Save all file.save_all_msg=Select directory for save decompiled sources file.select=Select