package jadx.gui.ui;
import jadx.gui.utils.NLS;
import jadx.gui.utils.Utils;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.text.BadLocationException;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.SearchContext;
import org.fife.ui.rtextarea.SearchEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class SearchBar extends JToolBar {
private static final long serialVersionUID = 1836871286618633003L;
private static final Logger LOG = LoggerFactory.getLogger(SearchDialog.class);
private static final Color COLOR_BG_ERROR = new Color(0xFFDFDE);
private static final Color COLOR_BG_WARN = new Color(0xFFFDD9);
private static final Color COLOR_BG_NORMAL = new Color(0xFFFFFF);
private static final Icon ICON_UP = Utils.openIcon("arrow_up");
private static final Icon ICON_DOWN = Utils.openIcon("arrow_down");
private static final Icon ICON_CLOSE = Utils.openIcon("cross");
private final RSyntaxTextArea rTextArea;
private final JTextField searchField;
private final JCheckBox markAllCB;
private final JCheckBox regexCB;
private final JCheckBox wholeWordCB;
private final JCheckBox matchCaseCB;
public SearchBar(RSyntaxTextArea textArea) {
rTextArea = textArea;
JLabel findLabel = new JLabel(NLS.str("search.find") + ":");
add(findLabel);
searchField = new JTextField(30);
searchField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ENTER:
// skip
break;
case KeyEvent.VK_ESCAPE:
toggle();
break;
default:
search(0);
break;
}
}
});
searchField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
search(1);
}
});
add(searchField);
JButton prevButton = new JButton(NLS.str("search.previous"));
prevButton.setIcon(ICON_UP);
prevButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
search(-1);
}
});
prevButton.setBorderPainted(false);
add(prevButton);
JButton nextButton = new JButton(NLS.str("search.next"));
nextButton.setIcon(ICON_DOWN);
nextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
search(1);
}
});
nextButton.setBorderPainted(false);
add(nextButton);
markAllCB = new JCheckBox(NLS.str("search.mark_all"));
markAllCB.addActionListener(new ForwardListener());
add(markAllCB);
regexCB = new JCheckBox(NLS.str("search.regex"));
regexCB.addActionListener(new ForwardListener());
add(regexCB);
matchCaseCB = new JCheckBox(NLS.str("search.match_case"));
matchCaseCB.addActionListener(new ForwardListener());
add(matchCaseCB);
wholeWordCB = new JCheckBox(NLS.str("search.whole_word"));
wholeWordCB.addActionListener(new ForwardListener());
add(wholeWordCB);
JButton closeButton = new JButton();
closeButton.setIcon(ICON_CLOSE);
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
toggle();
}
});
closeButton.setBorderPainted(false);
add(closeButton);
setFloatable(false);
setVisible(false);
}
public boolean toggle() {
boolean visible = !isVisible();
setVisible(visible);
if (visible) {
searchField.requestFocus();
searchField.selectAll();
} else {
rTextArea.requestFocus();
}
return visible;
}
private void search(int direction) {
String searchText = searchField.getText();
if (searchText == null
|| searchText.length() == 0
|| rTextArea.getText() == null) {
return;
}
boolean forward = direction >= 0;
boolean matchCase = matchCaseCB.isSelected();
boolean regex = regexCB.isSelected();
boolean wholeWord = wholeWordCB.isSelected();
if (markAllCB.isSelected()) {
rTextArea.markAll(searchText, matchCase, wholeWord, regex);
} else {
rTextArea.clearMarkAllHighlights();
}
SearchContext context = new SearchContext();
context.setSearchFor(searchText);
context.setMatchCase(matchCase);
context.setRegularExpression(regex);
context.setSearchForward(forward);
context.setWholeWord(wholeWord);
// TODO hack: move cursor before previous search for not jump to next occurrence
if (direction == 0 && !COLOR_BG_ERROR.equals(searchField.getBackground())) {
try {
int caretPos = rTextArea.getCaretPosition();
int lineNum = rTextArea.getLineOfOffset(caretPos) - 1;
if (lineNum > 1) {
rTextArea.setCaretPosition(rTextArea.getLineStartOffset(lineNum));
}
} catch (BadLocationException e) {
LOG.error("Caret move error", e);
}
}
boolean found = SearchEngine.find(rTextArea, context);
if (!found) {
int pos = SearchEngine.getNextMatchPos(searchText, rTextArea.getText(), forward, matchCase, wholeWord);
if (pos != -1) {
rTextArea.setCaretPosition(forward ? 0 : rTextArea.getDocument().getLength() - 1);
search(direction);
searchField.setBackground(COLOR_BG_WARN);
return;
}
searchField.setBackground(COLOR_BG_ERROR);
} else {
searchField.setBackground(COLOR_BG_NORMAL);
}
}
private class ForwardListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
search(0);
}
}
}