Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 09/20/2013
*
* FindToolBar - A tool bar for "find" operations in text areas.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.rsta.ui.search;
import java.awt.BorderLayout;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ResourceBundle;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
import org.fife.rsta.ui.AssistanceIconPanel;
import org.fife.rsta.ui.UIUtil;
import org.fife.ui.rtextarea.SearchContext;
/**
* A toolbar for search operations in a text editor application. This provides
* a more seamless experience than using a Find or Replace dialog.
*
* @author Robert Futrell
* @version 0.5
* @see FindDialog
*/
public class FindToolBar extends JPanel {
private SearchContext context;
protected ToolBarListener listener;
protected FindFieldListener findFieldListener;
protected SearchComboBox findCombo;
protected SearchComboBox replaceCombo;
protected JButton findButton;
protected JButton findPrevButton;
protected JCheckBox matchCaseCheckBox;
protected JCheckBox wholeWordCheckBox;
protected JCheckBox regexCheckBox;
protected JCheckBox markAllCheckBox;
private JLabel infoLabel;
private Timer markAllTimer;
/**
* Flag to prevent double-modification of SearchContext when e.g. a
* FindToolBar and ReplaceToolBar share the same SearchContext.
*/
private boolean settingFindTextFromEvent;
protected static final ResourceBundle searchMsg = ResourceBundle.getBundle(
"org.fife.rsta.ui.search.Search");
protected static final ResourceBundle msg = ResourceBundle.getBundle(
"org.fife.rsta.ui.search.SearchToolBar");
/**
* Creates the tool bar.
*
* @param listener An entity listening for search events.
*/
public FindToolBar(SearchListener listener) {
// Keep focus in this component when tabbing through search controls
setFocusCycleRoot(true);
installKeyboardShortcuts();
markAllTimer = new Timer(300, new MarkAllEventNotifier());
markAllTimer.setRepeats(false);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
addSearchListener(listener);
this.listener = new ToolBarListener();
// The user should set a shared instance between all subclass
// instances, but to be safe we set individual ones.
setSearchContext(new SearchContext());
ComponentOrientation orientation = ComponentOrientation.
getOrientation(getLocale());
add(Box.createHorizontalStrut(5));
add(createFieldPanel());
Box rest = new Box(BoxLayout.LINE_AXIS);
add(rest, BorderLayout.LINE_END);
rest.add(Box.createHorizontalStrut(5));
rest.add(createButtonPanel());
rest.add(Box.createHorizontalStrut(15));
infoLabel = new JLabel();
rest.add(infoLabel);
rest.add(Box.createHorizontalGlue());
// Get ready to go.
applyComponentOrientation(orientation);
}
/**
* Adds a {@link SearchListener} to this tool bar. This listener will
* be notified when find or replace operations are triggered.
*
* @param l The listener to add.
* @see #removeSearchListener(SearchListener)
*/
public void addSearchListener(SearchListener l) {
listenerList.add(SearchListener.class, l);
}
protected Container createButtonPanel() {
Box panel = new Box(BoxLayout.LINE_AXIS);
createFindButtons();
//JPanel bp = new JPanel(new GridLayout(1,2, 5,0));
//bp.add(findButton); bp.add(findPrevButton);
JPanel filler = new JPanel(new BorderLayout());
filler.setBorder(BorderFactory.createEmptyBorder());
filler.add(findButton);//bp);
panel.add(filler);
panel.add(Box.createHorizontalStrut(5));
matchCaseCheckBox = createCB("MatchCase");
panel.add(matchCaseCheckBox);
regexCheckBox = createCB("RegEx");
panel.add(regexCheckBox);
wholeWordCheckBox = createCB("WholeWord");
panel.add(wholeWordCheckBox);
markAllCheckBox = createCB("MarkAll");
panel.add(markAllCheckBox);
return panel;
}
protected JCheckBox createCB(String key) {
JCheckBox cb = new JCheckBox(searchMsg.getString(key));
cb.addActionListener(listener);
cb.addMouseListener(listener);
return cb;
}
/**
* Wraps the specified component in a panel with a leading "content assist
* available" icon in front of it.
*
* @param comp The component with content assist.
* @return The wrapper panel.
*/
protected Container createContentAssistablePanel(JComponent comp) {
JPanel temp = new JPanel(new BorderLayout());
temp.add(comp);
AssistanceIconPanel aip = new AssistanceIconPanel(comp);
temp.add(aip, BorderLayout.LINE_START);
return temp;
}
protected Container createFieldPanel() {
findFieldListener = new FindFieldListener();
JPanel temp = new JPanel(new BorderLayout());
findCombo = new SearchComboBox(this, false);
JTextComponent findField = UIUtil.getTextComponent(findCombo);
findFieldListener.install(findField);
temp.add(createContentAssistablePanel(findCombo));
return temp;
}
/**
* Creates the buttons for this tool bar.
*/
protected void createFindButtons() {
findPrevButton = new JButton(msg.getString("FindPrev"));
makeEnterActivateButton(findPrevButton);
findPrevButton.setActionCommand("FindPrevious");
findPrevButton.addActionListener(listener);
findPrevButton.setEnabled(false);
findButton = new JButton(searchMsg.getString("Find")) {
@Override
public Dimension getPreferredSize() {
return findPrevButton.getPreferredSize(); // Always bigger
}
};
makeEnterActivateButton(findButton);
findButton.setToolTipText(msg.getString("Find.ToolTip"));
findButton.setActionCommand("FindNext");
findButton.addActionListener(listener);
findButton.setEnabled(false);
}
/**
* Forces a "mark all" event to be sent out, if "mark all" is enabled.
*
* @param delay If the delay should be honored.
*/
protected void doMarkAll(boolean delay) {
if (context.getMarkAll() && !settingFindTextFromEvent) {
if (delay) {
markAllTimer.restart();
}
else {
fireMarkAllEvent();
}
}
}
void doSearch(boolean forward) {
if (forward) {
findButton.doClick(0);
}
else {
findPrevButton.doClick(0);
}
}
/**
* Fires a "mark all" search event.
*/
private void fireMarkAllEvent() {
SearchEvent se = new SearchEvent(this, SearchEvent.Type.MARK_ALL,
context);
fireSearchEvent(se);
}
/**
* Notifies all listeners that have registered interest for notification on
* this event type. The event instance is lazily created using the
* event parameter.
*
* @param e The ActionEvent object coming from a
* child component.
*/
protected void fireSearchEvent(SearchEvent e) {
// Process the listeners last to first, notifying
// those that are interested in this event
SearchListener[] listeners = listenerList.
getListeners(SearchListener.class);
int count = listeners==null ? 0 : listeners.length;
for (int i=count-1; i>=0; i--) {
listeners[i].searchEvent(e);
}
}
protected String getFindText() {
return UIUtil.getTextComponent(findCombo).getText();
}
/**
* Returns the delay between when the user types and when a "mark all"
* event is fired (assuming "mark all" is enabled), in milliseconds.
*
* @return The delay.
* @see #setMarkAllDelay(int)
*/
public int getMarkAllDelay() {
return markAllTimer.getInitialDelay();
}
protected String getReplaceText() {
if (replaceCombo==null) {
return null;
}
return UIUtil.getTextComponent(replaceCombo).getText();
}
/**
* Returns the search context for this tool bar.
*
* @return The search context.
* @see #setSearchContext(SearchContext)
*/
public SearchContext getSearchContext() {
return context;
}
/**
* Called when the regex checkbox is clicked (or its value is modified
* via a change to the search context). Subclasses can override
* to add custom behavior, but should call the super implementation.
*/
protected void handleRegExCheckBoxClicked() {
handleToggleButtons();
// "Content assist" support
boolean b = regexCheckBox.isSelected();
findCombo.setAutoCompleteEnabled(b);
}
/**
* Creates a search event object and notifies all registered listeners.
*
* @param e The event.
*/
protected void handleSearchAction(ActionEvent e) {
SearchEvent.Type type = null;
boolean forward = true;
String action = e.getActionCommand();
// JTextField returns *_DOWN_* modifiers, JButton returns the others (!)
int allowedModifiers =
InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_MASK | // field
InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK; // JButton
if ("FindNext".equals(action)) {
type = SearchEvent.Type.FIND;
int mods = e.getModifiers();
forward = (mods&allowedModifiers)==0;
// Add the item to the combo box's list, if it isn't already there.
JTextComponent tc = UIUtil.getTextComponent(findCombo);
findCombo.addItem(tc.getText());
}
else if ("FindPrevious".equals(action)) {
type = SearchEvent.Type.FIND;
forward = false;
// Add the item to the combo box's list, if it isn't already there.
JTextComponent tc = UIUtil.getTextComponent(findCombo);
findCombo.addItem(tc.getText());
}
else if ("Replace".equals(action)) {
type = SearchEvent.Type.REPLACE;
int mods = e.getModifiers();
forward = (mods&allowedModifiers)==0;
// Add the item to the combo box's list, if it isn't already there.
JTextComponent tc = UIUtil.getTextComponent(findCombo);
findCombo.addItem(tc.getText());
tc = UIUtil.getTextComponent(replaceCombo);
replaceCombo.addItem(tc.getText());
}
else if ("ReplaceAll".equals(action)) {
type = SearchEvent.Type.REPLACE_ALL;
// Add the item to the combo box's list, if it isn't already there.
JTextComponent tc = UIUtil.getTextComponent(findCombo);
findCombo.addItem(tc.getText());
tc = UIUtil.getTextComponent(replaceCombo);
replaceCombo.addItem(tc.getText());
}
context.setSearchFor(getFindText());
if (replaceCombo!=null) {
context.setReplaceWith(replaceCombo.getSelectedString());
}
// Note: This will toggle the "search forward" radio buttons in the
// Find/Replace dialogs if the application is using them AND these tool
// bars, but that is a rare occurrence. Cloning the context is out
// since that may cause problems for the application if it caches it.
context.setSearchForward(forward);
SearchEvent se = new SearchEvent(this, type, context);
fireSearchEvent(se);
handleToggleButtons(); // Replace button could toggle state
}
/**
* Returns whether any action-related buttons (Find Next, Replace, etc.)
* should be enabled. Subclasses can call this method when the "Find What"
* or "Replace With" text fields are modified. They can then
* enable/disable any components as appropriate.
*
* @return Whether the buttons should be enabled.
*/
protected FindReplaceButtonsEnableResult handleToggleButtons() {
FindReplaceButtonsEnableResult result =
new FindReplaceButtonsEnableResult(true, null);
String text = getFindText();
if (text.length()==0) {
result = new FindReplaceButtonsEnableResult(false, null);
}
else if (regexCheckBox.isSelected()) {
try {
Pattern.compile(text);
} catch (PatternSyntaxException pse) {
result = new FindReplaceButtonsEnableResult(false,
pse.getMessage());
}
}
boolean enable = result.getEnable();
findButton.setEnabled(enable);
findPrevButton.setEnabled(enable);
// setBackground doesn't show up with XP Look and Feel!
//findTextComboBox.setBackground(enable ?
// UIManager.getColor("ComboBox.background") : Color.PINK);
JTextComponent tc = UIUtil.getTextComponent(findCombo);
tc.setForeground(enable ? UIManager.getColor("TextField.foreground") :
UIUtil.getErrorTextForeground());
String tooltip = SearchUtil.getToolTip(result);
tc.setToolTipText(tooltip); // Always set, even if null
return result;
}
/**
* Initializes the UI in this tool bar from a search context. This is
* called whenever a new search context is installed on this tool bar
* (which should practically be never).
*/
protected void initUIFromContext() {
if (findCombo==null) { // First time through, stuff not initialized yet
return;
}
setFindText(context.getSearchFor());
if (replaceCombo!=null) {
setReplaceText(context.getReplaceWith());
}
matchCaseCheckBox.setSelected(context.getMatchCase());
wholeWordCheckBox.setSelected(context.getWholeWord());
regexCheckBox.setSelected(context.isRegularExpression());
markAllCheckBox.setSelected(context.getMarkAll());
}
private void installKeyboardShortcuts() {
InputMap im = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = getActionMap();
KeyStroke ks = KeyStroke.getKeyStroke("ENTER");
im.put(ks, "searchForward");
am.put("searchForward", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
doSearch(true);
}
});
int shift = InputEvent.SHIFT_MASK;
int ctrl = InputEvent.CTRL_MASK;
if (System.getProperty("os.name").toLowerCase().contains("os x")) {
ctrl = InputEvent.META_MASK;
}
ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, shift);
im.put(ks, "searchBackward");
ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, ctrl);
im.put(ks, "searchBackward");
am.put("searchForward", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
doSearch(false);
}
});
}
/**
* Makes the Enter key activate the button. In Swing, this is a
* complicated thing. It's LAF-dependent whether or not this works
* automatically; on most LAFs, it doesn't happen. In WindowsLookAndFeel
* it does, but *only* if the current window has a "default" button
* specified. Since these tool bars will typically be used in "main"
* application windows, which don't have default buttons, we'll just
* enable this property here and now.
*
* @param button The button that should respond to the Enter key.
*/
protected void makeEnterActivateButton(JButton button) {
InputMap im = button.getInputMap();
// Make "enter" being typed simulate clicking
im.put(KeyStroke.getKeyStroke("ENTER"), "pressed");
im.put(KeyStroke.getKeyStroke("released ENTER"), "released");
// Make "shift+enter" being typed simulate clicking also. The listener
// will handle the backwards searching. Not sure why the commented-out
// versions don't work, possibly SHIFT_MASK vs. SHIFT_DOWN_MASK issue.
//im.put(KeyStroke.getKeyStroke("pressed SHIFT ENTER"), "pressed");
//im.put(KeyStroke.getKeyStroke("released SHIFT ENTER"), "released");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK,
false), "pressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK,
true), "released");
}
/**
* Removes a {@link SearchListener} from this tool bar.
*
* @param l The listener to remove
* @see #addSearchListener(SearchListener)
*/
public void removeSearchListener(SearchListener l) {
listenerList.remove(SearchListener.class, l);
}
/**
* Makes the find field on this toolbar request focus. If it is already
* focused, its text is selected.
*/
@Override
public boolean requestFocusInWindow() {
JTextComponent findField = UIUtil.getTextComponent(findCombo);
findField.selectAll();
return findField.requestFocusInWindow();
}
/**
* Callback called when a contained combo box has its LookAndFeel
* modified. This is a hack for us to add listeners back to it.
*
* @param combo The combo box.
*/
void searchComboUpdateUICallback(SearchComboBox combo) {
findFieldListener.install(UIUtil.getTextComponent(combo));
}
protected void setFindText(String text) {
UIUtil.getTextComponent(findCombo).setText(text);
//findCombo.setSelectedItem(text);
}
/**
* Sets the delay between when the user types and when a "mark all"
* event is fired (assuming "mark all" is enabled), in milliseconds.
*
* @param millis The new delay. This should be >= zero.
* @see #getMarkAllDelay()
*/
public void setMarkAllDelay(int millis) {
markAllTimer.setInitialDelay(millis);
}
protected void setReplaceText(String text) {
if (replaceCombo!=null) {
UIUtil.getTextComponent(replaceCombo).setText(text);
//replaceCombo.setSelectedItem(text);
}
}
/**
* Sets the search context for this tool bar. You'll usually want to call
* this method for all tool bars and give them the same search context,
* so that their options (match case, etc.) stay in sync with one another.
*
* @param context The new search context. This cannot be null.
* @see #getSearchContext()
*/
public void setSearchContext(SearchContext context) {
if (this.context!=null) {
this.context.removePropertyChangeListener(listener);
}
this.context = context;
this.context.addPropertyChangeListener(listener);
initUIFromContext();
}
/**
* Listens for events in this tool bar. Keeps the UI in sync with the
* search context and vice versa.
*/
private class ToolBarListener extends MouseAdapter
implements ActionListener, PropertyChangeListener {
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source==matchCaseCheckBox) {
context.setMatchCase(matchCaseCheckBox.isSelected());
if (markAllCheckBox.isSelected()) {
doMarkAll(false);
}
}
else if (source==wholeWordCheckBox) {
context.setWholeWord(wholeWordCheckBox.isSelected());
if (markAllCheckBox.isSelected()) {
doMarkAll(false);
}
}
else if (source==regexCheckBox) {
context.setRegularExpression(regexCheckBox.isSelected());
if (markAllCheckBox.isSelected()) {
doMarkAll(false);
}
}
else if (source==markAllCheckBox) {
context.setMarkAll(markAllCheckBox.isSelected());
fireMarkAllEvent(); // Force an event to be fired
}
else {
handleSearchAction(e);
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() instanceof JCheckBox) { // Always true
findFieldListener.selectAll = false;
findCombo.requestFocusInWindow();
}
}
@Override
public void propertyChange(PropertyChangeEvent e) {
// A property changed on the context itself.
String prop = e.getPropertyName();
if (SearchContext.PROPERTY_MATCH_CASE.equals(prop)) {
boolean newValue = ((Boolean)e.getNewValue()).booleanValue();
matchCaseCheckBox.setSelected(newValue);
}
else if (SearchContext.PROPERTY_MATCH_WHOLE_WORD.equals(prop)) {
boolean newValue = ((Boolean)e.getNewValue()).booleanValue();
wholeWordCheckBox.setSelected(newValue);
}
//else if (SearchContext.PROPERTY_SEARCH_FORWARD.equals(prop)) {
// boolean newValue = ((Boolean)e.getNewValue()).booleanValue();
// ...
//}
//else if (SearchContext.PROPERTY_SELECTION_ONLY.equals(prop)) {
// boolean newValue = ((Boolean)e.getNewValue()).booleanValue();
// ...
//}
else if (SearchContext.PROPERTY_USE_REGEX.equals(prop)) {
boolean newValue = ((Boolean)e.getNewValue()).booleanValue();
regexCheckBox.setSelected(newValue);
handleRegExCheckBoxClicked();
}
else if (SearchContext.PROPERTY_MARK_ALL.equals(prop)) {
boolean newValue = ((Boolean)e.getNewValue()).booleanValue();
markAllCheckBox.setSelected(newValue);
// firing event handled in ActionListener, to prevent "other"
// tool bar from firing a second event
}
else if (SearchContext.PROPERTY_SEARCH_FOR.equals(prop)) {
String newValue = (String)e.getNewValue();
String oldValue = getFindText();
// Prevents IllegalStateExceptions
if (!newValue.equals(oldValue)) {
settingFindTextFromEvent = true;
setFindText(newValue);
settingFindTextFromEvent = false;
}
}
else if (SearchContext.PROPERTY_REPLACE_WITH.equals(prop)) {
String newValue = (String)e.getNewValue();
String oldValue = getReplaceText();
// Prevents IllegalStateExceptions
if (!newValue.equals(oldValue)) {
settingFindTextFromEvent = true;
setReplaceText(newValue);
settingFindTextFromEvent = false;
}
}
}
}
/**
* Listens for events in the Find (and Replace, in the subclass) search
* field.
*/
protected class FindFieldListener extends KeyAdapter
implements DocumentListener, FocusListener {
protected boolean selectAll;
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void focusGained(FocusEvent e) {
JTextField field = (JTextField)e.getComponent();
if (selectAll) {
field.selectAll();
}
selectAll = true;
}
@Override
public void focusLost(FocusEvent e) {
}
protected void handleDocumentEvent(DocumentEvent e) {
handleToggleButtons();
if (!settingFindTextFromEvent) {
JTextComponent findField = UIUtil.getTextComponent(findCombo);
if (e.getDocument()==findField.getDocument()) {
context.setSearchFor(findField.getText());
if (context.getMarkAll()) {
doMarkAll(true);
}
}
else { // Replace field's document
JTextComponent replaceField = UIUtil.getTextComponent(
replaceCombo);
context.setReplaceWith(replaceField.getText());
// Don't re-fire "mark all" events for "replace" text edits
}
}
}
@Override
public void insertUpdate(DocumentEvent e) {
handleDocumentEvent(e);
}
public void install(JTextComponent field) {
field.getDocument().addDocumentListener(this);
field.addKeyListener(this);
field.addFocusListener(this);
}
@Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar()=='\n') {
int mod = e.getModifiers();
int ctrlShift = InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK;
boolean forward = (mod&ctrlShift) == 0;
doSearch(forward);
}
}
@Override
public void removeUpdate(DocumentEvent e) {
handleDocumentEvent(e);
}
}
/**
* Called when the user edits the "Find" field's contents, after a slight
* delay. Fires a "mark all" search event for applications that want to
* display "mark all" results on the fly.
*/
private class MarkAllEventNotifier implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
fireMarkAllEvent();
}
}
}