org.fife.ui.rsyntaxtextarea.MarkOccurrencesSupport Maven / Gradle / Ivy
/*
* 01/06/2009
*
* MarkOccurrencesSupport.java - Handles marking all occurrences of the
* currently selected identifier in a text area.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.Caret;
import org.fife.ui.rtextarea.SmartHighlightPainter;
/**
* Marks all occurrences of the token at the current caret position, if it is
* an identifier.
*
* @author Robert Futrell
* @version 1.0
* @see OccurrenceMarker
*/
class MarkOccurrencesSupport implements CaretListener, ActionListener {
private RSyntaxTextArea textArea;
private Timer timer;
private SmartHighlightPainter p;
/**
* The default color used to mark occurrences.
*/
public static final Color DEFAULT_COLOR = new Color(224, 224, 224);
/**
* The default delay.
*/
private static final int DEFAULT_DELAY_MS = 1000;
/**
* Constructor. Creates a listener with a 1 second delay.
*/
public MarkOccurrencesSupport() {
this(DEFAULT_DELAY_MS);
}
/**
* Constructor.
*
* @param delay The delay between when the caret last moves and when the
* text should be scanned for matching occurrences. This should
* be in milliseconds.
*/
public MarkOccurrencesSupport(int delay) {
this(delay, DEFAULT_COLOR);
}
/**
* Constructor.
*
* @param delay The delay between when the caret last moves and when the
* text should be scanned for matching occurrences. This should
* be in milliseconds.
* @param color The color to use to mark the occurrences. This cannot be
* null
.
*/
public MarkOccurrencesSupport(int delay, Color color) {
timer = new Timer(delay, this);
timer.setRepeats(false);
p = new SmartHighlightPainter();
setColor(color);
}
/**
* Called after the caret has been moved and a fixed time delay has
* elapsed. This locates and highlights all occurrences of the identifier
* at the caret position, if any.
*
* Callers should not call this method directly, but should rather prefer
* {@link #doMarkOccurrences()} to mark occurrences.
*
* @param e The event.
* @see #doMarkOccurrences()
*/
public void actionPerformed(ActionEvent e) {
// Don't do anything if they are selecting text.
Caret c = textArea.getCaret();
if (c.getDot()!=c.getMark()) {
return;
}
RSyntaxDocument doc = (RSyntaxDocument)textArea.getDocument();
OccurrenceMarker occurrenceMarker = doc.getOccurrenceMarker();
boolean occurrencesChanged = false;
if (occurrenceMarker!=null) {
doc.readLock();
try {
Token t = occurrenceMarker.getTokenToMark(textArea);
if (t!=null && occurrenceMarker.isValidType(textArea, t) &&
!RSyntaxUtilities.isNonWordChar(t)) {
clear();
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
occurrenceMarker.markOccurrences(doc, t, h, p);
//textArea.repaint();
// TODO: Do a textArea.repaint() instead of repainting each
// marker as it's added if count is huge
occurrencesChanged = true;
}
} finally {
doc.readUnlock();
//time = System.currentTimeMillis() - time;
//System.out.println("MarkOccurrencesSupport took: " + time + " ms");
}
}
if (occurrencesChanged) {
textArea.fireMarkedOccurrencesChanged();
}
}
/**
* Called when the caret moves in the text area.
*
* @param e The event.
*/
public void caretUpdate(CaretEvent e) {
timer.restart();
}
/**
* Removes all highlights added to the text area by this listener.
*/
void clear() {
if (textArea!=null) {
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
h.clearMarkOccurrencesHighlights();
}
}
/**
* Immediately marks all occurrences of the token at the current caret
* position.
*/
public void doMarkOccurrences() {
timer.stop();
actionPerformed(null);
}
/**
* Returns the color being used to mark occurrences.
*
* @return The color being used.
* @see #setColor(Color)
*/
public Color getColor() {
return (Color)p.getPaint();
}
/**
* Returns the delay, in milliseconds.
*
* @return The delay.
* @see #setDelay(int)
*/
public int getDelay() {
return timer.getDelay();
}
/**
* Returns whether a border is painted around marked occurrences.
*
* @return Whether a border is painted.
* @see #setPaintBorder(boolean)
* @see #getColor()
*/
public boolean getPaintBorder() {
return p.getPaintBorder();
}
/**
* Installs this listener on a text area. If it is already installed on
* another text area, it is uninstalled first.
*
* @param textArea The text area to install on.
*/
public void install(RSyntaxTextArea textArea) {
if (this.textArea!=null) {
uninstall();
}
this.textArea = textArea;
textArea.addCaretListener(this);
if (textArea.getMarkOccurrencesColor()!=null) {
setColor(textArea.getMarkOccurrencesColor());
}
}
/**
* Sets the color to use when marking occurrences.
*
* @param color The color to use.
* @see #getColor()
* @see #setPaintBorder(boolean)
*/
public void setColor(Color color) {
p.setPaint(color);
if (textArea!=null) {
clear();
caretUpdate(null); // Force a highlight repaint.
}
}
/**
* Sets the delay between the last caret position change and when the
* text is scanned for matching identifiers. A delay is needed to prevent
* repeated scanning while the user is typing.
*
* @param delay The new delay.
* @see #getDelay()
*/
public void setDelay(int delay) {
timer.setDelay(delay);
}
/**
* Toggles whether a border is painted around marked highlights.
*
* @param paint Whether to paint a border.
* @see #getPaintBorder()
* @see #setColor(Color)
*/
public void setPaintBorder(boolean paint) {
if (paint!=p.getPaintBorder()) {
p.setPaintBorder(paint);
if (textArea!=null) {
textArea.repaint();
}
}
}
/**
* Uninstalls this listener from the current text area. Does nothing if
* it not currently installed on any text area.
*
* @see #install(RSyntaxTextArea)
*/
public void uninstall() {
if (textArea!=null) {
clear();
textArea.removeCaretListener(this);
}
}
}