package jadx.gui.ui; import jadx.gui.utils.NLS; import jadx.gui.utils.TextStandardActions; import jadx.gui.utils.search.TextSearchIndex; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.WindowConstants; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.EnumSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SearchDialog extends CommonSearchDialog { private static final long serialVersionUID = -5105405456969134105L; private static final Logger LOG = LoggerFactory.getLogger(SearchDialog.class); enum SearchOptions { CLASS, METHOD, FIELD, CODE } private Set<SearchOptions> options = EnumSet.allOf(SearchOptions.class); private JTextField searchField; public SearchDialog(MainWindow mainWindow, Set<SearchOptions> options) { super(mainWindow); this.options = options; initUI(); addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { openInit(); } }); } }); loadWindowPos(); } protected void openInit() { prepare(); String lastSearch = cache.getLastSearch(); if (lastSearch != null) { searchField.setText(lastSearch); searchField.selectAll(); } searchField.requestFocus(); } private synchronized void performSearch() { resultsModel.clear(); String text = searchField.getText(); if (text == null || text.isEmpty() || options.isEmpty()) { resultsTable.updateTable(); return; } cache.setLastSearch(text); TextSearchIndex index = cache.getTextIndex(); if (index == null) { resultsTable.updateTable(); return; } if (options.contains(SearchOptions.CLASS)) { resultsModel.addAll(index.searchClsName(text)); } if (options.contains(SearchOptions.METHOD)) { resultsModel.addAll(index.searchMthName(text)); } if (options.contains(SearchOptions.FIELD)) { resultsModel.addAll(index.searchFldName(text)); } if (options.contains(SearchOptions.CODE)) { resultsModel.addAll(index.searchCode(text)); } highlightText = text; resultsTable.updateTable(); } private class SearchFieldListener implements DocumentListener, ActionListener { private Timer timer; private synchronized void change() { if (timer != null) { timer.restart(); } else { timer = new Timer(300, this); timer.start(); } } @Override public void actionPerformed(ActionEvent e) { performSearch(); } public void changedUpdate(DocumentEvent e) { change(); } public void removeUpdate(DocumentEvent e) { change(); } public void insertUpdate(DocumentEvent e) { change(); } } private void initUI() { JLabel findLabel = new JLabel(NLS.str("search_dialog.open_by_name")); searchField = new JTextField(); searchField.setAlignmentX(LEFT_ALIGNMENT); searchField.getDocument().addDocumentListener(new SearchFieldListener()); new TextStandardActions(searchField); JCheckBox clsChBox = makeOptionsCheckBox(NLS.str("search_dialog.class"), SearchOptions.CLASS); JCheckBox mthChBox = makeOptionsCheckBox(NLS.str("search_dialog.method"), SearchOptions.METHOD); JCheckBox fldChBox = makeOptionsCheckBox(NLS.str("search_dialog.field"), SearchOptions.FIELD); JCheckBox codeChBox = makeOptionsCheckBox(NLS.str("search_dialog.code"), SearchOptions.CODE); JPanel searchOptions = new JPanel(new FlowLayout(FlowLayout.LEFT)); searchOptions.setBorder(BorderFactory.createTitledBorder(NLS.str("search_dialog.search_in"))); searchOptions.add(clsChBox); searchOptions.add(mthChBox); searchOptions.add(fldChBox); searchOptions.add(codeChBox); searchOptions.setAlignmentX(LEFT_ALIGNMENT); JPanel searchPane = new JPanel(); searchPane.setLayout(new BoxLayout(searchPane, BoxLayout.PAGE_AXIS)); findLabel.setLabelFor(searchField); searchPane.add(findLabel); searchPane.add(Box.createRigidArea(new Dimension(0, 5))); searchPane.add(searchField); searchPane.add(Box.createRigidArea(new Dimension(0, 5))); searchPane.add(searchOptions); searchPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); initCommon(); JPanel resultsPanel = initResultsTable(); JPanel buttonPane = initButtonsPanel(); Container contentPane = getContentPane(); contentPane.add(searchPane, BorderLayout.PAGE_START); contentPane.add(resultsPanel, BorderLayout.CENTER); contentPane.add(buttonPane, BorderLayout.PAGE_END); searchField.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { if (resultsModel.getRowCount() != 0) { resultsTable.setRowSelectionInterval(0, 0); } resultsTable.requestFocus(); } } }); setTitle(NLS.str("menu.text_search")); pack(); setSize(800, 500); setLocationRelativeTo(null); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setModalityType(ModalityType.MODELESS); } private JCheckBox makeOptionsCheckBox(String name, final SearchOptions opt) { final JCheckBox chBox = new JCheckBox(name); chBox.setAlignmentX(LEFT_ALIGNMENT); chBox.setSelected(options.contains(opt)); chBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (chBox.isSelected()) { options.add(opt); } else { options.remove(opt); } performSearch(); } }); return chBox; } @Override protected void loadFinished() { searchField.setEnabled(true); } @Override protected void loadStart() { searchField.setEnabled(false); } }