0001: /*
0002: * TextArea.java - Handles services.xml files in plugins
0003: * :tabSize=8:indentSize=8:noTabs=false:
0004: * :folding=explicit:collapseFolds=1:
0005: *
0006: * Copyright (C) 1999, 2005 Slava Pestov
0007: * Portions copyright (C) 2000 Ollie Rutherfurd
0008: * Portions copyright (C) 2006 Matthieu Casanova
0009: *
0010: * This program is free software; you can redistribute it and/or
0011: * modify it under the terms of the GNU General Public License
0012: * as published by the Free Software Foundation; either version 2
0013: * of the License, or any later version.
0014: *
0015: * This program is distributed in the hope that it will be useful,
0016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0018: * GNU General Public License for more details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with this program; if not, write to the Free Software
0022: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0023: */
0024: package org.gjt.sp.jedit.textarea;
0025:
0026: //{{{ Imports
0027: import org.gjt.sp.jedit.Debug;
0028: import org.gjt.sp.jedit.Mode;
0029: import org.gjt.sp.jedit.TextUtilities;
0030: import org.gjt.sp.jedit.buffer.*;
0031: import org.gjt.sp.jedit.input.AbstractInputHandler;
0032: import org.gjt.sp.jedit.input.DefaultInputHandlerProvider;
0033: import org.gjt.sp.jedit.input.InputHandlerProvider;
0034: import org.gjt.sp.jedit.input.TextAreaInputHandler;
0035: import org.gjt.sp.jedit.syntax.*;
0036: import org.gjt.sp.util.Log;
0037: import org.gjt.sp.util.StandardUtilities;
0038:
0039: import javax.swing.*;
0040: import javax.swing.event.CaretEvent;
0041: import javax.swing.event.CaretListener;
0042: import javax.swing.event.EventListenerList;
0043: import javax.swing.event.MouseInputAdapter;
0044: import javax.swing.plaf.metal.MetalLookAndFeel;
0045: import javax.swing.text.Segment;
0046: import java.awt.*;
0047: import java.awt.event.*;
0048: import java.awt.im.InputMethodRequests;
0049: import java.util.Iterator;
0050: import java.util.LinkedList;
0051: import java.util.TooManyListenersException;
0052:
0053: //}}}
0054:
0055: /**
0056: * jEdit's text component.<p>
0057: *
0058: * Unlike most other text editors, the selection API permits selection and
0059: * concurrent manipulation of multiple, non-contiguous regions of text.
0060: * Methods in this class that deal with selecting text rely upon classes derived
0061: * the {@link Selection} class.
0062: *
0063: * @author Slava Pestov
0064: * @author John Gellene (API documentation)
0065: * @version $Id: JEditTextArea.java 7148 2006-09-29 23:09:06 +0200 (ven., 29 sept. 2006) kpouer $
0066: */
0067: public class TextArea extends JComponent {
0068: //{{{ TextArea constructor
0069: public TextArea() {
0070: this (false);
0071: } //}}}
0072:
0073: //{{{ TextArea constructor
0074: /**
0075: * Instantiate a TextArea.
0076: * @param insideJEdit must be set to true if the textarea is embedded in jEdit
0077: */
0078: public TextArea(boolean insideJEdit) {
0079: this (null);
0080: inputHandlerProvider = new DefaultInputHandlerProvider(
0081: new TextAreaInputHandler(this ));
0082: setMouseHandler(new TextAreaMouseHandler(this ));
0083: if (insideJEdit) {
0084: return;
0085: }
0086:
0087: Font font1 = new Font("Monospaced", Font.PLAIN, 12);
0088: painter.setFont(font1);
0089: SyntaxStyle[] styles = new SyntaxStyle[1];
0090: styles[0] = new SyntaxStyle(Color.black, Color.white, font1);
0091: painter.setStyles(styles);
0092: painter.setBlockCaretEnabled(false);
0093:
0094: painter.setStructureHighlightEnabled(true);
0095: painter.setStructureHighlightColor(Color.black);
0096: painter.setEOLMarkersPainted(false);
0097: painter.setEOLMarkerColor(new Color(255, 102, 51));
0098: painter.setWrapGuidePainted(true);
0099: painter.setWrapGuideColor(new Color(125, 125, 255));
0100: painter.setCaretColor(Color.red);
0101: painter.setSelectionColor(new Color(204, 204, 255));
0102: painter.setMultipleSelectionColor(new Color(204, 255, 204));
0103: painter.setBackground(Color.white);
0104: painter.setForeground(Color.black);
0105: painter.setBlockCaretEnabled(false);
0106: painter.setLineHighlightEnabled(true);
0107: painter.setLineHighlightColor(new Color(255, 204, 255));
0108: painter.setAntiAlias(new AntiAlias(0));
0109: painter.setFractionalFontMetricsEnabled(false);
0110:
0111: gutter.setExpanded(false);
0112: gutter.setHighlightInterval(5);
0113: gutter.setCurrentLineHighlightEnabled(true);
0114: gutter.setStructureHighlightEnabled(true);
0115: gutter.setStructureHighlightColor(new Color(102, 102, 153));
0116: gutter.setBackground(new Color(219, 219, 219));
0117: gutter.setForeground(Color.black);
0118: gutter.setHighlightedForeground(new Color(153, 0, 102));
0119: gutter.setFoldColor(new Color(131, 131, 131));
0120: gutter.setCurrentLineForeground(new Color(255, 0, 51));
0121: gutter.setLineNumberAlignment(Gutter.RIGHT);
0122: gutter.setFont(new Font("Monospaced", Font.PLAIN, 10));
0123: gutter.setBorder(3, new Color(153, 0, 153), Color.white,
0124: painter.getBackground());
0125:
0126: setCaretBlinkEnabled(true);
0127: setElectricScroll(3);
0128:
0129: FoldHandler.foldHandlerProvider = new DefaultFoldHandlerProvider();
0130: JEditBuffer buffer = new JEditBuffer();
0131: TokenMarker tokenMarker = new TokenMarker();
0132: tokenMarker.addRuleSet(new ParserRuleSet("text", "MAIN"));
0133: buffer.setTokenMarker(tokenMarker);
0134: setBuffer(buffer);
0135: Mode mode = new Mode("text");
0136: mode.setTokenMarker(tokenMarker);
0137: ModeProvider.instance.addMode(mode);
0138: KillRing.setInstance(new KillRing());
0139: KillRing.getInstance().propertiesChanged(100);
0140: } //}}}
0141:
0142: //{{{ TextArea constructor
0143: /**
0144: * Creates a new JEditTextArea.
0145: */
0146: public TextArea(InputHandlerProvider inputHandlerProvider) {
0147: this .inputHandlerProvider = inputHandlerProvider;
0148: enableEvents(AWTEvent.FOCUS_EVENT_MASK
0149: | AWTEvent.KEY_EVENT_MASK);
0150:
0151: //{{{ Initialize some misc. stuff
0152: selectionManager = new SelectionManager(this );
0153: chunkCache = new ChunkCache(this );
0154: painter = new TextAreaPainter(this );
0155: repaintMgr = new FastRepaintManager(this , painter);
0156: gutter = new Gutter(this );
0157: gutter.setMouseActionsProvider(new MouseActions("gutter"));
0158: listenerList = new EventListenerList();
0159: caretEvent = new MutableCaretEvent();
0160: blink = true;
0161: offsetXY = new Point();
0162: structureMatchers = new LinkedList<StructureMatcher>();
0163: structureMatchers.add(new StructureMatcher.BracketMatcher());
0164: //}}}
0165:
0166: //{{{ Initialize the GUI
0167: setLayout(new ScrollLayout());
0168: add(ScrollLayout.CENTER, painter);
0169: add(ScrollLayout.LEFT, gutter);
0170:
0171: // some plugins add stuff in a "right-hand" gutter
0172: verticalBox = new Box(BoxLayout.X_AXIS);
0173: verticalBox.add(vertical = new JScrollBar(Adjustable.VERTICAL));
0174: vertical.setRequestFocusEnabled(false);
0175: add(ScrollLayout.RIGHT, verticalBox);
0176: add(ScrollLayout.BOTTOM, horizontal = new JScrollBar(
0177: Adjustable.HORIZONTAL));
0178: horizontal.setRequestFocusEnabled(false);
0179:
0180: horizontal.setValues(0, 0, 0, 0);
0181: //}}}
0182:
0183: //{{{ this ensures that the text area's look is slightly
0184: // more consistent with the rest of the metal l&f.
0185: // while it depends on not-so-well-documented portions
0186: // of Swing, it only affects appearance, so future
0187: // breakage shouldn't matter
0188: if (UIManager.getLookAndFeel() instanceof MetalLookAndFeel) {
0189: setBorder(new TextAreaBorder());
0190: vertical.putClientProperty("JScrollBar.isFreeStanding",
0191: Boolean.FALSE);
0192: horizontal.putClientProperty("JScrollBar.isFreeStanding",
0193: Boolean.FALSE);
0194: //horizontal.setBorder(null);
0195: }
0196: //}}}
0197:
0198: //{{{ Add some event listeners
0199: vertical.addAdjustmentListener(new AdjustHandler());
0200: horizontal.addAdjustmentListener(new AdjustHandler());
0201:
0202: addFocusListener(new FocusHandler());
0203: addMouseWheelListener(new MouseWheelHandler());
0204:
0205: //}}}
0206:
0207: // This doesn't seem very correct, but it fixes a problem
0208: // when setting the initial caret position for a buffer
0209: // (eg, from the recent file list)
0210: focusedComponent = this ;
0211:
0212: } //}}}
0213:
0214: //{{{ setMouseHandler() method
0215: public void setMouseHandler(MouseInputAdapter mouseInputAdapter) {
0216: mouseHandler = mouseInputAdapter;
0217: painter.addMouseListener(mouseHandler);
0218: painter.addMouseMotionListener(mouseHandler);
0219: } //}}}
0220:
0221: //{{{ setTransferHandler() method
0222: public void setTransferHandler(TransferHandler newHandler) {
0223: super .setTransferHandler(newHandler);
0224: try {
0225: getDropTarget().addDropTargetListener(
0226: new TextAreaDropHandler(this ));
0227: } catch (TooManyListenersException e) {
0228: Log.log(Log.ERROR, this , e);
0229: }
0230: } //}}}
0231:
0232: //{{{ toString() method
0233: public String toString() {
0234: StringBuilder builder = new StringBuilder();
0235: builder.append("caret: ").append(caret).append('\n');
0236: builder.append("caretLine: ").append(caretLine).append('\n');
0237: builder.append("caretScreenLine: ").append(caretScreenLine)
0238: .append('\n');
0239: builder.append("electricScroll: ").append(electricScroll)
0240: .append('\n');
0241: builder.append("horizontalOffset: ").append(horizontalOffset)
0242: .append('\n');
0243: builder.append("magicCaret: ").append(magicCaret).append('\n');
0244: builder.append("offsetXY").append(offsetXY.toString()).append(
0245: '\n');
0246: builder.append("oldCaretLine: ").append(oldCaretLine).append(
0247: '\n');
0248: builder.append("screenLastLine: ").append(screenLastLine)
0249: .append('\n');
0250: builder.append("visibleLines: ").append(visibleLines).append(
0251: '\n');
0252: builder.append("firstPhysicalLine: ").append(
0253: getFirstPhysicalLine()).append('\n');
0254: builder.append("physLastLine: ").append(physLastLine).append(
0255: '\n');
0256: return builder.toString();
0257: } //}}}
0258:
0259: //{{{ dispose() method
0260: /**
0261: * Plugins and macros should not call this method.
0262: * @since jEdit 4.2pre1
0263: */
0264: public void dispose() {
0265: DisplayManager.textAreaDisposed(this );
0266: } //}}}
0267:
0268: //{{{ getInputHandler() method
0269: /**
0270: * @since jEdit 4.3pre1
0271: */
0272: public AbstractInputHandler getInputHandler() {
0273: return inputHandlerProvider.getInputHandler();
0274: } //}}}
0275:
0276: //{{{ getPainter() method
0277: /**
0278: * Returns the object responsible for painting this text area.
0279: */
0280: public final TextAreaPainter getPainter() {
0281: return painter;
0282: } //}}}
0283:
0284: //{{{ getGutter() method
0285: /**
0286: * Returns the gutter to the left of the text area or null if the gutter
0287: * is disabled
0288: */
0289: public final Gutter getGutter() {
0290: return gutter;
0291: } //}}}
0292:
0293: //{{{ getDisplayManager() method
0294: /**
0295: * @return the display manager used by this text area.
0296: * @since jEdit 4.2pre1
0297: */
0298: public DisplayManager getDisplayManager() {
0299: return displayManager;
0300: } //}}}
0301:
0302: //{{{ isCaretBlinkEnabled() method
0303: /**
0304: * @return true if the caret is blinking, false otherwise.
0305: */
0306: public final boolean isCaretBlinkEnabled() {
0307: return caretBlinks;
0308: } //}}}
0309:
0310: //{{{ setCaretBlinkEnabled() method
0311: /**
0312: * Toggles caret blinking.
0313: * @param caretBlinks True if the caret should blink, false otherwise
0314: */
0315: public void setCaretBlinkEnabled(boolean caretBlinks) {
0316: this .caretBlinks = caretBlinks;
0317: if (!caretBlinks)
0318: blink = false;
0319:
0320: if (buffer != null)
0321: invalidateLine(caretLine);
0322: } //}}}
0323:
0324: //{{{ getElectricScroll() method
0325:
0326: /**
0327: * @return the minimum distance (in number of lines)
0328: * from the caret to the nearest edge of the screen
0329: * (top or bottom edge).
0330: */
0331: public final int getElectricScroll() {
0332: return electricScroll;
0333: } //}}}
0334:
0335: //{{{ setElectricScroll() method
0336: /**
0337: * Sets the number of lines from the top and bottom of the text
0338: * area that are always visible
0339: * @param electricScroll The number of lines always visible from
0340: * the top or bottom
0341: */
0342: public final void setElectricScroll(int electricScroll) {
0343: this .electricScroll = electricScroll;
0344: } //}}}
0345:
0346: //{{{ isQuickCopyEnabled() method
0347: /**
0348: * Returns if clicking the middle mouse button pastes the most
0349: * recent selection (% register), and if Control-dragging inserts
0350: * the selection at the caret.
0351: */
0352: public final boolean isQuickCopyEnabled() {
0353: return quickCopy;
0354: } //}}}
0355:
0356: //{{{ setQuickCopyEnabled() method
0357: /**
0358: * Sets if clicking the middle mouse button pastes the most
0359: * recent selection (% register), and if Control-dragging inserts
0360: * the selection at the caret.
0361: * @param quickCopy A boolean flag
0362: */
0363: public final void setQuickCopyEnabled(boolean quickCopy) {
0364: this .quickCopy = quickCopy;
0365: } //}}}
0366:
0367: //{{{ getBuffer() method
0368: /**
0369: * Returns the buffer this text area is editing.
0370: * @since jedit 4.3pre3
0371: *
0372: * Prior to 4.3pre3, this function returned a "Buffer" type.
0373: * If this causes your code to break, try calling view.getBuffer() instead of
0374: * view.getTextArea().getBuffer().
0375: *
0376: */
0377: public final JEditBuffer getBuffer() {
0378: return buffer;
0379: } //}}}
0380:
0381: //{{{ setBuffer() method
0382: /**
0383: * Sets the buffer this text area is editing.
0384: * If you don't run a standalone textarea in jEdit please do not call this method -
0385: * use {@link org.gjt.sp.jedit.EditPane#setBuffer(org.gjt.sp.jedit.Buffer)} instead.
0386: * @param buffer The buffer
0387: */
0388: public void setBuffer(JEditBuffer buffer) {
0389: if (this .buffer == buffer)
0390: return;
0391:
0392: try {
0393: bufferChanging = true;
0394:
0395: if (this .buffer != null) {
0396: // dubious?
0397: //setFirstLine(0);
0398:
0399: if (!buffer.isLoading())
0400: selectNone();
0401: caretLine = caret = caretScreenLine = 0;
0402: match = null;
0403: }
0404: boolean inCompoundEdit = false;
0405: if (this .buffer != null)
0406: inCompoundEdit = this .buffer.insideCompoundEdit();
0407: if (inCompoundEdit)
0408: this .buffer.endCompoundEdit();
0409: this .buffer = buffer;
0410: if (inCompoundEdit)
0411: this .buffer.beginCompoundEdit();
0412:
0413: chunkCache.setBuffer(buffer);
0414: repaintMgr.setFastScroll(false);
0415: propertiesChanged();
0416:
0417: if (displayManager != null) {
0418: DisplayManager.releaseDisplayManager(displayManager);
0419: }
0420:
0421: displayManager = DisplayManager.getDisplayManager(buffer,
0422: this );
0423:
0424: displayManager.init();
0425:
0426: if (buffer.isLoading())
0427: updateScrollBar();
0428:
0429: repaint();
0430:
0431: fireScrollEvent(true);
0432: } finally {
0433: bufferChanging = false;
0434: }
0435: } //}}}
0436:
0437: //{{{ isEditable() method
0438: /**
0439: * Returns true if this text area is editable, false otherwise.
0440: */
0441: public final boolean isEditable() {
0442: return buffer.isEditable();
0443: } //}}}
0444:
0445: //{{{ isDragInProgress() method
0446: /**
0447: * Drag and drop of text in jEdit is implementing using jEdit 1.4 APIs,
0448: * however since jEdit must run with Java 1.3, this class only has the
0449: * necessary support to call a hook method via reflection. This method
0450: * is called by the {@link org.gjt.sp.jedit.Java14} class to signal that
0451: * a drag is in progress.
0452: * @since jEdit 4.2pre5
0453: */
0454: public boolean isDragInProgress() {
0455: return dndInProgress;
0456: } //}}}
0457:
0458: //{{{ setDragInProgress() method
0459: /**
0460: * Drag and drop of text in jEdit is implementing using jEdit 1.4 APIs,
0461: * however since jEdit must run with Java 1.3, this class only has the
0462: * necessary support to call a hook method via reflection. This method
0463: * is called by the {@link org.gjt.sp.jedit.Java14} class to signal that
0464: * a drag is in progress.
0465: * @since jEdit 4.2pre5
0466: */
0467: public void setDragInProgress(boolean dndInProgress) {
0468: this .dndInProgress = dndInProgress;
0469: } //}}}
0470:
0471: //{{{ isDragEnabled() method
0472: /**
0473: * Returns if drag and drop of text is enabled.
0474: * @since jEdit 4.2pre5
0475: */
0476: public boolean isDragEnabled() {
0477: return dndEnabled;
0478: } //}}}
0479:
0480: //{{{ setDragEnabled() method
0481: /**
0482: * Sets if drag and drop of text is enabled.
0483: * @since jEdit 4.2pre5
0484: */
0485: public void setDragEnabled(boolean dndEnabled) {
0486: this .dndEnabled = dndEnabled;
0487: } //}}}
0488:
0489: //{{{ getJoinNonWordChars() method
0490: /**
0491: * If set, double clicking will join non-word characters to form one "word".
0492: * @since jEdit 4.3pre2
0493: */
0494: public boolean getJoinNonWordChars() {
0495: return joinNonWordChars;
0496: } //}}}
0497:
0498: //{{{ setJoinNonWordChars() method
0499: /**
0500: * If set, double clicking will join non-word characters to form one "word".
0501: * @since jEdit 4.3pre2
0502: */
0503: public void setJoinNonWordChars(boolean joinNonWordChars) {
0504: this .joinNonWordChars = joinNonWordChars;
0505: } //}}}
0506:
0507: //{{{ getCtrlForRectangularSelection() method
0508: /**
0509: * If set, CTRL enables rectangular selection mode while pressed.
0510: * @since jEdit 4.3pre10
0511: */
0512: public boolean isCtrlForRectangularSelection() {
0513: return ctrlForRectangularSelection;
0514: } //}}}
0515:
0516: //{{{ setCtrlForRectangularSelection() method
0517: /**
0518: * If set, CTRL enables rectangular selection mode while pressed.
0519: * @since jEdit 4.3pre10
0520: */
0521: public void setCtrlForRectangularSelection(
0522: boolean ctrlForRectangularSelection) {
0523: this .ctrlForRectangularSelection = ctrlForRectangularSelection;
0524: } //}}}
0525:
0526: //{{{ Scrolling
0527:
0528: //{{{ getFirstLine() method
0529: /**
0530: * Returns the vertical scroll bar position.
0531: * @since jEdit 4.2pre1
0532: */
0533: public final int getFirstLine() {
0534: return displayManager.firstLine.scrollLine
0535: + displayManager.firstLine.skew;
0536: } //}}}
0537:
0538: //{{{ setFirstLine() method
0539: /**
0540: * Sets the vertical scroll bar position
0541: *
0542: * @param firstLine The scroll bar position
0543: */
0544: public void setFirstLine(int firstLine) {
0545: //{{{ ensure we don't have empty space at the bottom or top, etc
0546: int max = displayManager.getScrollLineCount() - visibleLines
0547: + (lastLinePartial ? 1 : 0);
0548: if (firstLine > max)
0549: firstLine = max;
0550: if (firstLine < 0)
0551: firstLine = 0;
0552: //}}}
0553:
0554: if (Debug.SCROLL_DEBUG) {
0555: Log.log(Log.DEBUG, this , "setFirstLine() from "
0556: + getFirstLine() + " to " + firstLine);
0557: }
0558:
0559: int oldFirstLine = getFirstLine();
0560: if (firstLine == oldFirstLine)
0561: return;
0562:
0563: displayManager.setFirstLine(oldFirstLine, firstLine);
0564:
0565: repaint();
0566:
0567: fireScrollEvent(true);
0568: } //}}}
0569:
0570: //{{{ getFirstPhysicalLine() method
0571: /**
0572: * Returns the first visible physical line index.
0573: * @since jEdit 4.0pre4
0574: */
0575: public final int getFirstPhysicalLine() {
0576: return displayManager.firstLine.physicalLine;
0577: } //}}}
0578:
0579: //{{{ setFirstPhysicalLine() method
0580: /**
0581: * Sets the vertical scroll bar position.
0582: * @param physFirstLine The first physical line to display
0583: * @since jEdit 4.2pre1
0584: */
0585: public void setFirstPhysicalLine(int physFirstLine) {
0586: setFirstPhysicalLine(physFirstLine, 0);
0587: } //}}}
0588:
0589: //{{{ setFirstPhysicalLine() method
0590: /**
0591: * Sets the vertical scroll bar position.
0592: * @param physFirstLine The first physical line to display
0593: * @param skew A local screen line delta
0594: * @since jEdit 4.2pre1
0595: */
0596: public void setFirstPhysicalLine(int physFirstLine, int skew) {
0597: if (Debug.SCROLL_DEBUG) {
0598: Log.log(Log.DEBUG, this , "setFirstPhysicalLine("
0599: + physFirstLine + ',' + skew + ')');
0600: }
0601:
0602: int amount = physFirstLine
0603: - displayManager.firstLine.physicalLine;
0604:
0605: displayManager.setFirstPhysicalLine(amount, skew);
0606:
0607: repaint();
0608:
0609: fireScrollEvent(true);
0610: } //}}}
0611:
0612: //{{{ getLastPhysicalLine() method
0613: /**
0614: * Returns the last visible physical line index.
0615: * @since jEdit 4.0pre4
0616: */
0617: public final int getLastPhysicalLine() {
0618: return physLastLine;
0619: } //}}}
0620:
0621: //{{{ getLastScreenLine() method
0622: /**
0623: * Returns the last screen line index, it is different from
0624: * {@link #getVisibleLines()} because the buffer can have less lines than
0625: * the visible lines
0626: * @return the last screen line index.
0627: * @since jEdit 4.3pre1
0628: */
0629: public int getLastScreenLine() {
0630: return screenLastLine;
0631: } //}}}
0632:
0633: //{{{ getVisibleLines() method
0634: /**
0635: * Returns the number of lines visible in this text area.
0636: * @return the number of visible lines in the textarea
0637: */
0638: public final int getVisibleLines() {
0639: return visibleLines;
0640: } //}}}
0641:
0642: //{{{ getHorizontalOffset() method
0643: /**
0644: * Returns the horizontal offset of drawn lines.
0645: */
0646: public final int getHorizontalOffset() {
0647: return horizontalOffset;
0648: } //}}}
0649:
0650: //{{{ setHorizontalOffset() method
0651: /**
0652: * Sets the horizontal offset of drawn lines. This can be used to
0653: * implement horizontal scrolling.
0654: * @param horizontalOffset offset The new horizontal offset
0655: */
0656: public void setHorizontalOffset(int horizontalOffset) {
0657: if (horizontalOffset > 0)
0658: horizontalOffset = 0;
0659:
0660: if (horizontalOffset == this .horizontalOffset)
0661: return;
0662:
0663: this .horizontalOffset = horizontalOffset;
0664: painter.repaint();
0665:
0666: fireScrollEvent(false);
0667: } //}}}
0668:
0669: //{{{ scrollUpLine() method
0670: /**
0671: * Scrolls up by one line.
0672: * @since jEdit 2.7pre2
0673: */
0674: public void scrollUpLine() {
0675: setFirstLine(getFirstLine() - 1);
0676: } //}}}
0677:
0678: //{{{ scrollUpPage() method
0679: /**
0680: * Scrolls up by one page.
0681: * @since jEdit 2.7pre2
0682: */
0683: public void scrollUpPage() {
0684: setFirstLine(getFirstLine() - getVisibleLines()
0685: + (lastLinePartial ? 1 : 0));
0686: } //}}}
0687:
0688: //{{{ scrollDownLine() method
0689: /**
0690: * Scrolls down by one line.
0691: * @since jEdit 2.7pre2
0692: */
0693: public void scrollDownLine() {
0694: setFirstLine(getFirstLine() + 1);
0695: } //}}}
0696:
0697: //{{{ scrollDownPage() method
0698: /**
0699: * Scrolls down by one page.
0700: * @since jEdit 2.7pre2
0701: */
0702: public void scrollDownPage() {
0703: setFirstLine(getFirstLine() + getVisibleLines()
0704: - (lastLinePartial ? 1 : 0));
0705: } //}}}
0706:
0707: //{{{ scrollToCaret() method
0708: /**
0709: * Ensures that the caret is visible by scrolling the text area if
0710: * necessary.
0711: * @param doElectricScroll If true, electric scrolling will be performed
0712: */
0713: public void scrollToCaret(boolean doElectricScroll) {
0714: scrollTo(caretLine, caret
0715: - buffer.getLineStartOffset(caretLine),
0716: doElectricScroll);
0717: } //}}}
0718:
0719: //{{{ scrollTo() method
0720: /**
0721: * Ensures that the specified location in the buffer is visible.
0722: * @param offset The offset from the start of the buffer
0723: * @param doElectricScroll If true, electric scrolling will be performed
0724: * @since jEdit 4.2pre3
0725: */
0726: public void scrollTo(int offset, boolean doElectricScroll) {
0727: int line = buffer.getLineOfOffset(offset);
0728: scrollTo(line, offset - buffer.getLineStartOffset(line),
0729: doElectricScroll);
0730: } //}}}
0731:
0732: //{{{ scrollTo() method
0733: /**
0734: * Ensures that the specified location in the buffer is visible.
0735: * @param line The line number
0736: * @param offset The offset from the start of the line
0737: * @param doElectricScroll If true, electric scrolling will be performed
0738: * @since jEdit 4.0pre6
0739: */
0740: public void scrollTo(int line, int offset, boolean doElectricScroll) {
0741: if (Debug.SCROLL_TO_DEBUG)
0742: Log.log(Log.DEBUG, this , "scrollTo(), lineCount="
0743: + getLineCount());
0744:
0745: //{{{ Get ready
0746: int extraEndVirt;
0747: int lineLength = buffer.getLineLength(line);
0748: if (offset > lineLength) {
0749: extraEndVirt = charWidth * (offset - lineLength);
0750: offset = lineLength;
0751: } else
0752: extraEndVirt = 0;
0753:
0754: int _electricScroll = doElectricScroll
0755: && visibleLines - 1 > (electricScroll << 1) ? electricScroll
0756: : 0;
0757: //}}}
0758:
0759: if (visibleLines <= 1) {
0760: if (Debug.SCROLL_TO_DEBUG)
0761: Log.log(Log.DEBUG, this , "visibleLines <= 0");
0762: setFirstPhysicalLine(line, _electricScroll);
0763: return;
0764: }
0765:
0766: //{{{ Scroll vertically
0767: int screenLine = chunkCache.getScreenLineOfOffset(line, offset);
0768: int visibleLines = getVisibleLines();
0769: if (screenLine == -1) {
0770: if (Debug.SCROLL_TO_DEBUG)
0771: Log.log(Log.DEBUG, this , "screenLine == -1");
0772: ChunkCache.LineInfo[] infos = chunkCache
0773: .getLineInfosForPhysicalLine(line);
0774: int subregion = ChunkCache.getSubregionOfOffset(offset,
0775: infos);
0776: int prevLine = displayManager
0777: .getPrevVisibleLine(getFirstPhysicalLine());
0778: int nextLine = displayManager
0779: .getNextVisibleLine(getLastPhysicalLine());
0780: if (line == getFirstPhysicalLine()) {
0781: if (Debug.SCROLL_TO_DEBUG)
0782: Log.log(Log.DEBUG, this , line + " == "
0783: + getFirstPhysicalLine());
0784: setFirstPhysicalLine(line, subregion - _electricScroll);
0785: } else if (line == prevLine) {
0786: if (Debug.SCROLL_TO_DEBUG)
0787: Log.log(Log.DEBUG, this , line + " == " + prevLine);
0788: setFirstPhysicalLine(prevLine, subregion
0789: - _electricScroll);
0790: } else if (line == getLastPhysicalLine()) {
0791: if (Debug.SCROLL_TO_DEBUG)
0792: Log.log(Log.DEBUG, this , line + " == "
0793: + getLastPhysicalLine());
0794: setFirstPhysicalLine(line, subregion + _electricScroll
0795: - visibleLines + (lastLinePartial ? 2 : 1));
0796: } else if (line == nextLine) {
0797: if (Debug.SCROLL_TO_DEBUG)
0798: Log.log(Log.DEBUG, this , line + " == " + nextLine);
0799: setFirstPhysicalLine(nextLine, subregion
0800: + electricScroll - visibleLines
0801: + (lastLinePartial ? 2 : 1));
0802: } else {
0803: if (Debug.SCROLL_TO_DEBUG) {
0804: Log.log(Log.DEBUG, this , "neither");
0805: Log.log(Log.DEBUG, this , "Last physical line is "
0806: + getLastPhysicalLine());
0807: }
0808: setFirstPhysicalLine(line, subregion
0809: - (visibleLines >> 1));
0810: if (Debug.SCROLL_TO_DEBUG) {
0811: Log.log(Log.DEBUG, this , "Last physical line is "
0812: + getLastPhysicalLine());
0813: }
0814: }
0815: } else if (screenLine < _electricScroll) {
0816: if (Debug.SCROLL_TO_DEBUG)
0817: Log.log(Log.DEBUG, this , "electric up");
0818: setFirstLine(getFirstLine() - _electricScroll + screenLine);
0819: } else if (screenLine > visibleLines - _electricScroll
0820: - (lastLinePartial ? 2 : 1)) {
0821: if (Debug.SCROLL_TO_DEBUG)
0822: Log.log(Log.DEBUG, this , "electric down");
0823: setFirstLine(getFirstLine() + _electricScroll
0824: - visibleLines + screenLine
0825: + (lastLinePartial ? 2 : 1));
0826: } //}}}
0827:
0828: //{{{ Scroll horizontally
0829: if (!displayManager.isLineVisible(line))
0830: return;
0831:
0832: Point point = offsetToXY(line, offset, offsetXY);
0833:
0834: point.x += extraEndVirt;
0835:
0836: if (point.x < 0) {
0837: setHorizontalOffset(horizontalOffset - point.x + charWidth
0838: + 5);
0839: } else if (point.x >= painter.getWidth() - charWidth - 5) {
0840: setHorizontalOffset(horizontalOffset
0841: + (painter.getWidth() - point.x) - charWidth - 5);
0842: } //}}}
0843: } //}}}
0844:
0845: //{{{ addScrollListener() method
0846: /**
0847: * Adds a scroll listener to this text area.
0848: * @param listener The listener
0849: * @since jEdit 3.2pre2
0850: */
0851: public final void addScrollListener(ScrollListener listener) {
0852: listenerList.add(ScrollListener.class, listener);
0853: } //}}}
0854:
0855: //{{{ removeScrollListener() method
0856: /**
0857: * Removes a scroll listener from this text area.
0858: * @param listener The listener
0859: * @since jEdit 3.2pre2
0860: */
0861: public final void removeScrollListener(ScrollListener listener) {
0862: listenerList.remove(ScrollListener.class, listener);
0863: } //}}}
0864:
0865: //}}}
0866:
0867: //{{{ Screen line stuff
0868:
0869: //{{{ getPhysicalLineOfScreenLine() method
0870: /**
0871: * Returns the physical line number that contains the specified screen
0872: * line.
0873: * @param screenLine The screen line
0874: * @since jEdit 4.0pre6
0875: */
0876: public int getPhysicalLineOfScreenLine(int screenLine) {
0877: return chunkCache.getLineInfo(screenLine).physicalLine;
0878: } //}}}
0879:
0880: //{{{ getScreenLineOfOffset() method
0881: /**
0882: * Returns the screen (wrapped) line containing the specified offset.
0883: * Returns -1 if the line is not currently visible on the screen.
0884: * @param offset The offset
0885: * @since jEdit 4.0pre4
0886: */
0887: public int getScreenLineOfOffset(int offset) {
0888: int line = buffer.getLineOfOffset(offset);
0889: offset -= buffer.getLineStartOffset(line);
0890: return chunkCache.getScreenLineOfOffset(line, offset);
0891: } //}}}
0892:
0893: //{{{ getScreenLineStartOffset() method
0894: /**
0895: * Returns the start offset of the specified screen (wrapped) line.
0896: * @param line The line
0897: * @since jEdit 4.0pre4
0898: */
0899: public int getScreenLineStartOffset(int line) {
0900: ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
0901: if (lineInfo.physicalLine == -1)
0902: return -1;
0903:
0904: return buffer.getLineStartOffset(lineInfo.physicalLine)
0905: + lineInfo.offset;
0906: } //}}}
0907:
0908: //{{{ getScreenLineEndOffset() method
0909: /**
0910: * Returns the end offset of the specified screen (wrapped) line.
0911: * @param line The line
0912: * @since jEdit 4.0pre4
0913: */
0914: public int getScreenLineEndOffset(int line) {
0915: ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
0916: if (lineInfo.physicalLine == -1)
0917: return -1;
0918:
0919: return buffer.getLineStartOffset(lineInfo.physicalLine)
0920: + lineInfo.offset + lineInfo.length;
0921: } //}}}
0922:
0923: //}}}
0924:
0925: //{{{ Offset conversion
0926:
0927: //{{{ xyToOffset() method
0928: /**
0929: * Converts a point to an offset.
0930: * Note that unlike in previous jEdit versions, this method now returns
0931: * -1 if the y co-ordinate is out of bounds.
0932: *
0933: * @param x The x co-ordinate of the point
0934: * @param y The y co-ordinate of the point
0935: */
0936: public int xyToOffset(int x, int y) {
0937: return xyToOffset(x, y, true);
0938: } //}}}
0939:
0940: //{{{ xyToOffset() method
0941: /**
0942: * Converts a point to an offset.
0943: * Note that unlike in previous jEdit versions, this method now returns
0944: * -1 if the y co-ordinate is out of bounds.
0945: *
0946: * @param x The x co-ordinate of the point
0947: * @param y The y co-ordinate of the point
0948: * @param round Round up to next letter if past the middle of a letter?
0949: * @since jEdit 3.2pre6
0950: */
0951: public int xyToOffset(int x, int y, boolean round) {
0952: FontMetrics fm = painter.getFontMetrics();
0953: int height = fm.getHeight();
0954: int line = y / height;
0955:
0956: if (line < 0 || line >= visibleLines)
0957: return -1;
0958:
0959: return xToScreenLineOffset(line, x, round);
0960: } //}}}
0961:
0962: //{{{ xToScreenLineOffset() method
0963: /**
0964: * Converts a point in a given screen line to an offset.
0965: * Note that unlike in previous jEdit versions, this method now returns
0966: * -1 if the y co-ordinate is out of bounds.
0967: *
0968: * @param x The x co-ordinate of the point
0969: * @param screenLine The screen line
0970: * @param round Round up to next letter if past the middle of a letter?
0971: * @since jEdit 3.2pre6
0972: */
0973: public int xToScreenLineOffset(int screenLine, int x, boolean round) {
0974: ChunkCache.LineInfo lineInfo = chunkCache
0975: .getLineInfo(screenLine);
0976: if (lineInfo.physicalLine == -1) {
0977: return getLineEndOffset(displayManager.getLastVisibleLine()) - 1;
0978: } else {
0979: int offset = Chunk.xToOffset(lineInfo.chunks, x
0980: - horizontalOffset, round);
0981: if (offset == -1
0982: || offset == lineInfo.offset + lineInfo.length)
0983: offset = lineInfo.offset + lineInfo.length - 1;
0984:
0985: return getLineStartOffset(lineInfo.physicalLine) + offset;
0986: }
0987: } //}}}
0988:
0989: //{{{ offsetToXY() method
0990: /**
0991: * Converts an offset into a point in the text area painter's
0992: * co-ordinate space.
0993: * @param offset The offset
0994: * @return The location of the offset on screen, or <code>null</code>
0995: * if the specified offset is not visible
0996: */
0997: public Point offsetToXY(int offset) {
0998: int line = buffer.getLineOfOffset(offset);
0999: offset -= buffer.getLineStartOffset(line);
1000: Point retVal = new Point();
1001: return offsetToXY(line, offset, retVal);
1002: } //}}}
1003:
1004: //{{{ offsetToXY() method
1005: /**
1006: * Converts an offset into a point in the text area painter's
1007: * co-ordinate space.
1008: * @param line The line
1009: * @param offset The offset
1010: * @return The location of the offset on screen, or <code>null</code>
1011: * if the specified offset is not visible
1012: */
1013: public Point offsetToXY(int line, int offset) {
1014: return offsetToXY(line, offset, new Point());
1015: } //}}}
1016:
1017: //{{{ offsetToXY() method
1018: /**
1019: * Converts a line,offset pair into an x,y (pixel) point relative to the
1020: * upper left corner (0,0) of the text area.
1021: *
1022: * @param line The physical line number (from top of document)
1023: * @param offset The offset in characters, from the start of the line
1024: * @param retVal The point to store the return value in
1025: * @return <code>retVal</code> for convenience, or <code>null</code>
1026: * if the specified offset is not visible
1027: * @since jEdit 4.0pre4
1028: */
1029: public Point offsetToXY(int line, int offset, Point retVal) {
1030: if (!displayManager.isLineVisible(line))
1031: return null;
1032: int screenLine = chunkCache.getScreenLineOfOffset(line, offset);
1033: if (screenLine == -1)
1034: return null;
1035:
1036: FontMetrics fm = painter.getFontMetrics();
1037:
1038: retVal.y = screenLine * fm.getHeight();
1039:
1040: ChunkCache.LineInfo info = chunkCache.getLineInfo(screenLine);
1041:
1042: retVal.x = (int) (horizontalOffset + Chunk.offsetToX(
1043: info.chunks, offset));
1044:
1045: return retVal;
1046: } //}}}
1047:
1048: //}}}
1049:
1050: //{{{ Painting
1051:
1052: //{{{ invalidateScreenLineRange() method
1053: /**
1054: * Marks a range of screen lines as needing a repaint.
1055: * @param start The first line
1056: * @param end The last line
1057: * @since jEdit 4.0pre4
1058: */
1059: public void invalidateScreenLineRange(int start, int end) {
1060: if (buffer.isLoading())
1061: return;
1062:
1063: if (start > end) {
1064: int tmp = end;
1065: end = start;
1066: start = tmp;
1067: }
1068:
1069: if (chunkCache.needFullRepaint())
1070: end = visibleLines;
1071:
1072: FontMetrics fm = painter.getFontMetrics();
1073: int y = start * fm.getHeight();
1074: int height = (end - start + 1) * fm.getHeight();
1075: painter.repaint(0, y, painter.getWidth(), height);
1076: gutter.repaint(0, y, gutter.getWidth(), height);
1077: } //}}}
1078:
1079: //{{{ invalidateLine() method
1080: /**
1081: * Marks a line as needing a repaint.
1082: * @param line The physical line to invalidate
1083: */
1084: public void invalidateLine(int line) {
1085: if (!isShowing() || buffer.isLoading()
1086: || line < getFirstPhysicalLine() || line > physLastLine
1087: || !displayManager.isLineVisible(line))
1088: return;
1089:
1090: int startLine = -1;
1091: int endLine = -1;
1092:
1093: for (int i = 0; i < visibleLines; i++) {
1094: ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
1095:
1096: if ((info.physicalLine >= line || info.physicalLine == -1)
1097: && startLine == -1) {
1098: startLine = i;
1099: }
1100:
1101: if ((info.physicalLine >= line && info.lastSubregion)
1102: || info.physicalLine == -1) {
1103: endLine = i;
1104: break;
1105: }
1106: }
1107:
1108: if (chunkCache.needFullRepaint() || endLine == -1)
1109: endLine = visibleLines;
1110:
1111: invalidateScreenLineRange(startLine, endLine);
1112: } //}}}
1113:
1114: //{{{ invalidateLineRange() method
1115: /**
1116: * Marks a range of physical lines as needing a repaint.
1117: * @param start The first line to invalidate
1118: * @param end The last line to invalidate
1119: */
1120: public void invalidateLineRange(int start, int end) {
1121: if (!isShowing() || buffer.isLoading())
1122: return;
1123:
1124: if (end < start) {
1125: int tmp = end;
1126: end = start;
1127: start = tmp;
1128: }
1129:
1130: if (end < getFirstPhysicalLine()
1131: || start > getLastPhysicalLine())
1132: return;
1133:
1134: int startScreenLine = -1;
1135: int endScreenLine = -1;
1136:
1137: for (int i = 0; i < visibleLines; i++) {
1138: ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
1139:
1140: if ((info.physicalLine >= start || info.physicalLine == -1)
1141: && startScreenLine == -1) {
1142: startScreenLine = i;
1143: }
1144:
1145: if ((info.physicalLine >= end && info.lastSubregion)
1146: || info.physicalLine == -1) {
1147: endScreenLine = i;
1148: break;
1149: }
1150: }
1151:
1152: if (startScreenLine == -1)
1153: startScreenLine = 0;
1154:
1155: if (chunkCache.needFullRepaint() || endScreenLine == -1)
1156: endScreenLine = visibleLines;
1157:
1158: invalidateScreenLineRange(startScreenLine, endScreenLine);
1159: } //}}}
1160:
1161: //}}}
1162:
1163: //{{{ Convenience methods
1164:
1165: //{{{ getBufferLength() method
1166: /**
1167: * Returns the length of the buffer.
1168: */
1169: public final int getBufferLength() {
1170: return buffer.getLength();
1171: } //}}}
1172:
1173: //{{{ getLineCount() method
1174: /**
1175: * Returns the number of physical lines in the buffer.
1176: */
1177: public final int getLineCount() {
1178: return buffer.getLineCount();
1179: } //}}}
1180:
1181: //{{{ getLineOfOffset() method
1182: /**
1183: * Returns the line containing the specified offset.
1184: * @param offset The offset
1185: */
1186: public final int getLineOfOffset(int offset) {
1187: return buffer.getLineOfOffset(offset);
1188: } //}}}
1189:
1190: //{{{ getLineStartOffset() method
1191: /**
1192: * Returns the start offset of the specified line.
1193: * @param line The line (physical line)
1194: * @return The start offset of the specified line, or -1 if the line is
1195: * invalid
1196: */
1197: public int getLineStartOffset(int line) {
1198: return buffer.getLineStartOffset(line);
1199: } //}}}
1200:
1201: //{{{ getLineEndOffset() method
1202: /**
1203: * Returns the end offset of the specified line.
1204: * @param line The line (physical line)
1205: * @return The end offset of the specified line, or -1 if the line is
1206: * invalid.
1207: */
1208: public int getLineEndOffset(int line) {
1209: return buffer.getLineEndOffset(line);
1210: } //}}}
1211:
1212: //{{{ getLineLength() method
1213: /**
1214: * Returns the length of the specified line.
1215: * @param line The line
1216: */
1217: public int getLineLength(int line) {
1218: return buffer.getLineLength(line);
1219: } //}}}
1220:
1221: //{{{ getText() method
1222: /**
1223: * Returns the specified substring of the buffer.
1224: * @param start The start offset
1225: * @param len The length of the substring
1226: * @return The substring
1227: */
1228: public final String getText(int start, int len) {
1229: return buffer.getText(start, len);
1230: } //}}}
1231:
1232: //{{{ getText() method
1233: /**
1234: * Copies the specified substring of the buffer into a segment.
1235: * @param start The start offset
1236: * @param len The length of the substring
1237: * @param segment The segment
1238: */
1239: public final void getText(int start, int len, Segment segment) {
1240: buffer.getText(start, len, segment);
1241: } //}}}
1242:
1243: //{{{ getLineText() method
1244: /**
1245: * Returns the text on the specified line.
1246: * @param lineIndex the line number
1247: * @return The text, or null if the lineIndex is invalid
1248: */
1249: public final String getLineText(int lineIndex) {
1250: return buffer.getLineText(lineIndex);
1251: } //}}}
1252:
1253: //{{{ getLineText() method
1254: /**
1255: * Copies the text on the specified line into a Segment. If lineIndex
1256: * is invalid, the segment will contain a null string.
1257: * @param lineIndex The line number (physical line)
1258: * @param segment the segment into which the data will be stored.
1259: */
1260: public final void getLineText(int lineIndex, Segment segment) {
1261: buffer.getLineText(lineIndex, segment);
1262: } //}}}
1263:
1264: //{{{ getText() method
1265: /**
1266: * Returns the entire text of this text area.
1267: */
1268: public String getText() {
1269: return buffer.getText(0, buffer.getLength());
1270: } //}}}
1271:
1272: //{{{ setText() method
1273: /**
1274: * Sets the entire text of this text area.
1275: * @param text the new content of the buffer
1276: */
1277: public void setText(String text) {
1278: try {
1279: buffer.beginCompoundEdit();
1280: buffer.remove(0, buffer.getLength());
1281: buffer.insert(0, text);
1282: } finally {
1283: buffer.endCompoundEdit();
1284: }
1285: } //}}}
1286:
1287: //}}}
1288:
1289: //{{{ Selection
1290:
1291: //{{{ selectAll() method
1292: /**
1293: * Selects all text in the buffer. Preserves the scroll position.
1294: */
1295: public final void selectAll() {
1296: int firstLine = getFirstLine();
1297: int horizOffset = getHorizontalOffset();
1298:
1299: setSelection(new Selection.Range(0, buffer.getLength()));
1300: moveCaretPosition(buffer.getLength(), true);
1301:
1302: setFirstLine(firstLine);
1303: setHorizontalOffset(horizOffset);
1304: } //}}}
1305:
1306: //{{{ selectLine() method
1307: /**
1308: * Selects the current line.
1309: * @since jEdit 2.7pre2
1310: */
1311: public void selectLine() {
1312: int caretLine = getCaretLine();
1313: int start = getLineStartOffset(caretLine);
1314: int end = getLineEndOffset(caretLine) - 1;
1315: Selection s = new Selection.Range(start, end);
1316: if (multi)
1317: addToSelection(s);
1318: else
1319: setSelection(s);
1320: moveCaretPosition(end);
1321: } //}}}
1322:
1323: //{{{ selectParagraph() method
1324: /**
1325: * Selects the paragraph at the caret position.
1326: * @since jEdit 2.7pre2
1327: */
1328: public void selectParagraph() {
1329: int caretLine = getCaretLine();
1330:
1331: if (getLineLength(caretLine) == 0) {
1332: getToolkit().beep();
1333: return;
1334: }
1335:
1336: int start = caretLine;
1337: int end = caretLine;
1338:
1339: while (start >= 0) {
1340: if (getLineLength(start) == 0)
1341: break;
1342: else
1343: start--;
1344: }
1345:
1346: while (end < getLineCount()) {
1347: if (getLineLength(end) == 0)
1348: break;
1349: else
1350: end++;
1351: }
1352:
1353: int selectionStart = getLineStartOffset(start + 1);
1354: int selectionEnd = getLineEndOffset(end - 1) - 1;
1355: Selection s = new Selection.Range(selectionStart, selectionEnd);
1356: if (multi)
1357: addToSelection(s);
1358: else
1359: setSelection(s);
1360: moveCaretPosition(selectionEnd);
1361: } //}}}
1362:
1363: //{{{ selectWord() method
1364: /**
1365: * Selects the word at the caret position.
1366: * @since jEdit 2.7pre2
1367: */
1368: public void selectWord() {
1369: int line = getCaretLine();
1370: int lineStart = getLineStartOffset(line);
1371: int offset = getCaretPosition() - lineStart;
1372:
1373: if (getLineLength(line) == 0)
1374: return;
1375:
1376: String lineText = getLineText(line);
1377: String noWordSep = buffer.getStringProperty("noWordSep");
1378:
1379: if (offset == getLineLength(line))
1380: offset--;
1381:
1382: int wordStart = TextUtilities.findWordStart(lineText, offset,
1383: noWordSep, true, false, false);
1384: int wordEnd = TextUtilities.findWordEnd(lineText, offset + 1,
1385: noWordSep, true, false, false);
1386:
1387: Selection s = new Selection.Range(lineStart + wordStart,
1388: lineStart + wordEnd);
1389: if (multi)
1390: addToSelection(s);
1391: else
1392: setSelection(s);
1393: moveCaretPosition(lineStart + wordEnd);
1394: } //}}}
1395:
1396: //{{{ selectToMatchingBracket() method
1397: /**
1398: * Selects from the bracket at the specified position to the
1399: * corresponding bracket.
1400: * @since jEdit 4.2pre1
1401: */
1402: public Selection selectToMatchingBracket(int position,
1403: boolean quickCopy) {
1404: int positionLine = buffer.getLineOfOffset(position);
1405: int lineOffset = position
1406: - buffer.getLineStartOffset(positionLine);
1407: if (getLineLength(positionLine) != 0) {
1408: int bracket = TextUtilities.findMatchingBracket(buffer,
1409: positionLine, Math.max(0, lineOffset - 1));
1410:
1411: if (bracket != -1) {
1412: Selection s;
1413:
1414: if (bracket < position) {
1415: if (!quickCopy)
1416: moveCaretPosition(position, false);
1417: s = new Selection.Range(bracket, position);
1418: } else {
1419: if (!quickCopy)
1420: moveCaretPosition(bracket + 1, false);
1421: s = new Selection.Range(position - 1, bracket + 1);
1422: }
1423:
1424: if (!multi && !quickCopy)
1425: selectNone();
1426:
1427: addToSelection(s);
1428: return s;
1429: }
1430: }
1431:
1432: return null;
1433: } //}}}
1434:
1435: //{{{ selectToMatchingBracket() method
1436: /**
1437: * Selects from the bracket at the caret position to the corresponding
1438: * bracket.
1439: * @since jEdit 4.0pre2
1440: */
1441: public void selectToMatchingBracket() {
1442: selectToMatchingBracket(caret, false);
1443: } //}}}
1444:
1445: //{{{ selectBlock() method
1446: /**
1447: * Selects the code block surrounding the caret.
1448: * @since jEdit 2.7pre2
1449: */
1450: public void selectBlock() {
1451:
1452: Selection s = getSelectionAtOffset(caret);
1453: int start, end;
1454: if (s == null)
1455: start = end = caret;
1456: else {
1457: start = s.start;
1458: end = s.end;
1459: }
1460:
1461: String text = getText(0, buffer.getLength());
1462:
1463: // We can't do the backward scan if start == 0
1464: if (start == 0) {
1465: getToolkit().beep();
1466: return;
1467: }
1468:
1469: // Scan backwards, trying to find a bracket
1470: String openBrackets = "([{";
1471: String closeBrackets = ")]}";
1472: int count = 1;
1473: char openBracket = '\0';
1474: char closeBracket = '\0';
1475:
1476: backward_scan: while (--start > 0) {
1477: char c = text.charAt(start);
1478: int index = openBrackets.indexOf(c);
1479: if (index != -1) {
1480: if (--count == 0) {
1481: openBracket = c;
1482: closeBracket = closeBrackets.charAt(index);
1483: break backward_scan;
1484: }
1485: } else if (closeBrackets.indexOf(c) != -1)
1486: count++;
1487: }
1488:
1489: // Reset count
1490: count = 1;
1491:
1492: // Scan forward, matching that bracket
1493: if (openBracket == '\0') {
1494: getToolkit().beep();
1495: return;
1496: }
1497: forward_scan: do {
1498: char c = text.charAt(end);
1499: if (c == closeBracket) {
1500: if (--count == 0) {
1501: end++;
1502: break forward_scan;
1503: }
1504: } else if (c == openBracket)
1505: count++;
1506: } while (++end < buffer.getLength());
1507:
1508: s = new Selection.Range(start, end);
1509: if (multi)
1510: addToSelection(s);
1511: else
1512: setSelection(s);
1513: moveCaretPosition(end);
1514: } //}}}
1515:
1516: //{{{ lineInStructureScope() method
1517: /**
1518: * Returns if the specified line is contained in the currently
1519: * matched structure's scope.
1520: * @since jEdit 4.2pre3
1521: */
1522: public boolean lineInStructureScope(int line) {
1523: if (match == null)
1524: return false;
1525:
1526: if (match.startLine < caretLine)
1527: return line >= match.startLine && line <= caretLine;
1528: else
1529: return line <= match.endLine && line >= caretLine;
1530: } //}}}
1531:
1532: //{{{ invertSelection() method
1533: /**
1534: * Inverts the selection.
1535: * @since jEdit 4.0pre1
1536: */
1537: public final void invertSelection() {
1538: selectionManager.invertSelection();
1539: } //}}}
1540:
1541: //{{{ getSelectionCount() method
1542: /**
1543: * Returns the number of selections. This can be used to test
1544: * for the existence of selections.
1545: * @since jEdit 3.2pre2
1546: */
1547: public int getSelectionCount() {
1548: return selectionManager.getSelectionCount();
1549: } //}}}
1550:
1551: //{{{ getSelection() method
1552: /**
1553: * Returns the current selection.
1554: * @since jEdit 3.2pre1
1555: */
1556: public Selection[] getSelection() {
1557: return selectionManager.getSelection();
1558: } //}}}
1559:
1560: //{{{ getSelectionIterator() method
1561: /**
1562: * Returns the current selection.
1563: * @since jEdit 4.3pre1
1564: */
1565: public Iterator<Selection> getSelectionIterator() {
1566: return selectionManager.selection.iterator();
1567: } //}}}
1568:
1569: //{{{ getSelection() method
1570: /**
1571: * Returns the selection with the specified index. This must be
1572: * between 0 and the return value of <code>getSelectionCount()</code>.
1573: * @since jEdit 4.3pre1
1574: * @param index the index of the selection you want
1575: */
1576: public Selection getSelection(int index) {
1577: return selectionManager.selection.get(index);
1578: } //}}}
1579:
1580: //{{{ selectNone() method
1581: /**
1582: * Deselects everything.
1583: */
1584: public void selectNone() {
1585: invalidateSelectedLines();
1586: setSelection((Selection) null);
1587: } //}}}
1588:
1589: //{{{ setSelection() method
1590: /**
1591: * Sets the selection. Nested and overlapping selections are merged
1592: * where possible. Null elements of the array are ignored.
1593: * @param selection The new selection
1594: * since jEdit 3.2pre1
1595: */
1596: public void setSelection(Selection[] selection) {
1597: // invalidate the old selection
1598: invalidateSelectedLines();
1599: selectionManager.setSelection(selection);
1600: finishCaretUpdate(caretLine, NO_SCROLL, true);
1601: } //}}}
1602:
1603: //{{{ setSelection() method
1604: /**
1605: * Sets the selection. Nested and overlapping selections are merged
1606: * where possible.
1607: * @param selection The new selection
1608: * since jEdit 3.2pre1
1609: */
1610: public void setSelection(Selection selection) {
1611: invalidateSelectedLines();
1612: selectionManager.setSelection(selection);
1613: finishCaretUpdate(caretLine, NO_SCROLL, true);
1614: } //}}}
1615:
1616: //{{{ addToSelection() method
1617: /**
1618: * Adds to the selection. Nested and overlapping selections are merged
1619: * where possible.
1620: * @param selection The new selection
1621: * since jEdit 3.2pre1
1622: */
1623: public void addToSelection(Selection[] selection) {
1624: invalidateSelectedLines();
1625: selectionManager.addToSelection(selection);
1626: finishCaretUpdate(caretLine, NO_SCROLL, true);
1627: } //}}}
1628:
1629: //{{{ addToSelection() method
1630: /**
1631: * Adds to the selection. Nested and overlapping selections are merged
1632: * where possible.
1633: * @param selection The new selection
1634: * since jEdit 3.2pre1
1635: */
1636: public void addToSelection(Selection selection) {
1637: invalidateSelectedLines();
1638: selectionManager.addToSelection(selection);
1639: finishCaretUpdate(caretLine, NO_SCROLL, true);
1640: } //}}}
1641:
1642: //{{{ getSelectionAtOffset() method
1643: /**
1644: * Returns the selection containing the specific offset, or <code>null</code>
1645: * if there is no selection at that offset.
1646: * @param offset The offset
1647: * @since jEdit 3.2pre1
1648: */
1649: public Selection getSelectionAtOffset(int offset) {
1650: return selectionManager.getSelectionAtOffset(offset);
1651: } //}}}
1652:
1653: //{{{ removeFromSelection() method
1654: /**
1655: * Deactivates the specified selection.
1656: * @param sel The selection
1657: * @since jEdit 3.2pre1
1658: */
1659: public void removeFromSelection(Selection sel) {
1660: invalidateSelectedLines();
1661: selectionManager.removeFromSelection(sel);
1662: finishCaretUpdate(caretLine, NO_SCROLL, true);
1663: } //}}}
1664:
1665: //{{{ removeFromSelection() method
1666: /**
1667: * Deactivates the selection at the specified offset. If there is
1668: * no selection at that offset, does nothing.
1669: * @param offset The offset
1670: * @since jEdit 3.2pre1
1671: */
1672: public void removeFromSelection(int offset) {
1673: Selection sel = getSelectionAtOffset(offset);
1674: if (sel == null)
1675: return;
1676:
1677: invalidateSelectedLines();
1678: selectionManager.removeFromSelection(sel);
1679: finishCaretUpdate(caretLine, NO_SCROLL, true);
1680: } //}}}
1681:
1682: //{{{ resizeSelection() method
1683: /**
1684: * Resizes the selection at the specified offset, or creates a new
1685: * one if there is no selection at the specified offset. This is a
1686: * utility method that is mainly useful in the mouse event handler
1687: * because it handles the case of end being before offset gracefully
1688: * (unlike the rest of the selection API).
1689: * @param offset The offset
1690: * @param end The new selection end
1691: * @param extraEndVirt Only for rectangular selections - specifies how
1692: * far it extends into virtual space.
1693: * @param rect Make the selection rectangular?
1694: * @since jEdit 3.2pre1
1695: */
1696: public void resizeSelection(int offset, int end, int extraEndVirt,
1697: boolean rect) {
1698: Selection s = selectionManager.getSelectionAtOffset(offset);
1699: if (s != null) {
1700: invalidateLineRange(s.startLine, s.endLine);
1701: selectionManager.removeFromSelection(s);
1702: }
1703:
1704: selectionManager.resizeSelection(offset, end, extraEndVirt,
1705: rect);
1706: fireCaretEvent();
1707: } //}}}
1708:
1709: //{{{ extendSelection() method
1710: /**
1711: * Extends the selection at the specified offset, or creates a new
1712: * one if there is no selection at the specified offset. This is
1713: * different from resizing in that the new chunk is added to the
1714: * selection in question, instead of replacing it.
1715: * @param offset The offset
1716: * @param end The new selection end
1717: * @since jEdit 3.2pre1
1718: */
1719: public void extendSelection(int offset, int end) {
1720: extendSelection(offset, end, 0, 0);
1721: } //}}}
1722:
1723: //{{{ extendSelection() method
1724: /**
1725: * Extends the selection at the specified offset, or creates a new
1726: * one if there is no selection at the specified offset. This is
1727: * different from resizing in that the new chunk is added to the
1728: * selection in question, instead of replacing it.
1729: * @param offset The offset
1730: * @param end The new selection end
1731: * @param extraStartVirt Extra virtual space at the start
1732: * @param extraEndVirt Extra virtual space at the end
1733: * @since jEdit 4.2pre1
1734: */
1735: public void extendSelection(int offset, int end,
1736: int extraStartVirt, int extraEndVirt) {
1737: Selection s = getSelectionAtOffset(offset);
1738: if (s != null) {
1739: invalidateLineRange(s.startLine, s.endLine);
1740: selectionManager.removeFromSelection(s);
1741:
1742: if (offset == s.start) {
1743: offset = end;
1744: end = s.end;
1745: } else if (offset == s.end) {
1746: offset = s.start;
1747: }
1748: }
1749:
1750: if (end < offset) {
1751: int tmp = end;
1752: end = offset;
1753: offset = tmp;
1754: }
1755:
1756: if (rectangularSelectionMode) {
1757: s = new Selection.Rect(offset, end);
1758: ((Selection.Rect) s).extraStartVirt = extraStartVirt;
1759: ((Selection.Rect) s).extraEndVirt = extraEndVirt;
1760: } else
1761: s = new Selection.Range(offset, end);
1762:
1763: selectionManager.addToSelection(s);
1764: fireCaretEvent();
1765:
1766: if (rectangularSelectionMode && extraEndVirt != 0) {
1767: int line = getLineOfOffset(end);
1768: scrollTo(line, getLineLength(line) + extraEndVirt, false);
1769: }
1770: } //}}}
1771:
1772: //{{{ getSelectedText() method
1773: /**
1774: * Returns the text in the specified selection.
1775: * @param s The selection
1776: * @since jEdit 3.2pre1
1777: */
1778: public String getSelectedText(Selection s) {
1779: StringBuffer buf = new StringBuffer(s.end - s.start);
1780: s.getText(buffer, buf);
1781: return buf.toString();
1782: } //}}}
1783:
1784: //{{{ getSelectedText() method
1785: /**
1786: * Returns the text in all active selections.
1787: * @param separator The string to insert between each text chunk
1788: * (for example, a newline)
1789: * @since jEdit 3.2pre1
1790: */
1791: public String getSelectedText(String separator) {
1792: Selection[] sel = selectionManager.getSelection();
1793: if (sel.length == 0)
1794: return null;
1795:
1796: StringBuffer buf = new StringBuffer();
1797: for (int i = 0; i < sel.length; i++) {
1798: if (i != 0)
1799: buf.append(separator);
1800:
1801: sel[i].getText(buffer, buf);
1802: }
1803:
1804: return buf.toString();
1805: } //}}}
1806:
1807: //{{{ getSelectedText() method
1808: /**
1809: * Returns the text in all active selections, with a newline
1810: * between each text chunk.
1811: */
1812: public String getSelectedText() {
1813: return getSelectedText("\n");
1814: } //}}}
1815:
1816: //{{{ setSelectedText() method
1817: /**
1818: * Replaces the selection with the specified text.
1819: * @param s The selection
1820: * @param selectedText The new text
1821: * @since jEdit 3.2pre1
1822: */
1823: public void setSelectedText(Selection s, String selectedText) {
1824: if (!isEditable()) {
1825: throw new InternalError("Text component" + " read only");
1826: }
1827:
1828: try {
1829: buffer.beginCompoundEdit();
1830:
1831: moveCaretPosition(s.setText(buffer, selectedText));
1832: }
1833: // No matter what happends... stops us from leaving buffer
1834: // in a bad state
1835: finally {
1836: buffer.endCompoundEdit();
1837: }
1838:
1839: // no no no!!!!
1840: //selectNone();
1841: } //}}}
1842:
1843: //{{{ setSelectedText() method
1844: /**
1845: * Replaces the selection at the caret with the specified text.
1846: * If there is no selection at the caret, the text is inserted at
1847: * the caret position.
1848: */
1849: public void setSelectedText(String selectedText) {
1850: int newCaret = replaceSelection(selectedText);
1851: if (newCaret != -1)
1852: moveCaretPosition(newCaret);
1853: selectNone();
1854: } //}}}
1855:
1856: //{{{ setSelectedText() method
1857: /**
1858: * Replaces the selection at the caret with the specified text.
1859: * If there is no selection at the caret, the text is inserted at
1860: * the caret position.
1861: * @param selectedText The new selection
1862: * @param moveCaret Move caret to insertion location if necessary
1863: * @since jEdit 4.2pre5
1864: */
1865: public void setSelectedText(String selectedText, boolean moveCaret) {
1866: int newCaret = replaceSelection(selectedText);
1867: if (moveCaret && newCaret != -1)
1868: moveCaretPosition(newCaret);
1869: selectNone();
1870: } //}}}
1871:
1872: //{{{ replaceSelection() method
1873: /**
1874: * Set the selection, but does not deactivate it, and does not move the
1875: * caret.
1876: *
1877: * Please use {@link #setSelectedText(String)} instead.
1878: *
1879: * @param selectedText The new selection
1880: * @return The new caret position
1881: * @since 4.3pre1
1882: */
1883: public int replaceSelection(String selectedText) {
1884: if (!isEditable())
1885: throw new RuntimeException("Text component read only");
1886:
1887: int newCaret = -1;
1888:
1889: if (getSelectionCount() == 0) {
1890: // for compatibility with older jEdit versions
1891: buffer.insert(caret, selectedText);
1892: } else {
1893: try {
1894:
1895: buffer.beginCompoundEdit();
1896:
1897: Selection[] selection = getSelection();
1898: for (int i = 0; i < selection.length; i++)
1899: newCaret = selection[i].setText(buffer,
1900: selectedText);
1901: } finally {
1902: buffer.endCompoundEdit();
1903: }
1904: }
1905:
1906: return newCaret;
1907: } //}}}
1908:
1909: //{{{ getSelectedLines() method
1910: /**
1911: * Returns a sorted array of line numbers on which a selection or
1912: * selections are present.<p>
1913: *
1914: * This method is the most convenient way to iterate through selected
1915: * lines in a buffer. The line numbers in the array returned by this
1916: * method can be passed as a parameter to such methods as
1917: * {@link JEditBuffer#getLineText(int)}.
1918: *
1919: * @since jEdit 3.2pre1
1920: */
1921: public int[] getSelectedLines() {
1922: if (selectionManager.getSelectionCount() == 0)
1923: return new int[] { caretLine };
1924:
1925: return selectionManager.getSelectedLines();
1926: } //}}}
1927:
1928: //}}}
1929:
1930: //{{{ Caret
1931:
1932: //{{{ caretAutoScroll() method
1933: /**
1934: * Return if change in buffer should scroll this text area.
1935: * @since jEdit 4.3pre2
1936: */
1937: public boolean caretAutoScroll() {
1938: return focusedComponent == this ;
1939: } //}}}
1940:
1941: //{{{ addStructureMatcher() method
1942: /**
1943: * Adds a structure matcher.
1944: * @since jEdit 4.2pre3
1945: */
1946: public void addStructureMatcher(StructureMatcher matcher) {
1947: structureMatchers.add(matcher);
1948: } //}}}
1949:
1950: //{{{ removeStructureMatcher() method
1951: /**
1952: * Removes a structure matcher.
1953: * @since jEdit 4.2pre3
1954: */
1955: public void removeStructureMatcher(StructureMatcher matcher) {
1956: structureMatchers.remove(matcher);
1957: } //}}}
1958:
1959: //{{{ getStructureMatchStart() method
1960: /**
1961: * Returns the structure element (bracket, or XML tag, etc) matching the
1962: * one before the caret.
1963: * @since jEdit 4.2pre3
1964: */
1965: public StructureMatcher.Match getStructureMatch() {
1966: return match;
1967: } //}}}
1968:
1969: //{{{ blinkCaret() method
1970: /**
1971: * Blinks the caret.
1972: */
1973: public final void blinkCaret() {
1974: if (caretBlinks) {
1975: blink = !blink;
1976: invalidateLine(caretLine);
1977: } else
1978: blink = true;
1979: } //}}}
1980:
1981: //{{{ centerCaret() method
1982: /**
1983: * Centers the caret on the screen.
1984: * @since jEdit 2.7pre2
1985: */
1986: public void centerCaret() {
1987: int offset = getScreenLineStartOffset(visibleLines >> 1);
1988: if (offset == -1)
1989: getToolkit().beep();
1990: else
1991: setCaretPosition(offset);
1992: } //}}}
1993:
1994: //{{{ setCaretPosition() method
1995: /**
1996: * Sets the caret position and deactivates the selection.
1997: * @param newCaret The caret position
1998: */
1999: public void setCaretPosition(int newCaret) {
2000: selectNone();
2001: moveCaretPosition(newCaret, true);
2002: } //}}}
2003:
2004: //{{{ setCaretPosition() method
2005: /**
2006: * Sets the caret position and deactivates the selection.
2007: * @param newCaret The caret position
2008: * @param doElectricScroll Do electric scrolling?
2009: */
2010: public void setCaretPosition(int newCaret, boolean doElectricScroll) {
2011: selectNone();
2012: moveCaretPosition(newCaret, doElectricScroll);
2013: } //}}}
2014:
2015: //{{{ moveCaretPosition() method
2016: /**
2017: * Sets the caret position without deactivating the selection.
2018: * @param newCaret The caret position
2019: */
2020: public void moveCaretPosition(int newCaret) {
2021: moveCaretPosition(newCaret, true);
2022: } //}}}
2023:
2024: //{{{ moveCaretPosition() method
2025: /**
2026: * Sets the caret position without deactivating the selection.
2027: * @param newCaret The caret position
2028: * @param doElectricScroll Do electric scrolling?
2029: */
2030: public void moveCaretPosition(int newCaret, boolean doElectricScroll) {
2031: moveCaretPosition(newCaret, doElectricScroll ? ELECTRIC_SCROLL
2032: : NORMAL_SCROLL);
2033: } //}}}
2034:
2035: //{{{ moveCaretPosition() method
2036: public static final int NO_SCROLL = 0;
2037: public static final int NORMAL_SCROLL = 1;
2038: public static final int ELECTRIC_SCROLL = 2;
2039:
2040: /**
2041: * Sets the caret position without deactivating the selection.
2042: * @param newCaret The caret position
2043: * @param scrollMode The scroll mode (NO_SCROLL, NORMAL_SCROLL, or
2044: * ELECTRIC_SCROLL).
2045: * @since jEdit 4.2pre1
2046: */
2047: public void moveCaretPosition(int newCaret, int scrollMode) {
2048: if (newCaret < 0 || newCaret > buffer.getLength()) {
2049: throw new IllegalArgumentException("caret out of bounds: "
2050: + newCaret);
2051: }
2052:
2053: int oldCaretLine = caretLine;
2054:
2055: if (caret == newCaret)
2056: finishCaretUpdate(oldCaretLine, scrollMode, false);
2057: else {
2058: caret = newCaret;
2059: caretLine = getLineOfOffset(newCaret);
2060:
2061: magicCaret = -1;
2062:
2063: finishCaretUpdate(oldCaretLine, scrollMode, true);
2064: }
2065: } //}}}
2066:
2067: //{{{ getCaretPosition() method
2068: /**
2069: * Returns a zero-based index of the caret position.
2070: */
2071: public int getCaretPosition() {
2072: return caret;
2073: } //}}}
2074:
2075: //{{{ getCaretLine() method
2076: /**
2077: * Returns the line number containing the caret.
2078: */
2079: public int getCaretLine() {
2080: return caretLine;
2081: } //}}}
2082:
2083: //{{{ getMagicCaretPosition() method
2084: /**
2085: * Returns an internal position used to keep the caret in one
2086: * column while moving around lines of varying lengths.
2087: * @since jEdit 4.2pre1
2088: */
2089: public int getMagicCaretPosition() {
2090: if (magicCaret == -1) {
2091: magicCaret = chunkCache.subregionOffsetToX(caretLine, caret
2092: - getLineStartOffset(caretLine));
2093: }
2094:
2095: return magicCaret;
2096: } //}}}
2097:
2098: //{{{ setMagicCaretPosition() method
2099: /**
2100: * Sets the `magic' caret position. This can be used to preserve
2101: * the column position when moving up and down lines.
2102: * @param magicCaret The magic caret position
2103: * @since jEdit 4.2pre1
2104: */
2105: public void setMagicCaretPosition(int magicCaret) {
2106: this .magicCaret = magicCaret;
2107: } //}}}
2108:
2109: //{{{ addCaretListener() method
2110: /**
2111: * Adds a caret change listener to this text area.
2112: * @param listener The listener
2113: */
2114: public final void addCaretListener(CaretListener listener) {
2115: listenerList.add(CaretListener.class, listener);
2116: } //}}}
2117:
2118: //{{{ removeCaretListener() method
2119: /**
2120: * Removes a caret change listener from this text area.
2121: * @param listener The listener
2122: */
2123: public final void removeCaretListener(CaretListener listener) {
2124: listenerList.remove(CaretListener.class, listener);
2125: } //}}}
2126:
2127: //{{{ goToNextBracket() method
2128: /**
2129: * Moves the caret to the next closing bracket.
2130: * @param select true if you want to extend selection
2131: * @since jEdit 2.7pre2.
2132: */
2133: public void goToNextBracket(boolean select) {
2134: int newCaret = -1;
2135:
2136: if (caret != buffer.getLength()) {
2137: String text = getText(caret, buffer.getLength() - caret - 1);
2138:
2139: loop: for (int i = 0; i < text.length(); i++) {
2140: switch (text.charAt(i)) {
2141: case ')':
2142: case ']':
2143: case '}':
2144: newCaret = caret + i + 1;
2145: break loop;
2146: }
2147: }
2148: }
2149:
2150: if (newCaret == -1)
2151: getToolkit().beep();
2152: else {
2153: if (select)
2154: extendSelection(caret, newCaret);
2155: else if (!multi)
2156: selectNone();
2157: moveCaretPosition(newCaret);
2158: }
2159: } //}}}
2160:
2161: //{{{ goToNextCharacter() method
2162: /**
2163: * Moves the caret to the next character.
2164: * @param select true if you want to extend selection
2165: * @since jEdit 2.7pre2.
2166: */
2167: public void goToNextCharacter(boolean select) {
2168: Selection s = getSelectionAtOffset(caret);
2169:
2170: if (!select && s instanceof Selection.Range) {
2171: if (multi) {
2172: if (caret != s.end) {
2173: moveCaretPosition(s.end);
2174: return;
2175: }
2176: } else {
2177: setCaretPosition(s.end);
2178: return;
2179: }
2180: }
2181:
2182: int extraStartVirt, extraEndVirt;
2183: if (s instanceof Selection.Rect) {
2184: extraStartVirt = ((Selection.Rect) s).extraStartVirt;
2185: extraEndVirt = ((Selection.Rect) s).extraEndVirt;
2186: } else {
2187: extraStartVirt = 0;
2188: extraEndVirt = 0;
2189: }
2190:
2191: int newCaret = caret;
2192:
2193: if (caret == buffer.getLength()) {
2194: if (select
2195: && (rectangularSelectionMode || s instanceof Selection.Rect)) {
2196: if (s != null && caret == s.start)
2197: extraStartVirt++;
2198: else
2199: extraEndVirt++;
2200: } else {
2201: getToolkit().beep();
2202: return;
2203: }
2204: } else if (caret == getLineEndOffset(caretLine) - 1) {
2205: if (select
2206: && (rectangularSelectionMode || s instanceof Selection.Rect)) {
2207: if (s != null && caret == s.start)
2208: extraStartVirt++;
2209: else
2210: extraEndVirt++;
2211: } else {
2212: int line = displayManager.getNextVisibleLine(caretLine);
2213: if (line == -1) {
2214: getToolkit().beep();
2215: return;
2216: } else
2217: newCaret = getLineStartOffset(line);
2218: }
2219: } else
2220: newCaret = caret + 1;
2221:
2222: if (select)
2223: extendSelection(caret, newCaret, extraStartVirt,
2224: extraEndVirt);
2225: else if (!multi)
2226: selectNone();
2227:
2228: moveCaretPosition(newCaret);
2229: } //}}}
2230:
2231: //{{{ goToNextLine() method
2232: /**
2233: * Move the caret to the next line.
2234: * @param select true if you want to extend selection
2235: * @since jEdit 2.7pre2
2236: */
2237: public void goToNextLine(boolean select) {
2238: Selection s = getSelectionAtOffset(caret);
2239: boolean rectSelect = s == null ? rectangularSelectionMode
2240: : s instanceof Selection.Rect;
2241: int magic = getMagicCaretPosition();
2242: int newCaret = chunkCache.getBelowPosition(caretLine, caret
2243: - buffer.getLineStartOffset(caretLine), magic + 1,
2244: rectSelect && select);
2245: if (newCaret == -1) {
2246: int end = getLineEndOffset(caretLine) - 1;
2247: if (caret == end) {
2248: getToolkit().beep();
2249: return;
2250: } else
2251: newCaret = end;
2252: }
2253:
2254: _changeLine(select, newCaret);
2255:
2256: setMagicCaretPosition(magic);
2257: }//}}}
2258:
2259: //{{{ goToNextPage() method
2260: /**
2261: * Moves the caret to the next screenful.
2262: * @param select true if you want to extend selection
2263: * @since jEdit 2.7pre2.
2264: */
2265: public void goToNextPage(boolean select) {
2266: scrollToCaret(false);
2267: int magic = getMagicCaretPosition();
2268: if (caretLine < displayManager.getFirstVisibleLine()) {
2269: caretLine = displayManager.getNextVisibleLine(caretLine);
2270: }
2271:
2272: int newCaret;
2273:
2274: if (getFirstLine() + getVisibleLines() >= displayManager
2275: .getScrollLineCount()) {
2276: int lastVisibleLine = displayManager.getLastVisibleLine();
2277: newCaret = getLineEndOffset(lastVisibleLine) - 1;
2278: } else {
2279: int caretScreenLine = getScreenLineOfOffset(caret);
2280:
2281: scrollDownPage();
2282:
2283: newCaret = xToScreenLineOffset(caretScreenLine, magic, true);
2284: }
2285:
2286: if (select)
2287: extendSelection(caret, newCaret);
2288: else if (!multi)
2289: selectNone();
2290:
2291: moveCaretPosition(newCaret, false);
2292:
2293: setMagicCaretPosition(magic);
2294: } //}}}
2295:
2296: //{{{ goToNextParagraph() method
2297: /**
2298: * Moves the caret to the start of the next paragraph.
2299: * @param select true if you want to extend selection
2300: * @since jEdit 2.7pre2
2301: */
2302: public void goToNextParagraph(boolean select) {
2303: int lineNo = getCaretLine();
2304:
2305: int newCaret = getBufferLength();
2306:
2307: boolean foundBlank = false;
2308:
2309: loop: for (int i = lineNo + 1; i < getLineCount(); i++) {
2310: if (!displayManager.isLineVisible(i))
2311: continue;
2312:
2313: getLineText(i, lineSegment);
2314:
2315: for (int j = 0; j < lineSegment.count; j++) {
2316: switch (lineSegment.array[lineSegment.offset + j]) {
2317: case ' ':
2318: case '\t':
2319: break;
2320: default:
2321: if (foundBlank) {
2322: newCaret = getLineStartOffset(i);
2323: break loop;
2324: } else
2325: continue loop;
2326: }
2327: }
2328:
2329: foundBlank = true;
2330: }
2331:
2332: if (select)
2333: extendSelection(caret, newCaret);
2334: else if (!multi)
2335: selectNone();
2336: moveCaretPosition(newCaret);
2337: } //}}}
2338:
2339: //{{{ goToNextWord() method
2340: /**
2341: * Moves the caret to the start of the next word.
2342: * Note that if the "view.eatWhitespace" boolean propery is false,
2343: * this method moves the caret to the end of the current word instead.
2344: * @param select true if you want to extend selection
2345: * @since jEdit 2.7pre2
2346: */
2347: public void goToNextWord(boolean select) {
2348: goToNextWord(select, false);
2349: } //}}}
2350:
2351: //{{{ goToNextWord() method
2352: /**
2353: * Moves the caret to the start of the next word.
2354: * @since jEdit 4.1pre5
2355: */
2356: public void goToNextWord(boolean select, boolean eatWhitespace) {
2357: int lineStart = getLineStartOffset(caretLine);
2358: int newCaret = caret - lineStart;
2359: String lineText = getLineText(caretLine);
2360:
2361: if (newCaret == lineText.length()) {
2362: int nextLine = displayManager.getNextVisibleLine(caretLine);
2363: if (nextLine == -1) {
2364: getToolkit().beep();
2365: return;
2366: }
2367:
2368: newCaret = getLineStartOffset(nextLine);
2369: } else {
2370: String noWordSep = buffer.getStringProperty("noWordSep");
2371: boolean camelCasedWords = buffer
2372: .getBooleanProperty("camelCasedWords");
2373: newCaret = TextUtilities.findWordEnd(lineText,
2374: newCaret + 1, noWordSep, true, camelCasedWords,
2375: eatWhitespace);
2376:
2377: newCaret += lineStart;
2378: }
2379:
2380: if (select)
2381: extendSelection(caret, newCaret);
2382: else if (!multi)
2383: selectNone();
2384: moveCaretPosition(newCaret);
2385: } //}}}
2386:
2387: //{{{ goToPrevBracket() method
2388: /**
2389: * Moves the caret to the previous bracket.
2390: * @param select true if you want to extend selection
2391: * @since jEdit 2.7pre2
2392: */
2393: public void goToPrevBracket(boolean select) {
2394: String text = getText(0, caret);
2395:
2396: int newCaret = -1;
2397:
2398: loop: for (int i = getCaretPosition() - 1; i >= 0; i--) {
2399: switch (text.charAt(i)) {
2400: case '(':
2401: case '[':
2402: case '{':
2403: newCaret = i;
2404: break loop;
2405: }
2406: }
2407:
2408: if (newCaret == -1)
2409: getToolkit().beep();
2410: else {
2411: if (select)
2412: extendSelection(caret, newCaret);
2413: else if (!multi)
2414: selectNone();
2415: moveCaretPosition(newCaret);
2416: }
2417: } //}}}
2418:
2419: //{{{ goToPrevCharacter() method
2420: /**
2421: * Moves the caret to the previous character.
2422: * @param select true if you want to extend selection
2423: * @since jEdit 2.7pre2.
2424: */
2425: public void goToPrevCharacter(boolean select) {
2426: Selection s = getSelectionAtOffset(caret);
2427:
2428: if (caret == 0) {
2429: getToolkit().beep();
2430: return;
2431: }
2432:
2433: if (!select && s instanceof Selection.Range) {
2434: if (multi) {
2435: if (caret != s.start) {
2436: moveCaretPosition(s.start);
2437: return;
2438: }
2439: } else {
2440: setCaretPosition(s.start);
2441: return;
2442: }
2443: }
2444:
2445: int extraStartVirt = 0;
2446: int extraEndVirt = 0;
2447: int newCaret = caret;
2448:
2449: if (select && caret == getLineEndOffset(caretLine) - 1) {
2450: if (s instanceof Selection.Rect) {
2451: extraStartVirt = ((Selection.Rect) s).extraStartVirt;
2452: extraEndVirt = ((Selection.Rect) s).extraEndVirt;
2453: if (caret == s.start) {
2454: if (extraStartVirt == 0)
2455: newCaret = caret - 1;
2456: else
2457: extraStartVirt--;
2458: } else {
2459: if (extraEndVirt == 0)
2460: newCaret = caret - 1;
2461: else
2462: extraEndVirt--;
2463: }
2464: } else
2465: newCaret = caret - 1;
2466: } else if (caret == getLineStartOffset(caretLine)) {
2467: int line = displayManager.getPrevVisibleLine(caretLine);
2468: if (line == -1) {
2469: getToolkit().beep();
2470: return;
2471: }
2472: newCaret = getLineEndOffset(line) - 1;
2473: } else
2474: newCaret = caret - 1;
2475:
2476: if (select)
2477: extendSelection(caret, newCaret, extraStartVirt,
2478: extraEndVirt);
2479: else if (!multi)
2480: selectNone();
2481: moveCaretPosition(newCaret);
2482: } //}}}
2483:
2484: //{{{ goToPrevLine() method
2485: /**
2486: * Moves the caret to the previous line.
2487: * @param select true if you want to extend selection
2488: * @since jEdit 2.7pre2
2489: */
2490: public void goToPrevLine(boolean select) {
2491: Selection s = getSelectionAtOffset(caret);
2492: boolean rectSelect = s == null ? rectangularSelectionMode
2493: : s instanceof Selection.Rect;
2494: int magic = getMagicCaretPosition();
2495:
2496: int newCaret = chunkCache.getAbovePosition(caretLine, caret
2497: - buffer.getLineStartOffset(caretLine), magic + 1,
2498: rectSelect && select);
2499: if (newCaret == -1) {
2500: int start = getLineStartOffset(caretLine);
2501: if (caret == start) {
2502: getToolkit().beep();
2503: return;
2504: } else
2505: newCaret = start;
2506: }
2507:
2508: _changeLine(select, newCaret);
2509:
2510: setMagicCaretPosition(magic);
2511: } //}}}
2512:
2513: //{{{ goToPrevPage() method
2514: /**
2515: * Moves the caret to the previous screenful.
2516: * @param select true if you want to extend selection
2517: * @since jEdit 2.7pre2
2518: */
2519: public void goToPrevPage(boolean select) {
2520: scrollToCaret(false);
2521: int magic = getMagicCaretPosition();
2522:
2523: if (caretLine < displayManager.getFirstVisibleLine()) {
2524: caretLine = displayManager.getNextVisibleLine(caretLine);
2525: }
2526:
2527: int newCaret;
2528:
2529: if (getFirstLine() == 0) {
2530: int firstVisibleLine = displayManager.getFirstVisibleLine();
2531: newCaret = getLineStartOffset(firstVisibleLine);
2532: } else {
2533: int caretScreenLine = getScreenLineOfOffset(caret);
2534:
2535: scrollUpPage();
2536:
2537: newCaret = xToScreenLineOffset(caretScreenLine, magic, true);
2538: }
2539:
2540: if (select)
2541: extendSelection(caret, newCaret);
2542: else if (!multi)
2543: selectNone();
2544: moveCaretPosition(newCaret, false);
2545:
2546: setMagicCaretPosition(magic);
2547: } //}}}
2548:
2549: //{{{ goToPrevParagraph() method
2550: /**
2551: * Moves the caret to the start of the previous paragraph.
2552: * @param select true if you want to extend selection
2553: * @since jEdit 2.7pre2
2554: */
2555: public void goToPrevParagraph(boolean select) {
2556: int lineNo = caretLine;
2557: int newCaret = 0;
2558:
2559: boolean foundBlank = false;
2560:
2561: loop: for (int i = lineNo - 1; i >= 0; i--) {
2562: if (!displayManager.isLineVisible(i))
2563: continue;
2564:
2565: getLineText(i, lineSegment);
2566:
2567: for (int j = 0; j < lineSegment.count; j++) {
2568: switch (lineSegment.array[lineSegment.offset + j]) {
2569: case ' ':
2570: case '\t':
2571: break;
2572: default:
2573: if (foundBlank) {
2574: newCaret = getLineEndOffset(i) - 1;
2575: break loop;
2576: } else
2577: continue loop;
2578: }
2579: }
2580:
2581: foundBlank = true;
2582: }
2583:
2584: if (select)
2585: extendSelection(caret, newCaret);
2586: else if (!multi)
2587: selectNone();
2588: moveCaretPosition(newCaret);
2589: } //}}}
2590:
2591: //{{{ goToPrevWord() method
2592: /**
2593: * Moves the caret to the start of the previous word.
2594: * @param select true if you want to extend selection
2595: * @since jEdit 2.7pre2
2596: */
2597: public void goToPrevWord(boolean select) {
2598: goToPrevWord(select, false);
2599: } //}}}
2600:
2601: //{{{ goToPrevWord() method
2602: /**
2603: * Moves the caret to the start of the previous word.
2604: * @since jEdit 4.1pre5
2605: */
2606: public void goToPrevWord(boolean select, boolean eatWhitespace) {
2607: int lineStart = getLineStartOffset(caretLine);
2608: int newCaret = caret - lineStart;
2609: String lineText = getLineText(caretLine);
2610:
2611: if (newCaret == 0) {
2612: if (lineStart == 0) {
2613: getToolkit().beep();
2614: return;
2615: } else {
2616: int prevLine = displayManager
2617: .getPrevVisibleLine(caretLine);
2618: if (prevLine == -1) {
2619: getToolkit().beep();
2620: return;
2621: }
2622:
2623: newCaret = getLineEndOffset(prevLine) - 1;
2624: }
2625: } else {
2626: String noWordSep = buffer.getStringProperty("noWordSep");
2627: boolean camelCasedWords = buffer
2628: .getBooleanProperty("camelCasedWords");
2629: newCaret = TextUtilities.findWordStart(lineText,
2630: newCaret - 1, noWordSep, true, camelCasedWords,
2631: eatWhitespace);
2632:
2633: newCaret += lineStart;
2634: }
2635:
2636: if (select)
2637: extendSelection(caret, newCaret);
2638: else if (!multi)
2639: selectNone();
2640: moveCaretPosition(newCaret);
2641: } //}}}
2642:
2643: //{{{ smartHome() method
2644: /**
2645: * On subsequent invocations, first moves the caret to the first
2646: * non-whitespace character of the line, then the beginning of the
2647: * line, then to the first visible line.
2648: * @param select true if you want to extend selection
2649: * @since jEdit 4.3pre7
2650: */
2651: public void smartHome(boolean select) {
2652: switch (getInputHandler().getLastActionCount()) {
2653: case 1:
2654: goToStartOfWhiteSpace(select);
2655: break;
2656: case 2:
2657: goToStartOfLine(select);
2658: break;
2659: default: //case 3:
2660: goToFirstVisibleLine(select);
2661: break;
2662: }
2663: } //}}}
2664:
2665: //{{{ smartEnd() method
2666: /**
2667: * On subsequent invocations, first moves the caret to the last
2668: * non-whitespace character of the line, then the end of the
2669: * line, then to the last visible line.
2670: * @param select true if you want to extend selection
2671: * @since jEdit 4.3pre7
2672: */
2673: public void smartEnd(boolean select) {
2674: switch (getInputHandler().getLastActionCount()) {
2675: case 1:
2676: goToEndOfWhiteSpace(select);
2677: break;
2678: case 2:
2679: goToEndOfLine(select);
2680: break;
2681: default: //case 3:
2682: goToLastVisibleLine(select);
2683: break;
2684: }
2685: } //}}}
2686:
2687: //{{{ goToStartOfLine() method
2688: /**
2689: * Moves the caret to the beginning of the current line.
2690: * @param select true if you want to extend selection
2691: * @since jEdit 2.7pre2
2692: */
2693: public void goToStartOfLine(boolean select) {
2694: Selection s = getSelectionAtOffset(caret);
2695: int line = select || s == null ? caretLine : s.startLine;
2696: int newCaret = getLineStartOffset(line);
2697: if (select)
2698: extendSelection(caret, newCaret);
2699: else if (!multi)
2700: selectNone();
2701: moveCaretPosition(newCaret);
2702: } //}}}
2703:
2704: //{{{ goToEndOfLine() method
2705: /**
2706: * Moves the caret to the end of the current line.
2707: * @param select true if you want to extend selection
2708: * @since jEdit 2.7pre2
2709: */
2710: public void goToEndOfLine(boolean select) {
2711: Selection s = getSelectionAtOffset(caret);
2712: int line = select || s == null ? caretLine : s.endLine;
2713: int newCaret = getLineEndOffset(line) - 1;
2714: if (select)
2715: extendSelection(caret, newCaret);
2716: else if (!multi)
2717: selectNone();
2718: moveCaretPosition(newCaret);
2719:
2720: // so that end followed by up arrow will always put caret at
2721: // the end of the previous line, for example
2722: //setMagicCaretPosition(Integer.MAX_VALUE);
2723: } //}}}
2724:
2725: //{{{ goToStartOfWhiteSpace() method
2726: /**
2727: * Moves the caret to the first non-whitespace character of the current
2728: * line.
2729: * @param select true if you want to extend selection
2730: * @since jEdit 2.7pre2
2731: */
2732: public void goToStartOfWhiteSpace(boolean select) {
2733: Selection s = getSelectionAtOffset(caret);
2734: int line, offset;
2735: if (select || s == null) {
2736: line = caretLine;
2737: offset = caret - buffer.getLineStartOffset(line);
2738: } else {
2739: line = s.startLine;
2740: offset = s.start - buffer.getLineStartOffset(line);
2741: }
2742:
2743: int firstIndent = chunkCache.getSubregionStartOffset(line,
2744: offset);
2745: if (firstIndent == getLineStartOffset(line)) {
2746: firstIndent = StandardUtilities
2747: .getLeadingWhiteSpace(getLineText(line));
2748: if (firstIndent == getLineLength(line))
2749: firstIndent = 0;
2750: firstIndent += getLineStartOffset(line);
2751: }
2752:
2753: if (select)
2754: extendSelection(caret, firstIndent);
2755: else if (!multi)
2756: selectNone();
2757: moveCaretPosition(firstIndent);
2758: } //}}}
2759:
2760: //{{{ goToEndOfWhiteSpace() method
2761: /**
2762: * Moves the caret to the last non-whitespace character of the current
2763: * line.
2764: * @param select true if you want to extend selection
2765: * @since jEdit 2.7pre2
2766: */
2767: public void goToEndOfWhiteSpace(boolean select) {
2768: Selection s = getSelectionAtOffset(caret);
2769: int line, offset;
2770: if (select || s == null) {
2771: line = caretLine;
2772: offset = caret - getLineStartOffset(line);
2773: } else {
2774: line = s.endLine;
2775: offset = s.end - getLineStartOffset(line);
2776: }
2777:
2778: int lastIndent = chunkCache.getSubregionEndOffset(line, offset);
2779:
2780: if (lastIndent == getLineEndOffset(line)) {
2781: lastIndent = getLineLength(line)
2782: - StandardUtilities
2783: .getTrailingWhiteSpace(getLineText(line));
2784: if (lastIndent == 0)
2785: lastIndent = getLineLength(line);
2786: lastIndent += getLineStartOffset(line);
2787: } else {
2788: lastIndent--;
2789: }
2790:
2791: if (select)
2792: extendSelection(caret, lastIndent);
2793: else if (!multi)
2794: selectNone();
2795: moveCaretPosition(lastIndent);
2796: } //}}}
2797:
2798: //{{{ goToFirstVisibleLine() method
2799: /**
2800: * Moves the caret to the first visible line.
2801: * @param select true if you want to extend selection
2802: * @since jEdit 2.7pre2
2803: */
2804: public void goToFirstVisibleLine(boolean select) {
2805: int firstVisibleLine = getFirstLine() == 0 ? 0 : electricScroll;
2806: int firstVisible = getScreenLineStartOffset(firstVisibleLine);
2807: if (firstVisible == -1) {
2808: firstVisible = getLineStartOffset(displayManager
2809: .getFirstVisibleLine());
2810: }
2811:
2812: if (select)
2813: extendSelection(caret, firstVisible);
2814: else if (!multi)
2815: selectNone();
2816: moveCaretPosition(firstVisible);
2817: } //}}}
2818:
2819: //{{{ goToLastVisibleLine() method
2820: /**
2821: * Moves the caret to the last visible line.
2822: * @param select true if you want to extend selection
2823: * @since jEdit 2.7pre2
2824: */
2825: public void goToLastVisibleLine(boolean select) {
2826: int lastVisible;
2827:
2828: if (getFirstLine() + visibleLines >= displayManager
2829: .getScrollLineCount()) {
2830: lastVisible = getLineEndOffset(displayManager
2831: .getLastVisibleLine()) - 1;
2832: } else {
2833: lastVisible = visibleLines - electricScroll - 1;
2834: if (lastLinePartial)
2835: lastVisible--;
2836: if (lastVisible < 0)
2837: lastVisible = 0;
2838: lastVisible = getScreenLineEndOffset(lastVisible) - 1;
2839: if (lastVisible == -1) {
2840: lastVisible = getLineEndOffset(displayManager
2841: .getLastVisibleLine()) - 1;
2842: }
2843: }
2844:
2845: if (select)
2846: extendSelection(caret, lastVisible);
2847: else if (!multi)
2848: selectNone();
2849: moveCaretPosition(lastVisible);
2850: } //}}}
2851:
2852: //{{{ goToBufferStart() method
2853: /**
2854: * Moves the caret to the beginning of the buffer.
2855: * @param select true if you want to extend selection
2856: * @since jEdit 4.0pre3
2857: */
2858: public void goToBufferStart(boolean select) {
2859: int start = buffer.getLineStartOffset(displayManager
2860: .getFirstVisibleLine());
2861: if (select)
2862: extendSelection(caret, start);
2863: else if (!multi)
2864: selectNone();
2865: moveCaretPosition(start);
2866: } //}}}
2867:
2868: //{{{ goToBufferEnd() method
2869: /**
2870: * Moves the caret to the end of the buffer.
2871: * @param select true if you want to extend selection
2872: * @since jEdit 4.0pre3
2873: */
2874: public void goToBufferEnd(boolean select) {
2875: int end = buffer.getLineEndOffset(displayManager
2876: .getLastVisibleLine()) - 1;
2877: if (select)
2878: extendSelection(caret, end);
2879: else if (!multi)
2880: selectNone();
2881: moveCaretPosition(end);
2882: } //}}}
2883:
2884: //{{{ goToMatchingBracket() method
2885: /**
2886: * Moves the caret to the bracket matching the one before the caret.
2887: * @since jEdit 2.7pre3
2888: */
2889: public void goToMatchingBracket() {
2890: if (getLineLength(caretLine) != 0) {
2891: int dot = caret - getLineStartOffset(caretLine);
2892:
2893: int bracket = TextUtilities.findMatchingBracket(buffer,
2894: caretLine, Math.max(0, dot - 1));
2895: if (bracket != -1) {
2896: selectNone();
2897: moveCaretPosition(bracket + 1, false);
2898: return;
2899: }
2900: }
2901:
2902: getToolkit().beep();
2903: } //}}}
2904:
2905: //}}}
2906:
2907: //{{{ User input
2908:
2909: //{{{ userInput() method
2910: /**
2911: * Handles the insertion of the specified character. It performs the
2912: * following operations above and beyond simply inserting the text:
2913: * <ul>
2914: * <li>Inserting a TAB with a selection will shift to the right
2915: * <li>Inserting a BACK_SPACE or a DELETE will remove a character
2916: * <li>Inserting an indent open/close bracket will re-indent the current
2917: * line as necessary
2918: * </ul>
2919: *
2920: * @param ch The character
2921: * @see #setSelectedText(String)
2922: * @see #isOverwriteEnabled()
2923: * @since jEdit 4.3pre7
2924: */
2925: public void userInput(char ch) {
2926: if (!isEditable()) {
2927: getToolkit().beep();
2928: return;
2929: }
2930:
2931: /* Null before addNotify() */
2932: if (hiddenCursor != null)
2933: getPainter().setCursor(hiddenCursor);
2934:
2935: switch (ch) {
2936: case '\t':
2937: userInputTab();
2938: break;
2939: case '\b':
2940: backspace();
2941: break;
2942: case '\u007F':
2943: delete();
2944: break;
2945: default:
2946: boolean indent = buffer.isElectricKey(ch, caretLine);
2947: String str = String.valueOf(ch);
2948: if (getSelectionCount() == 0) {
2949: if (!doWordWrap(ch == ' '))
2950: insert(str, indent);
2951: } else
2952: replaceSelection(str);
2953: break;
2954: }
2955: } //}}}
2956:
2957: //{{{ isOverwriteEnabled() method
2958: /**
2959: * Returns true if overwrite mode is enabled, false otherwise.
2960: */
2961: public final boolean isOverwriteEnabled() {
2962: return overwrite;
2963: } //}}}
2964:
2965: //{{{ setOverwriteEnabled() method
2966: /**
2967: * Sets overwrite mode.
2968: */
2969: public final void setOverwriteEnabled(boolean overwrite) {
2970: blink = true;
2971: caretTimer.restart();
2972:
2973: this .overwrite = overwrite;
2974: invalidateLine(caretLine);
2975: fireStatusChanged(StatusListener.OVERWRITE_CHANGED, overwrite);
2976: } //}}}
2977:
2978: //{{{ toggleOverwriteEnabled() method
2979: /**
2980: * Toggles overwrite mode.
2981: * @since jEdit 2.7pre2
2982: */
2983: public final void toggleOverwriteEnabled() {
2984: setOverwriteEnabled(!overwrite);
2985: } //}}}
2986:
2987: //{{{ backspace() method
2988: /**
2989: * Deletes the character before the caret, or the selection, if one is
2990: * active.
2991: * @since jEdit 2.7pre2
2992: */
2993: public void backspace() {
2994: delete(false);
2995: } //}}}
2996:
2997: //{{{ backspaceWord() method
2998: /**
2999: * Deletes the word before the caret.
3000: * @since jEdit 2.7pre2
3001: */
3002: public void backspaceWord() {
3003: backspaceWord(false);
3004: } //}}}
3005:
3006: //{{{ backspaceWord() method
3007: /**
3008: * Deletes the word before the caret.
3009: * @param eatWhitespace If true, will eat whitespace
3010: * @since jEdit 4.2pre5
3011: */
3012: public void backspaceWord(boolean eatWhitespace) {
3013: if (!buffer.isEditable()) {
3014: getToolkit().beep();
3015: return;
3016: }
3017:
3018: if (getSelectionCount() != 0) {
3019: setSelectedText("");
3020: return;
3021: }
3022:
3023: int lineStart = getLineStartOffset(caretLine);
3024: int _caret = caret - lineStart;
3025:
3026: String lineText = getLineText(caretLine);
3027:
3028: if (_caret == 0) {
3029: if (lineStart == 0) {
3030: getToolkit().beep();
3031: return;
3032: }
3033: _caret--;
3034: } else {
3035: String noWordSep = buffer.getStringProperty("noWordSep");
3036: boolean camelCasedWords = buffer
3037: .getBooleanProperty("camelCasedWords");
3038: _caret = TextUtilities.findWordStart(lineText, _caret - 1,
3039: noWordSep, true, camelCasedWords, eatWhitespace);
3040: }
3041:
3042: buffer.remove(_caret + lineStart, caret - (_caret + lineStart));
3043: } //}}}
3044:
3045: //{{{ delete() method
3046: /**
3047: * Deletes the character after the caret.
3048: * @since jEdit 2.7pre2
3049: */
3050: public void delete() {
3051: delete(true);
3052: } //}}}
3053:
3054: //{{{ deleteToEndOfLine() method
3055: /**
3056: * Deletes from the caret to the end of the current line.
3057: * @since jEdit 2.7pre2
3058: */
3059: public void deleteToEndOfLine() {
3060: if (!buffer.isEditable()) {
3061: getToolkit().beep();
3062: return;
3063: }
3064:
3065: buffer.remove(caret, getLineEndOffset(caretLine) - caret - 1);
3066: } //}}}
3067:
3068: //{{{ deleteLine() method
3069: /**
3070: * Deletes the line containing the caret.
3071: * @since jEdit 2.7pre2
3072: */
3073: public void deleteLine() {
3074: if (!buffer.isEditable()) {
3075: getToolkit().beep();
3076: return;
3077: }
3078:
3079: int x = chunkCache.subregionOffsetToX(caretLine, caret
3080: - getLineStartOffset(caretLine));
3081: int[] lines = getSelectedLines();
3082:
3083: try {
3084: buffer.beginCompoundEdit();
3085:
3086: for (int i = lines.length - 1; i >= 0; i--) {
3087: int start = getLineStartOffset(lines[i]);
3088: int end = getLineEndOffset(lines[i]);
3089: if (end > buffer.getLength()) {
3090: if (start != 0)
3091: start--;
3092: end--;
3093: }
3094: buffer.remove(start, end - start);
3095: }
3096: } finally {
3097: buffer.endCompoundEdit();
3098: }
3099:
3100: int lastLine = displayManager.getLastVisibleLine();
3101:
3102: if (caretLine == lastLine) {
3103: int offset = chunkCache.xToSubregionOffset(lastLine, 0, x,
3104: true);
3105: setCaretPosition(buffer.getLineStartOffset(lastLine)
3106: + offset);
3107: } else {
3108: int offset = chunkCache.xToSubregionOffset(caretLine, 0, x,
3109: true);
3110: setCaretPosition(getLineStartOffset(caretLine) + offset);
3111: }
3112: } //}}}
3113:
3114: //{{{ deleteParagraph() method
3115: /**
3116: * Deletes the paragraph containing the caret.
3117: * @since jEdit 2.7pre2
3118: */
3119: public void deleteParagraph() {
3120: if (!buffer.isEditable()) {
3121: getToolkit().beep();
3122: return;
3123: }
3124:
3125: // find the beginning of the paragraph.
3126: int start = 0;
3127: for (int i = caretLine - 1; i >= 0; i--) {
3128: if (lineContainsSpaceAndTabs(i)) {
3129: start = getLineStartOffset(i);
3130: break;
3131: }
3132: }
3133:
3134: // Find the end of the paragraph
3135: int end = buffer.getLength();
3136: for (int i = caretLine + 1; i < getLineCount(); i++) {
3137: //if(!displayManager.isLineVisible(i))
3138: // continue loop;
3139:
3140: if (lineContainsSpaceAndTabs(i)) {
3141: end = getLineEndOffset(i) - 1;
3142: break;
3143: }
3144: }
3145:
3146: buffer.remove(start, end - start);
3147: } //}}}
3148:
3149: //{{{ deleteToStartOfLine() method
3150: /**
3151: * Deletes from the caret to the beginning of the current line.
3152: * @since jEdit 2.7pre2
3153: */
3154: public void deleteToStartOfLine() {
3155: if (!buffer.isEditable()) {
3156: getToolkit().beep();
3157: return;
3158: }
3159:
3160: buffer.remove(getLineStartOffset(caretLine), caret
3161: - getLineStartOffset(caretLine));
3162: } //}}}
3163:
3164: //{{{ deleteWord() method
3165: /**
3166: * Deletes the word in front of the caret.
3167: * @since jEdit 2.7pre2
3168: */
3169: public void deleteWord() {
3170: deleteWord(false);
3171: } //}}}
3172:
3173: //{{{ deleteWord() method
3174: /**
3175: * Deletes the word in front of the caret.
3176: *
3177: . * @param eatWhitespace If true, will eat whitespace
3178: * @since jEdit 4.2pre5
3179: */
3180: public void deleteWord(boolean eatWhitespace) {
3181: if (!buffer.isEditable()) {
3182: getToolkit().beep();
3183: return;
3184: }
3185:
3186: if (getSelectionCount() != 0) {
3187: setSelectedText("");
3188: return;
3189: }
3190:
3191: int lineStart = getLineStartOffset(caretLine);
3192: int _caret = caret - lineStart;
3193:
3194: String lineText = getLineText(caretLine);
3195:
3196: if (_caret == lineText.length()) {
3197: if (lineStart + _caret == buffer.getLength()) {
3198: getToolkit().beep();
3199: return;
3200: }
3201: _caret++;
3202: } else {
3203: String noWordSep = buffer.getStringProperty("noWordSep");
3204: boolean camelCasedWords = buffer
3205: .getBooleanProperty("camelCasedWords");
3206: _caret = TextUtilities.findWordEnd(lineText, _caret + 1,
3207: noWordSep, true, camelCasedWords, eatWhitespace);
3208: }
3209:
3210: buffer.remove(caret, (_caret + lineStart) - caret);
3211: } //}}}
3212:
3213: //{{{ isMultipleSelectionEnabled() method
3214: /**
3215: * Returns if multiple selection is enabled.
3216: * @since jEdit 3.2pre1
3217: */
3218: public final boolean isMultipleSelectionEnabled() {
3219: return multi;
3220: } //}}}
3221:
3222: //{{{ toggleMultipleSelectionEnabled() method
3223: /**
3224: * Toggles multiple selection.
3225: * @since jEdit 3.2pre1
3226: */
3227: public final void toggleMultipleSelectionEnabled() {
3228: setMultipleSelectionEnabled(!multi);
3229: } //}}}
3230:
3231: //{{{ setMultipleSelectionEnabled() method
3232: /**
3233: * Set multiple selection on or off according to the value of
3234: * <code>multi</code>. This only affects the ability to
3235: * make multiple selections in the user interface; macros and plugins
3236: * can manipulate them regardless of the setting of this flag. In fact,
3237: * in most cases, calling this method should not be necessary.
3238: *
3239: * @param multi Should multiple selection be enabled?
3240: * @since jEdit 3.2pre1
3241: */
3242: public final void setMultipleSelectionEnabled(boolean multi) {
3243: this .multi = multi;
3244: fireStatusChanged(StatusListener.MULTI_SELECT_CHANGED, multi);
3245: painter.repaint();
3246: } //}}}
3247:
3248: //{{{ isRectangularSelectionEnabled() method
3249: /**
3250: * Returns if rectangular selection is enabled.
3251: * @since jEdit 4.2pre1
3252: */
3253: public final boolean isRectangularSelectionEnabled() {
3254: return rectangularSelectionMode;
3255: } //}}}
3256:
3257: //{{{ toggleRectangularSelectionEnabled() method
3258: /**
3259: * Toggles rectangular selection.
3260: * @since jEdit 4.2pre1
3261: */
3262: public final void toggleRectangularSelectionEnabled() {
3263: setRectangularSelectionEnabled(!rectangularSelectionMode);
3264:
3265: if (getSelectionCount() == 1) {
3266: Selection s = getSelection(0);
3267: removeFromSelection(s);
3268: if (rectangularSelectionMode) {
3269: addToSelection(new Selection.Rect(s.getStart(), s
3270: .getEnd()));
3271: } else {
3272: addToSelection(new Selection.Range(s.getStart(), s
3273: .getEnd()));
3274: }
3275: }
3276: } //}}}
3277:
3278: //{{{ setRectangularSelectionEnabled() method
3279: /**
3280: * Set rectangular selection on or off according to the value of
3281: * <code>rectangularSelectionMode</code>. This only affects the ability
3282: * to make multiple selections from the keyboard. A rectangular
3283: * selection can always be created by dragging with the mouse by holding
3284: * down <b>Control</b>, regardless of the state of this flag.
3285: *
3286: * @param rectangularSelectionMode Should rectangular selection be
3287: * enabled?
3288: * @since jEdit 4.2pre1
3289: */
3290: public final void setRectangularSelectionEnabled(
3291: boolean rectangularSelectionMode) {
3292: this .rectangularSelectionMode = rectangularSelectionMode;
3293: fireStatusChanged(StatusListener.RECT_SELECT_CHANGED,
3294: rectangularSelectionMode);
3295: painter.repaint();
3296: } //}}}
3297:
3298: //}}}
3299:
3300: //{{{ Folding
3301:
3302: //{{{ goToParentFold() method
3303: /**
3304: * Moves the caret to the fold containing the one at the caret
3305: * position.
3306: * @since jEdit 4.0pre3
3307: */
3308: public void goToParentFold() {
3309: int line = -1;
3310: int level = buffer.getFoldLevel(caretLine);
3311: for (int i = caretLine - 1; i >= 0; i--) {
3312: if (buffer.getFoldLevel(i) < level) {
3313: line = i;
3314: break;
3315: }
3316: }
3317:
3318: if (line == -1) {
3319: getToolkit().beep();
3320: return;
3321: }
3322:
3323: int magic = getMagicCaretPosition();
3324:
3325: int newCaret = buffer.getLineStartOffset(line)
3326: + chunkCache.xToSubregionOffset(line, 0, magic + 1,
3327: true);
3328: if (!multi)
3329: selectNone();
3330:
3331: moveCaretPosition(newCaret);
3332: setMagicCaretPosition(magic);
3333: } //}}}
3334:
3335: //{{{ goToNextFold() method
3336: /**
3337: * Moves the caret to the next fold.
3338: * @param select true if you want to extend selection
3339: * @since jEdit 4.0pre3
3340: */
3341: public void goToNextFold(boolean select) {
3342: int nextFold = -1;
3343: for (int i = caretLine + 1; i < buffer.getLineCount(); i++) {
3344: if (buffer.isFoldStart(i)
3345: && displayManager.isLineVisible(i)) {
3346: nextFold = i;
3347: break;
3348: }
3349: }
3350:
3351: if (nextFold == -1) {
3352: getToolkit().beep();
3353: return;
3354: }
3355:
3356: int magic = getMagicCaretPosition();
3357:
3358: int newCaret = buffer.getLineStartOffset(nextFold)
3359: + chunkCache.xToSubregionOffset(nextFold, 0, magic + 1,
3360: true);
3361: if (select)
3362: extendSelection(caret, newCaret);
3363: else if (!multi)
3364: selectNone();
3365:
3366: moveCaretPosition(newCaret);
3367: setMagicCaretPosition(magic);
3368: } //}}}
3369:
3370: //{{{ goToPrevFold() method
3371: /**
3372: * Moves the caret to the previous fold.
3373: * @param select true if you want to extend selection
3374: * @since jEdit 4.0pre3
3375: */
3376: public void goToPrevFold(boolean select) {
3377: int prevFold = -1;
3378: for (int i = caretLine - 1; i >= 0; i--) {
3379: if (buffer.isFoldStart(i)
3380: && displayManager.isLineVisible(i)) {
3381: prevFold = i;
3382: break;
3383: }
3384: }
3385:
3386: if (prevFold == -1) {
3387: getToolkit().beep();
3388: return;
3389: }
3390:
3391: int magic = getMagicCaretPosition();
3392:
3393: int newCaret = buffer.getLineStartOffset(prevFold)
3394: + chunkCache.xToSubregionOffset(prevFold, 0, magic + 1,
3395: true);
3396: if (select)
3397: extendSelection(caret, newCaret);
3398: else if (!multi)
3399: selectNone();
3400:
3401: moveCaretPosition(newCaret);
3402: setMagicCaretPosition(magic);
3403: } //}}}
3404:
3405: //{{{ collapseFold() method
3406: /**
3407: * Like {@link DisplayManager#collapseFold(int)}, but
3408: * also moves the caret to the first line of the fold.
3409: * @since jEdit 4.0pre3
3410: */
3411: public void collapseFold() {
3412: collapseFold(caretLine);
3413: } //}}}
3414:
3415: //{{{ collapseFold() method
3416: /**
3417: * Like {@link DisplayManager#collapseFold(int)}, but
3418: * also moves the caret to the first line of the fold.
3419: * @since jEdit 4.3pre7
3420: */
3421: public void collapseFold(int line) {
3422: int x = chunkCache.subregionOffsetToX(caretLine, caret
3423: - getLineStartOffset(caretLine));
3424:
3425: displayManager.collapseFold(line);
3426:
3427: if (displayManager.isLineVisible(caretLine))
3428: return;
3429:
3430: line = displayManager.getPrevVisibleLine(caretLine);
3431:
3432: if (!multi) {
3433: // cannot use selectNone() beacause the finishCaretUpdate method will reopen the fold
3434: invalidateSelectedLines();
3435: selectionManager.setSelection((Selection) null);
3436: }
3437: moveCaretPosition(buffer.getLineStartOffset(line)
3438: + chunkCache.xToSubregionOffset(line, 0, x, true));
3439: } //}}}
3440:
3441: //{{{ expandFold() method
3442: /**
3443: * Like {@link DisplayManager#expandFold(int,boolean)}, but
3444: * also moves the caret to the first sub-fold.
3445: * @since jEdit 4.0pre3
3446: */
3447: public void expandFold(boolean fully) {
3448: int x = chunkCache.subregionOffsetToX(caretLine, caret
3449: - getLineStartOffset(caretLine));
3450:
3451: int line = displayManager.expandFold(caretLine, fully);
3452:
3453: if (!fully && line != -1) {
3454: if (!multi)
3455: selectNone();
3456: moveCaretPosition(getLineStartOffset(line)
3457: + chunkCache.xToSubregionOffset(line, 0, x, true));
3458: }
3459: } //}}}
3460:
3461: //{{{ selectFold() method
3462: /**
3463: * Selects the fold that contains the caret line number.
3464: * @since jEdit 3.1pre3
3465: */
3466: public void selectFold() {
3467: selectFold(caretLine);
3468: } //}}}
3469:
3470: //{{{ selectFold() method
3471: /**
3472: * Selects the fold that contains the specified line number.
3473: * @param line The line number
3474: * @since jEdit 4.0pre1
3475: */
3476: public void selectFold(int line) {
3477: int[] lines = buffer.getFoldAtLine(line);
3478:
3479: int newCaret = getLineEndOffset(lines[1]) - 1;
3480: Selection s = new Selection.Range(getLineStartOffset(lines[0]),
3481: newCaret);
3482: if (multi)
3483: addToSelection(s);
3484: else
3485: setSelection(s);
3486: moveCaretPosition(newCaret);
3487: } //}}}
3488:
3489: //{{{ narrowToFold() method
3490: /**
3491: * Hides all lines except those in the fold containing the caret.
3492: * @since jEdit 4.0pre1
3493: */
3494: public void narrowToFold() {
3495: int[] lines = buffer.getFoldAtLine(caretLine);
3496: if (lines[0] == 0 && lines[1] == buffer.getLineCount() - 1)
3497: getToolkit().beep();
3498: else
3499: displayManager.narrow(lines[0], lines[1]);
3500: } //}}}
3501:
3502: //{{{ narrowToSelection() method
3503: /**
3504: * Hides all lines except those in the selection.
3505: * @since jEdit 4.0pre1
3506: */
3507: public void narrowToSelection() {
3508: if (getSelectionCount() != 1) {
3509: getToolkit().beep();
3510: return;
3511: }
3512:
3513: Selection sel = getSelection(0);
3514: displayManager.narrow(sel.getStartLine(), sel.getEndLine());
3515:
3516: selectNone();
3517: } //}}}
3518:
3519: //{{{ addExplicitFold() method
3520: /**
3521: * Surrounds the selection with explicit fold markers.
3522: * @since jEdit 4.0pre3
3523: */
3524: public void addExplicitFold() throws TextAreaException {
3525: if (!buffer.isEditable()) {
3526: getToolkit().beep();
3527: return;
3528: }
3529: if (!buffer.getStringProperty("folding").equals("explicit")) {
3530: throw new TextAreaException("folding-not-explicit");
3531: }
3532:
3533: try {
3534: buffer.beginCompoundEdit();
3535:
3536: if (getSelectionCount() == 0) {
3537: addExplicitFold(caret, caret, caretLine, caretLine);
3538: } else {
3539: Selection[] selections = getSelection();
3540: Selection selection = null;
3541: int caretBack = 0;
3542: for (int i = 0; i < selections.length; i++) {
3543: selection = selections[i];
3544: caretBack = addExplicitFold(selection.start,
3545: selection.end, selection.startLine,
3546: selection.endLine);
3547: }
3548: // Selection cannot be null because there is at least 1 selection
3549: assert selection != null;
3550: setCaretPosition(selection.start - caretBack, false);
3551: }
3552: } finally {
3553: buffer.endCompoundEdit();
3554: }
3555: } //}}}
3556:
3557: //}}}
3558:
3559: //{{{ Text editing
3560:
3561: //{{{ lineComment() method
3562: /**
3563: * Prepends each line of the selection with the line comment string.
3564: * @since jEdit 3.2pre1
3565: */
3566: public void lineComment() {
3567: if (!buffer.isEditable()) {
3568: getToolkit().beep();
3569: return;
3570: }
3571: String comment = buffer.getContextSensitiveProperty(caret,
3572: "lineComment");
3573: if (comment == null || comment.length() == 0) {
3574: rangeLineComment();
3575: return;
3576: }
3577:
3578: comment += ' ';
3579:
3580: buffer.beginCompoundEdit();
3581:
3582: int[] lines = getSelectedLines();
3583:
3584: try {
3585: for (int i = 0; i < lines.length; i++) {
3586: String text = getLineText(lines[i]);
3587: buffer.insert(getLineStartOffset(lines[i])
3588: + StandardUtilities.getLeadingWhiteSpace(text),
3589: comment);
3590: }
3591: } finally {
3592: buffer.endCompoundEdit();
3593: }
3594:
3595: selectNone();
3596: } //}}}
3597:
3598: //{{{ rangeLineComment() method
3599: /**
3600: * This method will surround each selected line with a range comment.
3601: * This is used when calling line comment if the edit mode doesn't have
3602: * a line comment property
3603: * @since jEdit 4.3pre10
3604: */
3605: private void rangeLineComment() {
3606: String commentStart = buffer.getContextSensitiveProperty(caret,
3607: "commentStart");
3608: String commentEnd = buffer.getContextSensitiveProperty(caret,
3609: "commentEnd");
3610: if (!buffer.isEditable() || commentStart == null
3611: || commentEnd == null || commentStart.length() == 0
3612: || commentEnd.length() == 0) {
3613: getToolkit().beep();
3614: return;
3615: }
3616:
3617: commentStart += ' ';
3618: commentEnd = ' ' + commentEnd;
3619:
3620: try {
3621: buffer.beginCompoundEdit();
3622: int[] lines = getSelectedLines();
3623: for (int i = 0; i < lines.length; i++) {
3624: String text = getLineText(lines[i]);
3625: if (text.trim().length() == 0)
3626: continue;
3627: buffer.insert(getLineEndOffset(lines[i]) - 1,
3628: commentEnd);
3629: buffer.insert(getLineStartOffset(lines[i])
3630: + StandardUtilities.getLeadingWhiteSpace(text),
3631: commentStart);
3632: }
3633: } finally {
3634: buffer.endCompoundEdit();
3635: }
3636: } //}}}
3637:
3638: //{{{ rangeComment() method
3639: /**
3640: * Adds comment start and end strings to the beginning and end of the
3641: * selection.
3642: * @since jEdit 3.2pre1
3643: */
3644: public void rangeComment() {
3645: String commentStart = buffer.getContextSensitiveProperty(caret,
3646: "commentStart");
3647: String commentEnd = buffer.getContextSensitiveProperty(caret,
3648: "commentEnd");
3649: if (!buffer.isEditable() || commentStart == null
3650: || commentEnd == null || commentStart.length() == 0
3651: || commentEnd.length() == 0) {
3652: getToolkit().beep();
3653: return;
3654: }
3655:
3656: commentStart += ' ';
3657: commentEnd = ' ' + commentEnd;
3658:
3659: try {
3660: buffer.beginCompoundEdit();
3661:
3662: Selection[] selection = getSelection();
3663:
3664: if (selection.length == 0) {
3665: int oldCaret = caret;
3666: buffer.insert(caret, commentStart);
3667: buffer.insert(caret, commentEnd);
3668: setCaretPosition(oldCaret + commentStart.length());
3669: }
3670:
3671: for (int i = 0; i < selection.length; i++) {
3672: Selection s = selection[i];
3673: if (s instanceof Selection.Range) {
3674: buffer.insert(s.start, commentStart);
3675: buffer.insert(s.end, commentEnd);
3676: } else if (s instanceof Selection.Rect) {
3677: Selection.Rect rect = (Selection.Rect) s;
3678: int start = rect.getStartColumn(buffer);
3679: int end = rect.getEndColumn(buffer);
3680:
3681: for (int j = s.startLine; j <= s.endLine; j++) {
3682: buffer.insertAtColumn(j, end, commentEnd);
3683: buffer.insertAtColumn(j, start, commentStart);
3684: }
3685: }
3686: }
3687:
3688: selectNone();
3689: } finally {
3690: buffer.endCompoundEdit();
3691: }
3692: } //}}}
3693:
3694: //{{{ formatParagraph() method
3695: /**
3696: * Formats the paragraph containing the caret.
3697: * @since jEdit 2.7pre2
3698: */
3699: public void formatParagraph() throws TextAreaException {
3700: if (!buffer.isEditable()) {
3701: getToolkit().beep();
3702: return;
3703: }
3704:
3705: if (maxLineLen <= 0) {
3706: throw new TextAreaException("format-maxlinelen");
3707: }
3708:
3709: Selection[] selection = getSelection();
3710: if (selection.length != 0) {
3711: buffer.beginCompoundEdit();
3712:
3713: for (int i = 0; i < selection.length; i++) {
3714: Selection s = selection[i];
3715: setSelectedText(s, TextUtilities.format(
3716: getSelectedText(s), maxLineLen, buffer
3717: .getTabSize()));
3718: }
3719:
3720: buffer.endCompoundEdit();
3721: } else {
3722: int lineNo = getCaretLine();
3723:
3724: int start = 0, end = buffer.getLength();
3725:
3726: for (int i = lineNo - 1; i >= 0; i--) {
3727: if (lineContainsSpaceAndTabs(i)) {
3728: start = getLineEndOffset(i);
3729: break;
3730: }
3731: }
3732:
3733: for (int i = lineNo + 1; i < getLineCount(); i++) {
3734: if (lineContainsSpaceAndTabs(i)) {
3735: end = getLineStartOffset(i) - 1;
3736: break;
3737: }
3738: }
3739:
3740: try {
3741: buffer.beginCompoundEdit();
3742:
3743: String text = buffer.getText(start, end - start);
3744: int offset = getCaretPosition() - start;
3745: int noSpaceOffset = TextUtilities
3746: .indexIgnoringWhitespace(text, offset);
3747: buffer.remove(start, end - start);
3748: text = TextUtilities.format(text, maxLineLen, buffer
3749: .getTabSize());
3750: buffer.insert(start, text);
3751: int caretPos = start;
3752: if (text.length() != 0) {
3753: caretPos += Math.min(text.length(), TextUtilities
3754: .ignoringWhitespaceIndex(text,
3755: noSpaceOffset));
3756: }
3757: moveCaretPosition(caretPos);
3758: } finally {
3759: buffer.endCompoundEdit();
3760: }
3761: }
3762: } //}}}
3763:
3764: //{{{ spacesToTabs() method
3765: /**
3766: * Converts spaces to tabs in the selection.
3767: * @since jEdit 2.7pre2
3768: */
3769: public void spacesToTabs() {
3770: Selection[] selection = getSelection();
3771:
3772: if (!buffer.isEditable()) {
3773: getToolkit().beep();
3774: return;
3775: }
3776:
3777: buffer.beginCompoundEdit();
3778:
3779: if (selection.length == 0) {
3780: setText(TextUtilities.spacesToTabs(getText(), buffer
3781: .getTabSize()));
3782: } else {
3783: for (int i = 0; i < selection.length; i++) {
3784: Selection s = selection[i];
3785: setSelectedText(s, TextUtilities.spacesToTabs(
3786: getSelectedText(s), buffer.getTabSize()));
3787: }
3788: }
3789:
3790: buffer.endCompoundEdit();
3791: } //}}}
3792:
3793: //{{{ tabsToSpaces() method
3794: /**
3795: * Converts tabs to spaces in the selection.
3796: * @since jEdit 2.7pre2
3797: */
3798: public void tabsToSpaces() {
3799: Selection[] selection = getSelection();
3800:
3801: if (!buffer.isEditable()) {
3802: getToolkit().beep();
3803: return;
3804: }
3805:
3806: buffer.beginCompoundEdit();
3807:
3808: if (selection.length == 0) {
3809: setText(TextUtilities.tabsToSpaces(getText(), buffer
3810: .getTabSize()));
3811: } else {
3812: for (int i = 0; i < selection.length; i++) {
3813: Selection s = selection[i];
3814: setSelectedText(s, TextUtilities.tabsToSpaces(
3815: getSelectedText(s), buffer.getTabSize()));
3816: }
3817: }
3818:
3819: buffer.endCompoundEdit();
3820: } //}}}
3821:
3822: //{{{ toUpperCase() method
3823: /**
3824: * Converts the selected text to upper case.
3825: * @since jEdit 2.7pre2
3826: */
3827: public void toUpperCase() {
3828: if (!buffer.isEditable()) {
3829: getToolkit().beep();
3830: return;
3831: }
3832:
3833: Selection[] selection = getSelection();
3834: int caret = -1;
3835: if (selection.length == 0) {
3836: caret = getCaretPosition();
3837: selectWord();
3838: selection = getSelection();
3839: }
3840: if (selection.length == 0) {
3841: if (caret != -1)
3842: setCaretPosition(caret);
3843: getToolkit().beep();
3844: return;
3845: }
3846:
3847: buffer.beginCompoundEdit();
3848:
3849: for (int i = 0; i < selection.length; i++) {
3850: Selection s = selection[i];
3851: setSelectedText(s, getSelectedText(s).toUpperCase());
3852: }
3853:
3854: buffer.endCompoundEdit();
3855: if (caret != -1)
3856: setCaretPosition(caret);
3857: } //}}}
3858:
3859: //{{{ toLowerCase() method
3860: /**
3861: * Converts the selected text to lower case.
3862: * @since jEdit 2.7pre2
3863: */
3864: public void toLowerCase() {
3865: if (!buffer.isEditable()) {
3866: getToolkit().beep();
3867: return;
3868: }
3869:
3870: Selection[] selection = getSelection();
3871: int caret = -1;
3872: if (selection.length == 0) {
3873: caret = getCaretPosition();
3874: selectWord();
3875: selection = getSelection();
3876: }
3877: if (selection.length == 0) {
3878: if (caret != -1)
3879: setCaretPosition(caret);
3880: getToolkit().beep();
3881: return;
3882: }
3883:
3884: buffer.beginCompoundEdit();
3885:
3886: for (int i = 0; i < selection.length; i++) {
3887: Selection s = selection[i];
3888: setSelectedText(s, getSelectedText(s).toLowerCase());
3889: }
3890:
3891: buffer.endCompoundEdit();
3892: if (caret != -1)
3893: setCaretPosition(caret);
3894: } //}}}
3895:
3896: //{{{ removeTrailingWhiteSpace() method
3897: /**
3898: * Removes trailing whitespace from all lines in the selection.
3899: * @since jEdit 2.7pre2
3900: */
3901: public void removeTrailingWhiteSpace() {
3902: if (!buffer.isEditable())
3903: getToolkit().beep();
3904: else {
3905: buffer.removeTrailingWhiteSpace(getSelectedLines());
3906: }
3907: } //}}}
3908:
3909: //{{{ insertEnterAndIndent() method
3910: public void insertEnterAndIndent() {
3911: if (!isEditable())
3912: getToolkit().beep();
3913: else {
3914: try {
3915: buffer.beginCompoundEdit();
3916: setSelectedText("\n");
3917: buffer.indentLine(caretLine, true);
3918: } finally {
3919: buffer.endCompoundEdit();
3920: }
3921: }
3922: } //}}}
3923:
3924: //{{{ insertTabAndIndent() method
3925: public void insertTabAndIndent() {
3926: if (!isEditable()) {
3927: getToolkit().beep();
3928: return;
3929: }
3930:
3931: if (getSelectionCount() == 0) {
3932: // if caret is inside leading whitespace, indent.
3933: String text = buffer.getLineText(caretLine);
3934: int start = buffer.getLineStartOffset(caretLine);
3935: int whiteSpace = StandardUtilities
3936: .getLeadingWhiteSpace(text);
3937:
3938: if (caret - start <= whiteSpace
3939: && buffer.indentLine(caretLine, false))
3940: return;
3941: }
3942:
3943: userInput('\t');
3944: } //}}}
3945:
3946: //{{{ indentSelectedLines() method
3947: /**
3948: * Indents all selected lines.
3949: * @since jEdit 3.1pre3
3950: */
3951: public void indentSelectedLines() {
3952: if (!buffer.isEditable())
3953: getToolkit().beep();
3954: else {
3955: buffer.indentLines(getSelectedLines());
3956: selectNone();
3957: }
3958: } //}}}
3959:
3960: //{{{ shiftIndentLeft() method
3961: /**
3962: * Shifts the indent to the left.
3963: * @since jEdit 2.7pre2
3964: */
3965: public void shiftIndentLeft() {
3966: if (!buffer.isEditable())
3967: getToolkit().beep();
3968: else {
3969: buffer.shiftIndentLeft(getSelectedLines());
3970: }
3971: } //}}}
3972:
3973: //{{{ shiftIndentRight() method
3974: /**
3975: * Shifts the indent to the right.
3976: * @since jEdit 2.7pre2
3977: */
3978: public void shiftIndentRight() {
3979: if (!buffer.isEditable())
3980: getToolkit().beep();
3981: else
3982: buffer.shiftIndentRight(getSelectedLines());
3983: } //}}}
3984:
3985: //{{{ joinLines() method
3986: /**
3987: * Joins the current and the next line.
3988: * @since jEdit 2.7pre2
3989: */
3990: public void joinLines() {
3991: if (getSelectionCount() == 0) {
3992: int end = getLineEndOffset(caretLine);
3993: if (!buffer.isEditable() || end > buffer.getLength()) {
3994: getToolkit().beep();
3995: return;
3996: }
3997:
3998: try {
3999: buffer.beginCompoundEdit();
4000: String nextLineText = buffer.getLineText(caretLine + 1);
4001: buffer.remove(end - 1, StandardUtilities
4002: .getLeadingWhiteSpace(nextLineText) + 1);
4003: if (nextLineText.length() != 0)
4004: buffer.insert(end - 1, " ");
4005: } finally {
4006: buffer.endCompoundEdit();
4007: }
4008: setCaretPosition(end - 1);
4009: } else {
4010: try {
4011: buffer.beginCompoundEdit();
4012: Selection[] selections = selectionManager
4013: .getSelection();
4014: for (int i = 0; i < selections.length; i++) {
4015: Selection selection = selections[i];
4016: joinLines(selection);
4017: }
4018: } finally {
4019: buffer.endCompoundEdit();
4020: }
4021: }
4022: } //}}}
4023:
4024: //{{{ joinLines() method
4025: /**
4026: * Join the lines in the selection.
4027: * If you use this method you have to lock the buffer in compound edit mode
4028: *
4029: * @param selection the selection
4030: * @since jEdit 4.3pre8
4031: */
4032: private void joinLines(Selection selection) {
4033: do {
4034: if (selection.startLine == buffer.getLineCount() - 1)
4035: return;
4036: int end = getLineEndOffset(selection.startLine);
4037: String nextLineText = buffer
4038: .getLineText(selection.startLine + 1);
4039: buffer.remove(end - 1, StandardUtilities
4040: .getLeadingWhiteSpace(nextLineText) + 1);
4041: if (nextLineText.length() != 0)
4042: buffer.insert(end - 1, " ");
4043: } while (selection.startLine < selection.endLine);
4044: } //}}}
4045:
4046: //}}}
4047:
4048: //{{{ AWT stuff
4049:
4050: //{{{ addLeftOfScrollBar() method
4051: /**
4052: * Adds a component to the box left of the vertical scroll bar. The
4053: * ErrorList plugin uses this to show a global error overview, for
4054: * example.
4055: *
4056: * @param comp The component
4057: * @since jEdit 4.2pre1
4058: */
4059: public void addLeftOfScrollBar(Component comp) {
4060: verticalBox.add(comp, verticalBox.getComponentCount() - 1);
4061: } //}}}
4062:
4063: //{{{ removeLeftOfScrollBar() method
4064: /**
4065: * Removes a component from the box left of the vertical scroll bar.
4066: *
4067: * @param comp The component
4068: * @since jEdit 4.2pre1
4069: */
4070: public void removeLeftOfScrollBar(Component comp) {
4071: verticalBox.remove(comp);
4072: } //}}}
4073:
4074: //{{{ addNotify() method
4075: /**
4076: * Called by the AWT when this component is added to a parent.
4077: * Adds document listener.
4078: */
4079: public void addNotify() {
4080: super .addNotify();
4081:
4082: ToolTipManager.sharedInstance().registerComponent(painter);
4083: ToolTipManager.sharedInstance().registerComponent(gutter);
4084:
4085: recalculateVisibleLines();
4086: if (!buffer.isLoading())
4087: recalculateLastPhysicalLine();
4088: propertiesChanged();
4089:
4090: hiddenCursor = getToolkit().createCustomCursor(
4091: getGraphicsConfiguration().createCompatibleImage(16,
4092: 16, Transparency.BITMASK), new Point(0, 0),
4093: "Hidden");
4094: } //}}}
4095:
4096: //{{{ removeNotify() method
4097: /**
4098: * Called by the AWT when this component is removed from it's parent.
4099: * This clears the pointer to the currently focused component.
4100: * Also removes document listener.
4101: */
4102: public void removeNotify() {
4103: super .removeNotify();
4104:
4105: ToolTipManager.sharedInstance().unregisterComponent(painter);
4106: ToolTipManager.sharedInstance().unregisterComponent(gutter);
4107:
4108: if (focusedComponent == this )
4109: focusedComponent = null;
4110: } //}}}
4111:
4112: //{{{ getFocusTraversalKeysEnabled() method
4113: /**
4114: * Java 1.4 compatibility fix to make Tab key work.
4115: * @since jEdit 3.2pre4
4116: */
4117: public boolean getFocusTraversalKeysEnabled() {
4118: return false;
4119: } //}}}
4120:
4121: //{{{ getFocusCycleRoot() method
4122: /**
4123: * Java 1.4 compatibility fix to make Tab traversal work in a sane
4124: * manner.
4125: * @since jEdit 4.2pre3
4126: */
4127: public boolean getFocusCycleRoot() {
4128: return true;
4129: } //}}}
4130:
4131: //{{{ processKeyEvent() method
4132: public void processKeyEvent(KeyEvent evt) {
4133: getInputHandler().processKeyEvent(evt,
4134: 1 /* source=TEXTAREA (1) */, false);
4135: if (!evt.isConsumed())
4136: super .processKeyEvent(evt);
4137:
4138: } //}}}
4139:
4140: //{{{ addTopComponent() method
4141: /**
4142: * Adds a component above the gutter, text area, and vertical scroll bar.
4143: *
4144: * @since jEdit 4.2pre3
4145: */
4146: public void addTopComponent(Component comp) {
4147: add(ScrollLayout.TOP, comp);
4148: } //}}}
4149:
4150: //{{{ removeTopComponent() method
4151: /**
4152: * Removes a component from above the gutter, text area, and vertical scroll bar.
4153: *
4154: * @since jEdit 4.2pre3
4155: */
4156: public void removeTopComponent(Component comp) {
4157: remove(comp);
4158: } //}}}
4159:
4160: //{{{ Input method support
4161: private InputMethodSupport inputMethodSupport;
4162:
4163: public InputMethodRequests getInputMethodRequests() {
4164: if (inputMethodSupport == null) {
4165: inputMethodSupport = new InputMethodSupport(this );
4166: Log.log(Log.DEBUG, this , "InputMethodSupport is activated");
4167: }
4168: return inputMethodSupport;
4169: } //}}}
4170:
4171: //}}}
4172:
4173: //{{{ addStatusListener() method
4174: /**
4175: * Adds a scroll listener to this text area.
4176: * @param listener The listener
4177: * @since jEdit 4.3pre2
4178: */
4179: public final void addStatusListener(StatusListener listener) {
4180: listenerList.add(StatusListener.class, listener);
4181: } //}}}
4182:
4183: //{{{ removeStatusListener() method
4184: /**
4185: * Removes a scroll listener from this text area.
4186: * @param listener The listener
4187: * @since jEdit 4.3pre2
4188: */
4189: public final void removeStatusListener(StatusListener listener) {
4190: listenerList.remove(StatusListener.class, listener);
4191: } //}}}
4192:
4193: //{{{ propertiesChanged() method
4194: /**
4195: * Called by jEdit when necessary. Plugins should not call this method.
4196: */
4197: public void propertiesChanged() {
4198: if (buffer == null)
4199: return;
4200:
4201: int _tabSize = buffer.getTabSize();
4202: char[] foo = new char[_tabSize];
4203: for (int i = 0; i < foo.length; i++)
4204: foo[i] = ' ';
4205:
4206: tabSize = painter.getStringWidth(new String(foo));
4207:
4208: charWidth = (int) Math.round(painter.getFont().getStringBounds(
4209: foo, 0, 1, painter.getFontRenderContext()).getWidth());
4210:
4211: String oldWrap = wrap;
4212: wrap = buffer.getStringProperty("wrap");
4213: hardWrap = wrap.equals("hard");
4214: softWrap = wrap.equals("soft");
4215: boolean oldWrapToWidth = wrapToWidth;
4216: int oldWrapMargin = wrapMargin;
4217: setMaxLineLength(buffer.getIntegerProperty("maxLineLen", 0));
4218:
4219: boolean wrapSettingsChanged = !(wrap.equals(oldWrap)
4220: && oldWrapToWidth == wrapToWidth && oldWrapMargin == wrapMargin);
4221:
4222: if (displayManager != null && !bufferChanging
4223: && !buffer.isLoading() && wrapSettingsChanged) {
4224: displayManager.invalidateScreenLineCounts();
4225: displayManager.notifyScreenLineChanges();
4226: }
4227:
4228: repaintMgr.setFastScroll(false);
4229: chunkCache.invalidateAll();
4230: gutter.repaint();
4231: painter.repaint();
4232: } //}}}
4233:
4234: //{{{ Deprecated methods
4235:
4236: //{{{ getSelectionStart() method
4237: /**
4238: * @deprecated Instead, obtain a Selection instance using
4239: * any means, and call its <code>getStart()</code> method
4240: */
4241: public final int getSelectionStart() {
4242: if (getSelectionCount() != 1)
4243: return caret;
4244:
4245: return getSelection(0).getStart();
4246: } //}}}
4247:
4248: //{{{ getSelectionStart() method
4249: /**
4250: * @deprecated Instead, obtain a Selection instance using
4251: * any means, and call its <code>getStart(int)</code> method
4252: */
4253: public int getSelectionStart(int line) {
4254: if (getSelectionCount() != 1)
4255: return caret;
4256:
4257: return getSelection(0).getStart(buffer, line);
4258: } //}}}
4259:
4260: //{{{ getSelectionStartLine() method
4261: /**
4262: * @deprecated Instead, obtain a Selection instance using
4263: * any means, and call its <code>getStartLine()</code> method
4264: */
4265: public final int getSelectionStartLine() {
4266: if (getSelectionCount() != 1)
4267: return caret;
4268:
4269: return getSelection(0).getStartLine();
4270: } //}}}
4271:
4272: //{{{ setSelectionStart() method
4273: /**
4274: * @deprecated Do not use.
4275: */
4276: public final void setSelectionStart(int selectionStart) {
4277: int selectionEnd = getSelectionCount() == 1 ? getSelection(0)
4278: .getEnd() : caret;
4279: select(selectionStart, selectionEnd, true);
4280: } //}}}
4281:
4282: //{{{ getSelectionEnd() method
4283: /**
4284: * @deprecated Instead, obtain a Selection instance using
4285: * any means, and call its <code>getEnd()</code> method
4286: */
4287: public final int getSelectionEnd() {
4288: return getSelectionCount() == 1 ? getSelection(0).getEnd()
4289: : caret;
4290:
4291: } //}}}
4292:
4293: //{{{ getSelectionEnd() method
4294: /**
4295: * @deprecated Instead, obtain a Selection instance using
4296: * any means, and call its <code>getEnd(int)</code> method
4297: */
4298: public int getSelectionEnd(int line) {
4299: if (getSelectionCount() != 1)
4300: return caret;
4301:
4302: return getSelection(0).getEnd(buffer, line);
4303: } //}}}
4304:
4305: //{{{ getSelectionEndLine() method
4306: /**
4307: * @deprecated Instead, obtain a Selection instance using
4308: * any means, and call its <code>getEndLine()</code> method
4309: */
4310: public final int getSelectionEndLine() {
4311: if (getSelectionCount() != 1)
4312: return caret;
4313:
4314: return getSelection(0).getEndLine();
4315: } //}}}
4316:
4317: //{{{ setSelectionEnd() method
4318: /**
4319: * @deprecated Do not use.
4320: */
4321: public final void setSelectionEnd(int selectionEnd) {
4322: select(getSelectionStart(), selectionEnd, true);
4323: } //}}}
4324:
4325: //{{{ getMarkPosition() method
4326: /**
4327: * @deprecated Do not use.
4328: */
4329: public final int getMarkPosition() {
4330: Selection s = getSelectionAtOffset(caret);
4331: if (s == null)
4332: return caret;
4333:
4334: if (s.start == caret)
4335: return s.end;
4336: else if (s.end == caret)
4337: return s.start;
4338: else
4339: return caret;
4340: } //}}}
4341:
4342: //{{{ getMarkLine() method
4343: /**
4344: * @deprecated Do not use.
4345: */
4346: public final int getMarkLine() {
4347: if (getSelectionCount() != 1)
4348: return caretLine;
4349:
4350: Selection s = getSelection(0);
4351: if (s.start == caret)
4352: return s.endLine;
4353: else if (s.end == caret)
4354: return s.startLine;
4355: else
4356: return caretLine;
4357: } //}}}
4358:
4359: //{{{ select() method
4360: /**
4361: * @deprecated Instead, call either <code>addToSelection()</code>,
4362: * or <code>setSelection()</code> with a new Selection instance.
4363: */
4364: public void select(int start, int end) {
4365: select(start, end, true);
4366: } //}}}
4367:
4368: //{{{ select() method
4369: /**
4370: * @deprecated Instead, call either <code>addToSelection()</code>,
4371: * or <code>setSelection()</code> with a new Selection instance.
4372: */
4373: public void select(int start, int end, boolean doElectricScroll) {
4374: selectNone();
4375:
4376: int newStart, newEnd;
4377: if (start < end) {
4378: newStart = start;
4379: newEnd = end;
4380: } else {
4381: newStart = end;
4382: newEnd = start;
4383: }
4384:
4385: setSelection(new Selection.Range(newStart, newEnd));
4386: moveCaretPosition(end, doElectricScroll);
4387: } //}}}
4388:
4389: //{{{ isSelectionRectangular() method
4390: /**
4391: * @deprecated Instead, check if the appropriate Selection
4392: * is an instance of the Selection.Rect class.
4393: */
4394: public boolean isSelectionRectangular() {
4395: Selection s = getSelectionAtOffset(caret);
4396: return s != null && s instanceof Selection.Rect;
4397: } //}}}
4398:
4399: //}}}
4400:
4401: //{{{ Package-private members
4402:
4403: static TextArea focusedComponent;
4404:
4405: //{{{ Instance variables
4406: final Segment lineSegment = new Segment();
4407: MouseInputAdapter mouseHandler;
4408: final ChunkCache chunkCache;
4409: final FastRepaintManager repaintMgr;
4410: DisplayManager displayManager;
4411: final SelectionManager selectionManager;
4412: boolean bufferChanging;
4413:
4414: int maxHorizontalScrollWidth;
4415:
4416: String wrap;
4417: boolean hardWrap;
4418: boolean softWrap;
4419: boolean wrapToWidth;
4420: int maxLineLen;
4421: int wrapMargin;
4422: float tabSize;
4423: int charWidth;
4424:
4425: boolean scrollBarsInitialized;
4426:
4427: /**
4428: * Cursor location, measured as an offset (in pixels) from upper left corner
4429: * of the TextArea.
4430: */
4431: final Point offsetXY;
4432:
4433: boolean lastLinePartial;
4434:
4435: boolean blink;
4436:
4437: //}}}
4438:
4439: //{{{ isCaretVisible() method
4440: /**
4441: * Returns true if the caret is visible, false otherwise.
4442: */
4443: final boolean isCaretVisible() {
4444: return blink && hasFocus();
4445: } //}}}
4446:
4447: //{{{ isStructureHighlightVisible() method
4448: /**
4449: * Returns true if the structure highlight is visible, false otherwise.
4450: * @since jEdit 4.2pre3
4451: */
4452: final boolean isStructureHighlightVisible() {
4453: return match != null && hasFocus()
4454: && displayManager.isLineVisible(match.startLine)
4455: && displayManager.isLineVisible(match.endLine);
4456: } //}}}
4457:
4458: //{{{ updateMaxHorizontalScrollWidth() method
4459: void updateMaxHorizontalScrollWidth() {
4460: int max = chunkCache.getMaxHorizontalScrollWidth();
4461:
4462: if (max != maxHorizontalScrollWidth) {
4463: maxHorizontalScrollWidth = max;
4464: horizontal.setValues(Math.max(0, Math.min(
4465: maxHorizontalScrollWidth + charWidth
4466: - painter.getWidth(), -horizontalOffset)),
4467: painter.getWidth(), 0, maxHorizontalScrollWidth
4468: + charWidth);
4469: horizontal.setUnitIncrement(10);
4470: horizontal.setBlockIncrement(painter.getWidth());
4471: } else if (horizontal.getValue() != -horizontalOffset) {
4472: horizontal.setValue(-horizontalOffset);
4473: }
4474: } //}}}
4475:
4476: //{{{ recalculateVisibleLines() method
4477: void recalculateVisibleLines() {
4478: if (painter == null)
4479: return;
4480: int height = painter.getHeight();
4481: int lineHeight = painter.getFontMetrics().getHeight();
4482: if (lineHeight == 0)
4483: visibleLines = 0;
4484: else if (height <= 0) {
4485: visibleLines = 0;
4486: lastLinePartial = false;
4487: } else {
4488: visibleLines = height / lineHeight;
4489: lastLinePartial = (height % lineHeight != 0);
4490: if (lastLinePartial)
4491: visibleLines++;
4492: }
4493:
4494: chunkCache.recalculateVisibleLines();
4495:
4496: // this does the "trick" to eliminate blank space at the end
4497: if (displayManager != null && buffer != null
4498: && !buffer.isLoading())
4499: setFirstLine(getFirstLine());
4500:
4501: updateScrollBar();
4502: } //}}}
4503:
4504: //{{{ foldStructureChanged() method
4505: void foldStructureChanged() {
4506: repaintMgr.setFastScroll(false);
4507: chunkCache.invalidateAll();
4508: recalculateLastPhysicalLine();
4509: repaint();
4510: } //}}}
4511:
4512: //{{{ updateScrollBar() method
4513: /**
4514: * Updates the state of the scroll bars. This should be called
4515: * if the number of lines in the buffer changes, or when the
4516: * size of the text are changes.
4517: */
4518: void updateScrollBar() {
4519: if (buffer == null)
4520: return;
4521:
4522: if (Debug.SCROLL_DEBUG)
4523: Log.log(Log.DEBUG, this , "updateScrollBar(), slc="
4524: + displayManager.getScrollLineCount());
4525:
4526: if (vertical != null && visibleLines != 0) {
4527: if (Debug.SCROLL_DEBUG)
4528: Log.log(Log.DEBUG, this , "Vertical ok");
4529: int lineCount = displayManager.getScrollLineCount();
4530: int firstLine = getFirstLine();
4531: int visible = visibleLines - (lastLinePartial ? 1 : 0);
4532:
4533: vertical.setValues(firstLine, visible, 0, lineCount);
4534: vertical.setUnitIncrement(2);
4535: vertical.setBlockIncrement(visible);
4536: }
4537: } //}}}
4538:
4539: //{{{ _finishCaretUpdate() method
4540: /* called by DisplayManager.BufferChangeHandler.transactionComplete() */
4541: void _finishCaretUpdate() {
4542: if (!queuedCaretUpdate)
4543: return;
4544:
4545: try {
4546: if (match != null) {
4547: if (oldCaretLine < match.startLine)
4548: invalidateLineRange(oldCaretLine, match.endLine);
4549: else
4550: invalidateLineRange(match.startLine, oldCaretLine);
4551: match = null;
4552: }
4553:
4554: int newCaretScreenLine = chunkCache.getScreenLineOfOffset(
4555: caretLine, caret
4556: - buffer.getLineStartOffset(caretLine));
4557: if (caretScreenLine == -1)
4558: invalidateScreenLineRange(newCaretScreenLine,
4559: newCaretScreenLine);
4560: else
4561: invalidateScreenLineRange(caretScreenLine,
4562: newCaretScreenLine);
4563: caretScreenLine = newCaretScreenLine;
4564:
4565: invalidateSelectedLines();
4566:
4567: // When the user is typing, etc, we don't want the caret
4568: // to blink
4569: blink = true;
4570: caretTimer.restart();
4571:
4572: if (!displayManager.isLineVisible(caretLine)) {
4573: if (caretLine < displayManager.getFirstVisibleLine()
4574: || caretLine > displayManager
4575: .getLastVisibleLine()) {
4576: int collapseFolds = buffer.getIntegerProperty(
4577: "collapseFolds", 0);
4578: if (collapseFolds != 0) {
4579: displayManager.expandFolds(collapseFolds);
4580: displayManager.expandFold(caretLine, false);
4581: } else
4582: displayManager.expandAllFolds();
4583: } else
4584: displayManager.expandFold(caretLine, false);
4585: }
4586:
4587: if (queuedScrollMode == ELECTRIC_SCROLL)
4588: scrollToCaret(true);
4589: else if (queuedScrollMode == NORMAL_SCROLL)
4590: scrollToCaret(false);
4591:
4592: updateBracketHighlightWithDelay();
4593: if (queuedFireCaretEvent)
4594: fireCaretEvent();
4595: }
4596: // in case one of the above fails, we still want to
4597: // clear these flags.
4598: finally {
4599: queuedCaretUpdate = queuedFireCaretEvent = false;
4600: queuedScrollMode = NO_SCROLL;
4601: }
4602: } //}}}
4603:
4604: //{{{ invalidateStructureMatch() method
4605: void invalidateStructureMatch() {
4606: if (match != null)
4607: invalidateLineRange(match.startLine, match.endLine);
4608: } //}}}
4609:
4610: //{{{ startDragAndDrop() method
4611: void startDragAndDrop(InputEvent evt, boolean copy) {
4612: TransferHandler transferHandler = getTransferHandler();
4613: if (transferHandler != null) {
4614: Log.log(Log.DEBUG, this , "Drag and drop callback");
4615: transferHandler.exportAsDrag(this , evt,
4616: copy ? TransferHandler.COPY : TransferHandler.MOVE);
4617: }
4618: } //}}}
4619:
4620: //{{{ fireNarrowActive() method
4621: void fireNarrowActive() {
4622: Object[] listeners = listenerList.getListenerList();
4623: for (int i = listeners.length - 2; i >= 0; i--) {
4624: if (listeners[i] == StatusListener.class) {
4625: try {
4626: ((StatusListener) listeners[i + 1])
4627: .narrowActive(this );
4628: } catch (Throwable t) {
4629: Log.log(Log.ERROR, this , t);
4630: }
4631: }
4632: }
4633: } //}}}
4634:
4635: //}}}
4636:
4637: //{{{ Private members
4638:
4639: //{{{ Static variables
4640: private static final Timer caretTimer;
4641: private static final Timer structureTimer;
4642: //}}}
4643:
4644: //{{{ Instance variables
4645: protected Cursor hiddenCursor;
4646:
4647: private final Gutter gutter;
4648: protected final TextAreaPainter painter;
4649:
4650: private final EventListenerList listenerList;
4651: private final MutableCaretEvent caretEvent;
4652:
4653: private boolean caretBlinks;
4654: private InputHandlerProvider inputHandlerProvider;
4655:
4656: /** The last visible physical line index. */
4657: private int physLastLine;
4658:
4659: /**
4660: * The last screen line index.
4661: */
4662: private int screenLastLine;
4663:
4664: /** The visible lines count. */
4665: private int visibleLines;
4666: private int electricScroll;
4667:
4668: private int horizontalOffset;
4669:
4670: private boolean quickCopy;
4671:
4672: // JDiff, error list add stuff here
4673: private final Box verticalBox;
4674: private final JScrollBar vertical;
4675: private final JScrollBar horizontal;
4676:
4677: protected JEditBuffer buffer;
4678:
4679: protected int caret;
4680: protected int caretLine;
4681: private int caretScreenLine;
4682:
4683: private final java.util.List<StructureMatcher> structureMatchers;
4684: private StructureMatcher.Match match;
4685:
4686: private int magicCaret;
4687: /** Flag that tells if multiple selection is on. */
4688: protected boolean multi;
4689: private boolean overwrite;
4690: private boolean rectangularSelectionMode;
4691:
4692: private boolean dndEnabled;
4693: private boolean dndInProgress;
4694:
4695: // see finishCaretUpdate() & _finishCaretUpdate()
4696: private boolean queuedCaretUpdate;
4697: private int queuedScrollMode;
4698: private boolean queuedFireCaretEvent;
4699: private int oldCaretLine;
4700:
4701: private boolean joinNonWordChars;
4702: private boolean ctrlForRectangularSelection;
4703:
4704: //}}}
4705:
4706: //{{{ invalidateSelectedLines() method
4707: /**
4708: * Repaints the lines containing the selection.
4709: */
4710: private void invalidateSelectedLines() {
4711: // to hide line highlight if selections are being added later on
4712: invalidateLine(caretLine);
4713:
4714: for (Selection s : selectionManager.selection)
4715: invalidateLineRange(s.startLine, s.endLine);
4716: } //}}}
4717:
4718: //{{{ finishCaretUpdate() method
4719: /**
4720: * the collapsing of scrolling/event firing inside compound edits
4721: * greatly speeds up replace-all.
4722: */
4723: private void finishCaretUpdate(int oldCaretLine, int scrollMode,
4724: boolean fireCaretEvent) {
4725: queuedFireCaretEvent |= fireCaretEvent;
4726: queuedScrollMode = Math.max(scrollMode, queuedScrollMode);
4727:
4728: if (queuedCaretUpdate)
4729: return;
4730:
4731: this .oldCaretLine = oldCaretLine;
4732: queuedCaretUpdate = true;
4733:
4734: if (!buffer.isTransactionInProgress())
4735: _finishCaretUpdate();
4736: /* otherwise DisplayManager.BufferChangeHandler calls */
4737:
4738: repaintMgr.setFastScroll(false);
4739: } //}}}
4740:
4741: //{{{ fireCaretEvent() method
4742: private void fireCaretEvent() {
4743: Object[] listeners = listenerList.getListenerList();
4744: for (int i = listeners.length - 2; i >= 0; i--) {
4745: if (listeners[i] == CaretListener.class) {
4746: try {
4747: ((CaretListener) listeners[i + 1])
4748: .caretUpdate(caretEvent);
4749: } catch (Throwable t) {
4750: Log.log(Log.ERROR, this , t);
4751: }
4752: }
4753: }
4754: } //}}}
4755:
4756: //{{{ fireScrollEvent() method
4757: private void fireScrollEvent(boolean vertical) {
4758: Object[] listeners = listenerList.getListenerList();
4759: for (int i = listeners.length - 2; i >= 0; i--) {
4760: if (listeners[i] == ScrollListener.class) {
4761: try {
4762: if (vertical)
4763: ((ScrollListener) listeners[i + 1])
4764: .scrolledVertically(this );
4765: else
4766: ((ScrollListener) listeners[i + 1])
4767: .scrolledHorizontally(this );
4768: } catch (Throwable t) {
4769: Log.log(Log.ERROR, this , t);
4770: }
4771: }
4772: }
4773: } //}}}
4774:
4775: //{{{ fireStatusChanged() method
4776: private void fireStatusChanged(int flag, boolean value) {
4777: Object[] listeners = listenerList.getListenerList();
4778: for (int i = listeners.length - 2; i >= 0; i--) {
4779: if (listeners[i] == StatusListener.class) {
4780: try {
4781: ((StatusListener) listeners[i + 1]).statusChanged(
4782: this , flag, value);
4783: } catch (Throwable t) {
4784: Log.log(Log.ERROR, this , t);
4785: }
4786: }
4787: }
4788: } //}}}
4789:
4790: //{{{ fireBracketSelected() method
4791: private void fireBracketSelected(int line, String text) {
4792: Object[] listeners = listenerList.getListenerList();
4793: for (int i = listeners.length - 2; i >= 0; i--) {
4794: if (listeners[i] == StatusListener.class) {
4795: try {
4796: ((StatusListener) listeners[i + 1])
4797: .bracketSelected(this , line, text);
4798: } catch (Throwable t) {
4799: Log.log(Log.ERROR, this , t);
4800: }
4801: }
4802: }
4803: } //}}}
4804:
4805: //{{{ _changeLine() method
4806: private void _changeLine(boolean select, int newCaret) {
4807: if (select) {
4808: RectParams params = getRectParams(caret, newCaret);
4809: int extraStartVirt;
4810: int extraEndVirt;
4811: if (params == null) {
4812: extraStartVirt = 0;
4813: extraEndVirt = 0;
4814: } else {
4815: extraStartVirt = params.extraStartVirt;
4816: extraEndVirt = params.extraEndVirt;
4817: newCaret = params.newCaret;
4818: }
4819: extendSelection(caret, newCaret, extraStartVirt,
4820: extraEndVirt);
4821: } else if (!multi)
4822: selectNone();
4823:
4824: moveCaretPosition(newCaret);
4825: }//}}}
4826:
4827: /**
4828: * Check if the line contains only spaces and tabs.
4829: *
4830: * @param lineIndex the line index
4831: * @return <code>true</code> if the line contains only spaces and tabs
4832: */
4833: private boolean lineContainsSpaceAndTabs(int lineIndex) {
4834: getLineText(lineIndex, lineSegment);
4835:
4836: for (int j = 0; j < lineSegment.count; j++) {
4837: switch (lineSegment.array[lineSegment.offset + j]) {
4838: case ' ':
4839: case '\t':
4840: break;
4841: default:
4842: return false;
4843: }
4844: }
4845: return true;
4846: }
4847:
4848: //{{{ insert() method
4849: protected void insert(String str, boolean indent) {
4850: try {
4851: // Don't overstrike if we're on the end of
4852: // the line
4853: if (overwrite || indent)
4854: buffer.beginCompoundEdit();
4855:
4856: if (overwrite) {
4857: int caretLineEnd = getLineEndOffset(caretLine);
4858: if (caretLineEnd - caret > 1)
4859: buffer.remove(caret, 1);
4860: }
4861:
4862: buffer.insert(caret, str);
4863:
4864: if (indent)
4865: buffer.indentLine(caretLine, true);
4866: } finally {
4867: if (overwrite || indent)
4868: buffer.endCompoundEdit();
4869: }
4870: } //}}}
4871:
4872: //{{{ insertTab() method
4873: private void insertTab() {
4874: int tabSize = buffer.getTabSize();
4875: if (buffer.getBooleanProperty("noTabs")) {
4876: int lineStart = getLineStartOffset(caretLine);
4877:
4878: String line = getText(lineStart, caret - lineStart);
4879:
4880: int pos = 0;
4881:
4882: for (int i = 0; i < line.length(); i++) {
4883: switch (line.charAt(pos)) {
4884: case '\t':
4885: pos = 0;
4886: break;
4887: default:
4888: if (++pos >= tabSize)
4889: pos = 0;
4890: break;
4891: }
4892: }
4893:
4894: replaceSelection(StandardUtilities.createWhiteSpace(tabSize
4895: - pos, 0));
4896: } else
4897: replaceSelection("\t");
4898: } //}}}
4899:
4900: //{{{ userInputTab() method
4901: protected void userInputTab() {
4902: if (getSelectionCount() == 1) {
4903: Selection sel = getSelection(0);
4904: if (sel instanceof Selection.Rect
4905: || (sel.startLine == sel.endLine && (sel.start != buffer
4906: .getLineStartOffset(sel.startLine) || sel.end != buffer
4907: .getLineEndOffset(sel.startLine) - 1))) {
4908: insertTab();
4909: } else
4910: shiftIndentRight();
4911: } else if (getSelectionCount() != 0)
4912: shiftIndentRight();
4913: else
4914: insertTab();
4915: } //}}}
4916:
4917: //{{{ doWordWrap() method
4918: /**
4919: * Does hard wrap.
4920: */
4921: protected boolean doWordWrap(boolean spaceInserted) {
4922: if (!hardWrap || maxLineLen <= 0)
4923: return false;
4924:
4925: buffer.getLineText(caretLine, lineSegment);
4926:
4927: int start = getLineStartOffset(caretLine);
4928: int end = getLineEndOffset(caretLine);
4929: int len = end - start - 1;
4930:
4931: int caretPos = caret - start;
4932:
4933: // only wrap if we're at the end of a line, or the rest of the
4934: // line text is whitespace
4935: for (int i = caretPos; i < len; i++) {
4936: char ch = lineSegment.array[lineSegment.offset + i];
4937: if (ch != ' ' && ch != '\t')
4938: return false;
4939: }
4940:
4941: int tabSize = buffer.getTabSize();
4942:
4943: String wordBreakChars = buffer
4944: .getStringProperty("wordBreakChars");
4945:
4946: int lastInLine = 0; // last character before wrap
4947: int logicalLength = 0; // length with tabs expanded
4948: int lastWordOffset = -1;
4949: boolean lastWasSpace = true;
4950: for (int i = 0; i < caretPos; i++) {
4951: char ch = lineSegment.array[lineSegment.offset + i];
4952: if (ch == '\t') {
4953: logicalLength += tabSize - (logicalLength % tabSize);
4954: if (!lastWasSpace && logicalLength <= maxLineLen) {
4955: lastInLine = i;
4956: lastWordOffset = i;
4957: lastWasSpace = true;
4958: }
4959: } else if (ch == ' ') {
4960: logicalLength++;
4961: if (!lastWasSpace && logicalLength <= maxLineLen + 1) {
4962: lastInLine = i;
4963: lastWordOffset = i;
4964: lastWasSpace = true;
4965: }
4966: } else if (wordBreakChars != null
4967: && wordBreakChars.indexOf(ch) != -1) {
4968: logicalLength++;
4969: if (!lastWasSpace && logicalLength <= maxLineLen) {
4970: lastInLine = i;
4971: lastWordOffset = i;
4972: lastWasSpace = true;
4973: }
4974: } else {
4975: lastInLine = i;
4976: logicalLength++;
4977: lastWasSpace = false;
4978: }
4979: }
4980:
4981: boolean returnValue;
4982:
4983: int insertNewLineAt;
4984: if (spaceInserted && logicalLength == maxLineLen
4985: && lastInLine == caretPos - 1) {
4986: insertNewLineAt = caretPos;
4987: returnValue = true;
4988: } else if (logicalLength >= maxLineLen && lastWordOffset != -1) {
4989: insertNewLineAt = lastWordOffset;
4990: returnValue = false;
4991: } else
4992: return false;
4993:
4994: try {
4995: buffer.beginCompoundEdit();
4996: buffer.insert(start + insertNewLineAt, "\n");
4997: // caretLine would have been incremented
4998: // since insertNewLineAt <= caretPos
4999: buffer.indentLine(caretLine, true);
5000: } finally {
5001: buffer.endCompoundEdit();
5002: }
5003:
5004: /* only ever return true if space was pressed
5005: * with logicalLength == maxLineLen */
5006: return returnValue;
5007: } //}}}
5008:
5009: //{{{ updateStructureHighlightWithDelay() method
5010: private static void updateBracketHighlightWithDelay() {
5011: structureTimer.stop();
5012: structureTimer.start();
5013: } //}}}
5014:
5015: //{{{ updateStructureHighlight() method
5016: private void updateStructureHighlight() {
5017: if (!painter.isStructureHighlightEnabled()
5018: && !gutter.isStructureHighlightEnabled())
5019: return;
5020:
5021: for (StructureMatcher matcher : structureMatchers) {
5022: match = matcher.getMatch(this );
5023: if (match != null)
5024: break;
5025: }
5026:
5027: if (match != null) {
5028: if (caretLine < match.startLine)
5029: invalidateLineRange(caretLine, match.endLine);
5030: else
5031: invalidateLineRange(match.startLine, caretLine);
5032:
5033: if (!displayManager.isLineVisible(match.startLine)
5034: || chunkCache
5035: .getScreenLineOfOffset(
5036: match.startLine,
5037: match.start
5038: - getLineStartOffset(match.startLine)) == -1) {
5039: showStructureStatusMessage(match.startLine < caretLine);
5040: }
5041: }
5042: } //}}}
5043:
5044: //{{{ showStructureStatusMessage() method
5045: private void showStructureStatusMessage(boolean backward) {
5046: String text = buffer.getLineText(match.startLine).trim();
5047: if (backward && match.startLine != 0 && text.length() == 1) {
5048: switch (text.charAt(0)) {
5049: case '{':
5050: case '}':
5051: case '[':
5052: case ']':
5053: case '(':
5054: case ')':
5055: text = buffer.getLineText(match.startLine - 1).trim()
5056: + ' ' + text;
5057: break;
5058: }
5059: }
5060:
5061: // get rid of embedded tabs not removed by trim()
5062: fireBracketSelected(match.startLine + 1, text
5063: .replace('\t', ' '));
5064: } //}}}
5065:
5066: //{{{ recalculateLastPhysicalLine() method
5067: void recalculateLastPhysicalLine() {
5068: int oldScreenLastLine = screenLastLine;
5069: for (int i = visibleLines - 1; i >= 0; i--) {
5070: ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
5071: if (info.physicalLine != -1) {
5072: physLastLine = info.physicalLine;
5073: screenLastLine = i;
5074: break;
5075: }
5076: }
5077: invalidateScreenLineRange(oldScreenLastLine, screenLastLine);
5078: } //}}}
5079:
5080: //{{{ getRectParams() method
5081: static class RectParams {
5082: final int extraStartVirt;
5083: final int extraEndVirt;
5084: final int newCaret;
5085:
5086: RectParams(int extraStartVirt, int extraEndVirt, int newCaret) {
5087: this .extraStartVirt = extraStartVirt;
5088: this .extraEndVirt = extraEndVirt;
5089: this .newCaret = newCaret;
5090: }
5091: }
5092:
5093: /**
5094: * Used when doing S+UP/DOWN to simplify dealing with virtual space.
5095: */
5096: private RectParams getRectParams(int caret, int newCaret) {
5097: Selection s = getSelectionAtOffset(caret);
5098: int virtualWidth;
5099: if (s instanceof Selection.Rect) {
5100: if (caret == s.end) {
5101: virtualWidth = buffer.getVirtualWidth(s.endLine, s.end
5102: - getLineStartOffset(s.endLine))
5103: + ((Selection.Rect) s).extraEndVirt;
5104: } else {
5105: virtualWidth = buffer.getVirtualWidth(s.startLine,
5106: s.start - getLineStartOffset(s.startLine))
5107: + ((Selection.Rect) s).extraStartVirt;
5108: }
5109: } else if (rectangularSelectionMode) {
5110: virtualWidth = buffer.getVirtualWidth(caretLine, caret
5111: - buffer.getLineStartOffset(caretLine));
5112: } else
5113: return null;
5114:
5115: int newLine = getLineOfOffset(newCaret);
5116: int[] totalVirtualWidth = new int[1];
5117: int newOffset = buffer.getOffsetOfVirtualColumn(newLine,
5118: virtualWidth, totalVirtualWidth);
5119: if (newOffset == -1) {
5120: int extraVirt = virtualWidth - totalVirtualWidth[0];
5121: newCaret = getLineEndOffset(newLine) - 1;
5122:
5123: boolean bias;
5124: if (s == null)
5125: bias = newCaret < caret;
5126: else if (s.start == caret)
5127: bias = newCaret <= s.end;
5128: else if (s.end == caret)
5129: bias = newCaret <= s.start;
5130: else
5131: bias = false;
5132:
5133: RectParams returnValue;
5134: if (bias)
5135: returnValue = new RectParams(extraVirt, 0, newCaret);
5136: else
5137: returnValue = new RectParams(0, extraVirt, newCaret);
5138: return returnValue;
5139: } else {
5140: return new RectParams(0, 0, getLineStartOffset(newLine)
5141: + newOffset);
5142: }
5143: } //}}}
5144:
5145: //{{{ delete() method
5146: private void delete(boolean forward) {
5147: if (!buffer.isEditable()) {
5148: getToolkit().beep();
5149: return;
5150: }
5151:
5152: if (getSelectionCount() != 0) {
5153: Selection[] selections = getSelection();
5154: for (int i = 0; i < selections.length; i++) {
5155: Selection s = selections[i];
5156: if (s instanceof Selection.Rect) {
5157: Selection.Rect r = (Selection.Rect) s;
5158: int startColumn = r.getStartColumn(buffer);
5159: if (startColumn == r.getEndColumn(buffer)) {
5160: if (!forward && startColumn == 0)
5161: getToolkit().beep();
5162: else
5163: tallCaretDelete(r, forward);
5164: } else
5165: setSelectedText(s, null);
5166: } else
5167: setSelectedText(s, null);
5168: }
5169: } else if (forward) {
5170: if (caret == buffer.getLength()) {
5171: getToolkit().beep();
5172: return;
5173: }
5174:
5175: buffer.remove(caret, 1);
5176: } else {
5177: if (caret == 0) {
5178: getToolkit().beep();
5179: return;
5180: }
5181:
5182: buffer.remove(caret - 1, 1);
5183: }
5184: } //}}}
5185:
5186: //{{{ tallCaretDelete() method
5187: private void tallCaretDelete(Selection.Rect s, boolean forward) {
5188: try {
5189: buffer.beginCompoundEdit();
5190:
5191: int[] width = new int[1];
5192:
5193: int startCol = s.getStartColumn(buffer);
5194: int startLine = s.startLine;
5195: int endLine = s.endLine;
5196: for (int i = startLine; i <= endLine; i++) {
5197: int offset = buffer.getOffsetOfVirtualColumn(i,
5198: startCol, width);
5199: if (offset == -1) {
5200: if (width[0] == startCol)
5201: offset = getLineLength(i);
5202: else {
5203: if (i == startLine && !forward)
5204: shiftTallCaretLeft(s);
5205: continue;
5206: }
5207: }
5208: offset += buffer.getLineStartOffset(i);
5209: if (forward) {
5210: if (offset != buffer.getLineEndOffset(i) - 1)
5211: buffer.remove(offset, 1);
5212: } else
5213: buffer.remove(offset - 1, 1);
5214: }
5215: } finally {
5216: buffer.endCompoundEdit();
5217: }
5218: } //}}}
5219:
5220: //{{{ shiftTallCaretLeft() method
5221: private void shiftTallCaretLeft(Selection.Rect s) {
5222: removeFromSelection(s);
5223: addToSelection(new Selection.Rect(buffer, s.getStartLine(), s
5224: .getStartColumn(buffer) - 1, s.getEndLine(), s
5225: .getEndColumn(buffer) - 1));
5226: } //}}}
5227:
5228: //{{{ setMaxLineLength() method
5229: private void setMaxLineLength(int maxLineLen) {
5230: this .maxLineLen = maxLineLen;
5231:
5232: if (maxLineLen <= 0) {
5233: if (softWrap) {
5234: wrapToWidth = true;
5235: wrapMargin = painter.getWidth() - charWidth * 3;
5236: } else {
5237: wrapToWidth = false;
5238: wrapMargin = 0;
5239: }
5240: } else {
5241: // stupidity
5242: char[] foo = new char[maxLineLen];
5243: for (int i = 0; i < foo.length; i++) {
5244: foo[i] = ' ';
5245: }
5246: wrapToWidth = false;
5247: wrapMargin = (int) painter.getFont().getStringBounds(foo,
5248: 0, foo.length, painter.getFontRenderContext())
5249: .getWidth();
5250: }
5251: } //}}}
5252:
5253: //{{{ addExplicitFold() method
5254: /**
5255: * Add an explicit fold.
5256: * You should call this method inside a compoundEdit in the buffer.
5257: * You must also check if the buffer fold mode is explicit before
5258: * calling this method.
5259: *
5260: * @param caretStart the starting offset
5261: * @param caretEnd the end offset
5262: * @param lineStart the start line
5263: * @param lineEnd the end line
5264: * @since jEdit 4.3pre3
5265: */
5266: protected int addExplicitFold(int caretStart, int caretEnd,
5267: int lineStart, int lineEnd) {
5268: // need to "fix" the caret position so that we get the right rule.
5269: // taking the start offset one char ahead and the end offset one char
5270: // behing makes sure we get the right rule for the text being
5271: // wrapped (tricky around mode boundaries, e.g., php code embedded
5272: // in HTML code)
5273: int startCaret = caretStart < buffer.getLength() ? caretStart + 1
5274: : caretStart;
5275: int endCaret = caretEnd > 0 ? caretEnd - 1 : caretEnd;
5276:
5277: String startLineComment = buffer.getContextSensitiveProperty(
5278: startCaret, "lineComment");
5279: String startCommentStart = buffer.getContextSensitiveProperty(
5280: startCaret, "commentStart");
5281: String startCommentEnd = buffer.getContextSensitiveProperty(
5282: startCaret, "commentEnd");
5283: String endLineComment = buffer.getContextSensitiveProperty(
5284: endCaret, "lineComment");
5285: String endCommentStart = buffer.getContextSensitiveProperty(
5286: endCaret, "commentStart");
5287: String endCommentEnd = buffer.getContextSensitiveProperty(
5288: endCaret, "commentEnd");
5289:
5290: String start;
5291: int caretBack = 1;
5292: if (startLineComment != null)
5293: start = startLineComment + "{{{ ";
5294: else if (startCommentStart != null && startCommentEnd != null) {
5295: start = startCommentStart + "{{{ " + startCommentEnd;
5296: caretBack = 1 + startCommentStart.length();
5297: } else
5298: start = "{{{ ";
5299:
5300: if (startLineComment != null) {
5301: // add a new line if there's text after the comment
5302: // we're inserting
5303: if (buffer.getLineLength(lineStart) != caretStart) {
5304: start += '\n';
5305: }
5306: } else {
5307: // always insert a new line if there's no comment character.
5308: start += "\n";
5309: }
5310:
5311: String end;
5312: if (endLineComment != null)
5313: end = endLineComment + "}}}";
5314: else if (endCommentStart != null && endCommentEnd != null)
5315: end = endCommentStart + "}}}" + endCommentEnd;
5316: else
5317: end = "}}}";
5318:
5319: String line = buffer.getLineText(lineStart);
5320: String whitespace = line.substring(0, StandardUtilities
5321: .getLeadingWhiteSpace(line));
5322:
5323: if (endLineComment != null) {
5324: // if we're inserting a line comment into a non-empty
5325: // line, we'll need to add a line break so we don't
5326: // comment out existing code.
5327: if (buffer.getLineLength(lineEnd) != caretEnd) {
5328: end += '\n';
5329: }
5330: } else {
5331: // always insert a new line if there's no comment character.
5332: end += "\n";
5333: }
5334:
5335: if (caretEnd == buffer.getLineStartOffset(lineEnd))
5336: buffer.insert(caretEnd, end);
5337: else {
5338: String lineText = buffer.getText(caretEnd - 1, 1);
5339: if (Character.isWhitespace(lineText.charAt(0)))
5340: buffer.insert(caretEnd, end);
5341: else
5342: buffer.insert(caretEnd, ' ' + end);
5343: }
5344:
5345: buffer.insert(caretStart, start + whitespace);
5346:
5347: return caretBack;
5348: } //}}}
5349:
5350: //}}}
5351:
5352: //{{{ Inner classes
5353:
5354: //{{{ CaretBlinker class
5355: static class CaretBlinker implements ActionListener {
5356: //{{{ actionPerformed() method
5357: public void actionPerformed(ActionEvent evt) {
5358: if (focusedComponent != null && focusedComponent.hasFocus())
5359: focusedComponent.blinkCaret();
5360: } //}}}
5361: } //}}}
5362:
5363: //{{{ MutableCaretEvent class
5364: class MutableCaretEvent extends CaretEvent {
5365: //{{{ MutableCaretEvent constructor
5366: MutableCaretEvent() {
5367: super (TextArea.this );
5368: } //}}}
5369:
5370: //{{{ getDot() method
5371: public int getDot() {
5372: return getCaretPosition();
5373: } //}}}
5374:
5375: //{{{ getMark() method
5376: public int getMark() {
5377: return getMarkPosition();
5378: } //}}}
5379: } //}}}
5380:
5381: //{{{ AdjustHandler class
5382: class AdjustHandler implements AdjustmentListener {
5383: //{{{ adjustmentValueChanged() method
5384: public void adjustmentValueChanged(AdjustmentEvent evt) {
5385: if (!scrollBarsInitialized)
5386: return;
5387:
5388: if (evt.getAdjustable() == vertical)
5389: setFirstLine(vertical.getValue());
5390: else
5391: setHorizontalOffset(-horizontal.getValue());
5392: } //}}}
5393: } //}}}
5394:
5395: //{{{ FocusHandler class
5396: class FocusHandler implements FocusListener {
5397: //{{{ focusGained() method
5398: public void focusGained(FocusEvent evt) {
5399: if (bufferChanging)
5400: return;
5401:
5402: if (match != null) {
5403: if (caretLine < match.startLine)
5404: invalidateLineRange(caretLine, match.endLine);
5405: else
5406: invalidateLineRange(match.startLine, caretLine);
5407: } else
5408: invalidateLine(caretLine);
5409:
5410: focusedComponent = TextArea.this ;
5411: } //}}}
5412:
5413: //{{{ focusLost() method
5414: public void focusLost(FocusEvent evt) {
5415: if (!isShowing())
5416: return;
5417:
5418: if (match != null) {
5419: if (caretLine < match.startLine)
5420: invalidateLineRange(caretLine, match.endLine);
5421: else
5422: invalidateLineRange(match.startLine, caretLine);
5423: } else
5424: invalidateLine(caretLine);
5425: } //}}}
5426: } //}}}
5427:
5428: //{{{ MouseWheelHandler class
5429: class MouseWheelHandler implements MouseWheelListener {
5430: public void mouseWheelMoved(MouseWheelEvent e) {
5431: /****************************************************
5432: * move caret depending on pressed control-keys:
5433: * - Alt: move cursor, do not select
5434: * - Alt+(shift or control): move cursor, select
5435: * - shift: scroll page
5436: * - control: scroll single line
5437: * - <else>: scroll 3 lines
5438: ****************************************************/
5439: if (e.isAltDown()) {
5440: boolean select = e.isShiftDown() || e.isControlDown();
5441: if (e.getWheelRotation() < 0)
5442: goToPrevLine(select);
5443: else
5444: goToNextLine(select);
5445: } else if (e.isShiftDown()) {
5446: if (e.getWheelRotation() > 0)
5447: scrollDownPage();
5448: else
5449: scrollUpPage();
5450: } else if (e.isControlDown()) {
5451: setFirstLine(getFirstLine() + e.getWheelRotation());
5452: } else if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
5453: setFirstLine(getFirstLine() + e.getUnitsToScroll());
5454: } else {
5455: setFirstLine(getFirstLine() + 3 * e.getWheelRotation());
5456: }
5457: }
5458: } //}}}
5459:
5460: //}}}
5461:
5462: //{{{ Class initializer
5463: static {
5464: caretTimer = new Timer(500, new CaretBlinker());
5465: caretTimer.setInitialDelay(500);
5466: caretTimer.start();
5467:
5468: structureTimer = new Timer(100, new ActionListener() {
5469: public void actionPerformed(ActionEvent evt) {
5470: if (focusedComponent != null)
5471: focusedComponent.updateStructureHighlight();
5472: }
5473: });
5474: structureTimer.setInitialDelay(100);
5475: structureTimer.setRepeats(false);
5476: } //}}}
5477:
5478: //{{{ main() method
5479: public static void main(String[] args) {
5480: JFrame frame = new JFrame();
5481: TextArea text = new TextArea();
5482: frame.getContentPane().add(text);
5483: frame.pack();
5484: frame.setVisible(true);
5485: } //}}}
5486: }
|