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:
- * - * 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: - *

- * 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:
+ *

+ * 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: + *

+ * 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 @@
 		
 		
 		
+