org.fife.ui.rtextarea.RTextScrollPane Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rsyntaxtextarea Show documentation
Show all versions of rsyntaxtextarea Show documentation
RSyntaxTextArea is the syntax highlighting text editor for Swing applications. Features include syntax highlighting for 40+ languages, code folding, code completion, regex find and replace, macros, code templates, undo/redo, line numbering and bracket matching.
/*
* 11/14/2003
*
* RTextScrollPane.java - A JScrollPane that will only accept RTextAreas
* so that it can display line numbers, fold indicators, and icons.
*
* This library is distributed under a modified BSD license. See the included
* LICENSE file for details.
*/
package org.fife.ui.rtextarea;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.util.Arrays;
import java.util.Stack;
import javax.swing.JScrollPane;
/**
* An extension of JScrollPane
that will only take
* RTextArea
s (or javax.swing.JLayer
s decorating
* RTextArea
s) for its view. This class has the ability to show:
*
* - Line numbers
*
- Per-line icons (for bookmarks, debugging breakpoints, error markers, etc.)
*
- +/- icons to denote code folding regions.
*
*
* The actual "meat" of these extras is contained in the {@link Gutter} class.
* Each RTextScrollPane
has a Gutter
instance that
* it uses as its row header. The gutter is only made visible when one of its
* features is being used (line numbering, folding, and/or icons).
*
* @author Robert Futrell
* @version 1.0
*/
public class RTextScrollPane extends JScrollPane {
private Gutter gutter;
/**
* Constructor. If you use this constructor, you must call
* {@link #setViewportView(Component)} and pass in an {@link RTextArea}
* for this scroll pane to render line numbers properly.
*/
public RTextScrollPane() {
this(null, true);
}
/**
* Creates a scroll pane. A default value will be used for line number
* color (gray), and the current line's line number will be highlighted.
*
* @param textArea The text area this scroll pane will contain.
*/
public RTextScrollPane(RTextArea textArea) {
this(textArea, true);
}
/**
* Creates a scroll pane. A default value will be used for line number
* color (gray), and the current line's line number will be highlighted.
*
* @param comp The component this scroll pane should display. This should
* be an instance of {@link RTextArea},
* javax.swing.JLayer
(or the older
* org.jdesktop.jxlayer.JXLayer
), or null
.
* If this argument is null
, you must call
* {@link #setViewportView(Component)}, passing in an instance of
* one of the types above.
*/
public RTextScrollPane(Component comp) {
this(comp, true);
}
/**
* Creates a scroll pane. A default value will be used for line number
* color (gray), and the current line's line number will be highlighted.
*
* @param textArea The text area this scroll pane will contain. If this is
* null
, you must call
* {@link #setViewportView(Component)}, passing in an
* {@link RTextArea}.
* @param lineNumbers Whether line numbers should be enabled.
*/
public RTextScrollPane(RTextArea textArea, boolean lineNumbers) {
this(textArea, lineNumbers, Color.GRAY);
}
/**
* Creates a scroll pane. A default value will be used for line number
* color (gray), and the current line's line number will be highlighted.
*
* @param comp The component this scroll pane should display. This should
* be an instance of {@link RTextArea},
* javax.swing.JLayer
(or the older
* org.jdesktop.jxlayer.JXLayer
), or null
.
* If this argument is null
, you must call
* {@link #setViewportView(Component)}, passing in an instance of
* one of the types above.
* @param lineNumbers Whether line numbers should be enabled.
*/
public RTextScrollPane(Component comp, boolean lineNumbers) {
this(comp, lineNumbers, Color.GRAY);
}
/**
* Creates a scroll pane.
*
* @param comp The component this scroll pane should display. This should
* be an instance of {@link RTextArea},
* javax.swing.JLayer
(or the older
* org.jdesktop.jxlayer.JXLayer
), or null
.
* If this argument is null
, you must call
* {@link #setViewportView(Component)}, passing in an instance of
* one of the types above.
* @param lineNumbers Whether line numbers are initially enabled.
* @param lineNumberColor The color to use for line numbers.
*/
public RTextScrollPane(Component comp, boolean lineNumbers,
Color lineNumberColor) {
super(comp);
RTextArea textArea = getFirstRTextAreaDescendant(comp);
// Create the gutter for this document.
Font defaultFont = new Font(Font.MONOSPACED, Font.PLAIN, 12);
gutter = new Gutter(textArea);
gutter.setLineNumberFont(defaultFont);
gutter.setLineNumberColor(lineNumberColor);
setLineNumbersEnabled(lineNumbers);
// Set miscellaneous properties.
setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS);
setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
/**
* Ensures the gutter is visible if it's showing anything.
*/
private void checkGutterVisibility() {
int count = gutter.getComponentCount();
if (count==0) {
if (getRowHeader()!=null && getRowHeader().getView()==gutter) {
setRowHeaderView(null);
}
}
else {
if (getRowHeader()==null || getRowHeader().getView()==null) {
setRowHeaderView(gutter);
}
}
}
/**
* Returns the gutter.
*
* @return The gutter.
*/
public Gutter getGutter() {
return gutter;
}
/**
* Returns true
if the line numbers are enabled and visible.
*
* @return Whether line numbers are visible.
* @see #setLineNumbersEnabled(boolean)
*/
public boolean getLineNumbersEnabled() {
return gutter.getLineNumbersEnabled();
}
/**
* Returns the text area being displayed.
*
* @return The text area.
* @see #setViewportView(Component)
*/
public RTextArea getTextArea() {
Component view = getViewport().getView();
if (view instanceof RTextArea) {
return (RTextArea)view;
}
return getFirstRTextAreaDescendant(view);
}
/**
* Returns whether the fold indicator is enabled.
*
* @return Whether the fold indicator is enabled.
* @see #setFoldIndicatorEnabled(boolean)
*/
public boolean isFoldIndicatorEnabled() {
return gutter.isFoldIndicatorEnabled();
}
/**
* Returns whether the icon row header is enabled.
*
* @return Whether the icon row header is enabled.
* @see #setIconRowHeaderEnabled(boolean)
*/
public boolean isIconRowHeaderEnabled() {
return gutter.isIconRowHeaderEnabled();
}
/**
* Toggles whether the fold indicator is enabled.
*
* @param enabled Whether the fold indicator should be enabled.
* @see #isFoldIndicatorEnabled()
*/
public void setFoldIndicatorEnabled(boolean enabled) {
gutter.setFoldIndicatorEnabled(enabled);
checkGutterVisibility();
}
/**
* Toggles whether the icon row header (used for breakpoints, bookmarks,
* etc.) is enabled.
*
* @param enabled Whether the icon row header is enabled.
* @see #isIconRowHeaderEnabled()
*/
public void setIconRowHeaderEnabled(boolean enabled) {
gutter.setIconRowHeaderEnabled(enabled);
checkGutterVisibility();
}
/**
* Toggles whether line numbers are visible.
*
* @param enabled Whether line numbers should be visible.
* @see #getLineNumbersEnabled()
*/
public void setLineNumbersEnabled(boolean enabled) {
gutter.setLineNumbersEnabled(enabled);
checkGutterVisibility();
}
/**
* Sets the view for this scroll pane. This must be an {@link RTextArea}.
*
* @param view The new view.
* @see #getTextArea()
*/
@Override
public void setViewportView(Component view) {
RTextArea rtaCandidate;
if (!(view instanceof RTextArea)) {
rtaCandidate = getFirstRTextAreaDescendant(view);
if (rtaCandidate==null) {
throw new IllegalArgumentException(
"view must be either an RTextArea or a JLayer wrapping one");
}
}
else {
rtaCandidate = (RTextArea)view;
}
super.setViewportView(view);
if (gutter!=null) {
gutter.setTextArea(rtaCandidate);
}
}
/**
* Returns the first descendant of a component that is an
* RTextArea
. This is primarily here to support
* javax.swing.JLayer
s that wrap RTextArea
s.
*
* @param comp The component to recursively look through.
* @return The first descendant text area, or null
if none
* is found.
*/
private static RTextArea getFirstRTextAreaDescendant(Component comp) {
Stack stack = new Stack<>();
stack.add(comp);
while (!stack.isEmpty()) {
Component current = stack.pop();
if (current instanceof RTextArea) {
return (RTextArea)current;
}
if (current instanceof Container) {
Container container = (Container)current;
stack.addAll(Arrays.asList(container.getComponents()));
}
}
return null;
}
}