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

org.fife.ui.search.FindInFilesDialog Maven / Gradle / Ivy

Go to download

RText is a powerful, cross-platform programmer's text editor written in Java. It is designed to be easy to use, highly customizable and flexible. Part of RText's design is for the source code to be simple, easy to understand, and well documented, so that other programmers can look into its inner-workings and figure out how RText ticks with ease. A good place to start (besides the source code) is the Javadoc for all classes used in the project.

There is a newer version: 2.0.7
Show newest version
/*
 * 11/26/2003
 *
 * FindInFilesDialog.java - A dialog that allows you to search for text
 * in all files in a directory.
 * Copyright (C) 2003 Robert Futrell
 * robert_futrell at users.sourceforge.net
 * http://fifesoft.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.fife.ui.search;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import java.util.Vector;
import java.util.regex.Pattern;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.*;
import javax.swing.text.JTextComponent;

import org.fife.rtext.AssistanceIconPanel;
import org.fife.ui.FSATextField;
import org.fife.ui.RButton;
import org.fife.ui.RComboBoxModel;
import org.fife.ui.RScrollPane;
import org.fife.ui.StatusBar;
import org.fife.ui.UIUtil;
import org.fife.ui.rtextfilechooser.RDirectoryChooser;


/**
 * A dialog allowing the user to search for a text string in all files in a
 * directory, so they don't have to do the files one at a time.
 *
 * @author Robert Futrell
 * @version 0.8
 */
public class FindInFilesDialog extends AbstractSearchDialog
									implements ActionListener {

	/**
	 * Property notification sent out when the user does a search.  This
	 * notifies that the list of search strings in the "Find what" combo box
	 * has changed.  Note that the "old" value will always be
	 * null; the "new" value is a Vector of strings
	 * containing the new values.
	 */
	public static final String	SEARCH_STRINGS_PROPERTY	= "FindInFilesDialog.searchStrings";

	// Text fields in which the user enters parameters that are not
	// defined in AbstractSearchDialog.
	protected JComboBox inFilesComboBox;
	protected FSATextField inFolderTextField;

	protected JCheckBox subfoldersCheckBox;

	protected JButton findButton;
	private JButton browseButton;

	private JRadioButton matchingLinesRadioButton;
	private JRadioButton fileCountsOnlyRadioButton;

	protected JCheckBox verboseCheckBox;

	private StatusBar statusBar;

	private ResultsComponent resultsComponent;

	// This helps us work around the "bug" where JComboBox eats the first
	// Enter press.
	private String lastSearchString;
	private String lastInFilesString;

	// The listener list for FindInFilesEvents.
	private EventListenerList eventListenerList;

	private FindInFilesThread workerThread;
	private FindInFilesDocumentListener docListener;

	// Some strings cached from our resources for efficiency.
	private ResourceBundle resources;
	private String defaultStatusText;
	private String searchingCompleteString;


	/**
	 * Creates a new FindInFilesDialog.
	 *
	 * @param owner The main window that owns this dialog.
	 */
	public FindInFilesDialog(Frame owner) {
		this(owner, ResourceBundle.getBundle("org.fife.ui.search.Search"));
	}


	/**
	 * Creates a new FindInFilesDialog.
	 *
	 * @param owner The owner of this dialog.
	 * @param msg The resource bundle.
	 */
	public FindInFilesDialog(Frame owner, ResourceBundle msg) {

		super(owner, msg, true);
		this.setTitle(msg.getString("FindInFilesDialogTitle"));

		ComponentOrientation orientation = ComponentOrientation.
									getOrientation(getLocale());

		// These listeners will be used by all text fields.
		docListener = new FindInFilesDocumentListener();
		FindInFilesFocusAdapter focusAdapter = new FindInFilesFocusAdapter();
		FindInFilesKeyListener keyListener = new FindInFilesKeyListener();

		// Set the main content pane for the "Find in Files" dialog.
		JPanel contentPane = new JPanel();
		contentPane.setLayout(new BorderLayout());
		setContentPane(contentPane);

		// Make a "Find what" combo box.
		JTextComponent textField = getTextComponent(findTextCombo);
		textField.addFocusListener(focusAdapter);
		textField.addKeyListener(keyListener);
		textField.getDocument().addDocumentListener(docListener);

		// Make an "In files" combo box.
		inFilesComboBox = new JComboBox(new RComboBoxModel());
		inFilesComboBox.setEditable(true);
		textField = getTextComponent(inFilesComboBox);
		textField.addFocusListener(focusAdapter);
		textField.addKeyListener(keyListener);
		textField.getDocument().addDocumentListener(docListener);

		// Make an "In folder" text field.
		// NOTE:  Change the line below for "directories only", but
		// SLOW NFS paths because of File.isDirectory()...
		inFolderTextField = new FSATextField();//true);
		inFolderTextField.setText(System.getProperty("user.home"));
		inFolderTextField.addFocusListener(focusAdapter);
		inFolderTextField.getDocument().addDocumentListener(docListener);

		// Make a panel containing the edit boxes and their associated labels.
		JPanel inputPanel = createInputPanel(msg);

		// Make a "Conditions" panel.
		JPanel conditionsPanel = new JPanel();
		conditionsPanel.setBorder(createTitledBorder(msg.getString("Conditions")));
		conditionsPanel.setLayout(new BoxLayout(conditionsPanel, BoxLayout.PAGE_AXIS));
		conditionsPanel.add(caseCheckBox);
		conditionsPanel.add(wholeWordCheckBox);
		conditionsPanel.add(regExpCheckBox);

		// Make a "Report detail" panel.
		JPanel detailEtcPanel = createDetailsPanel(msg);

		// Make a panel containing the "Conditions" and "detailEtc" panels.
		JPanel bottomLeftPanel = new JPanel();
		bottomLeftPanel.setLayout(new BoxLayout(bottomLeftPanel, BoxLayout.LINE_AXIS));
		bottomLeftPanel.add(conditionsPanel);
		bottomLeftPanel.add(Box.createHorizontalStrut(10));
		bottomLeftPanel.add(detailEtcPanel);
		bottomLeftPanel.add(Box.createHorizontalGlue());

		// Make a panel containing all of the text fields, and the bottom left panel.
		JPanel leftPanel = new JPanel();
		leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
		leftPanel.add(inputPanel);
		leftPanel.add(bottomLeftPanel);

		// Make a panel containing the buttons.
		JPanel rightPanel2 = new JPanel(new GridLayout(3,1, 5,5));
		findButton = new RButton(msg.getString("Find"));
		findButton.setMnemonic((int)msg.getString("FindMnemonic").charAt(0));
		findButton.setActionCommand("FindInFiles");
		findButton.addActionListener(this);
		browseButton = new RButton(msg.getString("Browse"));
		browseButton.setMnemonic((int)msg.getString("BrowseMnemonic").charAt(0));
		browseButton.setActionCommand("Browse");
		browseButton.addActionListener(this);
		cancelButton = new RButton(msg.getString("Close"));
		cancelButton.setMnemonic((int)msg.getString("CloseMnemonic").charAt(0));
		cancelButton.setActionCommand("Close");
		cancelButton.addActionListener(this);
		rightPanel2.add(findButton);
		rightPanel2.add(browseButton);
		rightPanel2.add(cancelButton);
		JPanel rightPanel = new JPanel(new BorderLayout());
		if (orientation.isLeftToRight()) {
			rightPanel.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
		}
		else {
			rightPanel.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
		}
		rightPanel.add(rightPanel2, BorderLayout.NORTH);

		// Combine leftPanel and rightPanel.
		JPanel topPanel = new JPanel(new BorderLayout());
		topPanel.add(leftPanel);
		topPanel.add(rightPanel, BorderLayout.LINE_END);

		// Make a panel containing a "Verbose output" checkbox.
		JPanel extraOptionsPanel = createExtraOptionsPanel(msg);

		// Make the "results" panel.
		JPanel resultsPanel = new JPanel(new GridLayout(1,1, 3,3));
		Border empty5Border = UIUtil.getEmpty5Border();
		resultsPanel.setBorder(BorderFactory.createCompoundBorder(
			empty5Border,
			BorderFactory.createCompoundBorder(
				createTitledBorder(msg.getString("Results")),
				BorderFactory.createEmptyBorder(3,3,3,3)
			)));
		resultsComponent = createResultsComponent();
		JScrollPane resultsScrollPane = new RScrollPane((JComponent)resultsComponent);
		resultsScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		resultsScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		resultsPanel.add(resultsScrollPane);

		// Make the "status bar."
		statusBar = new org.fife.ui.StatusBar();

		// Initialize some variables.
		eventListenerList = new EventListenerList();
		this.resources = msg;
		defaultStatusText = resources.getString("DefaultStatusText");
		searchingCompleteString = resources.getString("SearchingComplete");

		// Put everything together.
		setStatusText(defaultStatusText);
		JPanel temp = new JPanel();
		temp.setBorder(empty5Border);
		temp.setLayout(new BoxLayout(temp, BoxLayout.Y_AXIS));
		temp.add(topPanel);
		temp.add(Box.createVerticalStrut(5));
		if (extraOptionsPanel!=null) {
			temp.add(extraOptionsPanel);
		}
		contentPane.add(temp, BorderLayout.NORTH);
		contentPane.add(resultsPanel);
		contentPane.add(statusBar, BorderLayout.SOUTH);
		getRootPane().setDefaultButton(findButton);
		setModal(false);
		applyComponentOrientation(orientation);
		pack();
		setLocationRelativeTo(owner);

	}


	/**
	 * Called whenever the user does something.
	 */
	public void actionPerformed(ActionEvent e) {

		String command = e.getActionCommand();

		// If the user selects the "Find" button...
		if (command.equals("FindInFiles")) {

			// Add the "Find What" item to the combo box's list.  Then, if
			// they just searched for an item that's already in the list
			// other than the first, move it to the first position.
			String item = getTextComponent(findTextCombo).getText();
			findTextCombo.addItem(item); // Ensures item is at index 0.
			findTextCombo.setSelectedIndex(0);

			// Add the "In Files" item to the combo box's list.  Then, if
			// they just searched for an item that's already in the list
			// other than the first, move it to the first position.
			item = getTextComponent(inFilesComboBox).getText();
			inFilesComboBox.addItem(item); // Ensures item is at index 0.
			inFilesComboBox.setSelectedIndex(0);

			// Update our "master list" of search strings.
			firePropertyChange(SEARCH_STRINGS_PROPERTY,
							null, getSearchStrings());

			// Actually perform the search.
			doFindInFiles();

		} // End of if (command.equals("FindInFiles")).


		// If the user selects the "Browse..." button...
		else if (command.equals("Browse")) {
			RDirectoryChooser chooser = new RDirectoryChooser(this);
			String dirName = inFolderTextField.getText().trim();
			if (dirName.length()>0) {
				File dir = new File(dirName);
				chooser.setChosenDirectory(dir);
			}
			chooser.setVisible(true);
			String directory = chooser.getChosenDirectory();
			if (directory!=null) {
				inFolderTextField.setFileSystemAware(false);
				inFolderTextField.setText(directory);
				inFolderTextField.setFileSystemAware(true);
			}
		}

		// If the user selects the Close/Stop button...
		else if (command.equals("Close")) {
			FindInFilesThread workerThread = getWorkerThread();
			if (workerThread!=null) { // Search going on => stop search.
				workerThread.interrupt();
				setSearching(false);
			}
			else { // No search => close the dialog.
				this.setVisible(false);
			}
		}

		// The superclass might care about this action.
		else {
			super.actionPerformed(e);
		}

	}


	/**
	 * Adds information on a match (or verbose search information) to the
	 * search table.

* * We assume this method is being called by {@link FindInFilesThread}, * not the EDT, so the match data is added via * SwingUtilities.invokeLater. Match data should never be * gathered on the EDT since it is a potentially long process to gather it. * * @param matchData Data about the found text. */ void addMatchData(final MatchData matchData) { final String dirName = inFolderTextField.getText(); SwingUtilities.invokeLater(new Runnable() { public void run() { getResultsComponent().addMatchData(matchData, dirName); } }); } /** * Adds a find-in-files listener to this find in files dialog. * * @param listener The listener to add. * @see #removeFindInFilesListener */ public void addFindInFilesListener(FindInFilesListener listener) { eventListenerList.add(FindInFilesListener.class, listener); } /** * Adds a file filter to the "In files:" combo box. * * @param filter The filter to add. */ public void addInFilesComboBoxFilter(String filter) { inFilesComboBox.addItem(filter); } /** * Clears the search results table. This method can be called from * threads other than the EDT. */ void clearSearchResults() { if (SwingUtilities.isEventDispatchThread()) { getResultsComponent().clear(); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { getResultsComponent().clear(); } }); } } /** * Creates the panel containing "Report Detail" options. * * @param msg The resource bundle. * @return The panel. */ protected JPanel createDetailsPanel(ResourceBundle msg) { JPanel detailPanel = new JPanel(); detailPanel.setBorder(createTitledBorder(msg.getString("ReportDetail"))); detailPanel.setLayout(new BoxLayout(detailPanel, BoxLayout.PAGE_AXIS)); matchingLinesRadioButton = new JRadioButton(msg.getString("MatchingLines")); matchingLinesRadioButton.setMnemonic((int)msg.getString("MatchingLinesMnemonic").charAt(0)); matchingLinesRadioButton.setSelected(true); detailPanel.add(matchingLinesRadioButton); fileCountsOnlyRadioButton = new JRadioButton(msg.getString("FileCounts")); fileCountsOnlyRadioButton.setMnemonic((int)msg.getString("FileCountsMnemonic").charAt(0)); ButtonGroup bg = new ButtonGroup(); bg.add(matchingLinesRadioButton); bg.add(fileCountsOnlyRadioButton); detailPanel.add(fileCountsOnlyRadioButton); // Make a panel containing the "Report detail" panel and some checkboxes. JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); subfoldersCheckBox = new JCheckBox(msg.getString("SearchSubfolders")); subfoldersCheckBox.setMnemonic((int)msg.getString("SearchSubfoldersMnemonic").charAt(0)); panel.add(detailPanel); panel.add(subfoldersCheckBox); return panel; } /** * Returns a panel containing any extra options, such as a "verbose" * output option. * * @param msg The resource bundle. * @return The panel, or null if there are no extra * options. */ protected JPanel createExtraOptionsPanel(ResourceBundle msg) { JPanel temp = new JPanel(); temp.setLayout(new BoxLayout(temp, BoxLayout.LINE_AXIS)); verboseCheckBox = new JCheckBox(msg.getString("Verbose")); verboseCheckBox.setMnemonic((int)msg.getString("VerboseMnemonic").charAt(0)); temp.add(verboseCheckBox); temp.add(Box.createHorizontalGlue()); return temp; } /** * Creates and returns the panel containing input fields and their * labels. * * @param msg The resource bundle. * @return The panel. */ protected JPanel createInputPanel(ResourceBundle msg) { JPanel inputPanel = new JPanel(new SpringLayout()); // Make labels to go with the combo boxes/text fields. JLabel findLabel = new JLabel(msg.getString("FindWhat")); findLabel.setLabelFor(findTextCombo); findLabel.setDisplayedMnemonic((int)msg.getString("FindWhatMnemonic").charAt(0)); JLabel inLabel = new JLabel(msg.getString("InFiles")); inLabel.setLabelFor(inFilesComboBox); inLabel.setDisplayedMnemonic((int)msg.getString("InFilesMnemonic").charAt(0)); JLabel dirLabel = new JLabel(msg.getString("InDirectory")); dirLabel.setLabelFor(inFolderTextField); dirLabel.setDisplayedMnemonic((int)msg.getString("InDirectoryMnemonic").charAt(0)); JPanel temp = new JPanel(new BorderLayout()); temp.add(findTextCombo); AssistanceIconPanel aip = new AssistanceIconPanel(findTextCombo); temp.add(aip, BorderLayout.LINE_START); JPanel temp2 = new JPanel(new BorderLayout()); temp2.add(inFilesComboBox); temp2.add(Box.createHorizontalStrut(AssistanceIconPanel.WIDTH), BorderLayout.LINE_START); JPanel temp3 = new JPanel(new BorderLayout()); temp3.add(inFolderTextField); temp3.add(Box.createHorizontalStrut(AssistanceIconPanel.WIDTH), BorderLayout.LINE_START); ComponentOrientation orientation = ComponentOrientation. getOrientation(getLocale()); // Make a panel of the edit fields and add it to inputPanel. if (orientation.isLeftToRight()) { inputPanel.add(findLabel); inputPanel.add(temp); inputPanel.add(inLabel); inputPanel.add(temp2); inputPanel.add(dirLabel); inputPanel.add(temp3); } else { inputPanel.add(temp); inputPanel.add(findLabel); inputPanel.add(temp2); inputPanel.add(inLabel); inputPanel.add(temp3); inputPanel.add(dirLabel); } UIUtil.makeSpringCompactGrid(inputPanel, 3,2, // rows,cols, 0,0, // initial-x, initial-y, 5,5); // x-spacing, y-spacing. return inputPanel; } /** * Creates and returns the component used to display search * results. * * @return The component. */ protected ResultsComponent createResultsComponent() { FindInFilesTable table = new FindInFilesTable(); table.addMouseListener(new FindInFilesDialogMouseListener(table)); return table; } /** * Returns the thread that will do the searching. * * @param directory The directory to search in. * @return The thread. */ protected FindInFilesThread createWorkerThread(File directory) { return new FindInFilesThread(this, directory); } /** * This function actually performs a search through the given directory. */ private void doFindInFiles() { // First, ensure that the directory they selected actually exists. String dirPath = inFolderTextField.getText(); final File directory = new File(dirPath); if (!directory.isDirectory()) { JOptionPane.showMessageDialog(this, resources.getString("ErrorDirNotExist") + dirPath, resources.getString("ErrorDialogTitle"), JOptionPane.ERROR_MESSAGE); inFolderTextField.selectAll(); inFolderTextField.requestFocusInWindow(); return; } // Next, if we're doing a regex search, ensure we have a valid // regex to search for. if (regExpCheckBox.isSelected()) { try { Pattern.compile(getSearchString()); } catch (Exception e) { // Doesn't usually happen; should be caught earlier. String text = e.getMessage(); if (text==null) { text = e.toString(); } JOptionPane.showMessageDialog(this, "Invalid regular expression:\n" + text + "\nPlease check your regular expression search string.", resources.getString("ErrorDialogTitle"), JOptionPane.ERROR_MESSAGE); return; } } // Show the hourglass cursor, as we may have a wait ahead of us. setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // Disable the buttons so the user doesn't think they can use them // while we're searching. setSearching(true); // Start searching! setWorkerThread(createWorkerThread(directory)); getWorkerThread().start(); } /** * Notifies all find-in-files listeners of a find-in-files event in this * dialog. * * @param e The event to notify all listeners about. */ protected void fireFindInFilesEvent(FindInFilesEvent e) { // Guaranteed to return a non-null array Object[] listeners = eventListenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==FindInFilesListener.class) { ((FindInFilesListener)listeners[i+1]). findInFilesFileSelected(e); } } } /** * Returns the resource bundle for this dialog. * * @return The resource bundle. */ ResourceBundle getBundle() { return resources; } /** * Returns whether to check subfolders. * * @return Whether or not to check subfolders. * @see #getMatchCase * @see #getMatchWholeWord * @see #getUseRegEx */ boolean getCheckSubfolders() { return subfoldersCheckBox.isSelected(); } /** * Returns whether the user wants verbose output about their search. * * @return Whether the user wants verbose output about their search. */ boolean getDoVerboseOutput() { return verboseCheckBox.isSelected(); } /** * Returns the contents of the "In Files:" combo box. * * @return The contents. */ String getInFilesComboBoxContents() { return (String)inFilesComboBox.getSelectedItem(); } /** * Returns the length of the text in a text component. * * @param c The text component. * @return The number of characters in that text component. */ protected static final int getLength(JTextComponent c) { return c.getDocument().getLength(); } /** * Returns whether matches should be case-sensitive. * * @return Whether or not matches should be case-sensitive. * @see #getCheckSubfolders * @see #getMatchWholeWord * @see #getUseRegEx */ boolean getMatchCase() { return caseCheckBox.isSelected(); } /** * Returns whether matches should be whole word. * * @return Whether or not matches should be whole word. * @see #getCheckSubfolders * @see #getMatchCase * @see #getUseRegEx */ boolean getMatchWholeWord() { return wholeWordCheckBox.isSelected(); } /** * Returns the component used to display results. * * @return The component. */ protected ResultsComponent getResultsComponent() { return resultsComponent; } /** * Returns a Vector containing all of the search * strings in the "Find what" combo box's history. * * @return The search strings in the Find combo box's history. */ public Vector getSearchStrings() { int itemCount = findTextCombo.getItemCount(); Vector vector = new Vector(itemCount); for (int i=0; inull if * no searching is going on. */ protected synchronized FindInFilesThread getWorkerThread() { return workerThread; } /** * 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 EnableResult handleToggleButtons() { EnableResult er = super.handleToggleButtons(); boolean enable = er.getEnable(); findButton.setEnabled(enable && isEverythingFilledIn()); JTextComponent tc = getTextComponent(findTextCombo); tc.setForeground(enable ? UIManager.getColor("TextField.foreground") : Color.RED); String tooltip = er.getToolTip(); String status = defaultStatusText; if (tooltip!=null) { status = tooltip; if (status.indexOf('\n')>-1) { status = status.substring(0, status.indexOf('\n')); } } setStatusText(status); if (tooltip!=null && tooltip.indexOf('\n')>-1) { tooltip = tooltip.replaceFirst("\\\n", "

");
			tooltip = "" + tooltip;
		}
		tc.setToolTipText(tooltip); // Always set, even if null

		return er;

	}


	/**
	 * Returns whether everything in the UI that needs to be filled in for
	 * a search to be performed is filled in.
	 *
	 * @return Whether eveything is filled in.
	 */
	protected boolean isEverythingFilledIn() {
		return getWorkerThread()==null && 
				getLength(getTextComponent(findTextCombo))>0 &&
				getLength(getTextComponent(inFilesComboBox))>0 &&
				getLength(inFolderTextField)>0;
	}


	/**
	 * Removes a find-in-files listener to this find in files dialog.
	 *
	 * @param listener The listener to remove
	 * @see  #addFindInFilesListener
	 */
	public void removeFindInFilesListener(FindInFilesListener listener) {
		eventListenerList.remove(FindInFilesListener.class, listener);
	}


	/**
	 * Called by the searching thread when searching was terminated early for
	 * some reason.
	 *
	 * @param message A message describing why searching was terminated.
	 */
	void searchCompleted(String message) {
		setStatusText(message);
		searchCompleted(-1);
	}


	/**
	 * Called by the searching thread when searching has completed.
	 *
	 * @param time The time in milliseconds the search took.
	 */
	void searchCompleted(final long time) {

		SwingUtilities.invokeLater(new Runnable() { public void run() {

			setWorkerThread(null);

			// Return the cursor to the regular one.
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

			// Re-enable the buttons since the user can do stuff again.
			setSearching(false);

			// If searching completed normally (e.g., wasn't terminated).
			if (time!=-1) {

				// Make the status bar indicate that searching completed.
				String temp = MessageFormat.format(searchingCompleteString,
								new Object[] { ""+(time/1000.0f) });
				setStatusText(temp);

				// Update the results list and notify the user if the
				// message wasn't found at all.
				if (getResultsComponent().getRowCount()==0) {
					String searchString = (String)findTextCombo.
												getSelectedItem();
					JOptionPane.showMessageDialog(FindInFilesDialog.this,
						resources.getString("SearchStringNotFound") +
												searchString + "'.",
						resources.getString("InfoDialogTitle"),
						JOptionPane.INFORMATION_MESSAGE);
				}

			}

			getResultsComponent().prettyUp();

		}});

	}


	/**
	 * This function should be called to update match case, whole word, etc.
	 *
	 * @param searchString The text the user wants to search for.
	 * @param matchCase Whether the "match case" checkbox should be checked.
	 * @param wholeWord Whether the "whole word" checkbox should be checked.
	 */
	public void setSearchParameters(String searchString, boolean matchCase,
								boolean wholeWord, boolean regExp) {
		findTextCombo.addItem(searchString);
		findTextCombo.setSelectedIndex(0);
		caseCheckBox.setSelected(matchCase);
		wholeWordCheckBox.setSelected(wholeWord);
		regExpCheckBox.setSelected(regExp);
	}


	/**
	 * This function should be called to update match case, whole word, etc.
	 */
	public void setSearchParameters(Vector findComboBoxStrings,
					boolean matchCase, boolean wholeWord, boolean regExp) {
		findTextCombo.removeAllItems();
		int size = findComboBoxStrings.size();
		for (int i=size-1; i>=0; i--) {
			findTextCombo.addItem(findComboBoxStrings.get(i));
		}
		if (size>0)
			findTextCombo.setSelectedIndex(0);
		caseCheckBox.setSelected(matchCase);
		wholeWordCheckBox.setSelected(wholeWord);
		regExpCheckBox.setSelected(regExp);
	}


	/**
	 * Enables or disables widgets in the dialog as appropriate.
	 *
	 * @param searching Whether searching is starting.
	 */
	protected void setSearching(boolean searching) {
		boolean enabled = !searching;
		findButton.setEnabled(enabled);
		browseButton.setEnabled(enabled);
		if (searching) {
			cancelButton.setText(resources.getString("Stop"));
			cancelButton.setMnemonic((int)resources.
								getString("StopMnemonic").charAt(0));
		}
		else {
			cancelButton.setText(resources.getString("Close"));
			cancelButton.setMnemonic((int)resources.
								getString("CloseMnemonic").charAt(0));
		}
		findTextCombo.setEnabled(enabled);
		inFilesComboBox.setEnabled(enabled);
		inFolderTextField.setEnabled(enabled);
	}


	/**
	 * Sets the String to search for.
	 *
	 * @param newSearchString The String to put into the
	 *        search field.
	 */
	public void setSearchString(String newSearchString) {
		findTextCombo.addItem(newSearchString);
		findTextCombo.setSelectedIndex(0);
	}


	/**
	 * Sets the text in the status bar.
	 *
	 * @param text The text to display.
	 */
	public void setStatusText(final String text) {
		// Check whether dialog is visible in case search table is
		// docked on another window.
		if (isVisible()) {
			if (SwingUtilities.isEventDispatchThread()) {
				statusBar.setStatusMessage(text);
			}
			else {
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						statusBar.setStatusMessage(text);
					}
				});
			}
		}
	}


	/**
	 * Displays or hides the Find in Files dialog.  Note that you should use
	 * this method and not show() to properly display this dialog.
	 *
	 * @param visible Whether the dialog should be displayed or hidden.
	 */
	public void setVisible(boolean visible) {

		super.setVisible(visible);

		// If they're making the dialog visible, make sure the status text
		// is "Ready" and not something left over from the last time the
		// dialog was visible.
		if (visible==true) {
			setStatusText(defaultStatusText);
		}

		// Give the "Find" text field focus.
		if (SwingUtilities.isEventDispatchThread()) {
			handleToggleButtons();
			findTextCombo.requestFocusInWindow();
			JTextComponent editor = getTextComponent(findTextCombo);
			editor.selectAll();
		}
		else {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					handleToggleButtons();
					findTextCombo.requestFocusInWindow();
					JTextComponent editor = getTextComponent(findTextCombo);
					editor.selectAll();
				}
			});
		}

	}


	/**
	 * Synchronizes access to our "worker" thread.
	 *
	 * @param workerThread The new worker thread.
	 * @see #getWorkerThread
	 */
	private synchronized void setWorkerThread(FindInFilesThread thread) {
		this.workerThread = thread;
	}


	/**
	 * Called whenever the user changes the Look and Feel, etc.
	 * This is overridden so we can reinstate the listeners that are evidently
	 * lost on the JTextField portion of our combo box.
	*/
	public void updateUI() {

		// Create listeners for the combo boxes.
		FindInFilesFocusAdapter focusAdapter = new FindInFilesFocusAdapter();
		FindInFilesKeyListener keyListener = new FindInFilesKeyListener();

		// Fix the Find What combo box's listeners.
		JTextComponent textField = getTextComponent(findTextCombo);
		textField.addFocusListener(focusAdapter);
		textField.addKeyListener(keyListener);
		textField.getDocument().addDocumentListener(docListener);

		// Fix the In Files combo box's listeners.
		textField = getTextComponent(inFilesComboBox);
		textField.addFocusListener(focusAdapter);
		textField.addKeyListener(keyListener);
		textField.getDocument().addDocumentListener(docListener);

		// Fix the In Folders combo box's listeners.
		inFolderTextField.addFocusListener(focusAdapter);
		inFolderTextField.getDocument().addDocumentListener(docListener);

	}


	/**
	 * Listens for changes in the "Find what" text field.
	 */
	private class FindInFilesDocumentListener implements DocumentListener {

		public void insertUpdate(DocumentEvent e) {
			handleToggleButtons();
		}

		public void removeUpdate(DocumentEvent e) {
			handleToggleButtons();
		}

		public void changedUpdate(DocumentEvent e) {
		}

	}


	/**
	 * Listens for the text field gaining focus.
	 */
	private class FindInFilesFocusAdapter extends FocusAdapter {

		public void focusGained(FocusEvent e) {

			Component component = e.getComponent();
			((JTextField)component).selectAll();

			if (component==getTextComponent(findTextCombo))
				// Remember what it originally was, in case they tabbed out.
				lastSearchString = (String)findTextCombo.getSelectedItem();

			else if (component==getTextComponent(inFilesComboBox))
				// Remember what it originally was, in case they tabbed out.
				lastInFilesString = (String)inFilesComboBox.getSelectedItem();

		}

	}


	/**
	 * Listens for the user to double-click on the results JList.  This class
	 * is what sends out FindInFilesEvents.
	 */
	class FindInFilesDialogMouseListener extends MouseAdapter {

		ResultsComponent comp;

		FindInFilesDialogMouseListener(ResultsComponent comp) {
			this.comp = comp;
		}

		public void mouseClicked(MouseEvent e) {
			if (e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2) {
				int row = comp.getSelectedRow();
				if (row==-1)
					return;
				MatchData data = comp.getMatchDataForRow(row);
				String fileName = data.getFileName();
				// Might be a directory if Verbose is enabled.
				if (!(new File(fileName).isFile())) {
					UIManager.getLookAndFeel().provideErrorFeedback(null);
					return;
				}
				String lineStr = data.getLineNumber();
				int line = -1;
				if (!FindInFilesThread.NO_LINE_NUMBER.equals(lineStr)) {
					// Should be in format "3" or "5-7".
					if (lineStr.indexOf('-')>-1) {
						lineStr =
							lineStr.substring(0, lineStr.indexOf('-'));
					}
					try {
						line = Integer.parseInt(lineStr);
					} catch (NumberFormatException nfe) {
						nfe.printStackTrace();
					}
				}
				fireFindInFilesEvent(new FindInFilesEvent(
							FindInFilesDialog.this, fileName, line));
			}
		}

	}


	/**
	 * Listens for key presses in the Find In Files dialog.
	 */
	private class FindInFilesKeyListener extends KeyAdapter {

		// Listens for a user releasing a key.
		public void keyReleased(KeyEvent e) {

			// This is an ugly hack to get around JComboBox's
			// insistence on eating the first Enter keypress
			// it receives when it has focus and its selected item
			// has changed since the last time it lost focus.
			if (e.getKeyCode()==KeyEvent.VK_ENTER && isPreJava6JRE()) {

				Object source = e.getSource();

				// If they pressed Enter in the 'Find What' combo box.
				if (source==getTextComponent(findTextCombo)) {
					String inFilesString = (String)inFilesComboBox.getSelectedItem();
					lastInFilesString = inFilesString;	// Just in case it changed too.
					String searchString = (String)findTextCombo.getSelectedItem();
					if (!searchString.equals(lastSearchString)) {
						findButton.doClick(0);
						lastSearchString = searchString;
						getTextComponent(findTextCombo).selectAll();
					}
				}

				// If they pressed enter in the 'In Files' combo box.
				else if (source==getTextComponent(inFilesComboBox)) {
					String searchString = (String)findTextCombo.getSelectedItem();
					lastSearchString = searchString;	// Just in case it changed too.
					String inFilesString = (String)inFilesComboBox.getSelectedItem();
					if (!inFilesString.equals(lastInFilesString)) {
						findButton.doClick(0);
						lastInFilesString = inFilesString;
						getTextComponent(inFilesComboBox).selectAll();
					}
				}

			}

		}

	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy