All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.rsta.ui.search.FindToolBar Maven / Gradle / Ivy

/*
 * 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();
		}

	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy