From 0d9bf48dcc4cebffefd3e36690d2eb94ce9914df Mon Sep 17 00:00:00 2001 From: bobbylight Date: Sun, 4 Oct 2026 19:09:20 -0400 Subject: [PATCH] build(deps): Bump build dependencies and sync checkstyle rules with RSyntaxTextArea Bumps spotbugs plugin to 6.5.9, checkstyle to 13.8.0, junit-bom to 6.1.1 and mockito to 5.23.0. Adds the LineEnding, IllegalSymbol, OverloadMethodsDeclarationOrder, UnusedTryResourceShouldBeUnnamed and NumericalPrefixesInfixesSuffixesCharacterCase checkstyle rules, and converts Java sources with CRLF line endings to LF to satisfy LineEnding. Co-Authored-By: Claude Sonnet 5.5 --- .editorconfig | 3 +- RSTAUI/build.gradle | 4 +- .../org/fife/rsta/ui/DecorativeIconPanel.java | 370 ++-- .../java/org/fife/rsta/ui/GoToDialog.java | 798 ++++---- .../rsta/ui/ResizableFrameContentPane.java | 134 +- .../java/org/fife/rsta/ui/SizeGripIcon.java | 202 +-- .../ui/search/AbstractFindReplaceDialog.java | 970 +++++----- .../org/fife/rsta/ui/search/FindDialog.java | 542 +++--- .../FindReplaceButtonsEnableResult.java | 86 +- .../org/fife/rsta/ui/search/FindToolBar.java | 1610 ++++++++--------- .../fife/rsta/ui/search/ReplaceToolBar.java | 590 +++--- .../org/fife/rsta/ui/search/SearchEvent.java | 146 +- .../org/fife/rsta/ui/search/SearchUtil.java | 92 +- build.gradle | 4 +- config/checkstyle/checkstyle.xml | 8 + 15 files changed, 2784 insertions(+), 2775 deletions(-) diff --git a/.editorconfig b/.editorconfig index 3603035..e69d731 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,13 @@ [*.java] indent_style = tab indent_size = 4 +end_of_line = lf trim_trailing_whitespace = true max_line_length = 120 [*.xml] indent_style = tab indent_size = 4 -trim_trailing_whitespace = true end_of_line = lf +trim_trailing_whitespace = true max_line_length = 120 diff --git a/RSTAUI/build.gradle b/RSTAUI/build.gradle index 304fa99..624776c 100644 --- a/RSTAUI/build.gradle +++ b/RSTAUI/build.gradle @@ -11,10 +11,10 @@ base { dependencies { api 'com.fifesoft:rsyntaxtextarea:4.0.1' api 'com.fifesoft:autocomplete:4.0.0' - testImplementation platform('org.junit:junit-bom:6.0.1') + testImplementation platform('org.junit:junit-bom:6.1.1') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation 'org.mockito:mockito-core:5.21.0' + testImplementation 'org.mockito:mockito-core:5.23.0' } ext.isReleaseVersion = !project.version.endsWith('SNAPSHOT') diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/DecorativeIconPanel.java b/RSTAUI/src/main/java/org/fife/rsta/ui/DecorativeIconPanel.java index 9d9e90b..a28ebe8 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/DecorativeIconPanel.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/DecorativeIconPanel.java @@ -1,185 +1,185 @@ -/* - * 07/30/2011 - * - * DecorativeIconPanel.java - Displays a small decorative icon beside some - * other component. - * This library is distributed under a modified BSD license. See the included - * RSTAUI.License.txt file for details. - */ -package org.fife.rsta.ui; - -import java.awt.BorderLayout; -import java.awt.Graphics; -import java.awt.event.MouseEvent; -import javax.swing.Icon; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import javax.swing.ToolTipManager; - -import org.fife.ui.autocomplete.EmptyIcon; - - -/** - * A panel that displays an 8x8 decorative icon for a component, such as a - * text field or combo box. This can be used to display error icons, warning - * icons, etc. - * - * @author Robert Futrell - * @version 1.1 - * @see AssistanceIconPanel - */ -public class DecorativeIconPanel extends JPanel { - - /** - * The width of this icon panel, to help align the components we're - * listening to with other combo boxes or text fields without a - * DecorativeIconPanel. - */ - public static final int DEFAULT_WIDTH = 8; - - private JLabel iconLabel; - private boolean showIcon; - private String tip; - private EmptyIcon emptyIcon; - - - /** - * Constructor. - */ - public DecorativeIconPanel() { - this(DEFAULT_WIDTH); - } - - - /** - * Constructor. - * - * @param iconWidth The with of decorative icons that will be added to - * this panel. This is used to ensure the proper amount of padding - * when no icon is being shown. - */ - public DecorativeIconPanel(int iconWidth) { - - setLayout(new BorderLayout()); - emptyIcon = new EmptyIcon(iconWidth); - - iconLabel = new JLabel(emptyIcon) { - @Override - public String getToolTipText(MouseEvent e) { - return showIcon ? tip : null; - } - }; - iconLabel.setVerticalAlignment(SwingConstants.TOP); - ToolTipManager.sharedInstance().registerComponent(iconLabel); - add(iconLabel, BorderLayout.NORTH); - } - - - /** - * Returns the icon being displayed. - * - * @return The icon. - * @see #setIcon(Icon) - */ - public Icon getIcon() { - return iconLabel.getIcon(); - } - - - /** - * Returns whether the icon (if any) is being rendered. - * - * @return Whether the icon is being rendered. - * @see #setShowIcon(boolean) - */ - public boolean getShowIcon() { - return showIcon; - } - - - /** - * Returns the tool tip displayed when the mouse hovers over the icon. - * If the icon is not being displayed, this parameter is ignored. - * - * @return The tool tip text. - * @see #setToolTipText(String) - */ - @Override - public String getToolTipText() { - return tip; - } - - - /** - * Paints any child components. Overridden so the user can explicitly - * hide the icon. - * - * @param g The graphics context. - * @see #setShowIcon(boolean) - */ - @Override - protected void paintChildren(Graphics g) { - if (showIcon) { - super.paintChildren(g); - } - } - - - /** - * Sets the icon to display. - * - * @param icon The new icon to display. - * @see #getIcon() - */ - public void setIcon(Icon icon) { - if (icon==null) { - icon = emptyIcon; - } - iconLabel.setIcon(icon); - } - - - /** - * Sets the size of the icon to display. This only needs to be - * called if the icon set being used changes at runtime. - * - * @param iconWidth The new icon size. - */ - public void setIconWidth(int iconWidth) { - if (iconWidth != emptyIcon.getIconWidth()) { - emptyIcon.setSize(iconWidth); - revalidate(); - repaint(); - } - } - - - /** - * Toggles whether the icon should be shown. - * - * @param show Whether to show the icon. - * @see #getShowIcon() - */ - public void setShowIcon(boolean show) { - if (show!=showIcon) { - showIcon = show; - repaint(); - } - } - - - /** - * Sets the tool tip text to display when the mouse is over the icon. - * This parameter is ignored if the icon is not being displayed. - * - * @param tip The tool tip text to display. - * @see #getToolTipText() - */ - @Override - public void setToolTipText(String tip) { - this.tip = tip; - } - - -} +/* + * 07/30/2011 + * + * DecorativeIconPanel.java - Displays a small decorative icon beside some + * other component. + * This library is distributed under a modified BSD license. See the included + * RSTAUI.License.txt file for details. + */ +package org.fife.rsta.ui; + +import java.awt.BorderLayout; +import java.awt.Graphics; +import java.awt.event.MouseEvent; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.ToolTipManager; + +import org.fife.ui.autocomplete.EmptyIcon; + + +/** + * A panel that displays an 8x8 decorative icon for a component, such as a + * text field or combo box. This can be used to display error icons, warning + * icons, etc. + * + * @author Robert Futrell + * @version 1.1 + * @see AssistanceIconPanel + */ +public class DecorativeIconPanel extends JPanel { + + /** + * The width of this icon panel, to help align the components we're + * listening to with other combo boxes or text fields without a + * DecorativeIconPanel. + */ + public static final int DEFAULT_WIDTH = 8; + + private JLabel iconLabel; + private boolean showIcon; + private String tip; + private EmptyIcon emptyIcon; + + + /** + * Constructor. + */ + public DecorativeIconPanel() { + this(DEFAULT_WIDTH); + } + + + /** + * Constructor. + * + * @param iconWidth The with of decorative icons that will be added to + * this panel. This is used to ensure the proper amount of padding + * when no icon is being shown. + */ + public DecorativeIconPanel(int iconWidth) { + + setLayout(new BorderLayout()); + emptyIcon = new EmptyIcon(iconWidth); + + iconLabel = new JLabel(emptyIcon) { + @Override + public String getToolTipText(MouseEvent e) { + return showIcon ? tip : null; + } + }; + iconLabel.setVerticalAlignment(SwingConstants.TOP); + ToolTipManager.sharedInstance().registerComponent(iconLabel); + add(iconLabel, BorderLayout.NORTH); + } + + + /** + * Returns the icon being displayed. + * + * @return The icon. + * @see #setIcon(Icon) + */ + public Icon getIcon() { + return iconLabel.getIcon(); + } + + + /** + * Returns whether the icon (if any) is being rendered. + * + * @return Whether the icon is being rendered. + * @see #setShowIcon(boolean) + */ + public boolean getShowIcon() { + return showIcon; + } + + + /** + * Returns the tool tip displayed when the mouse hovers over the icon. + * If the icon is not being displayed, this parameter is ignored. + * + * @return The tool tip text. + * @see #setToolTipText(String) + */ + @Override + public String getToolTipText() { + return tip; + } + + + /** + * Paints any child components. Overridden so the user can explicitly + * hide the icon. + * + * @param g The graphics context. + * @see #setShowIcon(boolean) + */ + @Override + protected void paintChildren(Graphics g) { + if (showIcon) { + super.paintChildren(g); + } + } + + + /** + * Sets the icon to display. + * + * @param icon The new icon to display. + * @see #getIcon() + */ + public void setIcon(Icon icon) { + if (icon==null) { + icon = emptyIcon; + } + iconLabel.setIcon(icon); + } + + + /** + * Sets the size of the icon to display. This only needs to be + * called if the icon set being used changes at runtime. + * + * @param iconWidth The new icon size. + */ + public void setIconWidth(int iconWidth) { + if (iconWidth != emptyIcon.getIconWidth()) { + emptyIcon.setSize(iconWidth); + revalidate(); + repaint(); + } + } + + + /** + * Toggles whether the icon should be shown. + * + * @param show Whether to show the icon. + * @see #getShowIcon() + */ + public void setShowIcon(boolean show) { + if (show!=showIcon) { + showIcon = show; + repaint(); + } + } + + + /** + * Sets the tool tip text to display when the mouse is over the icon. + * This parameter is ignored if the icon is not being displayed. + * + * @param tip The tool tip text to display. + * @see #getToolTipText() + */ + @Override + public void setToolTipText(String tip) { + this.tip = tip; + } + + +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/GoToDialog.java b/RSTAUI/src/main/java/org/fife/rsta/ui/GoToDialog.java index 0f3c0ab..bb42f49 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/GoToDialog.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/GoToDialog.java @@ -1,399 +1,399 @@ -/* - * 11/13/2003 - * - * GoToDialog.java - A dialog allowing you to skip to a specific line number. - * This library is distributed under a modified BSD license. See the included - * RSTAUI.License.txt file for details. - */ -package org.fife.rsta.ui; - -import java.awt.BorderLayout; -import java.awt.ComponentOrientation; -import java.awt.Container; -import java.awt.Dialog; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ResourceBundle; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JRootPane; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.AbstractDocument; -import javax.swing.text.AttributeSet; -import javax.swing.text.BadLocationException; -import javax.swing.text.DocumentFilter; - - -/** - * A "Go To" dialog allowing you to go to a specific line number in an - * instance of RSyntaxTextArea.

- * - * Example usage: - *

- * GoToDialog dialog = new GoToDialog(window);
- * dialog.setMaxLineNumberAllowed(textArea.getLineCount());
- * dialog.setVisible(true);
- * int line = dialog.getLineNumber();
- * if (line > 0) {
- *    try {
- *       textArea.setCaretPosition(textArea.getLineStartOffset(line-1));
- *    } catch (BadLocationException ble) {
- *       ble.printStackTrace(); // Never happens
- *    }
- * }
- * 
- * - * @author Robert Futrell - * @version 1.0 - */ -public class GoToDialog extends EscapableDialog { - - private JButton okButton; - private JButton cancelButton; - private JTextField lineNumberField; - private int maxLineNumberAllowed; // Number of lines in the document. - private int lineNumber; // The line to go to, or -1 for Cancel. - private String errorDialogTitle; - - private static final ResourceBundle MSG = ResourceBundle.getBundle("org.fife.rsta.ui.GoToDialog"); - - - /** - * Creates a new GoToDialog. - * - * @param owner The parent dialog. - */ - public GoToDialog(Dialog owner) { - super(owner); - init(); - } - - - /** - * Creates a new GoToDialog. - * - * @param owner The parent window. - */ - public GoToDialog(Frame owner) { - super(owner); - init(); - } - - - private void init() { - - ComponentOrientation orientation = ComponentOrientation. - getOrientation(getLocale()); - - lineNumber = -1; - maxLineNumberAllowed = 1; // Empty document has 1 line. - Listener l = new Listener(); - - // Set the main content pane for the "GoTo" dialog. - JPanel contentPane = new ResizableFrameContentPane(new BorderLayout()); - contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - setContentPane(contentPane); - - // Make a panel containing the "Line Number" edit box. - Box enterLineNumberPane = new Box(BoxLayout.LINE_AXIS); - enterLineNumberPane.setBorder(BorderFactory.createEmptyBorder( - 0, 0, 20, 0)); - lineNumberField = new JTextField(16); - lineNumberField.setText("1"); - AbstractDocument doc = (AbstractDocument)lineNumberField.getDocument(); - doc.addDocumentListener(l); - doc.setDocumentFilter(new NumberDocumentFilter()); - JLabel label = UIUtil.newLabel(MSG, "LineNumber", lineNumberField); - enterLineNumberPane.add(label); - enterLineNumberPane.add(Box.createHorizontalStrut(15)); - enterLineNumberPane.add(lineNumberField); - - // Make a panel containing the OK and Cancel buttons. - okButton = UIUtil.newButton(MSG, "OK"); - okButton.addActionListener(l); - cancelButton = UIUtil.newButton(MSG, "Cancel"); - cancelButton.addActionListener(l); - Container bottomPanel = createButtonPanel(okButton, cancelButton); - - // Put everything into a neat little package. - contentPane.add(enterLineNumberPane, BorderLayout.NORTH); - contentPane.add(bottomPanel, BorderLayout.SOUTH); - JRootPane rootPane = getRootPane(); - rootPane.setDefaultButton(okButton); - setTitle(MSG.getString("GotoDialogTitle")); - setModal(true); - applyComponentOrientation(orientation); - pack(); - setLocationRelativeTo(getParent()); - - } - - - /** - * Called when they've clicked OK or pressed Enter; check the line number - * they entered for validity and if it's okay, close this dialog. If it - * isn't okay, display an error message. - * - * @return Whether the line number was valid. In this case, this dialog - * will be hidden when this method returns. - */ - private boolean attemptToGetGoToLine() { - - try { - - lineNumber = Integer.parseInt(lineNumberField.getText()); - - if (lineNumber<1 || lineNumber>maxLineNumberAllowed) { - lineNumber = -1; - throw new NumberFormatException(); - } - - } catch (NumberFormatException nfe) { - displayInvalidLineNumberMessage(); - return false; - } - - // If we have a valid line number, close the dialog! - setVisible(false); - return true; - - } - - - /** - * Programmatically clicks the Cancel button. Used for testing purposes. - */ - void clickCancelButton() { - cancelButton.doClick(0); - } - - - /** - * Programmatically clicks the OK button. Used for testing purposes. - */ - protected void clickOkButton() { - okButton.doClick(0); - } - - - /** - * Returns a panel containing the OK and Cancel buttons. This panel is - * added to the bottom of this dialog. Applications that don't like these - * buttons right-aligned in the dialog can override this method to change - * that behavior. - * - * @param ok The OK button. - * @param cancel The Cancel button. - * @return A panel containing the two buttons. - */ - protected Container createButtonPanel(JButton ok, JButton cancel) { - JPanel buttonPanel = new JPanel(new GridLayout(1,2, 5,5)); - buttonPanel.add(ok); - buttonPanel.add(cancel); - JPanel bottomPanel = new JPanel(new BorderLayout()); - bottomPanel.add(buttonPanel, BorderLayout.LINE_END); - return bottomPanel; - } - - - /** - * Displays a message to the user that they have entered an invalid line - * number. The default implementation displays the error message in a - * modal. Subclasses that wish to have a slicker error delivery mechanism - * can override. - */ - protected void displayInvalidLineNumberMessage() { - JOptionPane.showMessageDialog(this, - MSG.getString("LineNumberRange") + maxLineNumberAllowed + ".", - getErrorDialogTitle(), - JOptionPane.ERROR_MESSAGE); - } - - - /** - * Called when the user clicks Cancel or hits the Escape key. This - * hides the dialog. - */ - @Override - protected void escapePressed() { - lineNumber = -1; - super.escapePressed(); - } - - - /** - * Returns the title for the error dialog. - * - * @return The title for the error dialog. - * @see #setErrorDialogTitle(String) - */ - public String getErrorDialogTitle() { - String title = errorDialogTitle; - if (title==null) { - title = MSG.getString("ErrorDialog.Title"); - } - return title; - } - - - /** - * Gets the line number the user entered to go to. - * - * @return The line number the user decided to go to, or -1 - * if the dialog was canceled. If valid, this will be 1-based, - * not 0-based. - * @see #setLineNumber(int) - */ - public int getLineNumber() { - return lineNumber; - } - - - /** - * Returns the maximum line number the user is allowed to enter. - * - * @return the maximum line number allowed. - * @see #setMaxLineNumberAllowed(int) - */ - public int getMaxLineNumberAllowed() { - return maxLineNumberAllowed; - } - - - /** - * Sets the title for the error dialog. - * - * @param title The new title. If this is null, a default - * value will be used. - * @see #getErrorDialogTitle() - */ - public void setErrorDialogTitle(String title) { - this.errorDialogTitle = title; - } - - - /** - * Sets the line number displayed in this dialog. - * - * @param lineNumber The new line number. - * @see #getLineNumber() - */ - protected void setLineNumber(int lineNumber) { - this.lineNumber = lineNumber; - lineNumberField.setText(String.valueOf(lineNumber)); - } - - - /** - * Sets the maximum line number for them to enter. - * - * @param max The new maximum line number value. - * @see #getMaxLineNumberAllowed() - */ - public void setMaxLineNumberAllowed(int max) { - this.maxLineNumberAllowed = max; - } - - - /** - * Overrides JDialog's setVisible method; decides - * whether buttons are enabled if the user is enabling the dialog. - */ - @Override - public void setVisible(boolean visible) { - if (visible) { - lineNumber = -1; - okButton.setEnabled(lineNumberField.getDocument().getLength()>0); - SwingUtilities.invokeLater(() -> { - lineNumberField.requestFocusInWindow(); - lineNumberField.selectAll(); - }); - } - super.setVisible(visible); - } - - - /** - * Listens for events in this dialog. - */ - private final class Listener implements ActionListener, DocumentListener { - - @Override - public void actionPerformed(ActionEvent e) { - Object source = e.getSource(); - if (okButton==source) { - attemptToGetGoToLine(); - } - else if (cancelButton==source) { - escapePressed(); - } - } - - @Override - public void changedUpdate(DocumentEvent e) { - } - - @Override - public void insertUpdate(DocumentEvent e) { - okButton.setEnabled(lineNumberField.getDocument().getLength()>0); - } - - @Override - public void removeUpdate(DocumentEvent e) { - okButton.setEnabled(lineNumberField.getDocument().getLength()>0); - } - - } - - - /** - * A document filter that only lets the user enter digits. - */ - private final class NumberDocumentFilter extends DocumentFilter { - - private String fix(String str) { - if (str!=null) { - int origLength = str.length(); - for (int i=0; i + * + * Example usage: + *
+ * GoToDialog dialog = new GoToDialog(window);
+ * dialog.setMaxLineNumberAllowed(textArea.getLineCount());
+ * dialog.setVisible(true);
+ * int line = dialog.getLineNumber();
+ * if (line > 0) {
+ *    try {
+ *       textArea.setCaretPosition(textArea.getLineStartOffset(line-1));
+ *    } catch (BadLocationException ble) {
+ *       ble.printStackTrace(); // Never happens
+ *    }
+ * }
+ * 
+ * + * @author Robert Futrell + * @version 1.0 + */ +public class GoToDialog extends EscapableDialog { + + private JButton okButton; + private JButton cancelButton; + private JTextField lineNumberField; + private int maxLineNumberAllowed; // Number of lines in the document. + private int lineNumber; // The line to go to, or -1 for Cancel. + private String errorDialogTitle; + + private static final ResourceBundle MSG = ResourceBundle.getBundle("org.fife.rsta.ui.GoToDialog"); + + + /** + * Creates a new GoToDialog. + * + * @param owner The parent dialog. + */ + public GoToDialog(Dialog owner) { + super(owner); + init(); + } + + + /** + * Creates a new GoToDialog. + * + * @param owner The parent window. + */ + public GoToDialog(Frame owner) { + super(owner); + init(); + } + + + private void init() { + + ComponentOrientation orientation = ComponentOrientation. + getOrientation(getLocale()); + + lineNumber = -1; + maxLineNumberAllowed = 1; // Empty document has 1 line. + Listener l = new Listener(); + + // Set the main content pane for the "GoTo" dialog. + JPanel contentPane = new ResizableFrameContentPane(new BorderLayout()); + contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + setContentPane(contentPane); + + // Make a panel containing the "Line Number" edit box. + Box enterLineNumberPane = new Box(BoxLayout.LINE_AXIS); + enterLineNumberPane.setBorder(BorderFactory.createEmptyBorder( + 0, 0, 20, 0)); + lineNumberField = new JTextField(16); + lineNumberField.setText("1"); + AbstractDocument doc = (AbstractDocument)lineNumberField.getDocument(); + doc.addDocumentListener(l); + doc.setDocumentFilter(new NumberDocumentFilter()); + JLabel label = UIUtil.newLabel(MSG, "LineNumber", lineNumberField); + enterLineNumberPane.add(label); + enterLineNumberPane.add(Box.createHorizontalStrut(15)); + enterLineNumberPane.add(lineNumberField); + + // Make a panel containing the OK and Cancel buttons. + okButton = UIUtil.newButton(MSG, "OK"); + okButton.addActionListener(l); + cancelButton = UIUtil.newButton(MSG, "Cancel"); + cancelButton.addActionListener(l); + Container bottomPanel = createButtonPanel(okButton, cancelButton); + + // Put everything into a neat little package. + contentPane.add(enterLineNumberPane, BorderLayout.NORTH); + contentPane.add(bottomPanel, BorderLayout.SOUTH); + JRootPane rootPane = getRootPane(); + rootPane.setDefaultButton(okButton); + setTitle(MSG.getString("GotoDialogTitle")); + setModal(true); + applyComponentOrientation(orientation); + pack(); + setLocationRelativeTo(getParent()); + + } + + + /** + * Called when they've clicked OK or pressed Enter; check the line number + * they entered for validity and if it's okay, close this dialog. If it + * isn't okay, display an error message. + * + * @return Whether the line number was valid. In this case, this dialog + * will be hidden when this method returns. + */ + private boolean attemptToGetGoToLine() { + + try { + + lineNumber = Integer.parseInt(lineNumberField.getText()); + + if (lineNumber<1 || lineNumber>maxLineNumberAllowed) { + lineNumber = -1; + throw new NumberFormatException(); + } + + } catch (NumberFormatException nfe) { + displayInvalidLineNumberMessage(); + return false; + } + + // If we have a valid line number, close the dialog! + setVisible(false); + return true; + + } + + + /** + * Programmatically clicks the Cancel button. Used for testing purposes. + */ + void clickCancelButton() { + cancelButton.doClick(0); + } + + + /** + * Programmatically clicks the OK button. Used for testing purposes. + */ + protected void clickOkButton() { + okButton.doClick(0); + } + + + /** + * Returns a panel containing the OK and Cancel buttons. This panel is + * added to the bottom of this dialog. Applications that don't like these + * buttons right-aligned in the dialog can override this method to change + * that behavior. + * + * @param ok The OK button. + * @param cancel The Cancel button. + * @return A panel containing the two buttons. + */ + protected Container createButtonPanel(JButton ok, JButton cancel) { + JPanel buttonPanel = new JPanel(new GridLayout(1,2, 5,5)); + buttonPanel.add(ok); + buttonPanel.add(cancel); + JPanel bottomPanel = new JPanel(new BorderLayout()); + bottomPanel.add(buttonPanel, BorderLayout.LINE_END); + return bottomPanel; + } + + + /** + * Displays a message to the user that they have entered an invalid line + * number. The default implementation displays the error message in a + * modal. Subclasses that wish to have a slicker error delivery mechanism + * can override. + */ + protected void displayInvalidLineNumberMessage() { + JOptionPane.showMessageDialog(this, + MSG.getString("LineNumberRange") + maxLineNumberAllowed + ".", + getErrorDialogTitle(), + JOptionPane.ERROR_MESSAGE); + } + + + /** + * Called when the user clicks Cancel or hits the Escape key. This + * hides the dialog. + */ + @Override + protected void escapePressed() { + lineNumber = -1; + super.escapePressed(); + } + + + /** + * Returns the title for the error dialog. + * + * @return The title for the error dialog. + * @see #setErrorDialogTitle(String) + */ + public String getErrorDialogTitle() { + String title = errorDialogTitle; + if (title==null) { + title = MSG.getString("ErrorDialog.Title"); + } + return title; + } + + + /** + * Gets the line number the user entered to go to. + * + * @return The line number the user decided to go to, or -1 + * if the dialog was canceled. If valid, this will be 1-based, + * not 0-based. + * @see #setLineNumber(int) + */ + public int getLineNumber() { + return lineNumber; + } + + + /** + * Returns the maximum line number the user is allowed to enter. + * + * @return the maximum line number allowed. + * @see #setMaxLineNumberAllowed(int) + */ + public int getMaxLineNumberAllowed() { + return maxLineNumberAllowed; + } + + + /** + * Sets the title for the error dialog. + * + * @param title The new title. If this is null, a default + * value will be used. + * @see #getErrorDialogTitle() + */ + public void setErrorDialogTitle(String title) { + this.errorDialogTitle = title; + } + + + /** + * Sets the line number displayed in this dialog. + * + * @param lineNumber The new line number. + * @see #getLineNumber() + */ + protected void setLineNumber(int lineNumber) { + this.lineNumber = lineNumber; + lineNumberField.setText(String.valueOf(lineNumber)); + } + + + /** + * Sets the maximum line number for them to enter. + * + * @param max The new maximum line number value. + * @see #getMaxLineNumberAllowed() + */ + public void setMaxLineNumberAllowed(int max) { + this.maxLineNumberAllowed = max; + } + + + /** + * Overrides JDialog's setVisible method; decides + * whether buttons are enabled if the user is enabling the dialog. + */ + @Override + public void setVisible(boolean visible) { + if (visible) { + lineNumber = -1; + okButton.setEnabled(lineNumberField.getDocument().getLength()>0); + SwingUtilities.invokeLater(() -> { + lineNumberField.requestFocusInWindow(); + lineNumberField.selectAll(); + }); + } + super.setVisible(visible); + } + + + /** + * Listens for events in this dialog. + */ + private final class Listener implements ActionListener, DocumentListener { + + @Override + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + if (okButton==source) { + attemptToGetGoToLine(); + } + else if (cancelButton==source) { + escapePressed(); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + + @Override + public void insertUpdate(DocumentEvent e) { + okButton.setEnabled(lineNumberField.getDocument().getLength()>0); + } + + @Override + public void removeUpdate(DocumentEvent e) { + okButton.setEnabled(lineNumberField.getDocument().getLength()>0); + } + + } + + + /** + * A document filter that only lets the user enter digits. + */ + private final class NumberDocumentFilter extends DocumentFilter { + + private String fix(String str) { + if (str!=null) { + int origLength = str.length(); + for (int i=0; iJDialogs - * and JFrames that are resizable. This panel has - * a size grip that can be dragged and cause a resize of the window, - * similar to that found on resizable Microsoft Windows dialogs. - * - * @author Robert Futrell - * @version 1.0 - */ -public class ResizableFrameContentPane extends JPanel { - - private static final long serialVersionUID = 1L; - - private SizeGripIcon gripIcon; - - - /** - * Constructor. - */ - public ResizableFrameContentPane() { - gripIcon = new SizeGripIcon(); - } - - - /** - * Constructor. - * - * @param layout The layout manager. - */ - public ResizableFrameContentPane(LayoutManager layout) { - super(layout); - gripIcon = new SizeGripIcon(); - } - - - /** - * Paints this panel. - * - * @param g The graphics context. - */ - /* - * We override paint() instead of paintComponent() as if we do the latter, - * sometimes child panels will be painted over our size grip, rendering it - * invisible. - */ - @Override - public void paint(Graphics g) { - super.paint(g); - gripIcon.paintIcon(this, g, this.getX(), this.getY()); - } - - +/* + * 09/07/2006 + * + * ResizableFrameContentPane.java - A content pane with a size grip that + * can be used to resize a sizable dialog or frame. + * This library is distributed under a modified BSD license. See the included + * RSTAUI.License.txt file for details. + */ +package org.fife.rsta.ui; + +import java.awt.*; +import javax.swing.*; + + + +/** + * A panel to be used as the content pane for JDialogs + * and JFrames that are resizable. This panel has + * a size grip that can be dragged and cause a resize of the window, + * similar to that found on resizable Microsoft Windows dialogs. + * + * @author Robert Futrell + * @version 1.0 + */ +public class ResizableFrameContentPane extends JPanel { + + private static final long serialVersionUID = 1L; + + private SizeGripIcon gripIcon; + + + /** + * Constructor. + */ + public ResizableFrameContentPane() { + gripIcon = new SizeGripIcon(); + } + + + /** + * Constructor. + * + * @param layout The layout manager. + */ + public ResizableFrameContentPane(LayoutManager layout) { + super(layout); + gripIcon = new SizeGripIcon(); + } + + + /** + * Paints this panel. + * + * @param g The graphics context. + */ + /* + * We override paint() instead of paintComponent() as if we do the latter, + * sometimes child panels will be painted over our size grip, rendering it + * invisible. + */ + @Override + public void paint(Graphics g) { + super.paint(g); + gripIcon.paintIcon(this, g, this.getX(), this.getY()); + } + + } \ No newline at end of file diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/SizeGripIcon.java b/RSTAUI/src/main/java/org/fife/rsta/ui/SizeGripIcon.java index 1034785..d5a5040 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/SizeGripIcon.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/SizeGripIcon.java @@ -1,102 +1,102 @@ -/* - * 09/07/2006 - * - * SizeGripIcon.java - An icon that paints a size grip. - * This library is distributed under a modified BSD license. See the included - * RSTAUI.License.txt file for details. - */ -package org.fife.rsta.ui; - -import java.awt.*; -import javax.swing.*; - - -/** - * An icon that looks like a Windows 98 or XP-style size grip. - * - * @author Robert Futrell - * @version 1.0 - */ -public class SizeGripIcon implements Icon { - - private static final int SIZE = 16; - - - /** - * Returns the height of this icon. - * - * @return This icon's height. - */ - @Override - public int getIconHeight() { - return SIZE; - } - - - /** - * Returns the width of this icon. - * - * @return This icon's width. - */ - @Override - public int getIconWidth() { - return SIZE; - } - - - /** - * Paints this icon. - * - * @param c The component to paint on. - * @param g The graphics context. - * @param x The x-coordinate at which to paint. - * @param y The y-coordinate at which to paint. - */ - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - - Dimension dim = c.getSize(); - Color c1 = UIManager.getColor("Label.disabledShadow"); - Color c2 = UIManager.getColor("Label.disabledForeground"); - - ComponentOrientation orientation = c.getComponentOrientation(); - int height = dim.height -= 3; - - if (orientation.isLeftToRight()) { - int width = dim.width -= 3; - g.setColor(c1); - g.fillRect(width-9,height-1, 3,3); - g.fillRect(width-5,height-1, 3,3); - g.fillRect(width-1,height-1, 3,3); - g.fillRect(width-5,height-5, 3,3); - g.fillRect(width-1,height-5, 3,3); - g.fillRect(width-1,height-9, 3,3); - g.setColor(c2); - g.fillRect(width-9,height-1, 2,2); - g.fillRect(width-5,height-1, 2,2); - g.fillRect(width-1,height-1, 2,2); - g.fillRect(width-5,height-5, 2,2); - g.fillRect(width-1,height-5, 2,2); - g.fillRect(width-1,height-9, 2,2); - } - else { - g.setColor(c1); - g.fillRect(10,height-1, 3,3); - g.fillRect(6,height-1, 3,3); - g.fillRect(2,height-1, 3,3); - g.fillRect(6,height-5, 3,3); - g.fillRect(2,height-5, 3,3); - g.fillRect(2,height-9, 3,3); - g.setColor(c2); - g.fillRect(10,height-1, 2,2); - g.fillRect(6,height-1, 2,2); - g.fillRect(2,height-1, 2,2); - g.fillRect(6,height-5, 2,2); - g.fillRect(2,height-5, 2,2); - g.fillRect(2,height-9, 2,2); - } - - } - - +/* + * 09/07/2006 + * + * SizeGripIcon.java - An icon that paints a size grip. + * This library is distributed under a modified BSD license. See the included + * RSTAUI.License.txt file for details. + */ +package org.fife.rsta.ui; + +import java.awt.*; +import javax.swing.*; + + +/** + * An icon that looks like a Windows 98 or XP-style size grip. + * + * @author Robert Futrell + * @version 1.0 + */ +public class SizeGripIcon implements Icon { + + private static final int SIZE = 16; + + + /** + * Returns the height of this icon. + * + * @return This icon's height. + */ + @Override + public int getIconHeight() { + return SIZE; + } + + + /** + * Returns the width of this icon. + * + * @return This icon's width. + */ + @Override + public int getIconWidth() { + return SIZE; + } + + + /** + * Paints this icon. + * + * @param c The component to paint on. + * @param g The graphics context. + * @param x The x-coordinate at which to paint. + * @param y The y-coordinate at which to paint. + */ + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + + Dimension dim = c.getSize(); + Color c1 = UIManager.getColor("Label.disabledShadow"); + Color c2 = UIManager.getColor("Label.disabledForeground"); + + ComponentOrientation orientation = c.getComponentOrientation(); + int height = dim.height -= 3; + + if (orientation.isLeftToRight()) { + int width = dim.width -= 3; + g.setColor(c1); + g.fillRect(width-9,height-1, 3,3); + g.fillRect(width-5,height-1, 3,3); + g.fillRect(width-1,height-1, 3,3); + g.fillRect(width-5,height-5, 3,3); + g.fillRect(width-1,height-5, 3,3); + g.fillRect(width-1,height-9, 3,3); + g.setColor(c2); + g.fillRect(width-9,height-1, 2,2); + g.fillRect(width-5,height-1, 2,2); + g.fillRect(width-1,height-1, 2,2); + g.fillRect(width-5,height-5, 2,2); + g.fillRect(width-1,height-5, 2,2); + g.fillRect(width-1,height-9, 2,2); + } + else { + g.setColor(c1); + g.fillRect(10,height-1, 3,3); + g.fillRect(6,height-1, 3,3); + g.fillRect(2,height-1, 3,3); + g.fillRect(6,height-5, 3,3); + g.fillRect(2,height-5, 3,3); + g.fillRect(2,height-9, 3,3); + g.setColor(c2); + g.fillRect(10,height-1, 2,2); + g.fillRect(6,height-1, 2,2); + g.fillRect(2,height-1, 2,2); + g.fillRect(6,height-5, 2,2); + g.fillRect(2,height-5, 2,2); + g.fillRect(2,height-9, 2,2); + } + + } + + } \ No newline at end of file diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/AbstractFindReplaceDialog.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/AbstractFindReplaceDialog.java index 6f52fb2..ed92c68 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/AbstractFindReplaceDialog.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/AbstractFindReplaceDialog.java @@ -1,485 +1,485 @@ -/* - * 04/08/2004 - * - * AbstractFindReplaceSearchDialog.java - Base class for FindDialog and - * ReplaceDialog. - * This library is distributed under a modified BSD license. See the included - * RSTAUI.License.txt file for details. - */ -package org.fife.rsta.ui.search; - -import java.awt.BorderLayout; -import java.awt.Dialog; -import java.awt.Frame; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; -import java.beans.PropertyChangeEvent; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; -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.JRadioButton; -import javax.swing.JRootPane; -import javax.swing.KeyStroke; -import javax.swing.UIManager; -import javax.swing.event.EventListenerList; -import javax.swing.text.JTextComponent; - -import org.fife.rsta.ui.UIUtil; -import org.fife.ui.rtextarea.SearchContext; - - -/** - * This is the base class for {@link FindDialog} and {@link ReplaceDialog}. It - * is basically all the features common to the two dialogs that weren't - * taken care of in {@link AbstractSearchDialog}. - * - * @author Robert Futrell - * @version 0.1 - */ -public abstract class AbstractFindReplaceDialog extends AbstractSearchDialog { - - /** - * Property fired when the user toggles the search direction radio buttons. - */ - public static final String SEARCH_DOWNWARD_PROPERTY = "SearchDialog.SearchDownward"; - - // The radio buttons for changing the search direction. - protected JRadioButton upButton; - protected JRadioButton downButton; - protected JPanel dirPanel; - private String dirPanelTitle; - protected JLabel findFieldLabel; - protected JButton findNextButton; - - /** - * The "mark all" check box. - */ - protected JCheckBox markAllCheckBox; - - /** - * Folks listening for events in this dialog. - */ - private EventListenerList listenerList; - - - /** - * Constructor. - * - * @param owner The dialog that owns this search dialog. - */ - public AbstractFindReplaceDialog(Dialog owner) { - super(owner); - init(); - } - - /** - * Constructor. Does the initializing for parts common to - * FindDialog and ReplaceDialog that isn't - * taken care of in AbstractSearchDialog's constructor. - * - * @param owner The window that owns this search dialog. - */ - public AbstractFindReplaceDialog(Frame owner) { - super(owner); - init(); - } - - - /** - * Listens for action events in this dialog. - * - * @param e The event that occurred. - */ - @Override - public void actionPerformed(ActionEvent e) { - - String command = e.getActionCommand(); - - if ("UpRadioButtonClicked".equals(command)) { - context.setSearchForward(false); - } - - else if ("DownRadioButtonClicked".equals(command)) { - context.setSearchForward(true); - } - - else if ("MarkAll".equals(command)) { - boolean checked = markAllCheckBox.isSelected(); - context.setMarkAll(checked); - } - - else if (SearchEvent.Type.FIND.name().equals(command)) { - doSearch(context.getSearchForward()); // Keep current direction - } - - else { - super.actionPerformed(e); - } - - } - - - /** - * Adds a {@link SearchListener} to this dialog. This listener will - * be notified when find or replace operations are triggered. For - * example, for a Replace dialog, a listener will receive notification - * when the user clicks "Find", "Replace", or "Replace All". - * - * @param l The listener to add. - * @see #removeSearchListener(SearchListener) - */ - public void addSearchListener(SearchListener l) { - listenerList.add(SearchListener.class, l); - } - - - private void doSearch(boolean forward) { - - // Add the item to the combo box's list, if it isn't already there. - JTextComponent tc = UIUtil.getTextComponent(findTextCombo); - findTextCombo.addItem(tc.getText()); - context.setSearchFor(getSearchString()); - - // If the ask is to search in the opposite direction from the UI's - // current direction, use a cloned search context to avoid updating - // the UI when we shouldn't (e.g. from a keyboard shortcut to search - // backward). - SearchContext contextToFire = context; - if (forward != context.getSearchForward()) { - contextToFire = context.clone(); - contextToFire.setSearchForward(forward); - } - - // Let parent application know - fireSearchEvent(SearchEvent.Type.FIND, contextToFire); - } - - /** - * Notifies all listeners that have registered interest in notification for - * this event type. The event instance is lazily created using the - * event parameter. - * - * @param type The type of search. - * @param context The search context to fire. If this is {@code null}, this - * dialog's current context (e.g. its current state) is used. This - * parameter allows for scenarios where we want to search differently - * than what our UI displays; for example, binding a keyboard - * shortcut to "search backwards" no matter what. - */ - protected void fireSearchEvent(SearchEvent.Type type, SearchContext context) { - - if (context == null) { - context = this.context; - } - - // Guaranteed to return a non-null array - Object[] listeners = listenerList.getListenerList(); - SearchEvent e = null; - // 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] == SearchListener.class) { - // Lazily create the event: - if (e == null) { - e = new SearchEvent(this, type, context); - } - ((SearchListener)listeners[i+1]).searchEvent(e); - } - } - } - - - /** - * Returns the text for the "Down" radio button. - * - * @return The text for the "Down" radio button. - * @see #setDownRadioButtonText - */ - public final String getDownRadioButtonText() { - return downButton.getText(); - } - - - /** - * Returns the text on the "Find" button. - * - * @return The text on the Find button. - * @see #setFindButtonText - */ - public final String getFindButtonText() { - return findNextButton.getText(); - } - - - /** - * Returns the label on the "Find what" text field. - * - * @return The text on the "Find what" text field. - * @see #setFindWhatLabelText - */ - public final String getFindWhatLabelText() { - return findFieldLabel.getText(); - } - - - /** - * Returns the text for the search direction's radio buttons' border. - * - * @return The text for the search radio buttons' border. - * @see #setSearchButtonsBorderText - */ - public final String getSearchButtonsBorderText() { - return dirPanelTitle; - } - - - /** - * Returns the text for the "Up" radio button. - * - * @return The text for the "Up" radio button. - * @see #setUpRadioButtonText - */ - public final String getUpRadioButtonText() { - return upButton.getText(); - } - - - /** - * Called whenever a property in the search context is modified. - * Subclasses should override if they listen for additional properties. - * - * @param e The property change event fired. - */ - @Override - protected void handleSearchContextPropertyChanged(PropertyChangeEvent e) { - - String prop = e.getPropertyName(); - - if (SearchContext.PROPERTY_SEARCH_FORWARD.equals(prop)) { - boolean newValue = (Boolean) e.getNewValue(); - JRadioButton button = newValue ? downButton : upButton; - button.setSelected(true); - } - - else if (SearchContext.PROPERTY_MARK_ALL.equals(prop)) { - boolean newValue = (Boolean) e.getNewValue(); - markAllCheckBox.setSelected(newValue); - } - - else { - super.handleSearchContextPropertyChanged(e); - } - - } - - - @Override - protected FindReplaceButtonsEnableResult handleToggleButtons() { - - FindReplaceButtonsEnableResult er = super.handleToggleButtons(); - boolean enable = er.getEnable(); - - findNextButton.setEnabled(enable); - - // setBackground doesn't show up with XP Look and Feel! - JTextComponent tc = UIUtil.getTextComponent(findTextCombo); - tc.setForeground(enable ? UIManager.getColor("TextField.foreground") : - UIUtil.getErrorTextForeground()); - - String tooltip = SearchUtil.getToolTip(er); - tc.setToolTipText(tooltip); // Always set, even if null - - return er; - - } - - - private void init() { - - listenerList = new EventListenerList(); - - // Make a panel containing the "search up/down" radio buttons. - dirPanel = new JPanel(); - dirPanel.setLayout(new BoxLayout(dirPanel, BoxLayout.LINE_AXIS)); - setSearchButtonsBorderText(getString("Direction")); - ButtonGroup bg = new ButtonGroup(); - upButton = new JRadioButton(getString("Up"), false); - upButton.setMnemonic((int)getString("UpMnemonic").charAt(0)); - downButton = new JRadioButton(getString("Down"), true); - downButton.setMnemonic((int)getString("DownMnemonic").charAt(0)); - upButton.setActionCommand("UpRadioButtonClicked"); - upButton.addActionListener(this); - downButton.setActionCommand("DownRadioButtonClicked"); - downButton.addActionListener(this); - bg.add(upButton); - bg.add(downButton); - dirPanel.add(upButton); - dirPanel.add(downButton); - - // Initialize the "mark all" button. - markAllCheckBox = new JCheckBox(getString("MarkAll")); - markAllCheckBox.setMnemonic((int)getString("MarkAllMnemonic").charAt(0)); - markAllCheckBox.setActionCommand("MarkAll"); - markAllCheckBox.addActionListener(this); - - // Rearrange the search conditions panel. - searchConditionsPanel.removeAll(); - searchConditionsPanel.setLayout(new BorderLayout()); - JPanel temp = new JPanel(); - temp.setLayout(new BoxLayout(temp, BoxLayout.PAGE_AXIS)); - temp.add(caseCheckBox); - temp.add(wholeWordCheckBox); - temp.add(wrapCheckBox); - searchConditionsPanel.add(temp, BorderLayout.LINE_START); - temp = new JPanel(); - temp.setLayout(new BoxLayout(temp, BoxLayout.PAGE_AXIS)); - temp.add(regexCheckBox); - temp.add(markAllCheckBox); - searchConditionsPanel.add(temp, BorderLayout.LINE_END); - - // Create the "Find what" label. - findFieldLabel = UIUtil.newLabel(getBundle(), "FindWhat",findTextCombo); - - // Create a "Find Next" button. - findNextButton = UIUtil.newButton(getBundle(), "Find"); - findNextButton.setActionCommand(SearchEvent.Type.FIND.name()); - findNextButton.addActionListener(this); - findNextButton.setDefaultCapable(true); - findNextButton.setEnabled(false); // Initially, nothing to look for. - - installKeyboardActions(); - - } - - - /** - * Adds extra keyboard actions for Find and Replace dialogs. - */ - private void installKeyboardActions() { - - JRootPane rootPane = getRootPane(); - InputMap im = rootPane.getInputMap( - JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - ActionMap am = rootPane.getActionMap(); - - int modifier = getToolkit().getMenuShortcutKeyMaskEx(); - KeyStroke ctrlF = KeyStroke.getKeyStroke(KeyEvent.VK_F, modifier); - im.put(ctrlF, "focusSearchForField"); - am.put("focusSearchForField", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - AbstractFindReplaceDialog.this.requestFocus(); - } - }); - - // Shift+Enter and Ctrl+Enter both do a backwards/opposite search - int shift = InputEvent.SHIFT_DOWN_MASK; - int ctrl = InputEvent.CTRL_DOWN_MASK; - if (System.getProperty("os.name").toLowerCase().contains("os x")) { - ctrl = InputEvent.META_DOWN_MASK; - } - KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, shift); - im.put(ks, "searchBackward"); - ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, ctrl); - im.put(ks, "searchBackward"); - am.put("searchBackward", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - doSearch(!context.getSearchForward()); - } - }); - } - - - /** - * Overridden to initialize UI elements specific to this subclass. - */ - @Override - protected void refreshUIFromContext() { - if (this.markAllCheckBox==null) { - return; // First time through, UI not realized yet - } - super.refreshUIFromContext(); - markAllCheckBox.setSelected(context.getMarkAll()); - boolean searchForward = context.getSearchForward(); - upButton.setSelected(!searchForward); - downButton.setSelected(searchForward); - } - - - /** - * Removes a {@link SearchListener} from this dialog. - * - * @param l The listener to remove - * @see #addSearchListener(SearchListener) - */ - public void removeSearchListener(SearchListener l) { - listenerList.remove(SearchListener.class, l); - } - - - /** - * Sets the text label for the "Down" radio button. - * - * @param text The new text label for the "Down" radio button. - * @see #getDownRadioButtonText - */ - public void setDownRadioButtonText(String text) { - downButton.setText(text); - } - - - /** - * Sets the text on the "Find" button. - * - * @param text The text for the Find button. - * @see #getFindButtonText - */ - public final void setFindButtonText(String text) { - findNextButton.setText(text); - } - - - /** - * Sets the label on the "Find what" text field. - * - * @param text The text for the "Find what" text field's label. - * @see #getFindWhatLabelText - */ - public void setFindWhatLabelText(String text) { - findFieldLabel.setText(text); - } - - - /** - * Sets the text for the search direction's radio buttons' border. - * - * @param text The text for the search radio buttons' border. - * @see #getSearchButtonsBorderText - */ - public final void setSearchButtonsBorderText(String text) { - dirPanelTitle = text; - dirPanel.setBorder(createTitledBorder(dirPanelTitle)); - } - - - /** - * Sets the text label for the "Up" radio button. - * - * @param text The new text label for the "Up" radio button. - * @see #getUpRadioButtonText - */ - public void setUpRadioButtonText(String text) { - upButton.setText(text); - } - - -} +/* + * 04/08/2004 + * + * AbstractFindReplaceSearchDialog.java - Base class for FindDialog and + * ReplaceDialog. + * This library is distributed under a modified BSD license. See the included + * RSTAUI.License.txt file for details. + */ +package org.fife.rsta.ui.search; + +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.beans.PropertyChangeEvent; +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +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.JRadioButton; +import javax.swing.JRootPane; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.event.EventListenerList; +import javax.swing.text.JTextComponent; + +import org.fife.rsta.ui.UIUtil; +import org.fife.ui.rtextarea.SearchContext; + + +/** + * This is the base class for {@link FindDialog} and {@link ReplaceDialog}. It + * is basically all the features common to the two dialogs that weren't + * taken care of in {@link AbstractSearchDialog}. + * + * @author Robert Futrell + * @version 0.1 + */ +public abstract class AbstractFindReplaceDialog extends AbstractSearchDialog { + + /** + * Property fired when the user toggles the search direction radio buttons. + */ + public static final String SEARCH_DOWNWARD_PROPERTY = "SearchDialog.SearchDownward"; + + // The radio buttons for changing the search direction. + protected JRadioButton upButton; + protected JRadioButton downButton; + protected JPanel dirPanel; + private String dirPanelTitle; + protected JLabel findFieldLabel; + protected JButton findNextButton; + + /** + * The "mark all" check box. + */ + protected JCheckBox markAllCheckBox; + + /** + * Folks listening for events in this dialog. + */ + private EventListenerList listenerList; + + + /** + * Constructor. + * + * @param owner The dialog that owns this search dialog. + */ + public AbstractFindReplaceDialog(Dialog owner) { + super(owner); + init(); + } + + /** + * Constructor. Does the initializing for parts common to + * FindDialog and ReplaceDialog that isn't + * taken care of in AbstractSearchDialog's constructor. + * + * @param owner The window that owns this search dialog. + */ + public AbstractFindReplaceDialog(Frame owner) { + super(owner); + init(); + } + + + /** + * Listens for action events in this dialog. + * + * @param e The event that occurred. + */ + @Override + public void actionPerformed(ActionEvent e) { + + String command = e.getActionCommand(); + + if ("UpRadioButtonClicked".equals(command)) { + context.setSearchForward(false); + } + + else if ("DownRadioButtonClicked".equals(command)) { + context.setSearchForward(true); + } + + else if ("MarkAll".equals(command)) { + boolean checked = markAllCheckBox.isSelected(); + context.setMarkAll(checked); + } + + else if (SearchEvent.Type.FIND.name().equals(command)) { + doSearch(context.getSearchForward()); // Keep current direction + } + + else { + super.actionPerformed(e); + } + + } + + + /** + * Adds a {@link SearchListener} to this dialog. This listener will + * be notified when find or replace operations are triggered. For + * example, for a Replace dialog, a listener will receive notification + * when the user clicks "Find", "Replace", or "Replace All". + * + * @param l The listener to add. + * @see #removeSearchListener(SearchListener) + */ + public void addSearchListener(SearchListener l) { + listenerList.add(SearchListener.class, l); + } + + + private void doSearch(boolean forward) { + + // Add the item to the combo box's list, if it isn't already there. + JTextComponent tc = UIUtil.getTextComponent(findTextCombo); + findTextCombo.addItem(tc.getText()); + context.setSearchFor(getSearchString()); + + // If the ask is to search in the opposite direction from the UI's + // current direction, use a cloned search context to avoid updating + // the UI when we shouldn't (e.g. from a keyboard shortcut to search + // backward). + SearchContext contextToFire = context; + if (forward != context.getSearchForward()) { + contextToFire = context.clone(); + contextToFire.setSearchForward(forward); + } + + // Let parent application know + fireSearchEvent(SearchEvent.Type.FIND, contextToFire); + } + + /** + * Notifies all listeners that have registered interest in notification for + * this event type. The event instance is lazily created using the + * event parameter. + * + * @param type The type of search. + * @param context The search context to fire. If this is {@code null}, this + * dialog's current context (e.g. its current state) is used. This + * parameter allows for scenarios where we want to search differently + * than what our UI displays; for example, binding a keyboard + * shortcut to "search backwards" no matter what. + */ + protected void fireSearchEvent(SearchEvent.Type type, SearchContext context) { + + if (context == null) { + context = this.context; + } + + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + SearchEvent e = null; + // 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] == SearchListener.class) { + // Lazily create the event: + if (e == null) { + e = new SearchEvent(this, type, context); + } + ((SearchListener)listeners[i+1]).searchEvent(e); + } + } + } + + + /** + * Returns the text for the "Down" radio button. + * + * @return The text for the "Down" radio button. + * @see #setDownRadioButtonText + */ + public final String getDownRadioButtonText() { + return downButton.getText(); + } + + + /** + * Returns the text on the "Find" button. + * + * @return The text on the Find button. + * @see #setFindButtonText + */ + public final String getFindButtonText() { + return findNextButton.getText(); + } + + + /** + * Returns the label on the "Find what" text field. + * + * @return The text on the "Find what" text field. + * @see #setFindWhatLabelText + */ + public final String getFindWhatLabelText() { + return findFieldLabel.getText(); + } + + + /** + * Returns the text for the search direction's radio buttons' border. + * + * @return The text for the search radio buttons' border. + * @see #setSearchButtonsBorderText + */ + public final String getSearchButtonsBorderText() { + return dirPanelTitle; + } + + + /** + * Returns the text for the "Up" radio button. + * + * @return The text for the "Up" radio button. + * @see #setUpRadioButtonText + */ + public final String getUpRadioButtonText() { + return upButton.getText(); + } + + + /** + * Called whenever a property in the search context is modified. + * Subclasses should override if they listen for additional properties. + * + * @param e The property change event fired. + */ + @Override + protected void handleSearchContextPropertyChanged(PropertyChangeEvent e) { + + String prop = e.getPropertyName(); + + if (SearchContext.PROPERTY_SEARCH_FORWARD.equals(prop)) { + boolean newValue = (Boolean) e.getNewValue(); + JRadioButton button = newValue ? downButton : upButton; + button.setSelected(true); + } + + else if (SearchContext.PROPERTY_MARK_ALL.equals(prop)) { + boolean newValue = (Boolean) e.getNewValue(); + markAllCheckBox.setSelected(newValue); + } + + else { + super.handleSearchContextPropertyChanged(e); + } + + } + + + @Override + protected FindReplaceButtonsEnableResult handleToggleButtons() { + + FindReplaceButtonsEnableResult er = super.handleToggleButtons(); + boolean enable = er.getEnable(); + + findNextButton.setEnabled(enable); + + // setBackground doesn't show up with XP Look and Feel! + JTextComponent tc = UIUtil.getTextComponent(findTextCombo); + tc.setForeground(enable ? UIManager.getColor("TextField.foreground") : + UIUtil.getErrorTextForeground()); + + String tooltip = SearchUtil.getToolTip(er); + tc.setToolTipText(tooltip); // Always set, even if null + + return er; + + } + + + private void init() { + + listenerList = new EventListenerList(); + + // Make a panel containing the "search up/down" radio buttons. + dirPanel = new JPanel(); + dirPanel.setLayout(new BoxLayout(dirPanel, BoxLayout.LINE_AXIS)); + setSearchButtonsBorderText(getString("Direction")); + ButtonGroup bg = new ButtonGroup(); + upButton = new JRadioButton(getString("Up"), false); + upButton.setMnemonic((int)getString("UpMnemonic").charAt(0)); + downButton = new JRadioButton(getString("Down"), true); + downButton.setMnemonic((int)getString("DownMnemonic").charAt(0)); + upButton.setActionCommand("UpRadioButtonClicked"); + upButton.addActionListener(this); + downButton.setActionCommand("DownRadioButtonClicked"); + downButton.addActionListener(this); + bg.add(upButton); + bg.add(downButton); + dirPanel.add(upButton); + dirPanel.add(downButton); + + // Initialize the "mark all" button. + markAllCheckBox = new JCheckBox(getString("MarkAll")); + markAllCheckBox.setMnemonic((int)getString("MarkAllMnemonic").charAt(0)); + markAllCheckBox.setActionCommand("MarkAll"); + markAllCheckBox.addActionListener(this); + + // Rearrange the search conditions panel. + searchConditionsPanel.removeAll(); + searchConditionsPanel.setLayout(new BorderLayout()); + JPanel temp = new JPanel(); + temp.setLayout(new BoxLayout(temp, BoxLayout.PAGE_AXIS)); + temp.add(caseCheckBox); + temp.add(wholeWordCheckBox); + temp.add(wrapCheckBox); + searchConditionsPanel.add(temp, BorderLayout.LINE_START); + temp = new JPanel(); + temp.setLayout(new BoxLayout(temp, BoxLayout.PAGE_AXIS)); + temp.add(regexCheckBox); + temp.add(markAllCheckBox); + searchConditionsPanel.add(temp, BorderLayout.LINE_END); + + // Create the "Find what" label. + findFieldLabel = UIUtil.newLabel(getBundle(), "FindWhat",findTextCombo); + + // Create a "Find Next" button. + findNextButton = UIUtil.newButton(getBundle(), "Find"); + findNextButton.setActionCommand(SearchEvent.Type.FIND.name()); + findNextButton.addActionListener(this); + findNextButton.setDefaultCapable(true); + findNextButton.setEnabled(false); // Initially, nothing to look for. + + installKeyboardActions(); + + } + + + /** + * Adds extra keyboard actions for Find and Replace dialogs. + */ + private void installKeyboardActions() { + + JRootPane rootPane = getRootPane(); + InputMap im = rootPane.getInputMap( + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + ActionMap am = rootPane.getActionMap(); + + int modifier = getToolkit().getMenuShortcutKeyMaskEx(); + KeyStroke ctrlF = KeyStroke.getKeyStroke(KeyEvent.VK_F, modifier); + im.put(ctrlF, "focusSearchForField"); + am.put("focusSearchForField", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + AbstractFindReplaceDialog.this.requestFocus(); + } + }); + + // Shift+Enter and Ctrl+Enter both do a backwards/opposite search + int shift = InputEvent.SHIFT_DOWN_MASK; + int ctrl = InputEvent.CTRL_DOWN_MASK; + if (System.getProperty("os.name").toLowerCase().contains("os x")) { + ctrl = InputEvent.META_DOWN_MASK; + } + KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, shift); + im.put(ks, "searchBackward"); + ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, ctrl); + im.put(ks, "searchBackward"); + am.put("searchBackward", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + doSearch(!context.getSearchForward()); + } + }); + } + + + /** + * Overridden to initialize UI elements specific to this subclass. + */ + @Override + protected void refreshUIFromContext() { + if (this.markAllCheckBox==null) { + return; // First time through, UI not realized yet + } + super.refreshUIFromContext(); + markAllCheckBox.setSelected(context.getMarkAll()); + boolean searchForward = context.getSearchForward(); + upButton.setSelected(!searchForward); + downButton.setSelected(searchForward); + } + + + /** + * Removes a {@link SearchListener} from this dialog. + * + * @param l The listener to remove + * @see #addSearchListener(SearchListener) + */ + public void removeSearchListener(SearchListener l) { + listenerList.remove(SearchListener.class, l); + } + + + /** + * Sets the text label for the "Down" radio button. + * + * @param text The new text label for the "Down" radio button. + * @see #getDownRadioButtonText + */ + public void setDownRadioButtonText(String text) { + downButton.setText(text); + } + + + /** + * Sets the text on the "Find" button. + * + * @param text The text for the Find button. + * @see #getFindButtonText + */ + public final void setFindButtonText(String text) { + findNextButton.setText(text); + } + + + /** + * Sets the label on the "Find what" text field. + * + * @param text The text for the "Find what" text field's label. + * @see #getFindWhatLabelText + */ + public void setFindWhatLabelText(String text) { + findFieldLabel.setText(text); + } + + + /** + * Sets the text for the search direction's radio buttons' border. + * + * @param text The text for the search radio buttons' border. + * @see #getSearchButtonsBorderText + */ + public final void setSearchButtonsBorderText(String text) { + dirPanelTitle = text; + dirPanel.setBorder(createTitledBorder(dirPanelTitle)); + } + + + /** + * Sets the text label for the "Up" radio button. + * + * @param text The new text label for the "Up" radio button. + * @see #getUpRadioButtonText + */ + public void setUpRadioButtonText(String text) { + upButton.setText(text); + } + + +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindDialog.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindDialog.java index 5a84950..c71ccea 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindDialog.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindDialog.java @@ -1,271 +1,271 @@ -/* - * 11/14/2003 - * - * FindDialog - Dialog for finding text in a GUI. - * This library is distributed under a modified BSD license. See the included - * RSTAUI.License.txt file for details. - */ -package org.fife.rsta.ui.search; - -import java.awt.BorderLayout; -import java.awt.ComponentOrientation; -import java.awt.Dialog; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; -import javax.swing.BorderFactory; -import javax.swing.BoxLayout; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.text.JTextComponent; -import javax.swing.SpringLayout; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -import org.fife.rsta.ui.AssistanceIconPanel; -import org.fife.rsta.ui.ResizableFrameContentPane; -import org.fife.rsta.ui.UIUtil; -import org.fife.ui.rtextarea.SearchContext; -import org.fife.ui.rtextarea.SearchEngine; - - -/** - * A "Find" dialog similar to those found in most Windows text editing - * applications. Contains many search options, including:
- *
    - *
  • Match Case - *
  • Match Whole Word - *
  • Use Regular Expressions - *
  • Search Forwards or Backwards - *
  • Mark all - *
- * The dialog also remembers your previous several selections in a combo box. - *

An application can use a FindDialog as follows. It is - * suggested that you create an Action or something similar to - * facilitate "bringing up" the Find dialog. Have the main application contain - * an object that implements {@link SearchListener}. This object will receive - * {@link SearchEvent}s of the following types from the Find dialog: - *

    - *
  • {@link SearchEvent.Type#FIND} action when the user clicks the - * "Find" button. - *
- * The application can then call i.e. - * {@link SearchEngine#find(javax.swing.JTextArea, org.fife.ui.rtextarea.SearchContext) SearchEngine.find()} - * to actually execute the search. - * - * @author Robert Futrell - * @version 1.0 - * @see FindToolBar - */ -public class FindDialog extends AbstractFindReplaceDialog { - - private static final long serialVersionUID = 1L; - - /** - * Our search listener, cached, so we can grab its selected text easily. - */ - protected SearchListener searchListener; - - - /** - * Creates a new FindDialog. - * - * @param owner The parent dialog. - * @param listener The component that listens for {@link SearchEvent}s. - */ - public FindDialog(Dialog owner, SearchListener listener) { - super(owner); - init(listener); - } - - - /** - * Creates a new FindDialog. - * - * @param owner The main window that owns this dialog. - * @param listener The component that listens for {@link SearchEvent}s. - */ - public FindDialog(Frame owner, SearchListener listener) { - super(owner); - init(listener); - } - - - /** - * Initializes find dialog-specific initialization stuff. - * - * @param listener The component that listens for {@link SearchEvent}s. - */ - private void init(SearchListener listener) { - - this.searchListener = listener; - - ComponentOrientation orientation = ComponentOrientation. - getOrientation(getLocale()); - - // Make a panel containing the "Find" edit box. - JPanel enterTextPane = new JPanel(new SpringLayout()); - enterTextPane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5)); - JTextComponent textField = UIUtil.getTextComponent(findTextCombo); - textField.addFocusListener(new FindFocusAdapter()); - textField.getDocument().addDocumentListener(new FindDocumentListener()); - JPanel temp = new JPanel(new BorderLayout()); - temp.add(findTextCombo); - AssistanceIconPanel aip = new AssistanceIconPanel(findTextCombo); - temp.add(aip, BorderLayout.LINE_START); - if (orientation.isLeftToRight()) { - enterTextPane.add(findFieldLabel); - enterTextPane.add(temp); - } - else { - enterTextPane.add(temp); - enterTextPane.add(findFieldLabel); - } - - UIUtil.makeSpringCompactGrid(enterTextPane, 1, 2, //rows, cols - 0,0, //initX, initY - 6, 6); //xPad, yPad - - // Make a panel containing the inherited search direction radio - // buttons and the inherited search options. - JPanel bottomPanel = new JPanel(new BorderLayout()); - temp = new JPanel(new BorderLayout()); - bottomPanel.setBorder(UIUtil.getEmpty5Border()); - temp.add(searchConditionsPanel, BorderLayout.LINE_START); - JPanel temp2 = new JPanel(new BorderLayout()); - temp2.add(dirPanel, BorderLayout.NORTH); - temp.add(temp2); - bottomPanel.add(temp, BorderLayout.LINE_START); - - // Now, make a panel containing all the above stuff. - JPanel leftPanel = new JPanel(); - leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS)); - leftPanel.add(enterTextPane); - leftPanel.add(bottomPanel); - - // Make a panel containing the action buttons. - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new GridLayout(2,1, 5,5)); - buttonPanel.add(findNextButton); - buttonPanel.add(cancelButton); - JPanel rightPanel = new JPanel(); - rightPanel.setLayout(new BorderLayout()); - rightPanel.add(buttonPanel, BorderLayout.NORTH); - - // Put everything into a neat little package. - JPanel contentPane = new JPanel(new BorderLayout()); - if (orientation.isLeftToRight()) { - contentPane.setBorder(BorderFactory.createEmptyBorder(5,0,0,5)); - } - else { - contentPane.setBorder(BorderFactory.createEmptyBorder(5,5,0,0)); - } - contentPane.add(leftPanel); - contentPane.add(rightPanel, BorderLayout.LINE_END); - temp = new ResizableFrameContentPane(new BorderLayout()); - temp.add(contentPane, BorderLayout.NORTH); - setContentPane(temp); - getRootPane().setDefaultButton(findNextButton); - setTitle(getString("FindDialogTitle")); - setResizable(true); - pack(); - setLocationRelativeTo(getParent()); - - setSearchContext(new SearchContext()); - addSearchListener(listener); - - applyComponentOrientation(orientation); - - } - - - /** - * Overrides JDialog's setVisible method; decides - * whether buttons are enabled. - * - * @param visible Whether the dialog should be visible. - */ - @Override - public void setVisible(boolean visible) { - - if (visible) { - - // Select text entered into the UI - String text = searchListener.getSelectedText(); - if (text!=null) { - findTextCombo.addItem(text); - } - - String selectedItem = findTextCombo.getSelectedString(); - boolean nonEmpty = selectedItem!=null && !selectedItem.isEmpty(); - findNextButton.setEnabled(nonEmpty); - super.setVisible(true); - focusFindTextField(); - - } - - else { - super.setVisible(false); - } - - } - - /** - * This method should be called whenever the LookAndFeel of - * the application changes. This calls - * SwingUtilities.updateComponentTreeUI(this) and does - * other necessary things.

- * Note that this is not an override, as JDialogs don't have an - * updateUI() method. - */ - public void updateUI() { - SwingUtilities.updateComponentTreeUI(this); - pack(); - JTextComponent textField = UIUtil.getTextComponent(findTextCombo); - textField.addFocusListener(new FindFocusAdapter()); - textField.getDocument().addDocumentListener(new FindDocumentListener()); - } - - - /** - * Listens for changes in the text field (find search field). - */ - private final class FindDocumentListener implements DocumentListener { - - @Override - public void insertUpdate(DocumentEvent e) { - handleToggleButtons(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - JTextComponent comp = UIUtil.getTextComponent(findTextCombo); - if (comp.getDocument().getLength()==0) { - findNextButton.setEnabled(false); - } - else { - handleToggleButtons(); - } - } - - @Override - public void changedUpdate(DocumentEvent e) { - } - - } - - - /** - * Listens for the text field gaining focus. All it does is select all - * text in the combo box's text area. - */ - private final class FindFocusAdapter extends FocusAdapter { - - @Override - public void focusGained(FocusEvent e) { - UIUtil.getTextComponent(findTextCombo).selectAll(); - } - - } -} +/* + * 11/14/2003 + * + * FindDialog - Dialog for finding text in a GUI. + * This library is distributed under a modified BSD license. See the included + * RSTAUI.License.txt file for details. + */ +package org.fife.rsta.ui.search; + +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; +import javax.swing.SpringLayout; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import org.fife.rsta.ui.AssistanceIconPanel; +import org.fife.rsta.ui.ResizableFrameContentPane; +import org.fife.rsta.ui.UIUtil; +import org.fife.ui.rtextarea.SearchContext; +import org.fife.ui.rtextarea.SearchEngine; + + +/** + * A "Find" dialog similar to those found in most Windows text editing + * applications. Contains many search options, including:
+ *

    + *
  • Match Case + *
  • Match Whole Word + *
  • Use Regular Expressions + *
  • Search Forwards or Backwards + *
  • Mark all + *
+ * The dialog also remembers your previous several selections in a combo box. + *

An application can use a FindDialog as follows. It is + * suggested that you create an Action or something similar to + * facilitate "bringing up" the Find dialog. Have the main application contain + * an object that implements {@link SearchListener}. This object will receive + * {@link SearchEvent}s of the following types from the Find dialog: + *

    + *
  • {@link SearchEvent.Type#FIND} action when the user clicks the + * "Find" button. + *
+ * The application can then call i.e. + * {@link SearchEngine#find(javax.swing.JTextArea, org.fife.ui.rtextarea.SearchContext) SearchEngine.find()} + * to actually execute the search. + * + * @author Robert Futrell + * @version 1.0 + * @see FindToolBar + */ +public class FindDialog extends AbstractFindReplaceDialog { + + private static final long serialVersionUID = 1L; + + /** + * Our search listener, cached, so we can grab its selected text easily. + */ + protected SearchListener searchListener; + + + /** + * Creates a new FindDialog. + * + * @param owner The parent dialog. + * @param listener The component that listens for {@link SearchEvent}s. + */ + public FindDialog(Dialog owner, SearchListener listener) { + super(owner); + init(listener); + } + + + /** + * Creates a new FindDialog. + * + * @param owner The main window that owns this dialog. + * @param listener The component that listens for {@link SearchEvent}s. + */ + public FindDialog(Frame owner, SearchListener listener) { + super(owner); + init(listener); + } + + + /** + * Initializes find dialog-specific initialization stuff. + * + * @param listener The component that listens for {@link SearchEvent}s. + */ + private void init(SearchListener listener) { + + this.searchListener = listener; + + ComponentOrientation orientation = ComponentOrientation. + getOrientation(getLocale()); + + // Make a panel containing the "Find" edit box. + JPanel enterTextPane = new JPanel(new SpringLayout()); + enterTextPane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5)); + JTextComponent textField = UIUtil.getTextComponent(findTextCombo); + textField.addFocusListener(new FindFocusAdapter()); + textField.getDocument().addDocumentListener(new FindDocumentListener()); + JPanel temp = new JPanel(new BorderLayout()); + temp.add(findTextCombo); + AssistanceIconPanel aip = new AssistanceIconPanel(findTextCombo); + temp.add(aip, BorderLayout.LINE_START); + if (orientation.isLeftToRight()) { + enterTextPane.add(findFieldLabel); + enterTextPane.add(temp); + } + else { + enterTextPane.add(temp); + enterTextPane.add(findFieldLabel); + } + + UIUtil.makeSpringCompactGrid(enterTextPane, 1, 2, //rows, cols + 0,0, //initX, initY + 6, 6); //xPad, yPad + + // Make a panel containing the inherited search direction radio + // buttons and the inherited search options. + JPanel bottomPanel = new JPanel(new BorderLayout()); + temp = new JPanel(new BorderLayout()); + bottomPanel.setBorder(UIUtil.getEmpty5Border()); + temp.add(searchConditionsPanel, BorderLayout.LINE_START); + JPanel temp2 = new JPanel(new BorderLayout()); + temp2.add(dirPanel, BorderLayout.NORTH); + temp.add(temp2); + bottomPanel.add(temp, BorderLayout.LINE_START); + + // Now, make a panel containing all the above stuff. + JPanel leftPanel = new JPanel(); + leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS)); + leftPanel.add(enterTextPane); + leftPanel.add(bottomPanel); + + // Make a panel containing the action buttons. + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridLayout(2,1, 5,5)); + buttonPanel.add(findNextButton); + buttonPanel.add(cancelButton); + JPanel rightPanel = new JPanel(); + rightPanel.setLayout(new BorderLayout()); + rightPanel.add(buttonPanel, BorderLayout.NORTH); + + // Put everything into a neat little package. + JPanel contentPane = new JPanel(new BorderLayout()); + if (orientation.isLeftToRight()) { + contentPane.setBorder(BorderFactory.createEmptyBorder(5,0,0,5)); + } + else { + contentPane.setBorder(BorderFactory.createEmptyBorder(5,5,0,0)); + } + contentPane.add(leftPanel); + contentPane.add(rightPanel, BorderLayout.LINE_END); + temp = new ResizableFrameContentPane(new BorderLayout()); + temp.add(contentPane, BorderLayout.NORTH); + setContentPane(temp); + getRootPane().setDefaultButton(findNextButton); + setTitle(getString("FindDialogTitle")); + setResizable(true); + pack(); + setLocationRelativeTo(getParent()); + + setSearchContext(new SearchContext()); + addSearchListener(listener); + + applyComponentOrientation(orientation); + + } + + + /** + * Overrides JDialog's setVisible method; decides + * whether buttons are enabled. + * + * @param visible Whether the dialog should be visible. + */ + @Override + public void setVisible(boolean visible) { + + if (visible) { + + // Select text entered into the UI + String text = searchListener.getSelectedText(); + if (text!=null) { + findTextCombo.addItem(text); + } + + String selectedItem = findTextCombo.getSelectedString(); + boolean nonEmpty = selectedItem!=null && !selectedItem.isEmpty(); + findNextButton.setEnabled(nonEmpty); + super.setVisible(true); + focusFindTextField(); + + } + + else { + super.setVisible(false); + } + + } + + /** + * This method should be called whenever the LookAndFeel of + * the application changes. This calls + * SwingUtilities.updateComponentTreeUI(this) and does + * other necessary things.

+ * Note that this is not an override, as JDialogs don't have an + * updateUI() method. + */ + public void updateUI() { + SwingUtilities.updateComponentTreeUI(this); + pack(); + JTextComponent textField = UIUtil.getTextComponent(findTextCombo); + textField.addFocusListener(new FindFocusAdapter()); + textField.getDocument().addDocumentListener(new FindDocumentListener()); + } + + + /** + * Listens for changes in the text field (find search field). + */ + private final class FindDocumentListener implements DocumentListener { + + @Override + public void insertUpdate(DocumentEvent e) { + handleToggleButtons(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + JTextComponent comp = UIUtil.getTextComponent(findTextCombo); + if (comp.getDocument().getLength()==0) { + findNextButton.setEnabled(false); + } + else { + handleToggleButtons(); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + + } + + + /** + * Listens for the text field gaining focus. All it does is select all + * text in the combo box's text area. + */ + private final class FindFocusAdapter extends FocusAdapter { + + @Override + public void focusGained(FocusEvent e) { + UIUtil.getTextComponent(findTextCombo).selectAll(); + } + + } +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindReplaceButtonsEnableResult.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindReplaceButtonsEnableResult.java index 109cabf..7a61b51 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindReplaceButtonsEnableResult.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindReplaceButtonsEnableResult.java @@ -1,43 +1,43 @@ -/* - * 09/20/2013 - * - * FindReplaceButtonsEnableResult - Whether "find" and "replace" buttons - * should be enabled. - * - * This library is distributed under a modified BSD license. See the included - * RSTAUI.license.txt file for details. - */ -package org.fife.rsta.ui.search; - -/** - * Returns the result of whether the "action" buttons such as "Find" - * and "Replace" should be enabled. - * - * @author Robert Futrell - * @version 1.0 - */ -// NOTE: This class is public to enable applications to create custom search -// dialogs that extend AbstractSearchDialog, such as a FindInFilesDialog. -public class FindReplaceButtonsEnableResult { - - private boolean enable; - private String error; - - public FindReplaceButtonsEnableResult(boolean enable, String error) { - this.enable = enable; - this.error = error; - } - - public boolean getEnable() { - return enable; - } - - public String getError() { - return error; - } - - public void setEnable(boolean enable) { - this.enable = enable; - } - -} +/* + * 09/20/2013 + * + * FindReplaceButtonsEnableResult - Whether "find" and "replace" buttons + * should be enabled. + * + * This library is distributed under a modified BSD license. See the included + * RSTAUI.license.txt file for details. + */ +package org.fife.rsta.ui.search; + +/** + * Returns the result of whether the "action" buttons such as "Find" + * and "Replace" should be enabled. + * + * @author Robert Futrell + * @version 1.0 + */ +// NOTE: This class is public to enable applications to create custom search +// dialogs that extend AbstractSearchDialog, such as a FindInFilesDialog. +public class FindReplaceButtonsEnableResult { + + private boolean enable; + private String error; + + public FindReplaceButtonsEnableResult(boolean enable, String error) { + this.enable = enable; + this.error = error; + } + + public boolean getEnable() { + return enable; + } + + public String getError() { + return error; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindToolBar.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindToolBar.java index 53009c3..4ca0b85 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindToolBar.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/FindToolBar.java @@ -1,805 +1,805 @@ -/* - * 09/20/2013 - * - * FindToolBar - A toolbar for "find" operations in text areas. - * - * This library is distributed under a modified BSD license. See the included - * RSTAUI.license.txt file for details. - */ -package org.fife.rsta.ui.search; - -import java.awt.*; -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.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; - protected JCheckBox wrapCheckBox; - 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 SEARCH_MSG = ResourceBundle.getBundle( - "org.fife.rsta.ui.search.Search"); - protected static final ResourceBundle MSG = ResourceBundle.getBundle( - "org.fife.rsta.ui.search.SearchToolBar"); - - /** - * Creates the toolbar. - * - * @param listener An entity listening for search events. - */ - public FindToolBar(SearchListener listener) { - - // Keep focus in this component when tabbing through search controls - setFocusCycleRoot(true); - - 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)); - - JLabel infoLabel = new JLabel(); - rest.add(infoLabel); - - rest.add(Box.createHorizontalGlue()); - - // Get ready to go. - applyComponentOrientation(orientation); - } - - - /** - * Adds a {@link SearchListener} to this toolbar. 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 filler = new JPanel(new BorderLayout()); - filler.setBorder(BorderFactory.createEmptyBorder()); - filler.add(findButton);//bp); - panel.add(filler); - panel.add(Box.createHorizontalStrut(6)); - - matchCaseCheckBox = createCB("MatchCase"); - panel.add(matchCaseCheckBox); - - regexCheckBox = createCB("RegEx"); - panel.add(regexCheckBox); - - wholeWordCheckBox = createCB("WholeWord"); - panel.add(wholeWordCheckBox); - - markAllCheckBox = createCB("MarkAll"); - panel.add(markAllCheckBox); - - wrapCheckBox = createCB("Wrap"); - panel.add(wrapCheckBox); - - return panel; - - } - - - protected JCheckBox createCB(String key) { - JCheckBox cb = new JCheckBox(SEARCH_MSG.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 toolbar. - */ - protected void createFindButtons() { - - findPrevButton = new JButton(MSG.getString("FindPrev")); - makeEnterActivateButton(findPrevButton); - findPrevButton.setActionCommand("FindPrevious"); - findPrevButton.addActionListener(listener); - findPrevButton.setEnabled(false); - - findButton = new JButton(SEARCH_MSG.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 in notification of - * 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 toolbar. - * - * @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 - ActionEvent.CTRL_MASK|ActionEvent.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()); - } - - // If the ask is to search in the opposite direction from the UI's - // current direction, use a cloned search context to avoid updating - // the UI when we shouldn't (e.g. from a keyboard shortcut to search - // backward). - SearchContext contextToFire = context; - if (forward != context.getSearchForward()) { - contextToFire = context.clone(); - contextToFire.setSearchForward(forward); - } - - SearchEvent se = new SearchEvent(this, type, contextToFire); - 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.isEmpty()) { - 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! - 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 toolbar from a search context. This is - * called whenever a new search context is installed on this toolbar - * (which should practically be never). - */ - private 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()); - wrapCheckBox.setSelected(context.getSearchWrap()); - } - - - /** - * Makes the Enter key activate the button. In Swing, this is a - * complicated thing. It's LAF-dependent whether 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 toolbars 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_DOWN_MASK, - false), "pressed"); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK, - true), "released"); - - } - - - /** - * Removes a {@link SearchListener} from this toolbar. - * - * @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)); - } - - - /** - * Sets the image to display by this dialog's text fields when content - * assistance is available. - * - * @param image The image. If this is {@code null}, a default image - * (a light bulb) is used. This should be kept small, around - * 8x8 for standard resolution monitors. - */ - public void setContentAssistImage(Image image) { - findCombo.setContentAssistImage(image); - } - - - 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 toolbar. You'll usually want to call - * this method for all toolbars 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 toolbar. Keeps the UI in sync with the - * search context and vice versa. - */ - private final 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 if (source == wrapCheckBox) { - context.setSearchWrap(wrapCheckBox.isSelected()); - } - 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(); - matchCaseCheckBox.setSelected(newValue); - } - else if (SearchContext.PROPERTY_MATCH_WHOLE_WORD.equals(prop)) { - boolean newValue = (Boolean) e.getNewValue(); - 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(); - regexCheckBox.setSelected(newValue); - handleRegExCheckBoxClicked(); - } - else if (SearchContext.PROPERTY_MARK_ALL.equals(prop)) { - boolean newValue = (Boolean) e.getNewValue(); - markAllCheckBox.setSelected(newValue); - // firing event handled in ActionListener, to prevent "other" - // toolbar 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; - } - } - else if (SearchContext.PROPERTY_SEARCH_WRAP.equals(prop)) { - boolean newValue = (Boolean)e.getNewValue(); - wrapCheckBox.setSelected(newValue); - } - - } - - } - - - /** - * 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.getModifiersEx(); - int ctrlShift = InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_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 final class MarkAllEventNotifier implements ActionListener { - - @Override - public void actionPerformed(ActionEvent e) { - fireMarkAllEvent(); - } - - } - - -} +/* + * 09/20/2013 + * + * FindToolBar - A toolbar for "find" operations in text areas. + * + * This library is distributed under a modified BSD license. See the included + * RSTAUI.license.txt file for details. + */ +package org.fife.rsta.ui.search; + +import java.awt.*; +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.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; + protected JCheckBox wrapCheckBox; + 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 SEARCH_MSG = ResourceBundle.getBundle( + "org.fife.rsta.ui.search.Search"); + protected static final ResourceBundle MSG = ResourceBundle.getBundle( + "org.fife.rsta.ui.search.SearchToolBar"); + + /** + * Creates the toolbar. + * + * @param listener An entity listening for search events. + */ + public FindToolBar(SearchListener listener) { + + // Keep focus in this component when tabbing through search controls + setFocusCycleRoot(true); + + 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)); + + JLabel infoLabel = new JLabel(); + rest.add(infoLabel); + + rest.add(Box.createHorizontalGlue()); + + // Get ready to go. + applyComponentOrientation(orientation); + } + + + /** + * Adds a {@link SearchListener} to this toolbar. 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 filler = new JPanel(new BorderLayout()); + filler.setBorder(BorderFactory.createEmptyBorder()); + filler.add(findButton);//bp); + panel.add(filler); + panel.add(Box.createHorizontalStrut(6)); + + matchCaseCheckBox = createCB("MatchCase"); + panel.add(matchCaseCheckBox); + + regexCheckBox = createCB("RegEx"); + panel.add(regexCheckBox); + + wholeWordCheckBox = createCB("WholeWord"); + panel.add(wholeWordCheckBox); + + markAllCheckBox = createCB("MarkAll"); + panel.add(markAllCheckBox); + + wrapCheckBox = createCB("Wrap"); + panel.add(wrapCheckBox); + + return panel; + + } + + + protected JCheckBox createCB(String key) { + JCheckBox cb = new JCheckBox(SEARCH_MSG.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 toolbar. + */ + protected void createFindButtons() { + + findPrevButton = new JButton(MSG.getString("FindPrev")); + makeEnterActivateButton(findPrevButton); + findPrevButton.setActionCommand("FindPrevious"); + findPrevButton.addActionListener(listener); + findPrevButton.setEnabled(false); + + findButton = new JButton(SEARCH_MSG.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 in notification of + * 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 toolbar. + * + * @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 + ActionEvent.CTRL_MASK|ActionEvent.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()); + } + + // If the ask is to search in the opposite direction from the UI's + // current direction, use a cloned search context to avoid updating + // the UI when we shouldn't (e.g. from a keyboard shortcut to search + // backward). + SearchContext contextToFire = context; + if (forward != context.getSearchForward()) { + contextToFire = context.clone(); + contextToFire.setSearchForward(forward); + } + + SearchEvent se = new SearchEvent(this, type, contextToFire); + 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.isEmpty()) { + 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! + 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 toolbar from a search context. This is + * called whenever a new search context is installed on this toolbar + * (which should practically be never). + */ + private 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()); + wrapCheckBox.setSelected(context.getSearchWrap()); + } + + + /** + * Makes the Enter key activate the button. In Swing, this is a + * complicated thing. It's LAF-dependent whether 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 toolbars 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_DOWN_MASK, + false), "pressed"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK, + true), "released"); + + } + + + /** + * Removes a {@link SearchListener} from this toolbar. + * + * @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)); + } + + + /** + * Sets the image to display by this dialog's text fields when content + * assistance is available. + * + * @param image The image. If this is {@code null}, a default image + * (a light bulb) is used. This should be kept small, around + * 8x8 for standard resolution monitors. + */ + public void setContentAssistImage(Image image) { + findCombo.setContentAssistImage(image); + } + + + 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 toolbar. You'll usually want to call + * this method for all toolbars 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 toolbar. Keeps the UI in sync with the + * search context and vice versa. + */ + private final 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 if (source == wrapCheckBox) { + context.setSearchWrap(wrapCheckBox.isSelected()); + } + 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(); + matchCaseCheckBox.setSelected(newValue); + } + else if (SearchContext.PROPERTY_MATCH_WHOLE_WORD.equals(prop)) { + boolean newValue = (Boolean) e.getNewValue(); + 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(); + regexCheckBox.setSelected(newValue); + handleRegExCheckBoxClicked(); + } + else if (SearchContext.PROPERTY_MARK_ALL.equals(prop)) { + boolean newValue = (Boolean) e.getNewValue(); + markAllCheckBox.setSelected(newValue); + // firing event handled in ActionListener, to prevent "other" + // toolbar 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; + } + } + else if (SearchContext.PROPERTY_SEARCH_WRAP.equals(prop)) { + boolean newValue = (Boolean)e.getNewValue(); + wrapCheckBox.setSelected(newValue); + } + + } + + } + + + /** + * 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.getModifiersEx(); + int ctrlShift = InputEvent.CTRL_DOWN_MASK|InputEvent.SHIFT_DOWN_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 final class MarkAllEventNotifier implements ActionListener { + + @Override + public void actionPerformed(ActionEvent e) { + fireMarkAllEvent(); + } + + } + + +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/ReplaceToolBar.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/ReplaceToolBar.java index 8daaf06..100c5e9 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/ReplaceToolBar.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/ReplaceToolBar.java @@ -1,295 +1,295 @@ -/* - * 09/20/2013 - * - * ReplaceToolBar - A toolbar for "replace" operations in text areas. - * - * This library is distributed under a modified BSD license. See the included - * RSTAUI.license.txt file for details. - */ -package org.fife.rsta.ui.search; - -import java.awt.*; -import java.awt.event.ActionEvent; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SpringLayout; -import javax.swing.event.DocumentEvent; -import javax.swing.text.JTextComponent; - -import org.fife.rsta.ui.UIUtil; -import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; - - -/** - * A toolbar for replace 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 FindToolBar - * @see ReplaceDialog - */ -public class ReplaceToolBar extends FindToolBar { - - private JButton replaceButton; - private JButton replaceAllButton; - - /** - * Our search listener, cached, so we can grab its selected text easily. - */ - protected SearchListener searchListener; - - - /** - * Creates the toolbar. - * - * @param listener An entity listening for search events. - */ - public ReplaceToolBar(SearchListener listener) { - super(listener); - this.searchListener = listener; - } - - - @Override - public void addNotify() { - super.addNotify(); - handleToggleButtons(); - } - - - @Override - protected Container createButtonPanel() { - - Box panel = new Box(BoxLayout.LINE_AXIS); - - JPanel bp = new JPanel(new GridLayout(2,2, 5,5)); - panel.add(bp); - - createFindButtons(); - - Component filler = Box.createRigidArea(new Dimension(5, 5)); - - bp.add(findButton); bp.add(replaceButton); - bp.add(replaceAllButton); bp.add(filler); - panel.add(bp); - - JPanel optionPanel = new JPanel(new SpringLayout()); - matchCaseCheckBox = createCB("MatchCase"); - regexCheckBox = createCB("RegEx"); - wholeWordCheckBox = createCB("WholeWord"); - markAllCheckBox = createCB("MarkAll"); - wrapCheckBox = createCB("Wrap"); - // We use a "spacing" middle row, instead of spacing in the call to - // UIUtil.makeSpringCompactGrid(), as the latter adds trailing - // spacing after the final "row", which screws up our alignment. - Dimension spacing = new Dimension(1, 5); - Component space1 = Box.createRigidArea(spacing); - Component space2 = Box.createRigidArea(spacing); - Component space3 = Box.createRigidArea(spacing); - Component space4 = Box.createRigidArea(spacing); - - ComponentOrientation orientation = ComponentOrientation. - getOrientation(getLocale()); - - if (orientation.isLeftToRight()) { - optionPanel.add(matchCaseCheckBox); optionPanel.add(wholeWordCheckBox); optionPanel.add(wrapCheckBox); - optionPanel.add(space1); optionPanel.add(space2); optionPanel.add(space3); - optionPanel.add(regexCheckBox); optionPanel.add(markAllCheckBox); optionPanel.add(space4); - } - else { - optionPanel.add(wrapCheckBox); optionPanel.add(wholeWordCheckBox); optionPanel.add(matchCaseCheckBox); - optionPanel.add(space3); optionPanel.add(space2); optionPanel.add(space1); - optionPanel.add(space4); optionPanel.add(markAllCheckBox); optionPanel.add(regexCheckBox); - } - UIUtil.makeSpringCompactGrid(optionPanel, 3,3, 0,0, 0,0); - panel.add(optionPanel); - - return panel; - - } - - - @Override - protected Container createFieldPanel() { - - findFieldListener = new ReplaceFindFieldListener(); - - JPanel temp = new JPanel(new SpringLayout()); - - JLabel findLabel = new JLabel(MSG.getString("FindWhat")); - JLabel replaceLabel = new JLabel(MSG.getString("ReplaceWith")); - - findCombo = new SearchComboBox(this, false); - JTextComponent findField = UIUtil.getTextComponent(findCombo); - findFieldListener.install(findField); - Container fcp = createContentAssistablePanel(findCombo); - - replaceCombo = new SearchComboBox(this, true); - JTextComponent replaceField = UIUtil.getTextComponent(replaceCombo); - findFieldListener.install(replaceField); - Container rcp = createContentAssistablePanel(replaceCombo); - - // We use a "spacing" middle row, instead of spacing in the call to - // UIUtil.makeSpringCompactGrid(), as the latter adds trailing - // spacing after the final "row", which screws up our alignment. - Dimension spacing = new Dimension(1, 5); - Component space1 = Box.createRigidArea(spacing); - Component space2 = Box.createRigidArea(spacing); - - if (getComponentOrientation().isLeftToRight()) { - temp.add(findLabel); temp.add(fcp); - temp.add(space1); temp.add(space2); - temp.add(replaceLabel); temp.add(rcp); - } - else { - temp.add(fcp); temp.add(findLabel); - temp.add(space2); temp.add(space1); - temp.add(rcp); temp.add(replaceLabel); - } - UIUtil.makeSpringCompactGrid(temp, 3,2, 0,0, 0,0); - - return temp; - } - - - @Override - protected void createFindButtons() { - - super.createFindButtons(); - - replaceButton = new JButton(SEARCH_MSG.getString("Replace")); - makeEnterActivateButton(replaceButton); - replaceButton.setToolTipText(MSG.getString("Replace.ToolTip")); - replaceButton.setActionCommand("Replace"); - replaceButton.addActionListener(listener); - replaceButton.setEnabled(false); - - replaceAllButton = new JButton(SEARCH_MSG.getString("ReplaceAll")); - makeEnterActivateButton(replaceAllButton); - replaceAllButton.setActionCommand("ReplaceAll"); - replaceAllButton.addActionListener(listener); - replaceAllButton.setEnabled(false); - - } - - - /** - * 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. - */ - @Override - protected void handleRegExCheckBoxClicked() { - super.handleRegExCheckBoxClicked(); - // "Content assist" support - boolean b = regexCheckBox.isSelected(); - replaceCombo.setAutoCompleteEnabled(b); - } - - - @Override - protected void handleSearchAction(ActionEvent e) { - String command = e.getActionCommand(); - super.handleSearchAction(e); - if ("FindNext".equals(command) || "FindPrevious".equals(command)) { - handleToggleButtons(); // Replace button could toggle state - } - } - - - @Override - protected FindReplaceButtonsEnableResult handleToggleButtons() { - - FindReplaceButtonsEnableResult er = super.handleToggleButtons(); - boolean shouldReplace = er.getEnable(); - replaceAllButton.setEnabled(shouldReplace); - - // "Replace" is only enabled if text to search for is selected in - // the UI. - if (shouldReplace) { - String text = searchListener.getSelectedText(); - shouldReplace = matchesSearchFor(text); - } - replaceButton.setEnabled(shouldReplace); - - return er; - } - - - // TODO: Share this code with AbstractSearchDialog - protected boolean matchesSearchFor(String text) { - if (text==null || text.isEmpty()) { - return false; - } - String searchFor = findCombo.getSelectedString(); - if (searchFor!=null && !searchFor.isEmpty()) { - boolean matchCase = matchCaseCheckBox.isSelected(); - if (regexCheckBox.isSelected()) { - int flags = Pattern.MULTILINE; // '^' and '$' are done per line. - flags = RSyntaxUtilities.getPatternFlags(matchCase, flags); - Pattern pattern; - try { - pattern = Pattern.compile(searchFor, flags); - } catch (PatternSyntaxException pse) { - pse.printStackTrace(); // Never happens - return false; - } - return pattern.matcher(text).matches(); - } - else { - if (matchCase) { - return searchFor.equals(text); - } - return searchFor.equalsIgnoreCase(text); - } - } - return false; - } - - - /** - * Overridden to possibly toggle the enabled state of the replace button. - */ - @Override - public boolean requestFocusInWindow() { - boolean result = super.requestFocusInWindow(); - handleToggleButtons(); // Replace button state may change - return result; - } - - @Override - public void setContentAssistImage(Image image) { - super.setContentAssistImage(image); - replaceCombo.setContentAssistImage(image); - } - - - /** - * Listens for the user typing into the search field. - */ - protected class ReplaceFindFieldListener extends FindFieldListener { - - @Override - protected void handleDocumentEvent(DocumentEvent e) { - super.handleDocumentEvent(e); - JTextComponent findField = UIUtil.getTextComponent(findCombo); - JTextComponent replaceField = UIUtil.getTextComponent(replaceCombo); - if (e.getDocument().equals(findField.getDocument())) { - handleToggleButtons(); - } - if (e.getDocument()==replaceField.getDocument()) { - getSearchContext().setReplaceWith(replaceField.getText()); - } - } - - } - - -} +/* + * 09/20/2013 + * + * ReplaceToolBar - A toolbar for "replace" operations in text areas. + * + * This library is distributed under a modified BSD license. See the included + * RSTAUI.license.txt file for details. + */ +package org.fife.rsta.ui.search; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SpringLayout; +import javax.swing.event.DocumentEvent; +import javax.swing.text.JTextComponent; + +import org.fife.rsta.ui.UIUtil; +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; + + +/** + * A toolbar for replace 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 FindToolBar + * @see ReplaceDialog + */ +public class ReplaceToolBar extends FindToolBar { + + private JButton replaceButton; + private JButton replaceAllButton; + + /** + * Our search listener, cached, so we can grab its selected text easily. + */ + protected SearchListener searchListener; + + + /** + * Creates the toolbar. + * + * @param listener An entity listening for search events. + */ + public ReplaceToolBar(SearchListener listener) { + super(listener); + this.searchListener = listener; + } + + + @Override + public void addNotify() { + super.addNotify(); + handleToggleButtons(); + } + + + @Override + protected Container createButtonPanel() { + + Box panel = new Box(BoxLayout.LINE_AXIS); + + JPanel bp = new JPanel(new GridLayout(2,2, 5,5)); + panel.add(bp); + + createFindButtons(); + + Component filler = Box.createRigidArea(new Dimension(5, 5)); + + bp.add(findButton); bp.add(replaceButton); + bp.add(replaceAllButton); bp.add(filler); + panel.add(bp); + + JPanel optionPanel = new JPanel(new SpringLayout()); + matchCaseCheckBox = createCB("MatchCase"); + regexCheckBox = createCB("RegEx"); + wholeWordCheckBox = createCB("WholeWord"); + markAllCheckBox = createCB("MarkAll"); + wrapCheckBox = createCB("Wrap"); + // We use a "spacing" middle row, instead of spacing in the call to + // UIUtil.makeSpringCompactGrid(), as the latter adds trailing + // spacing after the final "row", which screws up our alignment. + Dimension spacing = new Dimension(1, 5); + Component space1 = Box.createRigidArea(spacing); + Component space2 = Box.createRigidArea(spacing); + Component space3 = Box.createRigidArea(spacing); + Component space4 = Box.createRigidArea(spacing); + + ComponentOrientation orientation = ComponentOrientation. + getOrientation(getLocale()); + + if (orientation.isLeftToRight()) { + optionPanel.add(matchCaseCheckBox); optionPanel.add(wholeWordCheckBox); optionPanel.add(wrapCheckBox); + optionPanel.add(space1); optionPanel.add(space2); optionPanel.add(space3); + optionPanel.add(regexCheckBox); optionPanel.add(markAllCheckBox); optionPanel.add(space4); + } + else { + optionPanel.add(wrapCheckBox); optionPanel.add(wholeWordCheckBox); optionPanel.add(matchCaseCheckBox); + optionPanel.add(space3); optionPanel.add(space2); optionPanel.add(space1); + optionPanel.add(space4); optionPanel.add(markAllCheckBox); optionPanel.add(regexCheckBox); + } + UIUtil.makeSpringCompactGrid(optionPanel, 3,3, 0,0, 0,0); + panel.add(optionPanel); + + return panel; + + } + + + @Override + protected Container createFieldPanel() { + + findFieldListener = new ReplaceFindFieldListener(); + + JPanel temp = new JPanel(new SpringLayout()); + + JLabel findLabel = new JLabel(MSG.getString("FindWhat")); + JLabel replaceLabel = new JLabel(MSG.getString("ReplaceWith")); + + findCombo = new SearchComboBox(this, false); + JTextComponent findField = UIUtil.getTextComponent(findCombo); + findFieldListener.install(findField); + Container fcp = createContentAssistablePanel(findCombo); + + replaceCombo = new SearchComboBox(this, true); + JTextComponent replaceField = UIUtil.getTextComponent(replaceCombo); + findFieldListener.install(replaceField); + Container rcp = createContentAssistablePanel(replaceCombo); + + // We use a "spacing" middle row, instead of spacing in the call to + // UIUtil.makeSpringCompactGrid(), as the latter adds trailing + // spacing after the final "row", which screws up our alignment. + Dimension spacing = new Dimension(1, 5); + Component space1 = Box.createRigidArea(spacing); + Component space2 = Box.createRigidArea(spacing); + + if (getComponentOrientation().isLeftToRight()) { + temp.add(findLabel); temp.add(fcp); + temp.add(space1); temp.add(space2); + temp.add(replaceLabel); temp.add(rcp); + } + else { + temp.add(fcp); temp.add(findLabel); + temp.add(space2); temp.add(space1); + temp.add(rcp); temp.add(replaceLabel); + } + UIUtil.makeSpringCompactGrid(temp, 3,2, 0,0, 0,0); + + return temp; + } + + + @Override + protected void createFindButtons() { + + super.createFindButtons(); + + replaceButton = new JButton(SEARCH_MSG.getString("Replace")); + makeEnterActivateButton(replaceButton); + replaceButton.setToolTipText(MSG.getString("Replace.ToolTip")); + replaceButton.setActionCommand("Replace"); + replaceButton.addActionListener(listener); + replaceButton.setEnabled(false); + + replaceAllButton = new JButton(SEARCH_MSG.getString("ReplaceAll")); + makeEnterActivateButton(replaceAllButton); + replaceAllButton.setActionCommand("ReplaceAll"); + replaceAllButton.addActionListener(listener); + replaceAllButton.setEnabled(false); + + } + + + /** + * 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. + */ + @Override + protected void handleRegExCheckBoxClicked() { + super.handleRegExCheckBoxClicked(); + // "Content assist" support + boolean b = regexCheckBox.isSelected(); + replaceCombo.setAutoCompleteEnabled(b); + } + + + @Override + protected void handleSearchAction(ActionEvent e) { + String command = e.getActionCommand(); + super.handleSearchAction(e); + if ("FindNext".equals(command) || "FindPrevious".equals(command)) { + handleToggleButtons(); // Replace button could toggle state + } + } + + + @Override + protected FindReplaceButtonsEnableResult handleToggleButtons() { + + FindReplaceButtonsEnableResult er = super.handleToggleButtons(); + boolean shouldReplace = er.getEnable(); + replaceAllButton.setEnabled(shouldReplace); + + // "Replace" is only enabled if text to search for is selected in + // the UI. + if (shouldReplace) { + String text = searchListener.getSelectedText(); + shouldReplace = matchesSearchFor(text); + } + replaceButton.setEnabled(shouldReplace); + + return er; + } + + + // TODO: Share this code with AbstractSearchDialog + protected boolean matchesSearchFor(String text) { + if (text==null || text.isEmpty()) { + return false; + } + String searchFor = findCombo.getSelectedString(); + if (searchFor!=null && !searchFor.isEmpty()) { + boolean matchCase = matchCaseCheckBox.isSelected(); + if (regexCheckBox.isSelected()) { + int flags = Pattern.MULTILINE; // '^' and '$' are done per line. + flags = RSyntaxUtilities.getPatternFlags(matchCase, flags); + Pattern pattern; + try { + pattern = Pattern.compile(searchFor, flags); + } catch (PatternSyntaxException pse) { + pse.printStackTrace(); // Never happens + return false; + } + return pattern.matcher(text).matches(); + } + else { + if (matchCase) { + return searchFor.equals(text); + } + return searchFor.equalsIgnoreCase(text); + } + } + return false; + } + + + /** + * Overridden to possibly toggle the enabled state of the replace button. + */ + @Override + public boolean requestFocusInWindow() { + boolean result = super.requestFocusInWindow(); + handleToggleButtons(); // Replace button state may change + return result; + } + + @Override + public void setContentAssistImage(Image image) { + super.setContentAssistImage(image); + replaceCombo.setContentAssistImage(image); + } + + + /** + * Listens for the user typing into the search field. + */ + protected class ReplaceFindFieldListener extends FindFieldListener { + + @Override + protected void handleDocumentEvent(DocumentEvent e) { + super.handleDocumentEvent(e); + JTextComponent findField = UIUtil.getTextComponent(findCombo); + JTextComponent replaceField = UIUtil.getTextComponent(replaceCombo); + if (e.getDocument().equals(findField.getDocument())) { + handleToggleButtons(); + } + if (e.getDocument()==replaceField.getDocument()) { + getSearchContext().setReplaceWith(replaceField.getText()); + } + } + + } + + +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchEvent.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchEvent.java index bb10995..f182919 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchEvent.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchEvent.java @@ -1,73 +1,73 @@ -/* - * 09/20/2013 - * - * SearchEvent - The event fired for find/replace/mark all operations. - * - * This library is distributed under a modified BSD license. See the included - * RSTAUI.license.txt file for details. - */ -package org.fife.rsta.ui.search; - -import java.util.EventObject; - -import org.fife.ui.rtextarea.SearchContext; - - -/** - * The event fired whenever a user wants to search for or replace text in a - * Find or Replace dialog/toolbar. - * - * @author Robert Futrell - * @version 1.0 - */ -public class SearchEvent extends EventObject { - - private SearchContext context; - private Type type; - - public SearchEvent(Object source, Type type, SearchContext context) { - super(source); - this.type = type; - this.context = context; - } - - - public Type getType() { - return type; - } - - - public SearchContext getSearchContext() { - return context; - } - - - /** - * Types of search events. - */ - public enum Type { - - /** - * The event fired when the text to "mark all" has changed. - */ - MARK_ALL, - - /** - * The event fired when the user wants to find text in the editor. - */ - FIND, - - /** - * The event fired when the user wants to replace text in the editor. - */ - REPLACE, - - /** - * The event fired when the user wants to replace all instances of - * specific text with new text in the editor. - */ - REPLACE_ALL - - } - -} +/* + * 09/20/2013 + * + * SearchEvent - The event fired for find/replace/mark all operations. + * + * This library is distributed under a modified BSD license. See the included + * RSTAUI.license.txt file for details. + */ +package org.fife.rsta.ui.search; + +import java.util.EventObject; + +import org.fife.ui.rtextarea.SearchContext; + + +/** + * The event fired whenever a user wants to search for or replace text in a + * Find or Replace dialog/toolbar. + * + * @author Robert Futrell + * @version 1.0 + */ +public class SearchEvent extends EventObject { + + private SearchContext context; + private Type type; + + public SearchEvent(Object source, Type type, SearchContext context) { + super(source); + this.type = type; + this.context = context; + } + + + public Type getType() { + return type; + } + + + public SearchContext getSearchContext() { + return context; + } + + + /** + * Types of search events. + */ + public enum Type { + + /** + * The event fired when the text to "mark all" has changed. + */ + MARK_ALL, + + /** + * The event fired when the user wants to find text in the editor. + */ + FIND, + + /** + * The event fired when the user wants to replace text in the editor. + */ + REPLACE, + + /** + * The event fired when the user wants to replace all instances of + * specific text with new text in the editor. + */ + REPLACE_ALL + + } + +} diff --git a/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchUtil.java b/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchUtil.java index e3aca81..086e41a 100644 --- a/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchUtil.java +++ b/RSTAUI/src/main/java/org/fife/rsta/ui/search/SearchUtil.java @@ -1,46 +1,46 @@ -/* - * 09/20/2013 - * - * SearchUtil - Utility methods for this package. - * - * This library is distributed under a modified BSD license. See the included - * RSTAUI.license.txt file for details. - */ -package org.fife.rsta.ui.search; - - -/** - * Utility methods for this package. - * - * @author Robert Futrell - * @version 1.0 - */ -final class SearchUtil { - - - /** - * Private constructor to prevent instantiation. - */ - private SearchUtil() { - } - - /** - * Formats an error message from a find/replace button enable result for - * use in a tool tip. This assumes the error (if any) came from a - * PatternSyntaxException. - * - * @param res The result. - * @return The tool tip, or null if no error message was - * specified in res. - */ - public static String getToolTip(FindReplaceButtonsEnableResult res) { - String tooltip = res.getError(); - if (tooltip!=null && tooltip.indexOf('\n')>-1) { - tooltip = tooltip.replaceFirst("\\\n", "

");
-			tooltip = "" + tooltip;
-		}
-		return tooltip;
-	}
-
-
-}
+/*
+ * 09/20/2013
+ *
+ * SearchUtil - Utility methods for this package.
+ *
+ * This library is distributed under a modified BSD license.  See the included
+ * RSTAUI.license.txt file for details.
+ */
+package org.fife.rsta.ui.search;
+
+
+/**
+ * Utility methods for this package.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+final class SearchUtil {
+
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private SearchUtil() {
+    }
+
+	/**
+	 * Formats an error message from a find/replace button enable result for
+	 * use in a tool tip.  This assumes the error (if any) came from a
+	 * PatternSyntaxException.
+	 *
+	 * @param res The result.
+	 * @return The tool tip, or null if no error message was
+	 *         specified in res.
+	 */
+	public static String getToolTip(FindReplaceButtonsEnableResult res) {
+		String tooltip = res.getError();
+		if (tooltip!=null && tooltip.indexOf('\n')>-1) {
+			tooltip = tooltip.replaceFirst("\\\n", "
");
+			tooltip = "" + tooltip;
+		}
+		return tooltip;
+	}
+
+
+}
diff --git a/build.gradle b/build.gradle
index 8caf6ec..4ae881f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id 'com.github.spotbugs' version '6.4.8'
+    id 'com.github.spotbugs' version '6.5.9'
     id 'io.github.gradle-nexus.publish-plugin' version '2.0.0'
 }
 
@@ -48,7 +48,7 @@ subprojects {
     }
 
     checkstyle {
-        toolVersion = '12.3.0'
+        toolVersion = '13.8.0'
     }
 
     spotbugs {
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index c6dffd9..dff9fda 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -67,6 +67,7 @@
 		
 	
 
+	
 	
 		
 	
@@ -233,12 +234,16 @@
 		-->
 		
 		
+		
 		
 		
 		
 		
 		
 		
+		
+			
+		
 		
 		
 		
@@ -249,6 +254,8 @@
 		
 		
 		
+		
+		
 
 		
 		
@@ -268,6 +275,7 @@
 		
 		
 		
+