/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/textarea/JEditTextArea.java
Java | 2939 lines | 1745 code | 389 blank | 805 comment | 356 complexity | bf67965c8c844be000f5af3211356e62 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
Large files files are truncated, but you can click here to view the full file
/* * JEditTextArea.java - jEdit's text component * :tabSize=8:indentSize=8:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 1999, 2000, 2001 Slava Pestov * Portions copyright (C) 2000 Ollie Rutherfurd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.gjt.sp.jedit.textarea; //{{{ Imports import javax.swing.border.*; import javax.swing.event.*; import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.text.Segment; import javax.swing.undo.*; import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import org.gjt.sp.jedit.buffer.*; import org.gjt.sp.jedit.gui.*; import org.gjt.sp.jedit.syntax.*; import org.gjt.sp.jedit.*; import org.gjt.sp.util.Log; //}}} /** * jEdit's text component. * * @author Slava Pestov * @version $Id: JEditTextArea.java 3936 2001-12-21 07:02:14Z spestov $ */ public class JEditTextArea extends JComponent { //{{{ JEditTextArea constructor /** * Creates a new JEditTextArea. */ public JEditTextArea(View view) { enableEvents(AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK); this.view = view; //{{{ Initialize some misc. stuff selection = new Vector(); renderer = new TextRenderer(); painter = new TextAreaPainter(this); gutter = new Gutter(view,this); bufferHandler = new BufferChangeHandler(); listenerList = new EventListenerList(); caretEvent = new MutableCaretEvent(); bracketLine = bracketPosition = -1; blink = true; lineSegment = new Segment(); //}}} //{{{ Initialize the GUI setLayout(new ScrollLayout()); add(LEFT,gutter); add(CENTER,painter); add(RIGHT,vertical = new JScrollBar(JScrollBar.VERTICAL)); add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL)); horizontal.setValues(0,0,0,0); //}}} //{{{ this ensures that the text area's look is slightly // more consistent with the rest of the metal l&f. // while it depends on not-so-well-documented portions // of Swing, it only affects appearance, so future // breakage shouldn't matter if(UIManager.getLookAndFeel() instanceof MetalLookAndFeel) { setBorder(new TextAreaBorder()); vertical.putClientProperty("JScrollBar.isFreeStanding", Boolean.FALSE); horizontal.putClientProperty("JScrollBar.isFreeStanding", Boolean.FALSE); //horizontal.setBorder(null); } //}}} //{{{ Add some event listeners vertical.addAdjustmentListener(new AdjustHandler()); horizontal.addAdjustmentListener(new AdjustHandler()); painter.addComponentListener(new ComponentHandler()); mouseHandler = new MouseHandler(); painter.addMouseListener(mouseHandler); painter.addMouseMotionListener(mouseHandler); addFocusListener(new FocusHandler()); //}}} // This doesn't seem very correct, but it fixes a problem // when setting the initial caret position for a buffer // (eg, from the recent file list) focusedComponent = this; } //}}} //{{{ Getters and setters //{{{ getPainter() method /** * Returns the object responsible for painting this text area. */ public final TextAreaPainter getPainter() { return painter; } //}}} //{{{ getGutter() method /** * Returns the gutter to the left of the text area or null if the gutter * is disabled */ public final Gutter getGutter() { return gutter; } //}}} //{{{ getTextRenderer() method /** * Returns the text renderer instance. * @since jEdit 3.2pre6 */ public TextRenderer getTextRenderer() { return renderer; } //}}} //{{{ getFoldVisibilityManager() method /** * Returns the fold visibility manager used by this text area. * @since jEdit 4.0pre1 */ public FoldVisibilityManager getFoldVisibilityManager() { return foldVisibilityManager; } //}}} //{{{ isCaretBlinkEnabled() method /** * Returns true if the caret is blinking, false otherwise. */ public final boolean isCaretBlinkEnabled() { return caretBlinks; } //}}} //{{{ setCaretBlinkEnabled() method /** * 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; if(buffer != null) invalidateLine(caretLine); } //}}} //{{{ getElectricScroll() method /** * Returns the number of lines from the top and button of the * text area that are always visible. */ public final int getElectricScroll() { return electricScroll; } //}}} //{{{ setElectricScroll() method /** * 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; } //}}} //{{{ isMiddleMousePasteEnabled() method /** * Returns if clicking the middle mouse button pastes the most * recent selection (% register). */ public final boolean isMiddleMousePasteEnabled() { return middleMousePaste; } //}}} //{{{ setMiddleMousePasteEnabled() method /** * Sets if clicking the middle mouse button pastes the most * recent selection (% register). * @param middleMousePaste A boolean flag */ public final void setMiddleMousePasteEnabled(boolean middleMousePaste) { this.middleMousePaste = middleMousePaste; } //}}} //{{{ getBuffer() method /** * Returns the buffer this text area is editing. */ public final Buffer getBuffer() { return buffer; } //}}} //{{{ setBuffer() method /** * Sets the buffer this text area is editing. * @param buffer The buffer */ public void setBuffer(Buffer buffer) { if(this.buffer == buffer) return; try { bufferChanging = true; if(this.buffer != null) { this.buffer._releaseFoldVisibilityManager(foldVisibilityManager); this.buffer.removeBufferChangeListener(bufferHandler); } this.buffer = buffer; buffer.addBufferChangeListener(bufferHandler); bufferHandlerInstalled = true; foldVisibilityManager = buffer._getFoldVisibilityManager(this); setCaretPosition(0); // just in case, maybe not necessary?... physFirstLine = foldVisibilityManager.virtualToPhysical(0); painter.updateTabSize(); for(int i = 0; i < lineWidths.length; i++) { lineWidths[i] = 0; } updateScrollBars(); painter.repaint(); gutter.repaint(); } finally { bufferChanging = false; } } //}}} //{{{ isEditable() method /** * Returns true if this text area is editable, false otherwise. */ public final boolean isEditable() { return buffer.isEditable(); } //}}} //{{{ getRightClickPopup() method /** * Returns the right click popup menu. */ public final JPopupMenu getRightClickPopup() { return popup; } //}}} //{{{ setRightClickPopup() method /** * Sets the right click popup menu. * @param popup The popup */ public final void setRightClickPopup(JPopupMenu popup) { this.popup = popup; } //}}} //}}} //{{{ Scrolling //{{{ getFirstLine() method /** * Returns the line displayed at the text area's origin. This is * a virtual, not a physical, line number. */ public final int getFirstLine() { return firstLine; } //}}} //{{{ setFirstLine() method /** * Sets the line displayed at the text area's origin. This is * a virtual, not a physical, line number. */ public void setFirstLine(int firstLine) { if(firstLine == this.firstLine) return; _setFirstLine(firstLine); view.synchroScrollVertical(this,firstLine); } //}}} //{{{ _setFirstLine() method public void _setFirstLine(int firstLine) { firstLine = Math.max(0,firstLine); this.firstLine = firstLine; physFirstLine = virtualToPhysical(firstLine); maxHorizontalScrollWidth = 0; // hack so that if we scroll and the matching bracket // comes into view, it is highlighted // 3.2pre9 update: I am commenting this out once again because // I have changed the location of the repaintAndScroll() call // in the BufferChangeHandler, so this is called before the caret // position is updated, which can be potentially tricky. //if(bracketPosition == -1) // updateBracketHighlight(); if(this.firstLine != vertical.getValue()) updateScrollBars(); painter.repaint(); gutter.repaint(); fireScrollEvent(true); } //}}} //{{{ getVisibleLines() method /** * Returns the number of lines visible in this text area. */ public final int getVisibleLines() { return visibleLines; } //}}} //{{{ getHorizontalOffset() method /** * Returns the horizontal offset of drawn lines. */ public final int getHorizontalOffset() { return horizontalOffset; } //}}} //{{{ setHorizontalOffset() method /** * 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; _setHorizontalOffset(horizontalOffset); view.synchroScrollHorizontal(this,horizontalOffset); } //}}} //{{{ _setHorizontalOffset() method public void _setHorizontalOffset(int horizontalOffset) { this.horizontalOffset = horizontalOffset; if(horizontalOffset != horizontal.getValue()) updateScrollBars(); painter.repaint(); fireScrollEvent(false); } //}}} //{{{ setOrigin() method /** * @deprecated Use setFirstLine() and setHorizontalOffset() instead */ public boolean setOrigin(int firstLine, int horizontalOffset) { setFirstLine(firstLine); setHorizontalOffset(horizontalOffset); return true; } //}}} //{{{ updateScrollBars() method /** * Updates the state of the scroll bars. This should be called * if the number of lines in the buffer changes, or when the * size of the text are changes. */ public void updateScrollBars() { if(vertical != null && visibleLines != 0) { // don't display stuff past the end of the buffer if // we can help it int lineCount = getVirtualLineCount(); if(lineCount < firstLine + visibleLines) { // this will call updateScrollBars(), so // just return... int newFirstLine = Math.max(0,lineCount - visibleLines); if(newFirstLine != firstLine) { setFirstLine(newFirstLine); return; } } vertical.setValues(firstLine,visibleLines,0,lineCount); vertical.setUnitIncrement(2); vertical.setBlockIncrement(visibleLines); } int width = painter.getWidth(); if(horizontal != null && width != 0) { maxHorizontalScrollWidth = 0; painter.repaint(); horizontal.setUnitIncrement(painter.getFontMetrics() .charWidth('w')); horizontal.setBlockIncrement(width / 2); } } //}}} //{{{ scrollUpLine() method /** * Scrolls up by one line. * @since jEdit 2.7pre2 */ public void scrollUpLine() { if(firstLine > 0) setFirstLine(firstLine-1); else getToolkit().beep(); } //}}} //{{{ scrollUpPage() method /** * Scrolls up by one page. * @since jEdit 2.7pre2 */ public void scrollUpPage() { if(firstLine > 0) { int newFirstLine = firstLine - visibleLines; setFirstLine(newFirstLine); } else { getToolkit().beep(); } } //}}} //{{{ scrollDownLine() method /** * Scrolls down by one line. * @since jEdit 2.7pre2 */ public void scrollDownLine() { int numLines = getVirtualLineCount(); if(firstLine + visibleLines < numLines) setFirstLine(firstLine + 1); else getToolkit().beep(); } //}}} //{{{ scrollDownPage() method /** * Scrolls down by one page. * @since jEdit 2.7pre2 */ public void scrollDownPage() { int numLines = getVirtualLineCount(); if(firstLine + visibleLines < numLines) { int newFirstLine = firstLine + visibleLines; setFirstLine(newFirstLine + visibleLines < numLines ? newFirstLine : numLines - visibleLines); } else { getToolkit().beep(); } } //}}} //{{{ scrollToCaret() method /** * Ensures that the caret is visible by scrolling the text area if * necessary. * @param doElectricScroll If true, electric scrolling will be performed */ public void scrollToCaret(boolean doElectricScroll) { int offset = caret - getLineStartOffset(caretLine); int virtualCaretLine = physicalToVirtual(caretLine); // visibleLines == 0 before the component is realized // we can't do any proper scrolling then, so we have // this hack... if(visibleLines == 0) { setFirstLine(physicalToVirtual( Math.max(0,caretLine - electricScroll))); return; } int lineCount = getVirtualLineCount(); int electricScroll; if(doElectricScroll && visibleLines > this.electricScroll * 2) electricScroll = this.electricScroll; else electricScroll = 0; boolean changed = false; int _firstLine = (firstLine == 0 ? 0 : firstLine + electricScroll); int _lastLine = firstLine + visibleLines - electricScroll; if(virtualCaretLine > _firstLine && (virtualCaretLine < _lastLine || firstLine + visibleLines >= lineCount)) { // vertical scroll position is correct already } else if(_firstLine - virtualCaretLine > visibleLines || virtualCaretLine - _lastLine > visibleLines) { int startLine, endLine; Selection s = getSelectionAtOffset(caret); if(s == null) { startLine = endLine = virtualCaretLine; } else { startLine = physicalToVirtual(s.startLine); endLine = physicalToVirtual(s.endLine); } if(endLine - startLine <= visibleLines) firstLine = (startLine + endLine - visibleLines) / 2; else firstLine = physicalToVirtual(caretLine) - visibleLines / 2; firstLine = Math.min(firstLine,getVirtualLineCount() - visibleLines); firstLine = Math.max(firstLine,0); changed = true; } else if(virtualCaretLine < _firstLine) { firstLine = Math.max(0,virtualCaretLine - electricScroll); changed = true; } else if(virtualCaretLine >= _lastLine) { firstLine = (virtualCaretLine - visibleLines) + electricScroll + 1; if(firstLine >= getVirtualLineCount() - visibleLines) firstLine = getVirtualLineCount() - visibleLines; changed = true; } int x = offsetToX(caretLine,offset); int width = painter.getFontMetrics().charWidth('w'); if(x < 0) { horizontalOffset = Math.min(0,horizontalOffset - x + width + 5); changed = true; } else if(x >= painter.getWidth() - width - 5) { horizontalOffset = horizontalOffset + (painter.getWidth() - x) - width - 5; changed = true; } if(changed) { if(firstLine < 0) firstLine = 0; physFirstLine = virtualToPhysical(firstLine); updateScrollBars(); painter.repaint(); gutter.repaint(); view.synchroScrollVertical(this,firstLine); view.synchroScrollHorizontal(this,horizontalOffset); // fire events for both a horizontal and vertical scroll fireScrollEvent(true); fireScrollEvent(false); } } //}}} //{{{ addScrollListener() method /** * Adds a scroll listener to this text area. * @param listener The listener * @since jEdit 3.2pre2 */ public final void addScrollListener(ScrollListener listener) { listenerList.add(ScrollListener.class,listener); } //}}} //{{{ removeScrollListener() method /** * Removes a scroll listener from this text area. * @param listener The listener * @since jEdit 3.2pre2 */ public final void removeScrollListener(ScrollListener listener) { listenerList.remove(ScrollListener.class,listener); } //}}} //}}} //{{{ Offset conversion //{{{ lineToY() method /** * Converts a line index to a y co-ordinate. This must be a virtual, * not a physical, line number. * @param line The line */ public int lineToY(int line) { FontMetrics fm = painter.getFontMetrics(); return (line - firstLine) * fm.getHeight() - (fm.getLeading() + fm.getDescent()); } //}}} //{{{ yToLine() method /** * Converts a y co-ordinate to a virtual 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(getVirtualLineCount() - 1, y / height + firstLine)); } //}}} //{{{ offsetToX() method /** * Converts an offset in a line into an x co-ordinate. * @param line The line * @param offset The offset, from the start of the line */ public int offsetToX(int line, int offset) { Token tokens = buffer.markTokens(line).getFirstToken(); getLineText(line,lineSegment); char[] text = lineSegment.array; int off = lineSegment.offset; float x = (float)horizontalOffset; Toolkit toolkit = painter.getToolkit(); Font defaultFont = painter.getFont(); SyntaxStyle[] styles = painter.getStyles(); for(;;) { byte id = tokens.id; if(id == Token.END) return (int)x; Font font; if(id == Token.NULL) font = defaultFont; else font = styles[id].getFont(); int len = tokens.length; if(offset < len) { return (int)(x + renderer.charsWidth( text,off,offset,font,x,painter)); } else { x += renderer.charsWidth( text,off,len,font,x,painter); off += len; offset -= len; } tokens = tokens.next; } } //}}} //{{{ xToOffset() method /** * Converts an x co-ordinate to an offset within a line. * @param line The physical line index * @param x The x co-ordinate */ public int xToOffset(int line, int x) { return xToOffset(line,x,true); } //}}} //{{{ xToOffset() method /** * Converts an x co-ordinate to an offset within a line. * @param line The physical line index * @param x The x co-ordinate * @param round Round up to next letter if past the middle of a letter? * @since jEdit 3.2pre6 */ public int xToOffset(int line, int x, boolean round) { Token tokens = buffer.markTokens(line).getFirstToken(); getLineText(line,lineSegment); char[] text = lineSegment.array; int off = lineSegment.offset; Toolkit toolkit = painter.getToolkit(); Font defaultFont = painter.getFont(); SyntaxStyle[] styles = painter.getStyles(); float[] widthArray = new float[] { horizontalOffset }; for(;;) { byte id = tokens.id; if(id == Token.END) return lineSegment.count; Font font; if(id == Token.NULL) font = defaultFont; else font = styles[id].getFont(); int len = tokens.length; int offset = renderer.xToOffset(text,off,len,font,x, painter,round,widthArray); if(offset != -1) return offset - lineSegment.offset; off += len; tokens = tokens.next; } } //}}} //{{{ xyToOffset() method /** * 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) { return xyToOffset(x,y,true); } //}}} //{{{ xyToOffset() method /** * 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 * @param round Round up to next letter if past the middle of a letter? * @since jEdit 3.2pre6 */ public int xyToOffset(int x, int y, boolean round) { FontMetrics fm = painter.getFontMetrics(); int height = fm.getHeight(); int line = y / height + firstLine; if(line < 0) return 0; else if(line >= getVirtualLineCount()) { // WRONG!!! // return getBufferLength(); return getLineEndOffset(virtualToPhysical( getVirtualLineCount() - 1)) - 1; } else { line = virtualToPhysical(line); return getLineStartOffset(line) + xToOffset(line,x); } } //}}} //}}} //{{{ Painting //{{{ invalidateLine() method /** * Marks a line as needing a repaint. * @param line The physical line to invalidate */ public void invalidateLine(int line) { if(line < physFirstLine) return; int lineCount = buffer.getLineCount(); int virtualLineCount = foldVisibilityManager .getVirtualLineCount(); if(line >= lineCount) line = (line - lineCount) + virtualLineCount; else line = foldVisibilityManager.physicalToVirtual(line); if(line > firstLine + visibleLines + 1) return; FontMetrics fm = painter.getFontMetrics(); int y = lineToY(line) + fm.getDescent() + fm.getLeading(); painter.repaint(0,y,painter.getWidth(),fm.getHeight()); gutter.repaint(0,y,gutter.getWidth(),fm.getHeight()); } //}}} //{{{ invalidateLineRange() method /** * Marks a range of physical lines as needing a repaint. * @param firstLine The first line to invalidate * @param lastLine The last line to invalidate */ public void invalidateLineRange(int firstLine, int lastLine) { if(lastLine < firstLine) { int tmp = lastLine; lastLine = firstLine; firstLine = tmp; } if(lastLine < physFirstLine) return; int lineCount = buffer.getLineCount(); int virtualLineCount = foldVisibilityManager .getVirtualLineCount(); if(firstLine >= lineCount) firstLine = (firstLine - lineCount) + virtualLineCount; else firstLine = foldVisibilityManager.physicalToVirtual(firstLine); if(firstLine > firstLine + visibleLines + 1) return; if(lastLine >= lineCount) lastLine = (lastLine - lineCount) + virtualLineCount; else lastLine = foldVisibilityManager.physicalToVirtual(lastLine); invalidateVirtualLineRange(firstLine,lastLine); } //}}} //{{{ invalidateSelectedLines() method /** * Repaints the lines containing the selection. */ public void invalidateSelectedLines() { // to hide line highlight if selections are being added later on invalidateLine(caretLine); for(int i = 0; i < selection.size(); i++) { Selection s = (Selection)selection.elementAt(i); invalidateLineRange(s.startLine,s.endLine); } } //}}} //{{{ invalidateVirtualLineRange() method /** * Marks a range of virtual lines as needing a repaint. * @param firstLine The first line to invalidate * @param lastLine The last line to invalidate */ public void invalidateVirtualLineRange(int firstLine, int lastLine) { FontMetrics fm = painter.getFontMetrics(); int y = lineToY(firstLine) + fm.getDescent() + fm.getLeading(); int height = (lastLine - firstLine + 1) * fm.getHeight(); painter.repaint(0,y,painter.getWidth(),height); gutter.repaint(0,y,gutter.getWidth(),height); } //}}} //}}} //{{{ Convenience methods //{{{ physicalToVirtual() method /** * Converts a physical line number to a virtual line number. * @param line A physical line index * @since jEdit 4.0pre1 */ public int physicalToVirtual(int line) { return foldVisibilityManager.physicalToVirtual(line); } //}}} //{{{ virtualToPhysical() method /** * Converts a virtual line number to a physical line number. * @param line A virtual line index * @since jEdit 4.0pre1 */ public int virtualToPhysical(int line) { return foldVisibilityManager.virtualToPhysical(line); } //}}} //{{{ getBufferLength() method /** * Returns the length of the buffer. */ public final int getBufferLength() { return buffer.getLength(); } //}}} //{{{ getLineCount() method /** * Returns the number of physical lines in the buffer. */ public final int getLineCount() { return buffer.getLineCount(); } //}}} //{{{ getVirtualLineCount() method /** * Returns the number of virtual lines in the buffer. */ public final int getVirtualLineCount() { return foldVisibilityManager.getVirtualLineCount(); } //}}} //{{{ getLineOfOffset() method /** * Returns the line containing the specified offset. * @param offset The offset */ public final int getLineOfOffset(int offset) { return buffer.getLineOfOffset(offset); } //}}} //{{{ getLineStartOffset() method /** * 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) { return buffer.getLineStartOffset(line); } //}}} //{{{ getLineEndOffset() method /** * 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) { return buffer.getLineEndOffset(line); } //}}} //{{{ getLineLength() method /** * Returns the length of the specified line. * @param line The line */ public int getLineLength(int line) { return buffer.getLineLength(line); } //}}} //{{{ getText() method /** * Returns the specified substring of the buffer. * @param start The start offset * @param len The length of the substring * @return The substring */ public final String getText(int start, int len) { return buffer.getText(start,len); } //}}} //{{{ getText() method /** * Copies the specified substring of the buffer into a segment. * @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) { buffer.getText(start,len,segment); } //}}} //{{{ getLineText() method /** * 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) { return buffer.getLineText(lineIndex); } //}}} //{{{ getLineText() method /** * 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) { buffer.getLineText(lineIndex,segment); } //}}} //{{{ getText() method /** * Returns the entire text of this text area. */ public String getText() { return buffer.getText(0,buffer.getLength()); } //}}} //{{{ setText() method /** * Sets the entire text of this text area. */ public void setText(String text) { try { buffer.beginCompoundEdit(); buffer.remove(0,buffer.getLength()); buffer.insert(0,text); } finally { buffer.endCompoundEdit(); } } //}}} //}}} //{{{ Selection //{{{ selectAll() method /** * Selects all text in the buffer. */ public final void selectAll() { setSelection(new Selection.Range(0,buffer.getLength())); moveCaretPosition(buffer.getLength(),true); } //}}} //{{{ selectLine() method /** * Selects the current line. * @since jEdit 2.7pre2 */ public void selectLine() { int caretLine = getCaretLine(); int start = getLineStartOffset(caretLine); int end = getLineEndOffset(caretLine) - 1; Selection s = new Selection.Range(start,end); if(multi) addToSelection(s); else setSelection(s); moveCaretPosition(end); } //}}} //{{{ selectParagraph() method /** * Selects the paragraph at the caret position. * @since jEdit 2.7pre2 */ public void selectParagraph() { int caretLine = getCaretLine(); if(getLineLength(caretLine) == 0) { view.getToolkit().beep(); return; } int start = caretLine; int end = caretLine; while(start >= 0) { if(getLineLength(start) == 0) break; else start--; } while(end < getLineCount()) { if(getLineLength(end) == 0) break; else end++; } int selectionStart = getLineStartOffset(start + 1); int selectionEnd = getLineEndOffset(end - 1) - 1; Selection s = new Selection.Range(selectionStart,selectionEnd); if(multi) addToSelection(s); else setSelection(s); moveCaretPosition(selectionEnd); } //}}} //{{{ selectWord() method /** * Selects the word at the caret position. * @since jEdit 2.7pre2 */ public void selectWord() { int line = getCaretLine(); int lineStart = getLineStartOffset(line); int offset = getCaretPosition() - lineStart; if(getLineLength(line) == 0) return; String lineText = getLineText(line); String noWordSep = buffer.getStringProperty("noWordSep"); if(offset == getLineLength(line)) offset--; int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep); int wordEnd = TextUtilities.findWordEnd(lineText,offset+1,noWordSep); Selection s = new Selection.Range(lineStart + wordStart, lineStart + wordEnd); if(multi) addToSelection(s); else setSelection(s); moveCaretPosition(lineStart + wordEnd); } //}}} //{{{ selectToMatchingBracket() method /** * Selects from the bracket at the caret position to the corresponding * bracket. * @since jEdit 4.0pre2 */ public void selectToMatchingBracket() { int bracket = TextUtilities.findMatchingBracket(buffer,caretLine, Math.max(0,caret - buffer.getLineStartOffset(caretLine) - 1)); if(bracket != -1) { Selection s; if(bracket < caret) s = new Selection.Range(bracket + 1,caret - 1); else s = new Selection.Range(caret,bracket); if(multi) addToSelection(s); else setSelection(s); return; } } //}}} //{{{ selectBlock() method /** * Selects the code block surrounding the caret. * @since jEdit 2.7pre2 */ public void selectBlock() { String openBrackets = "([{"; String closeBrackets = ")]}"; Selection s = getSelectionAtOffset(caret); int start, end; if(s == null) start = end = caret; else { start = s.start; end = s.end; } String text = getText(0,buffer.getLength()); // Scan backwards, trying to find a bracket int count = 1; char openBracket = '\0'; char closeBracket = '\0'; // We can't do the backward scan if start == 0 if(start == 0) { view.getToolkit().beep(); return; } backward_scan: while(--start > 0) { char c = text.charAt(start); int index = openBrackets.indexOf(c); if(index != -1) { if(--count == 0) { openBracket = c; closeBracket = closeBrackets.charAt(index); break backward_scan; } } else if(closeBrackets.indexOf(c) != -1) count++; } // Reset count count = 1; // Scan forward, matching that bracket if(openBracket == '\0') { getToolkit().beep(); return; } else { forward_scan: do { char c = text.charAt(end); if(c == closeBracket) { if(--count == 0) { end++; break forward_scan; } } else if(c == openBracket) count++; } while(++end < buffer.getLength()); } s = new Selection.Range(start,end); if(multi) addToSelection(s); else setSelection(s); moveCaretPosition(end); } //}}} //{{{ invertSelection() method /** * Inverts the selection. * @since jEdit 4.0pre1 */ public final void invertSelection() { Selection[] newSelection = new Selection[selection.size() + 1]; int lastOffset = 0; for(int i = 0; i < selection.size(); i++) { Selection s = (Selection)selection.elementAt(i); newSelection[i] = new Selection.Range(lastOffset, s.getStart()); lastOffset = s.getEnd(); } newSelection[selection.size()] = new Selection.Range( lastOffset,buffer.getLength()); setSelection(newSelection); } //}}} //{{{ getSelectionCount() method /** * Returns the number of selections. This is primarily for use by the * the status bar. * @since jEdit 3.2pre2 */ public int getSelectionCount() { return selection.size(); } //}}} //{{{ getSelection() method /** * Returns the current selection. * @since jEdit 3.2pre1 */ public Selection[] getSelection() { Selection[] sel = new Selection[selection.size()]; selection.copyInto(sel); return sel; } //}}} //{{{ selectNone() method /** * Deselects everything. */ public void selectNone() { setSelection((Selection)null); } //}}} //{{{ setSelection() method /** * Sets the selection. * @param selection The new selection * since jEdit 3.2pre1 */ public void setSelection(Selection[] selection) { // invalidate the old selection invalidateSelectedLines(); this.selection.removeAllElements(); if(selection != null) { for(int i = 0; i < selection.length; i++) _addToSelection(selection[i]); } fireCaretEvent(); } //}}} //{{{ setSelection() method /** * Sets the selection. * @param selection The new selection * since jEdit 3.2pre1 */ public void setSelection(Selection selection) { invalidateSelectedLines(); this.selection.removeAllElements(); if(selection != null) _addToSelection(selection); fireCaretEvent(); } //}}} //{{{ addToSelection() method /** * Adds to the selection. * @param selection The new selection * since jEdit 3.2pre1 */ public void addToSelection(Selection[] selection) { if(selection != null) { for(int i = 0; i < selection.length; i++) _addToSelection(selection[i]); } // to hide current line highlight invalidateLine(caretLine); fireCaretEvent(); } //}}} //{{{ addToSelection() method /** * Adds to the selection. * @param selection The new selection * since jEdit 3.2pre1 */ public void addToSelection(Selection selection) { _addToSelection(selection); // to hide current line highlight invalidateLine(caretLine); fireCaretEvent(); } //}}} //{{{ getSelectionAtOffset() method /** * Returns the selection containing the specific offset, or null * if there is no selection at that offset. * @param offset The offset * @since jEdit 3.2pre1 */ public Selection getSelectionAtOffset(int offset) { if(selection != null) { for(int i = 0; i < selection.size(); i++) { Selection s = (Selection)selection.elementAt(i); if(offset >= s.start && offset <= s.end) return s; } } return null; } //}}} //{{{ removeFromSelection() method /** * Deactivates the specified selection. * @param s The selection * @since jEdit 3.2pre1 */ public void removeFromSelection(Selection sel) { selection.removeElement(sel); invalidateLineRange(sel.startLine,sel.endLine); // to hide current line highlight invalidateLine(caretLine); fireCaretEvent(); } //}}} //{{{ removeFromSelection() method /** * Deactivates the selection at the specified offset. If there is * no selection at that offset, does nothing. * @param offset The offset * @since jEdit 3.2pre1 */ public void removeFromSelection(int offset) { Selection sel = getSelectionAtOffset(offset); if(sel == null) return; selection.removeElement(sel); invalidateLineRange(sel.startLine,sel.endLine); // to hide current line highlight invalidateLine(caretLine); fireCaretEvent(); } //}}} //{{{ resizeSelection() method /** * Resizes the selection at the specified offset, or creates a new * one if there is no selection at the specified offset. This is a * utility method that is mainly useful in the mouse event handler * because it handles the case of end being before offset gracefully * (unlike the rest of the selection API). * @param offset The offset * @param end The new selection end * @param rect Make the selection rectangular? * @since jEdit 3.2pre1 */ public void resizeSelection(int offset, int end, boolean rect) { Selection s = getSelectionAtOffset(offset); if(s != null) { invalidateLineRange(s.startLine,s.endLine); selection.removeElement(s); } if(end < offset) { int tmp = offset; offset = end; end = tmp; } Selection newSel; if(rect) newSel = new Selection.Rect(offset,end); else newSel = new Selection.Range(offset,end); _addToSelection(newSel); fireCaretEvent(); } //}}} //{{{ extendSelection() method /** * Extends the selection at the specified offset, or creates a new * one if there is no selection at the specified offset. This is * different from resizing in that the new chunk is added to the * selection in question, instead of replacing it. * @param offset The offset * @param end The new selection end * @param rect Make the selection rectangular? * @since jEdit 3.2pre1 */ public void extendSelection(int offset, int end) { Selection s = getSelectionAtOffset(offset); if(s != null) { invalidateLineRange(s.startLine,s.endLine); selection.removeElement(s); if(offset == s.start) { offset = end; end = s.end; } else if(offset == s.end) { offset = s.start; } } if(end < offset) { int tmp = end; end = offset; offset = tmp; } _addToSelection(new Selection.Range(offset,end)); fireCaretEvent(); } //}}} //{{{ getSelectedText() method /** * Returns the text in the specified selection. * @param s The selection * @since jEdit 3.2pre1 */ public String getSelectedText(Selection s) { StringBuffer buf = new StringBuffer(); getSelectedText(s,buf); return buf.toString(); } //}}} //{{{ getSelectedText() method /** * Returns the text in all active selections. * @param separator The string to insert between each text chunk * (for example, a newline) * @since jEdit 3.2pre1 */ public String getSelectedText(String separator) { if(selection.size() == 0) return null; StringBuffer buf = new StringBuffer(); for(int i = 0; i < selection.size(); i++) { if(i != 0) buf.append(separator); getSelectedText((Selection)selection.elementAt(i),buf); } return buf.toString(); } //}}} //{{{ getSelectedText() method /** * Returns the text in all active selections, with a newline * between each text chunk. */ public String getSelectedText() { return getSelectedText("\n"); } //}}} //{{{ setSelectedText() method /** * Replaces the selection with the specified text. * @param s The selection * @param selectedText The new text * @since jEdit 3.2pre1 */ public void setSelectedText(Selection s, String selectedText) { if(!isEditable()) { throw new InternalError("Text component" + " read only"); } try { buffer.beginCompoundEdit(); if(s instanceof Selection.Rect) { int start = s.start - getLineStartOffset(s.startLine); int end = s.end - getLineStartOffset(s.endLine); // Certain rectangles satisfy this condition... if(end < start) { int tmp = end; end = start; start = tmp; } int lastNewline = 0; int currNewline = 0; for(int i = s.startLine; i <= s.endLine; i++) { int lineStart = getLineStartOffset(i); int lineEnd = getLineEndOffset(i) - 1; int rectStart = Math.min(lineEnd,lineStart + start); buffer.remove(rectStart,Math.min(lineEnd - rectStart, end - start)); if(selectedText == null) continue; currNewline = selectedText.indexOf('\n',lastNewline); if(currNewline == -1) currNewline = selectedText.length(); buffer.insert(rectStart,selectedText .substring(lastNewline,currNewline)); lastNewline = Math.min(selectedText.length(), currNewline + 1); } if(selectedText != null && currNewline != selectedText.length()) { int offset = getLineEndOffset(s.endLine) - 1; buffer.insert(offset,"\n"); buffer.insert(offset + 1,selectedText .substring(currNewline + 1)); } } else { buffer.remove(s.start,s.end - s.start); if(selectedText != null && selectedText.length() != 0) { buffer.insert(s.start,selectedText); } } } // No matter what happends... stops us from leaving buffer // in a bad state finally { buffer.endCompoundEdit(); } // no no no!!!! //selectNone(); } //}}} //{{{ setSelectedText() method /** * Replaces the selection at the caret with the specified text. * If there is no selection at the caret, the text is inserted at * the caret position. */ public void setSelectedText(String selectedText) { if(!isEditable()) { throw new InternalError("Text component" + " read only"); } Selection[] selection = getSelection(); if(selection.length == 0) { // for compatibility with older jEdit versions buffer.insert(caret,selectedText); } else { try { buffer.beginCompoundEdit(); for(int i = 0; i < selection.length; i++) { setSelectedText(selection[i],selectedText); } } finally { buffer.endCompoundEdit(); } } selectNone(); } //}}} //{{{ getSelectedLines() method /** * Returns an array of all line numbers that contain a selection. * This array will also include the line number containing the * caret, for convinience. * @since jEdit 3.2pre1 */ public int[] getSelectedLines() { if(selection.size() == 0) return new int[] { caretLine }; Integer line; Hashtable hash = new Hashtable(); for(int i = 0; i < selection.size(); i++) { Selection s = (Selection)selection.elementAt(i); int endLine = (s.end == getLineStartOffset(s.endLine) ? s.endLine - 1 : s.endLine); for(int j = s.startLine; j <= endLine; j++) { line = new Integer(j); hash.put(line,line); } } int[] returnValue = new int[hash.size()]; int i = 0; Enumeration keys = hash.keys(); while(keys.hasMoreElements()) { line = (Integer)keys.nextElement(); returnValue[i++] = line.intValue(); } quicksort(returnValue,0,returnValue.length - 1); return returnValue; } //}}} //{{{ showSelectLineRangeDialog() method /** * Displays the 'select line range' dialog box, and selects the * specified range of lines. * @since jEdit 2.7pre2 */ public void showSelectLineRangeDialog() { new SelectLineRange(view); } //}}} //}}} //{{{ Old selection API //{{{ getSelectionStart() method /** * @deprecated Instead, obtain a Selection instance using * any means, and call its <code>getStart()</code> method */ public final int getSelectionStart() { if(selection.size() != 1) return caret; return ((Selection)selection.elementAt(0)).getStart(); } //}}} //{{{ getSelectionStart() method /** * @deprecated Instead, obtain a Selection instance using * any means, and call its <code>getStart(int)</code> method */ public int getSelectionStart(int line) { if(selection.size() != 1) return caret; return ((Selection)selection.elementAt(0)).getStart( buffer,line); } //}}} //{{{ getSelectionStartLine() method /** * @deprecated Instead, obtain a Selection instance using * any means, and call its <code>getStartLine()</code> method */ public final int getSelectionStartLine() { if(selection.size() != 1) return caret; return ((Selection)selection.elementAt(0)).getStartLine(); } //}}} //{{{ setSelectionStart() method /** * @deprecated Do not use. */ public final void setSelectionStart(int selectionStart) { select(selectionStart,getSelectionEnd(),true); } //}}} //{{{ getSelectionEnd() method /** * @deprecated Instead, obtain a Selection instance using * any means, and call its <code>getEnd()</code> method */ public final int getSelectionEnd() { if(selection.size() != 1) return caret; return ((Selection)selection.elementAt(0)).getEnd(); } //}}} //{{{ getSelectionEnd() method /** * @deprecated Instead, obtain a Selection instance using * any means, and call its <code>getEnd(int)</code> method */ public int getSelectionEnd(int line) { if(selection.size() != 1) return caret; return ((Selection)selection.elementAt(0)).getEnd( buffer,line); } //}}} //{{{ getSelectionEndLine() method /** * @deprecated Instead, obtain a Selection instance using * any means, and call its <code>getEndLine()</code> method */ public final int getSelectionEndLine() { if(selection.size() != 1) return caret; return ((Selection)selection.elementAt(0)).getEndLine(); } //}}} //{{{ setSelectionEnd() method /** * @deprecated Do not use. */ public final void setSelectionEnd(int selectionEnd) { select(getSelectionStart(),selectionEnd,true); } //}}} //{{{ getMarkPosition() method /** * @deprecated Do not use. */ public final int getMarkPosition() { Selection s = getSelectionAtOffset(caret); if(s == null) return caret; if(s.start == caret) return s.end; else if(s.end == caret) return s.start; else return caret; } //}}} //{{{ getMarkLine() method /** * @deprecated Do not use. */ public final int getMarkLine() { if(selection.size() != 1) return caretLine; Selection s = (Selection)selection.elementAt(0); if(s.start == caret) return s.endLine; else if(s.end == caret) return s.startLine; else return caretLine; } //}}} //{{{ select() method /** * @deprecated Instead, call either <code>addToSelection()</code>, * or <code>setSelection()</code> with a new Selection instance. */ public void select(int start, int end) { select(start,end,true); } //}}} //{{{ select() method /** * @deprecated Instead, call either <code>addToSelection()</code>, * or <code>setSelection()</code> with a new Selection instance. */ public void select(int start, int end, boolean doElectricScroll) { selectNone(); int newStart, newEnd; if(start < end) { newStart = start; newEnd = end; } else { newStart = end; newEnd = start; } setSelection(new Selection.Range(newStart,newEnd)); moveCaretPosition(end,doElectricScroll); } //}}} //{{{ isSelectionRectangular() method /** * @deprecated Instead, check if the appropriate Selection * is an instance of the Selection.Rect class. */ public boolean isSelectionRectangular() { Selection s = getSelectionAtOffset(caret); if(s == null) return false; else return (s instanceof Selection.Rect); } //}}} //}}} //{{{ Caret //{{{ blinkCaret() method /** * Blinks the caret. */ public final void blinkCaret() { if(caretBlinks) { blink = !blink; invalidateLine(caretLine); } else blink = true; } //}}} //{{{ centerCaret() method /** * Centers the caret on the screen. * @since jEdit 2.7pre2 */ public void centerCaret() { int gotoLine = virtualToPhysical(firstLine + visibleLines / 2); if(gotoLine < 0 || gotoLine >= getLineCount()) { getToolkit().beep(); return; } setCaretPosition(getLineStartOffset(gotoLine)); } //}}} //{{{ setCaretPosition() method /** * Sets the caret position and deactivates the selection. * @param caret The caret position */ public void setCaretPosition(int newCaret) { invalidateSelectedLines(); selection.removeAllElements(); moveCaretPosition(newCaret,true); } //}}} //{{{ setCaretPosition() method /** * Sets the caret position and deactivates the selection. * @param caret The caret position * @param doElectricScroll Do electric scrolling? */ public void setCaretPosition(int newCaret, boolean doElectricScroll) { invalidateSelectedLines(); selection.removeAllElements(); moveCaretPosition(newCaret,doElectricScroll); } //}}} //{{{ moveCaretPosition() method /** * Sets the caret position without deactivating the selection. * @param caret The caret position */ public void moveCaretPosition(int newCaret) { moveCaretPosition(newCaret,true); } //}}} //{{{ moveCaretPosition() method /** * Sets the caret position without deactivating the selection. * @param caret The caret position * @param doElectricScroll Do electric scrolling? */ public void moveCaretPosition(int newCaret, boolean doElectricScroll) { if(newCaret < 0 || newCaret > buffer.getLength()) { throw new IllegalArgumentException("caret out of bounds: " + newCaret); } // When the user is typing, etc, we don't want the caret // to blink blink = true; caretTimer.restart(); if(caret == newCaret) { // so that C+y <marker>, for example, will return // to the saved location even if the caret was // never moved but the user scrolled instead scrollToCaret(doElectricScroll); return; } int newCaretLine = getLineOfOffset(newCaret); magicCaret = -1; if(!foldVisibilityManager.isLineVisible(newCaretLine)) { if(foldVisibilityManager.isNarrowed()) { int collapseFolds = buffer.getIntegerProperty( "collapseFolds",0); if(collapseFolds != 0) foldVisibilityManager.expandFolds(collapseFolds); else foldVisibilityManager.expandAllFolds(); } else foldVisibilityManager.expandFold(newCaretLine,false); } invalidateLineRange(caretLine,newCaretLine); caret = newCaret; caretLine = newCaretLine; if(focusedComponent == this) scrollToCaret(doElectricScroll); updateBracketHighlight(); fireCaretEvent(); } //}}} //{{{ getCaretPosition() method /** * Returns the caret position. */ public int getCaretPosition() { return caret; } //}}} //{{{ getCaretLine() method /** * Returns the line number containing the caret. */ public int getCaretLine() { return caretLine; } //}}} //{{{ getMagicCaretPosition() method /** * Returns the `magic' caret position. This can be used to preserve * the column position when moving up and down lines. */ public final int getMagicCaretPosition() { if(magicCaret == -1) { magicCaret = offsetToX(caretLine,caret - getLineStartOffset(caretLine)); } return magicCaret; } //}}} //{{{ setMagicCaretPosition() method /** * 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(in…
Large files files are truncated, but you can click here to view the full file