- Joined
- Feb 22, 2006
- Messages
- 960
I have a small problem with the open source JEditTextArea. I want to add Key Strokes to it but don't get it to work.
So actually the JEditTextArea uses an InputHandler for KeyStrokes... so the InputHandler doc says I have to add the actions etc...
that's what I got but I don't know what to add for the string parameter
Here for those who may want to look into the JEditTextArea/InputHandler
(JEditTextArea is slightly edited so not the original)
It would be nice if someone would have any idea to help me
Edit: Ok problem solved ...
So actually the JEditTextArea uses an InputHandler for KeyStrokes... so the InputHandler doc says I have to add the actions etc...
that's what I got but I don't know what to add for the string parameter
Code:
codeArea = new JEditTextArea(this);
codeArea.getInputHandler().addKeyBinding("NO IDEA WHAT TO ADD",
new ActionListener() {
public void actionPerformed(ActionEvent e) {
codeArea.paste();
}
});
Here for those who may want to look into the JEditTextArea/InputHandler
(JEditTextArea is slightly edited so not the original)
Code:
package SyntaxHighlighting;
/*
* JEditTextArea.java - jEdit's text component
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
import Gui.LinePanel;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.*;
import javax.swing.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.*;
import java.util.Enumeration;
import java.util.Vector;
/**
* jEdit's text area component. It is more suited for editing program
* source code than JEditorPane, because it drops the unnecessary features
* (images, variable-width lines, and so on) and adds a whole bunch of
* useful goodies such as:
* <ul>
* <li>More flexible key binding scheme
* <li>Supports macro recorders
* <li>Rectangular selection
* <li>Bracket highlighting
* <li>Syntax highlighting
* <li>Command repetition
* <li>Block caret can be enabled
* </ul>
* It is also faster and doesn't have as many problems. It can be used
* in other applications; the only other part of jEdit it depends on is
* the syntax package.<p>
*
* To use it in your app, treat it like any other component, for example:
* <pre>JEditTextArea ta = new JEditTextArea();
* ta.setTokenMarker(new JavaTokenMarker());
* ta.setText("public class Test {\n"
* + " public static void main(String[] args) {\n"
* + " System.out.println(\"Hello World\");\n"
* + " }\n"
* + "}");</pre>
*
* @author Slava Pestov
* @version $Id: JEditTextArea.java,v 1.36 1999/12/13 03:40:30 sp Exp $
*/
public class JEditTextArea extends JComponent
{
/**
* Adding components with this name to the text area will place
* them left of the horizontal scroll bar. In jEdit, the status
* bar is added this way.
*/
public static String LEFT_OF_SCROLLBAR = "los";
private LinePanel panel;
/**
* Creates a new JEditTextArea with the default settings.
*/
public JEditTextArea(LinePanel panel)
{
this(TextAreaDefaults.getDefaults(),panel);
}
/**
* Creates a new JEditTextArea with the specified settings.
* @param defaults The default settings
*/
public JEditTextArea(TextAreaDefaults defaults,LinePanel panel)
{
// Enable the necessary events
enableEvents(AWTEvent.KEY_EVENT_MASK);
this.panel = panel;
// Initialize some misc. stuff
painter = new TextAreaPainter(this,defaults,panel);
documentHandler = new DocumentHandler();
listenerList = new EventListenerList();
caretEvent = new MutableCaretEvent();
lineSegment = new Segment();
bracketLine = bracketPosition = -1;
blink = true;
// Initialize the GUI
setLayout(new ScrollLayout());
add(CENTER,painter);
add(RIGHT,vertical = new JScrollBar(JScrollBar.VERTICAL));
add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
// Add some event listeners
vertical.addAdjustmentListener(new AdjustHandler());
horizontal.addAdjustmentListener(new AdjustHandler());
painter.addComponentListener(new ComponentHandler());
painter.addMouseListener(new MouseHandler());
painter.addMouseMotionListener(new DragHandler());
addFocusListener(new FocusHandler());
// Load the defaults
setInputHandler(defaults.inputHandler);
setDocument(defaults.document);
editable = defaults.editable;
caretVisible = defaults.caretVisible;
caretBlinks = defaults.caretBlinks;
electricScroll = defaults.electricScroll;
popup = defaults.popup;
// We don't seem to get the initial focus event?
focusedComponent = this;
}
/**
* Returns if this component can be traversed by pressing
* the Tab key. This returns false.
*/
public final boolean isManagingFocus()
{
return true;
}
/**
* Returns the object responsible for painting this text area.
*/
public final TextAreaPainter getPainter()
{
return painter;
}
/**
* Returns the input handler.
*/
public final InputHandler getInputHandler()
{
return inputHandler;
}
/**
* Sets the input handler.
* @param inputHandler The new input handler
*/
public void setInputHandler(InputHandler inputHandler)
{
this.inputHandler = inputHandler;
}
/**
* Returns true if the caret is blinking, false otherwise.
*/
public final boolean isCaretBlinkEnabled()
{
return caretBlinks;
}
/**
* Toggles caret blinking.
* @param caretBlinks True if the caret should blink, false otherwise
*/
public void setCaretBlinkEnabled(boolean caretBlinks)
{
this.caretBlinks = caretBlinks;
if(!caretBlinks)
blink = false;
painter.invalidateSelectedLines();
}
/**
* Returns true if the caret is visible, false otherwise.
*/
public final boolean isCaretVisible()
{
return (!caretBlinks || blink) && caretVisible;
}
/**
* Sets if the caret should be visible.
* @param caretVisible True if the caret should be visible, false
* otherwise
*/
public void setCaretVisible(boolean caretVisible)
{
this.caretVisible = caretVisible;
blink = true;
painter.invalidateSelectedLines();
}
/**
* Blinks the caret.
*/
public final void blinkCaret()
{
if(caretBlinks)
{
blink = !blink;
painter.invalidateSelectedLines();
}
else
blink = true;
}
/**
* Returns the number of lines from the top and button of the
* text area that are always visible.
*/
public final int getElectricScroll()
{
return electricScroll;
}
/**
* Sets the number of lines from the top and bottom of the text
* area that are always visible
* @param electricScroll The number of lines always visible from
* the top or bottom
*/
public final void setElectricScroll(int electricScroll)
{
this.electricScroll = electricScroll;
}
/**
* Updates the state of the scroll bars. This should be called
* if the number of lines in the document changes, or when the
* size of the text are changes.
*/
public void updateScrollBars()
{
if(vertical != null && visibleLines != 0)
{
vertical.setValues(firstLine,visibleLines,0,getLineCount());
vertical.setUnitIncrement(2);
vertical.setBlockIncrement(visibleLines);
}
int width = painter.getWidth();
if(horizontal != null && width != 0)
{
horizontal.setValues(-horizontalOffset,width,0,width * 5);
horizontal.setUnitIncrement(painter.getFontMetrics()
.charWidth('w'));
horizontal.setBlockIncrement(width / 2);
}
}
/**
* Returns the line displayed at the text area's origin.
*/
public final int getFirstLine()
{
return firstLine;
}
/**
* Sets the line displayed at the text area's origin without
* updating the scroll bars.
*/
public void setFirstLine(int firstLine)
{
if(firstLine == this.firstLine)
return;
int oldFirstLine = this.firstLine;
this.firstLine = firstLine;
if(firstLine != vertical.getValue())
updateScrollBars();
painter.repaint();
}
/**
* Returns the number of lines visible in this text area.
*/
public final int getVisibleLines()
{
return visibleLines;
}
/**
* Recalculates the number of visible lines. This should not
* be called directly.
*/
public final void recalculateVisibleLines()
{
if(painter == null)
return;
int height = painter.getHeight();
int lineHeight = painter.getFontMetrics().getHeight();
int oldVisibleLines = visibleLines;
visibleLines = height / lineHeight;
updateScrollBars();
}
/**
* Returns the horizontal offset of drawn lines.
*/
public final int getHorizontalOffset()
{
return horizontalOffset;
}
/**
* Sets the horizontal offset of drawn lines. This can be used to
* implement horizontal scrolling.
* @param horizontalOffset offset The new horizontal offset
*/
public void setHorizontalOffset(int horizontalOffset)
{
if(horizontalOffset == this.horizontalOffset)
return;
this.horizontalOffset = horizontalOffset;
if(horizontalOffset != horizontal.getValue())
updateScrollBars();
painter.repaint();
}
/**
* A fast way of changing both the first line and horizontal
* offset.
* @param firstLine The new first line
* @param horizontalOffset The new horizontal offset
* @return True if any of the values were changed, false otherwise
*/
public boolean setOrigin(int firstLine, int horizontalOffset)
{
boolean changed = false;
int oldFirstLine = this.firstLine;
if(horizontalOffset != this.horizontalOffset)
{
this.horizontalOffset = horizontalOffset;
changed = true;
}
if(firstLine != this.firstLine)
{
this.firstLine = firstLine;
changed = true;
}
if(changed)
{
updateScrollBars();
painter.repaint();
}
return changed;
}
/**
* Ensures that the caret is visible by scrolling the text area if
* necessary.
* @return True if scrolling was actually performed, false if the
* caret was already visible
*/
public boolean scrollToCaret()
{
int line = getCaretLine();
int lineStart = getLineStartOffset(line);
int offset = Math.max(0,Math.min(getLineLength(line) - 1,
getCaretPosition() - lineStart));
return scrollTo(line,offset);
}
/**
* Ensures that the specified line and offset is visible by scrolling
* the text area if necessary.
* @param line The line to scroll to
* @param offset The offset in the line to scroll to
* @return True if scrolling was actually performed, false if the
* line and offset was already visible
*/
public boolean scrollTo(int line, int offset)
{
// visibleLines == 0 before the component is realized
// we can't do any proper scrolling then, so we have
// this hack...
if(visibleLines == 0)
{
setFirstLine(Math.max(0,line - electricScroll));
return true;
}
int newFirstLine = firstLine;
int newHorizontalOffset = horizontalOffset;
if(line < firstLine + electricScroll)
{
newFirstLine = Math.max(0,line - electricScroll);
}
else if(line + electricScroll >= firstLine + visibleLines)
{
newFirstLine = (line - visibleLines) + electricScroll + 1;
if(newFirstLine + visibleLines >= getLineCount())
newFirstLine = getLineCount() - visibleLines;
if(newFirstLine < 0)
newFirstLine = 0;
}
int x = _offsetToX(line,offset);
int width = painter.getFontMetrics().charWidth('w');
if(x < 0)
{
newHorizontalOffset = Math.min(0,horizontalOffset
- x + width + 5);
}
else if(x + width >= painter.getWidth())
{
newHorizontalOffset = horizontalOffset +
(painter.getWidth() - x) - width - 5;
}
return setOrigin(newFirstLine,newHorizontalOffset);
}
/**
* Converts a line index to a y co-ordinate.
* @param line The line
*/
public int lineToY(int line)
{
FontMetrics fm = painter.getFontMetrics();
return (line - firstLine) * fm.getHeight()
- (fm.getLeading() + fm.getMaxDescent());
}
/**
* Converts a y co-ordinate to a line index.
* @param y The y co-ordinate
*/
public int yToLine(int y)
{
FontMetrics fm = painter.getFontMetrics();
int height = fm.getHeight();
return Math.max(0,Math.min(getLineCount() - 1,
y / height + firstLine));
}
/**
* Converts an offset in a line into an x co-ordinate. This is a
* slow version that can be used any time.
* @param line The line
* @param offset The offset, from the start of the line
*/
public final int offsetToX(int line, int offset)
{
// don't use cached tokens
painter.currentLineTokens = null;
return _offsetToX(line,offset);
}
/**
* Converts an offset in a line into an x co-ordinate. This is a
* fast version that should only be used if no changes were made
* to the text since the last repaint.
* @param line The line
* @param offset The offset, from the start of the line
*/
public int _offsetToX(int line, int offset)
{
TokenMarker tokenMarker = getTokenMarker();
/* Use painter's cached info for speed */
FontMetrics fm = painter.getFontMetrics();
getLineText(line,lineSegment);
int segmentOffset = lineSegment.offset;
int x = horizontalOffset;
/* If syntax coloring is disabled, do simple translation */
if(tokenMarker == null)
{
lineSegment.count = offset;
return x + Utilities.getTabbedTextWidth(lineSegment,
fm,x,painter,0);
}
/* If syntax coloring is enabled, we have to do this because
* tokens can vary in width */
else
{
Token tokens;
if(painter.currentLineIndex == line
&& painter.currentLineTokens != null)
tokens = painter.currentLineTokens;
else
{
painter.currentLineIndex = line;
tokens = painter.currentLineTokens
= tokenMarker.markTokens(lineSegment,line);
}
Toolkit toolkit = painter.getToolkit();
Font defaultFont = painter.getFont();
SyntaxStyle[] styles = painter.getStyles();
for(;;)
{
byte id = tokens.id;
if(id == Token.END)
{
return x;
}
if(id == Token.NULL)
fm = painter.getFontMetrics();
else
fm = styles[id].getFontMetrics(defaultFont);
int length = tokens.length;
if(offset + segmentOffset < lineSegment.offset + length)
{
lineSegment.count = offset - (lineSegment.offset - segmentOffset);
return x + Utilities.getTabbedTextWidth(
lineSegment,fm,x,painter,0);
}
else
{
lineSegment.count = length;
x += Utilities.getTabbedTextWidth(
lineSegment,fm,x,painter,0);
lineSegment.offset += length;
}
tokens = tokens.next;
}
}
}
/**
* Converts an x co-ordinate to an offset within a line.
* @param line The line
* @param x The x co-ordinate
*/
public int xToOffset(int line, int x)
{
TokenMarker tokenMarker = getTokenMarker();
/* Use painter's cached info for speed */
FontMetrics fm = painter.getFontMetrics();
getLineText(line,lineSegment);
char[] segmentArray = lineSegment.array;
int segmentOffset = lineSegment.offset;
int segmentCount = lineSegment.count;
int width = horizontalOffset;
if(tokenMarker == null)
{
for(int i = 0; i < segmentCount; i++)
{
char c = segmentArray[i + segmentOffset];
int charWidth;
if(c == '\t')
charWidth = (int)painter.nextTabStop(width,i)
- width;
else
charWidth = fm.charWidth(c);
if(painter.isBlockCaretEnabled())
{
if(x - charWidth <= width)
return i;
}
else
{
if(x - charWidth / 2 <= width)
return i;
}
width += charWidth;
}
return segmentCount;
}
else
{
Token tokens;
if(painter.currentLineIndex == line && painter
.currentLineTokens != null)
tokens = painter.currentLineTokens;
else
{
painter.currentLineIndex = line;
tokens = painter.currentLineTokens
= tokenMarker.markTokens(lineSegment,line);
}
int offset = 0;
Toolkit toolkit = painter.getToolkit();
Font defaultFont = painter.getFont();
SyntaxStyle[] styles = painter.getStyles();
for(;;)
{
byte id = tokens.id;
if(id == Token.END)
return offset;
if(id == Token.NULL)
fm = painter.getFontMetrics();
else
fm = styles[id].getFontMetrics(defaultFont);
int length = tokens.length;
for(int i = 0; i < length; i++)
{
char c = segmentArray[segmentOffset + offset + i];
int charWidth;
if(c == '\t')
charWidth = (int)painter.nextTabStop(width,offset + i)
- width;
else
charWidth = fm.charWidth(c);
if(painter.isBlockCaretEnabled())
{
if(x - charWidth <= width)
return offset + i;
}
else
{
if(x - charWidth / 2 <= width)
return offset + i;
}
width += charWidth;
}
offset += length;
tokens = tokens.next;
}
}
}
/**
* Converts a point to an offset, from the start of the text.
* @param x The x co-ordinate of the point
* @param y The y co-ordinate of the point
*/
public int xyToOffset(int x, int y)
{
int line = yToLine(y);
int start = getLineStartOffset(line);
return start + xToOffset(line,x);
}
/**
* Returns the document this text area is editing.
*/
public final SyntaxDocument getDocument()
{
return document;
}
/**
* Sets the document this text area is editing.
* @param document The document
*/
public void setDocument(SyntaxDocument document)
{
if(this.document == document)
return;
if(this.document != null)
this.document.removeDocumentListener(documentHandler);
this.document = document;
document.addDocumentListener(documentHandler);
select(0,0);
updateScrollBars();
painter.repaint();
}
/**
* Returns the document's token marker. Equivalent to calling
* <code>getDocument().getTokenMarker()</code>.
*/
public final TokenMarker getTokenMarker()
{
return document.getTokenMarker();
}
/**
* Sets the document's token marker. Equivalent to caling
* <code>getDocument().setTokenMarker()</code>.
* @param tokenMarker The token marker
*/
public final void setTokenMarker(TokenMarker tokenMarker)
{
document.setTokenMarker(tokenMarker);
}
/**
* Returns the length of the document. Equivalent to calling
* <code>getDocument().getLength()</code>.
*/
public final int getDocumentLength()
{
return document.getLength();
}
/**
* Returns the number of lines in the document.
*/
public final int getLineCount()
{
return document.getDefaultRootElement().getElementCount();
}
/**
* Returns the line containing the specified offset.
* @param offset The offset
*/
public final int getLineOfOffset(int offset)
{
return document.getDefaultRootElement().getElementIndex(offset);
}
/**
* Returns the start offset of the specified line.
* @param line The line
* @return The start offset of the specified line, or -1 if the line is
* invalid
*/
public int getLineStartOffset(int line)
{
Element lineElement = document.getDefaultRootElement()
.getElement(line);
if(lineElement == null)
return -1;
else
return lineElement.getStartOffset();
}
/**
* Returns the end offset of the specified line.
* @param line The line
* @return The end offset of the specified line, or -1 if the line is
* invalid.
*/
public int getLineEndOffset(int line)
{
Element lineElement = document.getDefaultRootElement()
.getElement(line);
if(lineElement == null)
return -1;
else
return lineElement.getEndOffset();
}
/**
* Returns the length of the specified line.
* @param line The line
*/
public int getLineLength(int line)
{
Element lineElement = document.getDefaultRootElement()
.getElement(line);
if(lineElement == null)
return -1;
else
return lineElement.getEndOffset()
- lineElement.getStartOffset() - 1;
}
/**
* Returns the entire text of this text area.
*/
public String getText()
{
try
{
return document.getText(0,document.getLength());
}
catch(BadLocationException bl)
{
bl.printStackTrace();
return null;
}
}
/**
* Sets the entire text of this text area.
*/
public void setText(String text)
{
try
{
document.beginCompoundEdit();
document.remove(0,document.getLength());
document.insertString(0,text,null);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
finally
{
document.endCompoundEdit();
}
}
/**
* Returns the specified substring of the document.
* @param start The start offset
* @param len The length of the substring
* @return The substring, or null if the offsets are invalid
*/
public final String getText(int start, int len)
{
try
{
return document.getText(start,len);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
return null;
}
}
/**
* Copies the specified substring of the document into a segment.
* If the offsets are invalid, the segment will contain a null string.
* @param start The start offset
* @param len The length of the substring
* @param segment The segment
*/
public final void getText(int start, int len, Segment segment)
{
try
{
document.getText(start,len,segment);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
segment.offset = segment.count = 0;
}
}
/**
* Returns the text on the specified line.
* @param lineIndex The line
* @return The text, or null if the line is invalid
*/
public final String getLineText(int lineIndex)
{
int start = getLineStartOffset(lineIndex);
return getText(start,getLineEndOffset(lineIndex) - start - 1);
}
/**
* Copies the text on the specified line into a segment. If the line
* is invalid, the segment will contain a null string.
* @param lineIndex The line
*/
public final void getLineText(int lineIndex, Segment segment)
{
int start = getLineStartOffset(lineIndex);
getText(start,getLineEndOffset(lineIndex) - start - 1,segment);
}
/**
* Returns the selection start offset.
*/
public final int getSelectionStart()
{
return selectionStart;
}
/**
* Returns the offset where the selection starts on the specified
* line.
*/
public int getSelectionStart(int line)
{
if(line == selectionStartLine)
return selectionStart;
else if(rectSelect)
{
Element map = document.getDefaultRootElement();
int start = selectionStart - map.getElement(selectionStartLine)
.getStartOffset();
Element lineElement = map.getElement(line);
int lineStart = lineElement.getStartOffset();
int lineEnd = lineElement.getEndOffset() - 1;
return Math.min(lineEnd,lineStart + start);
}
else
return getLineStartOffset(line);
}
/**
* Returns the selection start line.
*/
public final int getSelectionStartLine()
{
return selectionStartLine;
}
/**
* Sets the selection start. The new selection will be the new
* selection start and the old selection end.
* @param selectionStart The selection start
* @see #select(int,int)
*/
public final void setSelectionStart(int selectionStart)
{
select(selectionStart,selectionEnd);
}
/**
* Returns the selection end offset.
*/
public final int getSelectionEnd()
{
return selectionEnd;
}
/**
* Returns the offset where the selection ends on the specified
* line.
*/
public int getSelectionEnd(int line)
{
if(line == selectionEndLine)
return selectionEnd;
else if(rectSelect)
{
Element map = document.getDefaultRootElement();
int end = selectionEnd - map.getElement(selectionEndLine)
.getStartOffset();
Element lineElement = map.getElement(line);
int lineStart = lineElement.getStartOffset();
int lineEnd = lineElement.getEndOffset() - 1;
return Math.min(lineEnd,lineStart + end);
}
else
return getLineEndOffset(line) - 1;
}
/**
* Returns the selection end line.
*/
public final int getSelectionEndLine()
{
return selectionEndLine;
}
/**
* Sets the selection end. The new selection will be the old
* selection start and the bew selection end.
* @param selectionEnd The selection end
* @see #select(int,int)
*/
public final void setSelectionEnd(int selectionEnd)
{
select(selectionStart,selectionEnd);
}
/**
* Returns the caret position. This will either be the selection
* start or the selection end, depending on which direction the
* selection was made in.
*/
public final int getCaretPosition()
{
return (biasLeft ? selectionStart : selectionEnd);
}
/**
* Returns the caret line.
*/
public final int getCaretLine()
{
return (biasLeft ? selectionStartLine : selectionEndLine);
}
/**
* Returns the mark position. This will be the opposite selection
* bound to the caret position.
* @see #getCaretPosition()
*/
public final int getMarkPosition()
{
return (biasLeft ? selectionEnd : selectionStart);
}
/**
* Returns the mark line.
*/
public final int getMarkLine()
{
return (biasLeft ? selectionEndLine : selectionStartLine);
}
/**
* Sets the caret position. The new selection will consist of the
* caret position only (hence no text will be selected)
* @param caret The caret position
* @see #select(int,int)
*/
public final void setCaretPosition(int caret)
{
select(caret,caret);
}
/**
* Selects all text in the document.
*/
public final void selectAll()
{
select(0,getDocumentLength());
}
/**
* Moves the mark to the caret position.
*/
public final void selectNone()
{
select(getCaretPosition(),getCaretPosition());
}
/**
* Selects from the start offset to the end offset. This is the
* general selection method used by all other selecting methods.
* The caret position will be start if start < end, and end
* if end > start.
* @param start The start offset
* @param end The end offset
*/
public void select(int start, int end)
{
int newStart, newEnd;
boolean newBias;
if(start <= end)
{
newStart = start;
newEnd = end;
newBias = false;
}
else
{
newStart = end;
newEnd = start;
newBias = true;
}
if(newStart < 0 || newEnd > getDocumentLength())
{
throw new IllegalArgumentException("Bounds out of"
+ " range: " + newStart + "," +
newEnd);
}
// If the new position is the same as the old, we don't
// do all this crap, however we still do the stuff at
// the end (clearing magic position, scrolling)
if(newStart != selectionStart || newEnd != selectionEnd
|| newBias != biasLeft)
{
int newStartLine = getLineOfOffset(newStart);
int newEndLine = getLineOfOffset(newEnd);
if(painter.isBracketHighlightEnabled())
{
if(bracketLine != -1)
painter.invalidateLine(bracketLine);
updateBracketHighlight(end);
if(bracketLine != -1)
painter.invalidateLine(bracketLine);
}
painter.invalidateLineRange(selectionStartLine,selectionEndLine);
painter.invalidateLineRange(newStartLine,newEndLine);
document.addUndoableEdit(new CaretUndo(
selectionStart,selectionEnd));
selectionStart = newStart;
selectionEnd = newEnd;
selectionStartLine = newStartLine;
selectionEndLine = newEndLine;
biasLeft = newBias;
fireCaretEvent();
}
// When the user is typing, etc, we don't want the caret
// to blink
blink = true;
caretTimer.restart();
// Disable rectangle select if selection start = selection end
if(selectionStart == selectionEnd)
rectSelect = false;
// Clear the `magic' caret position used by up/down
magicCaret = -1;
scrollToCaret();
}
/**
* Returns the selected text, or null if no selection is active.
*/
public final String getSelectedText()
{
if(selectionStart == selectionEnd)
return null;
if(rectSelect)
{
// Return each row of the selection on a new line
Element map = document.getDefaultRootElement();
int start = selectionStart - map.getElement(selectionStartLine)
.getStartOffset();
int end = selectionEnd - map.getElement(selectionEndLine)
.getStartOffset();
// Certain rectangles satisfy this condition...
if(end < start)
{
int tmp = end;
end = start;
start = tmp;
}
StringBuffer buf = new StringBuffer();
Segment seg = new Segment();
for(int i = selectionStartLine; i <= selectionEndLine; i++)
{
Element lineElement = map.getElement(i);
int lineStart = lineElement.getStartOffset();
int lineEnd = lineElement.getEndOffset() - 1;
int lineLen = lineEnd - lineStart;
lineStart = Math.min(lineStart + start,lineEnd);
lineLen = Math.min(end - start,lineEnd - lineStart);
getText(lineStart,lineLen,seg);
buf.append(seg.array,seg.offset,seg.count);
if(i != selectionEndLine)
buf.append('\n');
}
return buf.toString();
}
else
{
return getText(selectionStart,
selectionEnd - selectionStart);
}
}
/**
* Replaces the selection with the specified text.
* @param selectedText The replacement text for the selection
*/
public void setSelectedText(String selectedText)
{
if(!editable)
{
throw new InternalError("Text component"
+ " read only");
}
document.beginCompoundEdit();
try
{
if(rectSelect)
{
Element map = document.getDefaultRootElement();
int start = selectionStart - map.getElement(selectionStartLine)
.getStartOffset();
int end = selectionEnd - map.getElement(selectionEndLine)
.getStartOffset();
// Certain rectangles satisfy this condition...
if(end < start)
{
int tmp = end;
end = start;
start = tmp;
}
int lastNewline = 0;
int currNewline = 0;
for(int i = selectionStartLine; i <= selectionEndLine; i++)
{
Element lineElement = map.getElement(i);
int lineStart = lineElement.getStartOffset();
int lineEnd = lineElement.getEndOffset() - 1;
int rectStart = Math.min(lineEnd,lineStart + start);
document.remove(rectStart,Math.min(lineEnd - rectStart,
end - start));
if(selectedText == null)
continue;
currNewline = selectedText.indexOf('\n',lastNewline);
if(currNewline == -1)
currNewline = selectedText.length();
document.insertString(rectStart,selectedText
.substring(lastNewline,currNewline),null);
lastNewline = Math.min(selectedText.length(),
currNewline + 1);
}
if(selectedText != null &&
currNewline != selectedText.length())
{
int offset = map.getElement(selectionEndLine)
.getEndOffset() - 1;
document.insertString(offset,"\n",null);
document.insertString(offset + 1,selectedText
.substring(currNewline + 1),null);
}
}
else
{
document.remove(selectionStart,
selectionEnd - selectionStart);
if(selectedText != null)
{
document.insertString(selectionStart,
selectedText,null);
}
}
}
catch(BadLocationException bl)
{
bl.printStackTrace();
throw new InternalError("Cannot replace"
+ " selection");
}
// No matter what happends... stops us from leaving document
// in a bad state
finally
{
document.endCompoundEdit();
}
setCaretPosition(selectionEnd);
}
/**
* Returns true if this text area is editable, false otherwise.
*/
public final boolean isEditable()
{
return editable;
}
/**
* Sets if this component is editable.
* @param editable True if this text area should be editable,
* false otherwise
*/
public final void setEditable(boolean editable)
{
this.editable = editable;
}
/**
* Returns the right click popup menu.
*/
public final JPopupMenu getRightClickPopup()
{
return popup;
}
/**
* Sets the right click popup menu.
* @param popup The popup
*/
public final void setRightClickPopup(JPopupMenu popup)
{
this.popup = popup;
}
/**
* Returns the `magic' caret position. This can be used to preserve
* the column position when moving up and down lines.
*/
public final int getMagicCaretPosition()
{
return magicCaret;
}
/**
* Sets the `magic' caret position. This can be used to preserve
* the column position when moving up and down lines.
* @param magicCaret The magic caret position
*/
public final void setMagicCaretPosition(int magicCaret)
{
this.magicCaret = magicCaret;
}
/**
* Similar to <code>setSelectedText()</code>, but overstrikes the
* appropriate number of characters if overwrite mode is enabled.
* @param str The string
* @see #setSelectedText(String)
* @see #isOverwriteEnabled()
*/
public void overwriteSetSelectedText(String str)
{
// Don't overstrike if there is a selection
if(!overwrite || selectionStart != selectionEnd)
{
setSelectedText(str);
return;
}
// Don't overstrike if we're on the end of
// the line
int caret = getCaretPosition();
int caretLineEnd = getLineEndOffset(getCaretLine());
if(caretLineEnd - caret <= str.length())
{
setSelectedText(str);
return;
}
document.beginCompoundEdit();
try
{
document.remove(caret,str.length());
document.insertString(caret,str,null);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
finally
{
document.endCompoundEdit();
}
}
/**
* Returns true if overwrite mode is enabled, false otherwise.
*/
public final boolean isOverwriteEnabled()
{
return overwrite;
}
/**
* Sets if overwrite mode should be enabled.
* @param overwrite True if overwrite mode should be enabled,
* false otherwise.
*/
public final void setOverwriteEnabled(boolean overwrite)
{
this.overwrite = overwrite;
painter.invalidateSelectedLines();
}
/**
* Returns true if the selection is rectangular, false otherwise.
*/
public final boolean isSelectionRectangular()
{
return rectSelect;
}
/**
* Sets if the selection should be rectangular.
* @param overwrite True if the selection should be rectangular,
* false otherwise.
*/
public final void setSelectionRectangular(boolean rectSelect)
{
this.rectSelect = rectSelect;
painter.invalidateSelectedLines();
}
/**
* Returns the position of the highlighted bracket (the bracket
* matching the one before the caret)
*/
public final int getBracketPosition()
{
return bracketPosition;
}
/**
* Returns the line of the highlighted bracket (the bracket
* matching the one before the caret)
*/
public final int getBracketLine()
{
return bracketLine;
}
/**
* Adds a caret change listener to this text area.
* @param listener The listener
*/
public final void addCaretListener(CaretListener listener)
{
listenerList.add(CaretListener.class,listener);
}
/**
* Removes a caret change listener from this text area.
* @param listener The listener
*/
public final void removeCaretListener(CaretListener listener)
{
listenerList.remove(CaretListener.class,listener);
}
/**
* Deletes the selected text from the text area and places it
* into the clipboard.
*/
public void cut()
{
if(editable)
{
copy();
setSelectedText("");
}
}
/**
* Places the selected text into the clipboard.
*/
public void copy()
{
if(selectionStart != selectionEnd)
{
Clipboard clipboard = getToolkit().getSystemClipboard();
String selection = getSelectedText();
int repeatCount = inputHandler.getRepeatCount();
StringBuffer buf = new StringBuffer();
for(int i = 0; i < repeatCount; i++)
buf.append(selection);
clipboard.setContents(new StringSelection(buf.toString()),null);
}
}
/**
* Inserts the clipboard contents into the text.
*/
public void paste()
{
if(editable)
{
Clipboard clipboard = getToolkit().getSystemClipboard();
try
{
// The MacOS MRJ doesn't convert \r to \n,
// so do it here
String selection = ((String)clipboard
.getContents(this).getTransferData(
DataFlavor.stringFlavor))
.replace('\r','\n');
int repeatCount = inputHandler.getRepeatCount();
StringBuffer buf = new StringBuffer();
for(int i = 0; i < repeatCount; i++)
buf.append(selection);
selection = buf.toString();
setSelectedText(selection);
}
catch(Exception e)
{
getToolkit().beep();
System.err.println("Clipboard does not"
+ " contain a string");
}
}
}
/**
* Called by the AWT when this component is removed from it's parent.
* This stops clears the currently focused component.
*/
public void removeNotify()
{
super.removeNotify();
if(focusedComponent == this)
focusedComponent = null;
}
/**
* Forwards key events directly to the input handler.
* This is slightly faster than using a KeyListener
* because some Swing overhead is avoided.
*/
public void processKeyEvent(KeyEvent evt)
{
if(inputHandler == null)
return;
switch(evt.getID())
{
case KeyEvent.KEY_TYPED:
inputHandler.keyTyped(evt);
break;
case KeyEvent.KEY_PRESSED:
inputHandler.keyPressed(evt);
break;
case KeyEvent.KEY_RELEASED:
inputHandler.keyReleased(evt);
break;
}
}
// protected members
protected static String CENTER = "center";
protected static String RIGHT = "right";
protected static String BOTTOM = "bottom";
protected static JEditTextArea focusedComponent;
protected static Timer caretTimer;
protected TextAreaPainter painter;
protected JPopupMenu popup;
protected EventListenerList listenerList;
protected MutableCaretEvent caretEvent;
protected boolean caretBlinks;
protected boolean caretVisible;
protected boolean blink;
protected boolean editable;
protected int firstLine;
protected int visibleLines;
protected int electricScroll;
protected int horizontalOffset;
protected JScrollBar vertical;
protected JScrollBar horizontal;
protected boolean scrollBarsInitialized;
protected InputHandler inputHandler;
protected SyntaxDocument document;
protected DocumentHandler documentHandler;
protected Segment lineSegment;
protected int selectionStart;
protected int selectionStartLine;
protected int selectionEnd;
protected int selectionEndLine;
protected boolean biasLeft;
protected int bracketPosition;
protected int bracketLine;
protected int magicCaret;
protected boolean overwrite;
protected boolean rectSelect;
protected void fireCaretEvent()
{
Object[] listeners = listenerList.getListenerList();
for(int i = listeners.length - 2; i >= 0; i--)
{
if(listeners[i] == CaretListener.class)
{
((CaretListener)listeners[i+1]).caretUpdate(caretEvent);
}
}
}
protected void updateBracketHighlight(int newCaretPosition)
{
if(newCaretPosition == 0)
{
bracketPosition = bracketLine = -1;
return;
}
try
{
int offset = TextUtilities.findMatchingBracket(
document,newCaretPosition - 1);
if(offset != -1)
{
bracketLine = getLineOfOffset(offset);
bracketPosition = offset - getLineStartOffset(bracketLine);
return;
}
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
bracketLine = bracketPosition = -1;
}
protected void documentChanged(DocumentEvent evt)
{
DocumentEvent.ElementChange ch = evt.getChange(
document.getDefaultRootElement());
int count;
if(ch == null)
count = 0;
else
count = ch.getChildrenAdded().length -
ch.getChildrenRemoved().length;
int line = getLineOfOffset(evt.getOffset());
if(count == 0)
{
painter.invalidateLine(line);
}
// do magic stuff
else if(line < firstLine)
{
setFirstLine(firstLine + count);
}
// end of magic stuff
else
{
painter.invalidateLineRange(line,firstLine + visibleLines);
updateScrollBars();
}
}
class ScrollLayout implements LayoutManager
{
public void addLayoutComponent(String name, Component comp)
{
if(name.equals(CENTER))
center = comp;
else if(name.equals(RIGHT))
right = comp;
else if(name.equals(BOTTOM))
bottom = comp;
else if(name.equals(LEFT_OF_SCROLLBAR))
leftOfScrollBar.addElement(comp);
}
public void removeLayoutComponent(Component comp)
{
if(center == comp)
center = null;
if(right == comp)
right = null;
if(bottom == comp)
bottom = null;
else
leftOfScrollBar.removeElement(comp);
}
public Dimension preferredLayoutSize(Container parent)
{
Dimension dim = new Dimension();
Insets insets = getInsets();
dim.width = insets.left + insets.right;
dim.height = insets.top + insets.bottom;
Dimension centerPref = center.getPreferredSize();
dim.width += centerPref.width;
dim.height += centerPref.height;
Dimension rightPref = right.getPreferredSize();
dim.width += rightPref.width;
Dimension bottomPref = bottom.getPreferredSize();
dim.height += bottomPref.height;
return dim;
}
public Dimension minimumLayoutSize(Container parent)
{
Dimension dim = new Dimension();
Insets insets = getInsets();
dim.width = insets.left + insets.right;
dim.height = insets.top + insets.bottom;
Dimension centerPref = center.getMinimumSize();
dim.width += centerPref.width;
dim.height += centerPref.height;
Dimension rightPref = right.getMinimumSize();
dim.width += rightPref.width;
Dimension bottomPref = bottom.getMinimumSize();
dim.height += bottomPref.height;
return dim;
}
public void layoutContainer(Container parent)
{
Dimension size = parent.getSize();
Insets insets = parent.getInsets();
int itop = insets.top;
int ileft = insets.left;
int ibottom = insets.bottom;
int iright = insets.right;
int rightWidth = right.getPreferredSize().width;
int bottomHeight = bottom.getPreferredSize().height;
int centerWidth = size.width - rightWidth - ileft - iright;
int centerHeight = size.height - bottomHeight - itop - ibottom;
center.setBounds(
ileft,
itop,
centerWidth,
centerHeight);
right.setBounds(
ileft + centerWidth,
itop,
rightWidth,
centerHeight);
// Lay out all status components, in order
Enumeration status = leftOfScrollBar.elements();
while(status.hasMoreElements())
{
Component comp = (Component)status.nextElement();
Dimension dim = comp.getPreferredSize();
comp.setBounds(ileft,
itop + centerHeight,
dim.width,
bottomHeight);
ileft += dim.width;
}
bottom.setBounds(
ileft,
itop + centerHeight,
size.width - rightWidth - ileft - iright,
bottomHeight);
}
// private members
private Component center;
private Component right;
private Component bottom;
private Vector leftOfScrollBar = new Vector();
}
static class CaretBlinker implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
if(focusedComponent != null
&& focusedComponent.hasFocus())
focusedComponent.blinkCaret();
}
}
class MutableCaretEvent extends CaretEvent
{
MutableCaretEvent()
{
super(JEditTextArea.this);
}
public int getDot()
{
return getCaretPosition();
}
public int getMark()
{
return getMarkPosition();
}
}
class AdjustHandler implements AdjustmentListener
{
public void adjustmentValueChanged(final AdjustmentEvent evt)
{
if(!scrollBarsInitialized)
return;
// If this is not done, mousePressed events accumilate
// and the result is that scrolling doesn't stop after
// the mouse is released
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
if(evt.getAdjustable() == vertical)
setFirstLine(vertical.getValue());
else
setHorizontalOffset(-horizontal.getValue());
}
});
}
}
class ComponentHandler extends ComponentAdapter
{
public void componentResized(ComponentEvent evt)
{
recalculateVisibleLines();
scrollBarsInitialized = true;
}
}
class DocumentHandler implements DocumentListener
{
public void insertUpdate(DocumentEvent evt)
{
documentChanged(evt);
int offset = evt.getOffset();
int length = evt.getLength();
int newStart;
int newEnd;
if(selectionStart > offset || (selectionStart
== selectionEnd && selectionStart == offset))
newStart = selectionStart + length;
else
newStart = selectionStart;
if(selectionEnd >= offset)
newEnd = selectionEnd + length;
else
newEnd = selectionEnd;
select(newStart,newEnd);
}
public void removeUpdate(DocumentEvent evt)
{
documentChanged(evt);
int offset = evt.getOffset();
int length = evt.getLength();
int newStart;
int newEnd;
if(selectionStart > offset)
{
if(selectionStart > offset + length)
newStart = selectionStart - length;
else
newStart = offset;
}
else
newStart = selectionStart;
if(selectionEnd > offset)
{
if(selectionEnd > offset + length)
newEnd = selectionEnd - length;
else
newEnd = offset;
}
else
newEnd = selectionEnd;
select(newStart,newEnd);
}
public void changedUpdate(DocumentEvent evt)
{
}
}
class DragHandler implements MouseMotionListener
{
public void mouseDragged(MouseEvent evt)
{
if(popup != null && popup.isVisible())
return;
setSelectionRectangular((evt.getModifiers()
& InputEvent.CTRL_MASK) != 0);
select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
}
public void mouseMoved(MouseEvent evt) {}
}
class FocusHandler implements FocusListener
{
public void focusGained(FocusEvent evt)
{
setCaretVisible(true);
focusedComponent = JEditTextArea.this;
}
public void focusLost(FocusEvent evt)
{
setCaretVisible(false);
focusedComponent = null;
}
}
class MouseHandler extends MouseAdapter
{
public void mousePressed(MouseEvent evt)
{
requestFocus();
// Focus events not fired sometimes?
setCaretVisible(true);
focusedComponent = JEditTextArea.this;
if((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0
&& popup != null)
{
popup.show(painter,evt.getX(),evt.getY());
return;
}
int line = yToLine(evt.getY());
int offset = xToOffset(line,evt.getX());
int dot = getLineStartOffset(line) + offset;
switch(evt.getClickCount())
{
case 1:
doSingleClick(evt,line,offset,dot);
break;
case 2:
// It uses the bracket matching stuff, so
// it can throw a BLE
try
{
doDoubleClick(evt,line,offset,dot);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
break;
case 3:
doTripleClick(evt,line,offset,dot);
break;
}
}
private void doSingleClick(MouseEvent evt, int line,
int offset, int dot)
{
if((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0)
{
rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
select(getMarkPosition(),dot);
}
else
setCaretPosition(dot);
}
private void doDoubleClick(MouseEvent evt, int line,
int offset, int dot) throws BadLocationException
{
// Ignore empty lines
if(getLineLength(line) == 0)
return;
try
{
int bracket = TextUtilities.findMatchingBracket(
document,Math.max(0,dot - 1));
if(bracket != -1)
{
int mark = getMarkPosition();
// Hack
if(bracket > mark)
{
bracket++;
mark--;
}
select(mark,bracket);
return;
}
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
// Ok, it's not a bracket... select the word
String lineText = getLineText(line);
char ch = lineText.charAt(Math.max(0,offset - 1));
String noWordSep = (String)document.getProperty("noWordSep");
if(noWordSep == null)
noWordSep = "";
// If the user clicked on a non-letter char,
// we select the surrounding non-letters
boolean selectNoLetter = (!Character
.isLetterOrDigit(ch)
&& noWordSep.indexOf(ch) == -1);
int wordStart = 0;
for(int i = offset - 1; i >= 0; i--)
{
ch = lineText.charAt(i);
if(selectNoLetter ^ (!Character
.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1))
{
wordStart = i + 1;
break;
}
}
int wordEnd = lineText.length();
for(int i = offset; i < lineText.length(); i++)
{
ch = lineText.charAt(i);
if(selectNoLetter ^ (!Character
.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1))
{
wordEnd = i;
break;
}
}
int lineStart = getLineStartOffset(line);
select(lineStart + wordStart,lineStart + wordEnd);
/*
String lineText = getLineText(line);
String noWordSep = (String)document.getProperty("noWordSep");
int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
int wordEnd = TextUtilities.findWordEnd(lineText,offset,noWordSep);
int lineStart = getLineStartOffset(line);
select(lineStart + wordStart,lineStart + wordEnd);
*/
}
private void doTripleClick(MouseEvent evt, int line,
int offset, int dot)
{
select(getLineStartOffset(line),getLineEndOffset(line)-1);
}
}
class CaretUndo extends AbstractUndoableEdit
{
private int start;
private int end;
CaretUndo(int start, int end)
{
this.start = start;
this.end = end;
}
public boolean isSignificant()
{
return false;
}
public String getPresentationName()
{
return "caret move";
}
public void undo() throws CannotUndoException
{
super.undo();
select(start,end);
}
public void redo() throws CannotRedoException
{
super.redo();
select(start,end);
}
public boolean addEdit(UndoableEdit edit)
{
if(edit instanceof CaretUndo)
{
CaretUndo cedit = (CaretUndo)edit;
start = cedit.start;
end = cedit.end;
cedit.die();
return true;
}
else
return false;
}
}
static
{
caretTimer = new Timer(500,new CaretBlinker());
caretTimer.setInitialDelay(500);
caretTimer.start();
}
}
Code:
package SyntaxHighlighting;
/*
* InputHandler.java - Manages key bindings and executes actions
* Copyright (C) 1999 Slava Pestov
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
import javax.swing.text.*;
import javax.swing.JPopupMenu;
import java.awt.event.*;
import java.awt.Component;
import java.util.*;
/**
* An input handler converts the user's key strokes into concrete actions.
* It also takes care of macro recording and action repetition.<p>
*
* This class provides all the necessary support code for an input
* handler, but doesn't actually do any key binding logic. It is up
* to the implementations of this class to do so.
*
* @author Slava Pestov
* @version $Id: InputHandler.java,v 1.14 1999/12/13 03:40:30 sp Exp $
* @see org.gjt.sp.jedit.textarea.DefaultInputHandler
*/
public abstract class InputHandler extends KeyAdapter
{
/**
* If this client property is set to Boolean.TRUE on the text area,
* the home/end keys will support 'smart' BRIEF-like behaviour
* (one press = start/end of line, two presses = start/end of
* viewscreen, three presses = start/end of document). By default,
* this property is not set.
*/
public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
public static final ActionListener BACKSPACE = new backspace();
public static final ActionListener BACKSPACE_WORD = new backspace_word();
public static final ActionListener DELETE = new delete();
public static final ActionListener DELETE_WORD = new delete_word();
public static final ActionListener END = new end(false);
public static final ActionListener DOCUMENT_END = new document_end(false);
public static final ActionListener SELECT_END = new end(true);
public static final ActionListener SELECT_DOC_END = new document_end(true);
public static final ActionListener INSERT_BREAK = new insert_break();
public static final ActionListener INSERT_TAB = new insert_tab();
public static final ActionListener HOME = new home(false);
public static final ActionListener DOCUMENT_HOME = new document_home(false);
public static final ActionListener SELECT_HOME = new home(true);
public static final ActionListener SELECT_DOC_HOME = new document_home(true);
public static final ActionListener NEXT_CHAR = new next_char(false);
public static final ActionListener NEXT_LINE = new next_line(false);
public static final ActionListener NEXT_PAGE = new next_page(false);
public static final ActionListener NEXT_WORD = new next_word(false);
public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
public static final ActionListener OVERWRITE = new overwrite();
public static final ActionListener PREV_CHAR = new prev_char(false);
public static final ActionListener PREV_LINE = new prev_line(false);
public static final ActionListener PREV_PAGE = new prev_page(false);
public static final ActionListener PREV_WORD = new prev_word(false);
public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
public static final ActionListener REPEAT = new repeat();
public static final ActionListener TOGGLE_RECT = new toggle_rect();
// Default action
public static final ActionListener INSERT_CHAR = new insert_char();
private static Hashtable actions;
static
{
actions = new Hashtable();
actions.put("backspace",BACKSPACE);
actions.put("backspace-word",BACKSPACE_WORD);
actions.put("delete",DELETE);
actions.put("delete-word",DELETE_WORD);
actions.put("end",END);
actions.put("select-end",SELECT_END);
actions.put("document-end",DOCUMENT_END);
actions.put("select-doc-end",SELECT_DOC_END);
actions.put("insert-break",INSERT_BREAK);
actions.put("insert-tab",INSERT_TAB);
actions.put("home",HOME);
actions.put("select-home",SELECT_HOME);
actions.put("document-home",DOCUMENT_HOME);
actions.put("select-doc-home",SELECT_DOC_HOME);
actions.put("next-char",NEXT_CHAR);
actions.put("next-line",NEXT_LINE);
actions.put("next-page",NEXT_PAGE);
actions.put("next-word",NEXT_WORD);
actions.put("select-next-char",SELECT_NEXT_CHAR);
actions.put("select-next-line",SELECT_NEXT_LINE);
actions.put("select-next-page",SELECT_NEXT_PAGE);
actions.put("select-next-word",SELECT_NEXT_WORD);
actions.put("overwrite",OVERWRITE);
actions.put("prev-char",PREV_CHAR);
actions.put("prev-line",PREV_LINE);
actions.put("prev-page",PREV_PAGE);
actions.put("prev-word",PREV_WORD);
actions.put("select-prev-char",SELECT_PREV_CHAR);
actions.put("select-prev-line",SELECT_PREV_LINE);
actions.put("select-prev-page",SELECT_PREV_PAGE);
actions.put("select-prev-word",SELECT_PREV_WORD);
actions.put("repeat",REPEAT);
actions.put("toggle-rect",TOGGLE_RECT);
actions.put("insert-char",INSERT_CHAR);
}
/**
* Returns a named text area action.
* @param name The action name
*/
public static ActionListener getAction(String name)
{
return (ActionListener)actions.get(name);
}
/**
* Returns the name of the specified text area action.
* @param listener The action
*/
public static String getActionName(ActionListener listener)
{
Enumeration enumT = getActions();
while(enumT.hasMoreElements())
{
String name = (String)enumT.nextElement();
ActionListener _listener = getAction(name);
if(_listener == listener)
return name;
}
return null;
}
/**
* Returns an enumeration of all available actions.
*/
public static Enumeration getActions()
{
return actions.keys();
}
/**
* Adds the default key bindings to this input handler.
* This should not be called in the constructor of this
* input handler, because applications might load the
* key bindings from a file, etc.
*/
public abstract void addDefaultKeyBindings();
/**
* Adds a key binding to this input handler.
* @param keyBinding The key binding (the format of this is
* input-handler specific)
* @param action The action
*/
public abstract void addKeyBinding(String keyBinding, ActionListener action);
/**
* Removes a key binding from this input handler.
* @param keyBinding The key binding
*/
public abstract void removeKeyBinding(String keyBinding);
/**
* Removes all key bindings from this input handler.
*/
public abstract void removeAllKeyBindings();
/**
* Grabs the next key typed event and invokes the specified
* action with the key as a the action command.
* @param action The action
*/
public void grabNextKeyStroke(ActionListener listener)
{
grabAction = listener;
}
/**
* Returns if repeating is enabled. When repeating is enabled,
* actions will be executed multiple times. This is usually
* invoked with a special key stroke in the input handler.
*/
public boolean isRepeatEnabled()
{
return repeat;
}
/**
* Enables repeating. When repeating is enabled, actions will be
* executed multiple times. Once repeating is enabled, the input
* handler should read a number from the keyboard.
*/
public void setRepeatEnabled(boolean repeat)
{
this.repeat = repeat;
}
/**
* Returns the number of times the next action will be repeated.
*/
public int getRepeatCount()
{
return (repeat ? Math.max(1,repeatCount) : 1);
}
/**
* Sets the number of times the next action will be repeated.
* @param repeatCount The repeat count
*/
public void setRepeatCount(int repeatCount)
{
this.repeatCount = repeatCount;
}
/**
* Returns the macro recorder. If this is non-null, all executed
* actions should be forwarded to the recorder.
*/
public InputHandler.MacroRecorder getMacroRecorder()
{
return recorder;
}
/**
* Sets the macro recorder. If this is non-null, all executed
* actions should be forwarded to the recorder.
* @param recorder The macro recorder
*/
public void setMacroRecorder(InputHandler.MacroRecorder recorder)
{
this.recorder = recorder;
}
/**
* Returns a copy of this input handler that shares the same
* key bindings. Setting key bindings in the copy will also
* set them in the original.
*/
public abstract InputHandler copy();
/**
* Executes the specified action, repeating and recording it as
* necessary.
* @param listener The action listener
* @param source The event source
* @param actionCommand The action command
*/
public void executeAction(ActionListener listener, Object source,
String actionCommand)
{
// create event
ActionEvent evt = new ActionEvent(source,
ActionEvent.ACTION_PERFORMED,
actionCommand);
// don't do anything if the action is a wrapper
// (like EditAction.Wrapper)
if(listener instanceof Wrapper)
{
listener.actionPerformed(evt);
return;
}
// remember old values, in case action changes them
boolean _repeat = repeat;
int _repeatCount = getRepeatCount();
// execute the action
if(listener instanceof InputHandler.NonRepeatable)
listener.actionPerformed(evt);
else
{
for(int i = 0; i < Math.max(1,repeatCount); i++)
listener.actionPerformed(evt);
}
// do recording. Notice that we do no recording whatsoever
// for actions that grab keys
if(grabAction == null)
{
if(recorder != null)
{
if(!(listener instanceof InputHandler.NonRecordable))
{
if(_repeatCount != 1)
recorder.actionPerformed(REPEAT,String.valueOf(_repeatCount));
recorder.actionPerformed(listener,actionCommand);
}
}
// If repeat was true originally, clear it
// Otherwise it might have been set by the action, etc
if(_repeat)
{
repeat = false;
repeatCount = 0;
}
}
}
/**
* Returns the text area that fired the specified event.
* @param evt The event
*/
public static JEditTextArea getTextArea(EventObject evt)
{
if(evt != null)
{
Object o = evt.getSource();
if(o instanceof Component)
{
// find the parent text area
Component c = (Component)o;
for(;;)
{
if(c instanceof JEditTextArea)
return (JEditTextArea)c;
else if(c == null)
break;
if(c instanceof JPopupMenu)
c = ((JPopupMenu)c)
.getInvoker();
else
c = c.getParent();
}
}
}
// this shouldn't happen
System.err.println("BUG: getTextArea() returning null");
System.err.println("Report this to Slava Pestov <[email protected]>");
return null;
}
// protected members
/**
* If a key is being grabbed, this method should be called with
* the appropriate key event. It executes the grab action with
* the typed character as the parameter.
*/
protected void handleGrabAction(KeyEvent evt)
{
// Clear it *before* it is executed so that executeAction()
// resets the repeat count
ActionListener _grabAction = grabAction;
grabAction = null;
executeAction(_grabAction,evt.getSource(),
String.valueOf(evt.getKeyChar()));
}
// protected members
protected ActionListener grabAction;
protected boolean repeat;
protected int repeatCount;
protected InputHandler.MacroRecorder recorder;
/**
* If an action implements this interface, it should not be repeated.
* Instead, it will handle the repetition itself.
*/
public interface NonRepeatable {}
/**
* If an action implements this interface, it should not be recorded
* by the macro recorder. Instead, it will do its own recording.
*/
public interface NonRecordable {}
/**
* For use by EditAction.Wrapper only.
* @since jEdit 2.2final
*/
public interface Wrapper {}
/**
* Macro recorder.
*/
public interface MacroRecorder
{
void actionPerformed(ActionListener listener,
String actionCommand);
}
public static class backspace implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
if(!textArea.isEditable())
{
textArea.getToolkit().beep();
return;
}
if(textArea.getSelectionStart()
!= textArea.getSelectionEnd())
{
textArea.setSelectedText("");
}
else
{
int caret = textArea.getCaretPosition();
if(caret == 0)
{
textArea.getToolkit().beep();
return;
}
try
{
textArea.getDocument().remove(caret - 1,1);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
}
}
}
public static class backspace_word implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int start = textArea.getSelectionStart();
if(start != textArea.getSelectionEnd())
{
textArea.setSelectedText("");
}
int line = textArea.getCaretLine();
int lineStart = textArea.getLineStartOffset(line);
int caret = start - lineStart;
String lineText = textArea.getLineText(textArea
.getCaretLine());
if(caret == 0)
{
if(lineStart == 0)
{
textArea.getToolkit().beep();
return;
}
caret--;
}
else
{
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
}
try
{
textArea.getDocument().remove(
caret + lineStart,
start - (caret + lineStart));
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
}
}
public static class delete implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
if(!textArea.isEditable())
{
textArea.getToolkit().beep();
return;
}
if(textArea.getSelectionStart()
!= textArea.getSelectionEnd())
{
textArea.setSelectedText("");
}
else
{
int caret = textArea.getCaretPosition();
if(caret == textArea.getDocumentLength())
{
textArea.getToolkit().beep();
return;
}
try
{
textArea.getDocument().remove(caret,1);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
}
}
}
public static class delete_word implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int start = textArea.getSelectionStart();
if(start != textArea.getSelectionEnd())
{
textArea.setSelectedText("");
}
int line = textArea.getCaretLine();
int lineStart = textArea.getLineStartOffset(line);
int caret = start - lineStart;
String lineText = textArea.getLineText(textArea
.getCaretLine());
if(caret == lineText.length())
{
if(lineStart + caret == textArea.getDocumentLength())
{
textArea.getToolkit().beep();
return;
}
caret++;
}
else
{
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
}
try
{
textArea.getDocument().remove(start,
(caret + lineStart) - start);
}
catch(BadLocationException bl)
{
bl.printStackTrace();
}
}
}
public static class end implements ActionListener
{
private boolean select;
public end(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
int lastOfLine = textArea.getLineEndOffset(
textArea.getCaretLine()) - 1;
int lastVisibleLine = textArea.getFirstLine()
+ textArea.getVisibleLines();
if(lastVisibleLine >= textArea.getLineCount())
{
lastVisibleLine = Math.min(textArea.getLineCount() - 1,
lastVisibleLine);
}
else
lastVisibleLine -= (textArea.getElectricScroll() + 1);
int lastVisible = textArea.getLineEndOffset(lastVisibleLine) - 1;
int lastDocument = textArea.getDocumentLength();
if(caret == lastDocument)
{
textArea.getToolkit().beep();
return;
}
else if(!Boolean.TRUE.equals(textArea.getClientProperty(
SMART_HOME_END_PROPERTY)))
caret = lastOfLine;
else if(caret == lastVisible)
caret = lastDocument;
else if(caret == lastOfLine)
caret = lastVisible;
else
caret = lastOfLine;
if(select)
textArea.select(textArea.getMarkPosition(),caret);
else
textArea.setCaretPosition(caret);
}
}
public static class document_end implements ActionListener
{
private boolean select;
public document_end(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
if(select)
textArea.select(textArea.getMarkPosition(),
textArea.getDocumentLength());
else
textArea.setCaretPosition(textArea
.getDocumentLength());
}
}
public static class home implements ActionListener
{
private boolean select;
public home(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
int firstLine = textArea.getFirstLine();
int firstOfLine = textArea.getLineStartOffset(
textArea.getCaretLine());
int firstVisibleLine = (firstLine == 0 ? 0 :
firstLine + textArea.getElectricScroll());
int firstVisible = textArea.getLineStartOffset(
firstVisibleLine);
if(caret == 0)
{
textArea.getToolkit().beep();
return;
}
else if(!Boolean.TRUE.equals(textArea.getClientProperty(
SMART_HOME_END_PROPERTY)))
caret = firstOfLine;
else if(caret == firstVisible)
caret = 0;
else if(caret == firstOfLine)
caret = firstVisible;
else
caret = firstOfLine;
if(select)
textArea.select(textArea.getMarkPosition(),caret);
else
textArea.setCaretPosition(caret);
}
}
public static class document_home implements ActionListener
{
private boolean select;
public document_home(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
if(select)
textArea.select(textArea.getMarkPosition(),0);
else
textArea.setCaretPosition(0);
}
}
public static class insert_break implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
if(!textArea.isEditable())
{
textArea.getToolkit().beep();
return;
}
textArea.setSelectedText("\n");
}
}
public static class insert_tab implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
if(!textArea.isEditable())
{
textArea.getToolkit().beep();
return;
}
textArea.overwriteSetSelectedText("\t");
}
}
public static class next_char implements ActionListener
{
private boolean select;
public next_char(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
if(caret == textArea.getDocumentLength())
{
textArea.getToolkit().beep();
return;
}
if(select)
textArea.select(textArea.getMarkPosition(),
caret + 1);
else
textArea.setCaretPosition(caret + 1);
}
}
public static class next_line implements ActionListener
{
private boolean select;
public next_line(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
int line = textArea.getCaretLine();
if(line == textArea.getLineCount() - 1)
{
textArea.getToolkit().beep();
return;
}
int magic = textArea.getMagicCaretPosition();
if(magic == -1)
{
magic = textArea.offsetToX(line,
caret - textArea.getLineStartOffset(line));
}
caret = textArea.getLineStartOffset(line + 1)
+ textArea.xToOffset(line + 1,magic);
if(select)
textArea.select(textArea.getMarkPosition(),caret);
else
textArea.setCaretPosition(caret);
textArea.setMagicCaretPosition(magic);
}
}
public static class next_page implements ActionListener
{
private boolean select;
public next_page(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int lineCount = textArea.getLineCount();
int firstLine = textArea.getFirstLine();
int visibleLines = textArea.getVisibleLines();
int line = textArea.getCaretLine();
firstLine += visibleLines;
if(firstLine + visibleLines >= lineCount - 1)
firstLine = lineCount - visibleLines;
textArea.setFirstLine(firstLine);
int caret = textArea.getLineStartOffset(
Math.min(textArea.getLineCount() - 1,
line + visibleLines));
if(select)
textArea.select(textArea.getMarkPosition(),caret);
else
textArea.setCaretPosition(caret);
}
}
public static class next_word implements ActionListener
{
private boolean select;
public next_word(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
int line = textArea.getCaretLine();
int lineStart = textArea.getLineStartOffset(line);
caret -= lineStart;
String lineText = textArea.getLineText(textArea
.getCaretLine());
if(caret == lineText.length())
{
if(lineStart + caret == textArea.getDocumentLength())
{
textArea.getToolkit().beep();
return;
}
caret++;
}
else
{
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
}
if(select)
textArea.select(textArea.getMarkPosition(),
lineStart + caret);
else
textArea.setCaretPosition(lineStart + caret);
}
}
public static class overwrite implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
textArea.setOverwriteEnabled(
!textArea.isOverwriteEnabled());
}
}
public static class prev_char implements ActionListener
{
private boolean select;
public prev_char(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
if(caret == 0)
{
textArea.getToolkit().beep();
return;
}
if(select)
textArea.select(textArea.getMarkPosition(),
caret - 1);
else
textArea.setCaretPosition(caret - 1);
}
}
public static class prev_line implements ActionListener
{
private boolean select;
public prev_line(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
int line = textArea.getCaretLine();
if(line == 0)
{
textArea.getToolkit().beep();
return;
}
int magic = textArea.getMagicCaretPosition();
if(magic == -1)
{
magic = textArea.offsetToX(line,
caret - textArea.getLineStartOffset(line));
}
caret = textArea.getLineStartOffset(line - 1)
+ textArea.xToOffset(line - 1,magic);
if(select)
textArea.select(textArea.getMarkPosition(),caret);
else
textArea.setCaretPosition(caret);
textArea.setMagicCaretPosition(magic);
}
}
public static class prev_page implements ActionListener
{
private boolean select;
public prev_page(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int firstLine = textArea.getFirstLine();
int visibleLines = textArea.getVisibleLines();
int line = textArea.getCaretLine();
if(firstLine < visibleLines)
firstLine = visibleLines;
textArea.setFirstLine(firstLine - visibleLines);
int caret = textArea.getLineStartOffset(
Math.max(0,line - visibleLines));
if(select)
textArea.select(textArea.getMarkPosition(),caret);
else
textArea.setCaretPosition(caret);
}
}
public static class prev_word implements ActionListener
{
private boolean select;
public prev_word(boolean select)
{
this.select = select;
}
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
int line = textArea.getCaretLine();
int lineStart = textArea.getLineStartOffset(line);
caret -= lineStart;
String lineText = textArea.getLineText(textArea
.getCaretLine());
if(caret == 0)
{
if(lineStart == 0)
{
textArea.getToolkit().beep();
return;
}
caret--;
}
else
{
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
}
if(select)
textArea.select(textArea.getMarkPosition(),
lineStart + caret);
else
textArea.setCaretPosition(lineStart + caret);
}
}
public static class repeat implements ActionListener,
InputHandler.NonRecordable
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
textArea.getInputHandler().setRepeatEnabled(true);
String actionCommand = evt.getActionCommand();
if(actionCommand != null)
{
textArea.getInputHandler().setRepeatCount(
Integer.parseInt(actionCommand));
}
}
}
public static class toggle_rect implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
textArea.setSelectionRectangular(
!textArea.isSelectionRectangular());
}
}
public static class insert_char implements ActionListener,
InputHandler.NonRepeatable
{
public void actionPerformed(ActionEvent evt)
{
JEditTextArea textArea = getTextArea(evt);
String str = evt.getActionCommand();
int repeatCount = textArea.getInputHandler().getRepeatCount();
if(textArea.isEditable())
{
StringBuffer buf = new StringBuffer();
for(int i = 0; i < repeatCount; i++)
buf.append(str);
textArea.overwriteSetSelectedText(buf.toString());
}
else
{
textArea.getToolkit().beep();
}
}
}
}
It would be nice if someone would have any idea to help me
Edit: Ok problem solved ...
Last edited: