Index: StyledText.java =================================================================== RCS file: /home/eclipse/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java,v retrieving revision 1.138 diff -u -r1.138 StyledText.java --- StyledText.java 24 Jan 2003 17:20:41 -0000 1.138 +++ StyledText.java 27 Jan 2003 02:30:40 -0000 @@ -1,9 +1,9 @@ package org.eclipse.swt.custom; /* - * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. - * This file is made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at + * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. + * This file is made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html */ @@ -18,22 +18,22 @@ import org.eclipse.swt.widgets.*; /** - * A StyledText is an editable user interface object that displays lines - * of text. The following style attributes can be defined for the text: + * A StyledText is an editable user interface object that displays lines + * of text. The following style attributes can be defined for the text: *
- * In addition to text style attributes, the background color of a line may + * In addition to text style attributes, the background color of a line may * be specified. *
*- * There are two ways to use this widget when specifying text style information. - * You may use the API that is defined for StyledText or you may define your own - * LineStyleListener. If you define your own listener, you will be responsible - * for maintaining the text style information for the widget. IMPORTANT: You may + * There are two ways to use this widget when specifying text style information. + * You may use the API that is defined for StyledText or you may define your own + * LineStyleListener. If you define your own listener, you will be responsible + * for maintaining the text style information for the widget. IMPORTANT: You may * not define your own listener and use the StyledText API. The following * StyledText API is not supported if you have defined a LineStyleListener: *
* There are two ways to use this widget when specifying line background colors. - * You may use the API that is defined for StyledText or you may define your own - * LineBackgroundListener. If you define your own listener, you will be responsible - * for maintaining the line background color information for the widget. - * IMPORTANT: You may not define your own listener and use the StyledText API. - * The following StyledText API is not supported if you have defined a + * You may use the API that is defined for StyledText or you may define your own + * LineBackgroundListener. If you define your own listener, you will be responsible + * for maintaining the line background color information for the widget. + * IMPORTANT: You may not define your own listener and use the StyledText API. + * The following StyledText API is not supported if you have defined a * LineBackgroundListener: *
* The content implementation for this widget may also be user-defined. To do so, * you must implement the StyledTextContent interface and use the StyledText API - * setContent(StyledTextContent) to initialize the widget. + * setContent(StyledTextContent) to initialize the widget. *
*
* IMPORTANT: This class is not intended to be subclassed.
@@ -71,1480 +71,1486 @@
*
*/
public class StyledText extends Canvas {
- static final char TAB = '\t';
- static final String PlatformLineDelimiter = System.getProperty("line.separator");
- static final int BIDI_CARET_WIDTH = 4;
- static final int XINSET = BIDI_CARET_WIDTH - 1;
- static final int DEFAULT_WIDTH = 64;
- static final int DEFAULT_HEIGHT = 64;
-
- static final int ExtendedModify = 3000;
- static final int LineGetBackground = 3001;
- static final int LineGetStyle = 3002;
- static final int TextChanging = 3003;
- static final int TextSet = 3004;
- static final int VerifyKey = 3005;
- static final int TextChanged = 3006;
- static final int LineGetSegments = 3007;
-
- Color selectionBackground; // selection background color
- Color selectionForeground; // selection foreground color
- StyledTextContent logicalContent; // native content (default or user specified)
- StyledTextContent content; // line wrapping content, same as logicalContent if word wrap is off
- DisplayRenderer renderer;
- TextChangeListener textChangeListener; // listener for TextChanging, TextChanged and TextSet events from StyledTextContent
- DefaultLineStyler defaultLineStyler;// used for setStyles API when no LineStyleListener is registered
- LineCache lineCache;
- boolean userLineStyle = false; // true=widget is using a user defined line style listener for line styles. false=widget is using the default line styler to store line styles
- boolean userLineBackground = false; // true=widget is using a user defined line background listener for line backgrounds. false=widget is using the default line styler to store line backgrounds
- int verticalScrollOffset = 0; // pixel based
- int horizontalScrollOffset = 0; // pixel based
- int topIndex = 0; // top visible line
- int topOffset = 0; // offset of first character in top line
- int clientAreaHeight = 0; // the client area height. Needed to calculate content width for new
- // visible lines during Resize callback
- int clientAreaWidth = 0; // the client area width. Needed during Resize callback to determine
- // if line wrap needs to be recalculated
- int lineHeight; // line height=font height
- int tabLength = 4; // number of characters in a tab
- int lineEndSpaceWidth; // space, in pixel, used to indicated a selected line break
- int leftMargin = 1;
- int topMargin = 1;
- int rightMargin = 2;
- int bottomMargin = 2;
- Cursor ibeamCursor;
- int columnX; // keep track of the horizontal caret position
- // when changing lines/pages. Fixes bug 5935
- int caretOffset = 0;
- Point selection = new Point(0, 0); // x is character offset, y is length
- int selectionAnchor; // position of selection anchor. 0 based offset from beginning of text
- Point doubleClickSelection; // selection after last mouse double click
- boolean editable = true;
- boolean wordWrap = false;
- boolean doubleClickEnabled = true; // see getDoubleClickEnabled
- boolean overwrite = false; // insert/overwrite edit mode
- int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default.
- Hashtable keyActionMap = new Hashtable();
- Color background = null; // workaround for bug 4791
- Color foreground = null; //
- Clipboard clipboard;
- boolean mouseDoubleClick = false; // true=a double click ocurred. Don't do mouse swipe selection.
- int autoScrollDirection = SWT.NULL; // the direction of autoscrolling (up, down, right, left)
- int lastTextChangeStart; // cache data of the
- int lastTextChangeNewLineCount; // last text changing
- int lastTextChangeNewCharCount; // event for use in the
- int lastTextChangeReplaceLineCount; // text changed handler
- int lastTextChangeReplaceCharCount;
- boolean isBidi;
- boolean bidiColoring = false; // apply the BIDI algorithm on text segments of the same color
- Image leftCaretBitmap = null;
- Image rightCaretBitmap = null;
- int caretDirection = SWT.NULL;
- PaletteData caretPalette = null;
- int lastCaretDirection = SWT.NULL;
- boolean isCarbon; // flag set to true on Mac OSX
-
- /**
- * The Printing class implements printing of a range of text.
- * An instance of
RTFWriter
class is used to write widget content as
- * rich text. The implementation complies with the RTF specification
- * version 1.5.
- * - * toString() is guaranteed to return a valid RTF string only after - * close() has been called. - *
- *- * Whole and partial lines and line breaks can be written. Lines will be - * formatted using the styles queried from the LineStyleListener, if - * set, or those set directly in the widget. All styles are applied to - * the RTF stream like they are rendered by the widget. In addition, the - * widget font name and size is used for the whole text. - *
- */ - class RTFWriter extends TextWriter { - final int DEFAULT_FOREGROUND = 0; - final int DEFAULT_BACKGROUND = 1; - Vector colorTable = new Vector(); - boolean WriteUnicode; - - /** - * Creates a RTF writer that writes content starting at offset "start" - * in the document.start
and length
can be set to specify partial
- * lines.
- *
- *
- * @param start start offset of content to write, 0 based from
- * beginning of document
- * @param length length of content to write
- */
- public RTFWriter(int start, int length) {
- super(start, length);
- colorTable.addElement(getForeground());
- colorTable.addElement(getBackground());
- setUnicode();
- }
- /**
- * Closes the RTF writer. Once closed no more content can be written.
- * NOTE: toString()
does not return a valid RTF string until
- * close()
has been called.
- */
- public void close() {
- if (isClosed() == false) {
- writeHeader();
- write("\n}}\0");
- super.close();
- }
- }
- /**
- * Returns the index of the specified color in the RTF color table.
- *
- *
- * @param color the color
- * @param defaultIndex return value if color is null
- * @return the index of the specified color in the RTF color table
- * or "defaultIndex" if "color" is null.
- */
- int getColorIndex(Color color, int defaultIndex) {
- int index;
-
- if (color == null) {
- index = defaultIndex;
- }
- else {
- index = colorTable.indexOf(color);
- if (index == -1) {
- index = colorTable.size();
- colorTable.addElement(color);
- }
- }
- return index;
- }
- /**
- * Determines if Unicode RTF should be written.
- * Don't write Unicode RTF on Windows 95/98/ME or NT.
- */
- void setUnicode() {
- final String Win95 = "windows 95";
- final String Win98 = "windows 98";
- final String WinME = "windows me";
- final String WinNT = "windows nt";
- String osName = System.getProperty("os.name").toLowerCase();
- String osVersion = System.getProperty("os.version");
- int majorVersion = 0;
-
- if (osName.startsWith(WinNT) && osVersion != null) {
- int majorIndex = osVersion.indexOf('.');
- if (majorIndex != -1) {
- osVersion = osVersion.substring(0, majorIndex);
- try {
- majorVersion = Integer.parseInt(osVersion);
- }
- catch (NumberFormatException exception) {
- // ignore exception. version number remains unknown.
- // will write without Unicode
- }
- }
- }
- if (osName != null &&
- osName.startsWith(Win95) == false &&
- osName.startsWith(Win98) == false &&
- osName.startsWith(WinME) == false &&
- (osName.startsWith(WinNT) == false || majorVersion > 4)) {
- WriteUnicode = true;
- }
- else {
- WriteUnicode = false;
- }
- }
- /**
- * Appends the specified segment of "string" to the RTF data.
- * Copy from start
up to, but excluding, end
.
- *
- * - * @param string string to copy a segment from. Must not contain - * line breaks. Line breaks should be written using writeLineDelimiter() - * @param start start offset of segment. 0 based. - * @param end end offset of segment - */ - void write(String string, int start, int end) { - for (int index = start; index < end; index++) { - char ch = string.charAt(index); - if (ch > 0xFF && WriteUnicode) { - // write the sub string from the last escaped character - // to the current one. Fixes bug 21698. - if (index > start) { - write(string.substring(start, index)); - } - write("\\u"); - write(Integer.toString((short) ch)); - write(' '); // control word delimiter - start = index + 1; - } - else - if (ch == '}' || ch == '{' || ch == '\\') { - // write the sub string from the last escaped character - // to the current one. Fixes bug 21698. - if (index > start) { - write(string.substring(start, index)); - } - write('\\'); - write(ch); - start = index + 1; - } - } - // write from the last escaped character to the end. - // Fixes bug 21698. - if (start < end) { - write(string.substring(start, end)); - } - } - /** - * Writes the RTF header including font table and color table. - */ - void writeHeader() { - StringBuffer header = new StringBuffer(); - FontData fontData = getFont().getFontData()[0]; - header.append("{\\rtf1\\ansi"); - // specify code page, necessary for copy to work in bidi - // systems that don't support Unicode RTF. - String cpg = System.getProperty("file.encoding").toLowerCase(); - if (cpg.startsWith("cp") || cpg.startsWith("ms")) { - cpg = cpg.substring(2, cpg.length()); - header.append("\\ansicpg"); - header.append(cpg); - } - header.append("\\uc0\\deff0{\\fonttbl{\\f0\\fnil "); - header.append(fontData.getName()); - header.append(";}}\n{\\colortbl"); - for (int i = 0; i < colorTable.size(); i++) { - Color color = (Color) colorTable.elementAt(i); - header.append("\\red"); - header.append(color.getRed()); - header.append("\\green"); - header.append(color.getGreen()); - header.append("\\blue"); - header.append(color.getBlue()); - header.append(";"); - } - // some RTF readers ignore the deff0 font tag. Explicitly - // set the font for the whole document to work around this. - header.append("}\n{\\f0\\fs"); - // font size is specified in half points - header.append(fontData.getHeight() * 2); - header.append(" "); - write(header.toString(), 0); - } - /** - * Appends the specified line text to the RTF data. Lines will be formatted - * using the styles queried from the LineStyleListener, if set, or those set - * directly in the widget. - *
- * - * @param line line text to write as RTF. Must not contain line breaks - * Line breaks should be written using writeLineDelimiter() - * @param lineOffset offset of the line. 0 based from the start of the - * widget document. Any text occurring before the start offset or after the - * end offset specified during object creation is ignored. - * @exception SWTException
- * - * @param lineDelimiter line delimiter to write as RTF. - * @exception SWTException
- *
- * @param line line text to write as RTF. Must not contain line breaks
- * Line breaks should be written using writeLineDelimiter()
- * @param lineOffset offset of the line. 0 based from the start of the
- * widget document. Any text occurring before the start offset or after the
- * end offset specified during object creation is ignored.
- * @param styles styles to use for formatting. Must not be null.
- * @param linebackground line background color to use for formatting.
- * May be null.
- */
- void writeStyledLine(String line, int lineOffset, StyleRange[] styles, Color lineBackground) {
- int lineLength = line.length();
- int lineIndex;
- int copyEnd;
- int startOffset = getStart();
- int endOffset = startOffset + super.getCharCount();
- int lineEndOffset = Math.min(lineLength, endOffset - lineOffset);
- int writeOffset = startOffset - lineOffset;
-
- if (writeOffset >= line.length()) {
- return; // whole line is outside write range
- }
- else
- if (writeOffset > 0) {
- lineIndex = writeOffset; // line starts before RTF write start
- }
- else {
- lineIndex = 0;
- }
- if (lineBackground != null) {
- write("{\\highlight");
- write(getColorIndex(lineBackground, DEFAULT_BACKGROUND));
- write(" ");
- }
- for (int i = 0; i < styles.length; i++) {
- StyleRange style = styles[i];
- int start = style.start - lineOffset;
- int end = start + style.length;
- int colorIndex;
- // skip over partial first line
- if (end < writeOffset) {
- continue;
- }
- // style starts beyond line end or RTF write end
- if (start >= lineEndOffset) {
- break;
- }
- // write any unstyled text
- if (lineIndex < start) {
- // copy to start of style
- // style starting betond end of write range or end of line
- // is guarded against above.
- write(line, lineIndex, start);
- lineIndex = start;
- }
- // write styled text
- colorIndex = getColorIndex(style.background, DEFAULT_BACKGROUND);
- write("{\\cf");
- write(getColorIndex(style.foreground, DEFAULT_FOREGROUND));
- if (colorIndex != DEFAULT_BACKGROUND) {
- write("\\highlight");
- write(colorIndex);
- }
- if (style.fontStyle == SWT.BOLD) {
- write("\\b");
- }
- write(" ");
- // copy to end of style or end of write range or end of line
- copyEnd = Math.min(end, lineEndOffset);
- // guard against invalid styles and let style processing continue
- copyEnd = Math.max(copyEnd, lineIndex);
- write(line, lineIndex, copyEnd);
- if (style.fontStyle == SWT.BOLD) {
- write("\\b0");
- }
- write("}");
- lineIndex = copyEnd;
- }
- // write unstyled text at the end of the line
- if (lineIndex < lineEndOffset) {
- write(line, lineIndex, lineEndOffset);
- }
- if (lineBackground != null) {
- write("}");
- }
- }
- }
- /**
- * The TextWriter
class is used to write widget content to
- * a string. Whole and partial lines and line breaks can be written. To write
- * partial lines, specify the start and length of the desired segment
- * during object creation.
- *
- * NOTE: toString()
is guaranteed to return a valid string only after close()
- * has been called.
- */
- class TextWriter {
- private StringBuffer buffer;
- private int startOffset; // offset of first character that will be written
- private int endOffset; // offset of last character that will be written.
- // 0 based from the beginning of the widget text.
- private boolean isClosed = false;
-
- /**
- * Creates a writer that writes content starting at offset "start"
- * in the document. start
and length
can be set to specify partial lines.
- *
- *
- * @param start start offset of content to write, 0 based from beginning of document
- * @param length length of content to write
- */
- public TextWriter(int start, int length) {
- buffer = new StringBuffer(length);
- startOffset = start;
- endOffset = start + length;
- }
- /**
- * Closes the writer. Once closed no more content can be written.
- * NOTE: toString()
is not guaranteed to return a valid string unless
- * the writer is closed.
- */
- public void close() {
- if (isClosed == false) {
- isClosed = true;
- }
- }
- /**
- * Returns the number of characters to write.
- */
- public int getCharCount() {
- return endOffset - startOffset;
- }
- /**
- * Returns the offset where writing starts. 0 based from the start of
- * the widget text. Used to write partial lines.
- */
- public int getStart() {
- return startOffset;
- }
- /**
- * Returns whether the writer is closed.
- */
- public boolean isClosed() {
- return isClosed;
- }
- /**
- * Returns the string. close()
must be called before toString()
- * is guaranteed to return a valid string.
- *
- * - * @return the string - */ - public String toString() { - return buffer.toString(); - } - /** - * Appends the given string to the data. - */ - void write(String string) { - buffer.append(string); - } - /** - * Inserts the given string to the data at the specified offset. - * Do nothing if "offset" is < 0 or > getCharCount() - *
- * - * @param string text to insert - * @param offset offset in the existing data to insert "string" at. - */ - void write(String string, int offset) { - if (offset < 0 || offset > buffer.length()) { - return; - } - buffer.insert(offset, string); - } - /** - * Appends the given int to the data. - */ - void write(int i) { - buffer.append(i); - } - /** - * Appends the given character to the data. - */ - void write(char i) { - buffer.append(i); - } - /** - * Appends the specified line text to the data. - *
- * - * @param line line text to write. Must not contain line breaks - * Line breaks should be written using writeLineDelimiter() - * @param lineOffset offset of the line. 0 based from the start of the - * widget document. Any text occurring before the start offset or after the - * end offset specified during object creation is ignored. - * @exception SWTException
- * - * @param lineDelimiter line delimiter to write - * @exception SWTException
getWidth
.
- */
- interface LineCache {
- /**
- * Calculates the lines in the specified range.
- *
- *
- * @param startLine first line to calculate
- * @param lineCount number of lines to calculate
- */
- public void calculate(int startLine, int lineCount);
- /**
- * Returns a width that will be used by the StyledText
- * widget to size a horizontal scroll bar.
- *
- *
- * @return the line width
- */
- public int getWidth();
- /**
- * Resets the lines in the specified range.
- * This method is called in StyledText.redraw()
- * and allows implementors to call redraw themselves during reset.
- *
- * - * @param startLine the first line to reset - * @param lineCount the number of lines to reset - * @param calculateMaxWidth true=implementors should retain a - * valid width even if it is affected by the reset operation. - * false=the width may be set to 0 - */ - public void redrawReset(int startLine, int lineCount, boolean calculateMaxWidth); - /** - * Resets the lines in the specified range. - *
- * - * @param startLine the first line to reset - * @param lineCount the number of lines to reset - * @param calculateMaxWidth true=implementors should retain a - * valid width even if it is affected by the reset operation. - * false=the width may be set to 0 - */ - public void reset(int startLine, int lineCount, boolean calculateMaxWidth); - /** - * Called when a text change occurred. - *
- *
- * @param startOffset the start offset of the text change
- * @param newLineCount the number of inserted lines
- * @param replaceLineCount the number of deleted lines
- * @param newCharCount the number of new characters
- * @param replaceCharCount the number of deleted characters
- */
- public void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount);
- }
- /**
- * Keeps track of line widths and the longest line in the
- * StyledText document.
- * Line widths are calculated when requested by a call to
- * calculate
and cached until reset by a call
- * to redrawReset
or reset
.
- */
- class ContentWidthCache implements LineCache {
- StyledText parent; // parent widget, used to create a GC for line measuring
- int[] lineWidth; // width in pixel of each line in the document, -1 for unknown width
- int lineCount; // number of lines in lineWidth array
- int maxWidth; // maximum line width of all measured lines
- int maxWidthLineIndex; // index of the widest line
-
- /**
- * Creates a new ContentWidthCache
and allocates space
- * for the given number of lines.
- *
- * - * @param parent the StyledText widget used to create a GC for - * line measuring - * @param lineCount initial number of lines to allocate space for - */ - public ContentWidthCache(StyledText parent, int lineCount) { - this.lineCount = lineCount; - this.parent = parent; - lineWidth = new int[lineCount]; - reset(0, lineCount, false); - } - /** - * Calculates the width of each line in the given range if it has - * not been calculated yet. - * If any line in the given range is wider than the currently widest - * line, the maximum line width is updated, - *
- * - * @param startLine first line to calculate the line width of - * @param lineCount number of lines to calculate the line width for - */ - public void calculate(int startLine, int lineCount) { - GC gc = null; - int caretWidth = 0; - int stopLine = startLine + lineCount; - - for (int i = startLine; i < stopLine; i++) { - if (lineWidth[i] == -1) { - String line = content.getLine(i); - int lineOffset = content.getOffsetAtLine(i); - - if (gc == null) { - gc = parent.getGC(); - caretWidth = getCaretWidth(); - } - lineWidth[i] = contentWidth(line, lineOffset, gc) + caretWidth; - } - if (lineWidth[i] > maxWidth) { - maxWidth = lineWidth[i]; - maxWidthLineIndex = i; - } - } - if (gc != null) { - gc.dispose(); - } - } - /** - * Calculates the width of the visible lines in the specified - * range. - *
- * - * @param startLine the first changed line - * @param newLineCount the number of inserted lines - */ - void calculateVisible(int startLine, int newLineCount) { - int topIndex = parent.getTopIndex(); - int bottomLine = Math.min(getPartialBottomIndex(), startLine + newLineCount); - - startLine = Math.max(startLine, topIndex); - calculate(startLine, bottomLine - startLine + 1); - } - /** - * Measures the width of the given line. - *
- *
- * @param line the line to measure
- * @param lineOffset start offset of the line to measure, relative
- * to the start of the document
- * @param gc the GC to use for measuring the line
- * @param currentFont the font currently set in gc. Cached for better
- * performance. Null when running in a bidi locale.
- * @return the width of the given line
- */
- int contentWidth(String line, int lineOffset, GC gc) {
- int width;
-
- if (isBidi()) {
- StyledTextBidi bidi = getStyledTextBidi(line, lineOffset, gc);
- width = bidi.getTextWidth();
- }
- else {
- StyledTextEvent event = renderer.getLineStyleData(lineOffset, line);
- StyleRange[] styles = null;
- if (event != null) {
- styles = renderer.filterLineStyles(event.styles);
- }
- width = renderer.getTextWidth(line, lineOffset, 0, line.length(), styles, 0, gc);
- }
- return width + leftMargin;
- }
- /**
- * Grows the lineWidth
array to accomodate new line width
- * information.
- *
- * - * @param numLines the number of elements to increase the array by - */ - void expandLines(int numLines) { - int size = lineWidth.length; - if (size - lineCount >= numLines) { - return; - } - int[] newLines = new int[Math.max(size * 2, size + numLines)]; - System.arraycopy(lineWidth, 0, newLines, 0, size); - lineWidth = newLines; - reset(size, lineWidth.length - size, false); - } - /** - * Returns the width of the longest measured line. - *
- * - * @return the width of the longest measured line. - */ - public int getWidth() { - return maxWidth; - } - /** - * Updates the line width array to reflect inserted or deleted lines. - *
- * - * @param start the starting line of the change that took place - * @param delta the number of lines in the change, > 0 indicates lines inserted, - * < 0 indicates lines deleted - */ - void linesChanged(int startLine, int delta) { - boolean inserting = delta > 0; - - if (delta == 0) { - return; - } - if (inserting) { - // shift the lines down to make room for new lines - expandLines(delta); - for (int i = lineCount - 1; i >= startLine; i--) { - lineWidth[i + delta] = lineWidth[i]; - } - // reset the new lines - for (int i = startLine + 1; i <= startLine + delta && i < lineWidth.length; i++) { - lineWidth[i] = -1; - } - // have new lines been inserted above the longest line? - if (maxWidthLineIndex >= startLine) { - maxWidthLineIndex += delta; - } - } - else { - // shift up the lines - for (int i = startLine - delta; i < lineCount; i++) { - lineWidth[i+delta] = lineWidth[i]; - } - // has the longest line been removed? - if (maxWidthLineIndex > startLine && maxWidthLineIndex <= startLine - delta) { - maxWidth = 0; - maxWidthLineIndex = -1; - } - else - if (maxWidthLineIndex >= startLine - delta) { - maxWidthLineIndex += delta; - } - } - lineCount += delta; - } - /** - * Resets the line width of the lines in the specified range. - *
- * - * @param startLine the first line to reset - * @param lineCount the number of lines to reset - * @param calculateMaxWidth true=if the widest line is being - * reset the maximum width of all remaining cached lines is - * calculated. false=the maximum width is set to 0 if the - * widest line is being reset. - */ - public void redrawReset(int startLine, int lineCount, boolean calculateMaxWidth) { - reset(startLine, lineCount, calculateMaxWidth); - } - /** - * Resets the line width of the lines in the specified range. - *
- * - * @param startLine the first line to reset - * @param lineCount the number of lines to reset - * @param calculateMaxWidth true=if the widest line is being - * reset the maximum width of all remaining cached lines is - * calculated. false=the maximum width is set to 0 if the - * widest line is being reset. - */ - public void reset(int startLine, int lineCount, boolean calculateMaxWidth) { - int endLine = startLine + lineCount; - - if (startLine < 0 || endLine > lineWidth.length) { - return; - } - for (int i = startLine; i < endLine; i++) { - lineWidth[i] = -1; - } - // if the longest line is one of the reset lines, the maximum line - // width is no longer valid - if (maxWidthLineIndex >= startLine && maxWidthLineIndex < endLine) { - maxWidth = 0; - maxWidthLineIndex = -1; - if (calculateMaxWidth) { - for (int i = 0; i < lineCount; i++) { - if (lineWidth[i] > maxWidth) { - maxWidth = lineWidth[i]; - maxWidthLineIndex = i; - } - } - } - } - } - /** - * Updates the line width array to reflect a text change. - * Lines affected by the text change will be reset. - *
- *
- * @param startOffset the start offset of the text change
- * @param newLineCount the number of inserted lines
- * @param replaceLineCount the number of deleted lines
- * @param newCharCount the number of new characters
- * @param replaceCharCount the number of deleted characters
- */
- public void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount) {
- int startLine = parent.getLineAtOffset(startOffset);
- boolean removedMaxLine = (maxWidthLineIndex > startLine && maxWidthLineIndex <= startLine + replaceLineCount);
- // entire text deleted?
- if (startLine == 0 && replaceLineCount == lineCount) {
- lineCount = newLineCount;
- lineWidth = new int[lineCount];
- reset(0, lineCount, false);
- maxWidth = 0;
- }
- else {
- linesChanged(startLine, -replaceLineCount);
- linesChanged(startLine, newLineCount);
- lineWidth[startLine] = -1;
- }
- // only calculate the visible lines. otherwise measurements of changed lines
- // outside the visible area may subsequently change again without the
- // lines ever being visible.
- calculateVisible(startLine, newLineCount);
- // maxWidthLineIndex will be -1 (i.e., unknown line width) if the widget has
- // not been visible yet and the changed lines have therefore not been
- // calculated above.
- if (removedMaxLine ||
- (maxWidthLineIndex != -1 && lineWidth[maxWidthLineIndex] < maxWidth)) {
- // longest line has been removed or changed and is now shorter.
- // need to recalculate maximum content width for all lines
- maxWidth = 0;
- for (int i = 0; i < lineCount; i++) {
- if (lineWidth[i] > maxWidth) {
- maxWidth = lineWidth[i];
- maxWidthLineIndex = i;
- }
- }
- }
- }
- }
- /**
- * Updates the line wrapping of the content.
- * The line wrapping must always be in a consistent state.
- * Therefore, when reset
or redrawReset
- * is called, the line wrapping is recalculated immediately
- * instead of in calculate
.
- */
- class WordWrapCache implements LineCache {
- StyledText parent;
- WrappedContent visualContent;
-
- /**
- * Creates a new WordWrapCache
and calculates an initial
- * line wrapping.
- *
- * - * @param parent the StyledText widget to wrap content in. - * @param content the content provider that does the actual line wrapping. - */ - public WordWrapCache(StyledText parent, WrappedContent content) { - this.parent = parent; - visualContent = content; - visualContent.wrapLines(); - } - /** - * Do nothing. Lines are wrapped immediately after reset. - *
- * - * @param startLine first line to calculate - * @param lineCount number of lines to calculate - */ - public void calculate(int startLine, int lineCount) { - } - /** - * Returns the client area width. Lines are wrapped so there - * is no horizontal scroll bar. - *
- *
- * @return the line width
- */
- public int getWidth() {
- return parent.getClientArea().width;
- }
- /**
- * Wraps the lines in the specified range.
- * This method is called in StyledText.redraw()
.
- * A redraw is therefore not necessary.
- *
- * - * @param startLine the first line to reset - * @param lineCount the number of lines to reset - * @param calculateMaxWidth true=implementors should retain a - * valid width even if it is affected by the reset operation. - * false=the width may be set to 0 - */ - public void redrawReset(int startLine, int lineCount, boolean calculateMaxWidth) { - if (lineCount == visualContent.getLineCount()) { - // do a full rewrap if all lines are reset - visualContent.wrapLines(); - } - else { - visualContent.reset(startLine, lineCount); - } - } - /** - * Rewraps the lines in the specified range and redraws - * the widget if the line wrapping has changed. - *
- * - * @param startLine the first line to reset - * @param lineCount the number of lines to reset - * @param calculateMaxWidth true=implementors should retain a - * valid width even if it is affected by the reset operation. - * false=the width may be set to 0 - */ - public void reset(int startLine, int lineCount, boolean calculateMaxWidth) { - int itemCount = getPartialBottomIndex() - topIndex + 1; - int[] oldLineOffsets = new int[itemCount]; - - for (int i = 0; i < itemCount; i++) { - oldLineOffsets[i] = visualContent.getOffsetAtLine(i + topIndex); - } - redrawReset(startLine, lineCount, calculateMaxWidth); - // check for cases which will require a full redraw - if (getPartialBottomIndex() - topIndex + 1 != itemCount) { - // number of visible lines has changed - parent.internalRedraw(); - } - else { - for (int i = 0; i < itemCount; i++) { - if (visualContent.getOffsetAtLine(i + topIndex) != oldLineOffsets[i]) { - // wrapping of one of the visible lines has changed - parent.internalRedraw(); - break; - } - } - } - } - /** - * Passes the text change notification to the line wrap content. - *
- *
- * @param startOffset the start offset of the text change
- * @param newLineCount the number of inserted lines
- * @param replaceLineCount the number of deleted lines
- * @param newCharCount the number of new characters
- * @param replaceCharCount the number of deleted characters
- */
- public void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount) {
- int startLine = visualContent.getLineAtOffset(startOffset);
-
- visualContent.textChanged(startOffset, newLineCount, replaceLineCount, newCharCount, replaceCharCount);
- if (startLine <= getPartialBottomIndex()) {
- // only redraw if the text change is inside or above the
- // visible lines. if it is below the visible lines it will
- // not affect the word wrapping. fixes bug 14047.
- parent.internalRedraw();
- }
- }
- }
+ static final char TAB = '\t';
+ static final String PlatformLineDelimiter = System.getProperty("line.separator");
+ static final int BIDI_CARET_WIDTH = 4;
+ static final int XINSET = BIDI_CARET_WIDTH - 1;
+ static final int DEFAULT_WIDTH = 64;
+ static final int DEFAULT_HEIGHT = 64;
+
+ static final int ExtendedModify = 3000;
+ static final int LineGetBackground = 3001;
+ static final int LineGetStyle = 3002;
+ static final int TextChanging = 3003;
+ static final int TextSet = 3004;
+ static final int VerifyKey = 3005;
+ static final int TextChanged = 3006;
+ static final int LineGetSegments = 3007;
+
+ Color selectionBackground; // selection background color
+ Color selectionForeground; // selection foreground color
+ StyledTextContent logicalContent; // native content (default or user specified)
+ StyledTextContent content; // line wrapping content, same as logicalContent if word wrap is off
+ DisplayRenderer renderer;
+ TextChangeListener textChangeListener; // listener for TextChanging, TextChanged and TextSet events from StyledTextContent
+ DefaultLineStyler defaultLineStyler;// used for setStyles API when no LineStyleListener is registered
+ LineCache lineCache;
+ boolean userLineStyle = false; // true=widget is using a user defined line style listener for line styles. false=widget is using the default line styler to store line styles
+ boolean userLineBackground = false; // true=widget is using a user defined line background listener for line backgrounds. false=widget is using the default line styler to store line backgrounds
+ int verticalScrollOffset = 0; // pixel based
+ int horizontalScrollOffset = 0; // pixel based
+ int topIndex = 0; // top visible line
+ int topOffset = 0; // offset of first character in top line
+ int clientAreaHeight = 0; // the client area height. Needed to calculate content width for new
+ // visible lines during Resize callback
+ int clientAreaWidth = 0; // the client area width. Needed during Resize callback to determine
+ // if line wrap needs to be recalculated
+ int lineHeight; // line height=font height
+ int tabLength = 4; // number of characters in a tab
+ int lineEndSpaceWidth; // space, in pixel, used to indicated a selected line break
+ int leftMargin = 1;
+ int topMargin = 1;
+ int rightMargin = 2;
+ int bottomMargin = 2;
+ Cursor ibeamCursor;
+ Cursor arrowCursor;
+ Cursor currentCursor; // tracks the current mouse pointer
+ Cursor customCursor = null;
+ int columnX; // keep track of the horizontal caret position
+ // when changing lines/pages. Fixes bug 5935
+ int caretOffset = 0;
+ Point selection = new Point(0, 0); // x is the beginning character offset, y is the ending character offset
+ int selectionAnchor; // position of selection anchor. 0 based offset from beginning of text
+ Point doubleClickSelection; // selection after last mouse double click
+ boolean editable = true;
+ boolean wordWrap = false;
+ boolean doubleClickEnabled = true; // see getDoubleClickEnabled
+ boolean overwrite = false; // insert/overwrite edit mode
+ int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default.
+ Hashtable keyActionMap = new Hashtable();
+ Color background = null; // workaround for bug 4791
+ Color foreground = null; //
+ Clipboard clipboard;
+ boolean mouseDoubleClick = false; // true=a double click ocurred. Don't do mouse swipe selection.
+ int autoScrollDirection = SWT.NULL; // the direction of autoscrolling (up, down, right, left)
+ int lastTextChangeStart; // cache data of the
+ int lastTextChangeNewLineCount; // last text changing
+ int lastTextChangeNewCharCount; // event for use in the
+ int lastTextChangeReplaceLineCount; // text changed handler
+ int lastTextChangeReplaceCharCount;
+ boolean isBidi;
+ boolean bidiColoring = false; // apply the BIDI algorithm on text segments of the same color
+ Image leftCaretBitmap = null;
+ Image rightCaretBitmap = null;
+ int caretDirection = SWT.NULL;
+ PaletteData caretPalette = null;
+ int lastCaretDirection = SWT.NULL;
+ boolean isCarbon; // flag set to true on Mac OSX
+
+ /**
+ * The Printing class implements printing of a range of text.
+ * An instance of
RTFWriter
class is used to write widget content as
+ * rich text. The implementation complies with the RTF specification
+ * version 1.5.
+ * + * toString() is guaranteed to return a valid RTF string only after + * close() has been called. + *
+ *+ * Whole and partial lines and line breaks can be written. Lines will be + * formatted using the styles queried from the LineStyleListener, if + * set, or those set directly in the widget. All styles are applied to + * the RTF stream like they are rendered by the widget. In addition, the + * widget font name and size is used for the whole text. + *
+ */ + class RTFWriter extends TextWriter { + final int DEFAULT_FOREGROUND = 0; + final int DEFAULT_BACKGROUND = 1; + Vector colorTable = new Vector(); + boolean WriteUnicode; + + /** + * Creates a RTF writer that writes content starting at offset "start" + * in the document.start
and length
can be set to specify partial
+ * lines.
+ *
+ *
+ * @param start start offset of content to write, 0 based from
+ * beginning of document
+ * @param length length of content to write
+ */
+ public RTFWriter(int start, int length) {
+ super(start, length);
+ colorTable.addElement(getForeground());
+ colorTable.addElement(getBackground());
+ setUnicode();
+ }
+ /**
+ * Closes the RTF writer. Once closed no more content can be written.
+ * NOTE: toString()
does not return a valid RTF string until
+ * close()
has been called.
+ */
+ public void close() {
+ if (isClosed() == false) {
+ writeHeader();
+ write("\n}}\0");
+ super.close();
+ }
+ }
+ /**
+ * Returns the index of the specified color in the RTF color table.
+ *
+ *
+ * @param color the color
+ * @param defaultIndex return value if color is null
+ * @return the index of the specified color in the RTF color table
+ * or "defaultIndex" if "color" is null.
+ */
+ int getColorIndex(Color color, int defaultIndex) {
+ int index;
+
+ if (color == null) {
+ index = defaultIndex;
+ }
+ else {
+ index = colorTable.indexOf(color);
+ if (index == -1) {
+ index = colorTable.size();
+ colorTable.addElement(color);
+ }
+ }
+ return index;
+ }
+ /**
+ * Determines if Unicode RTF should be written.
+ * Don't write Unicode RTF on Windows 95/98/ME or NT.
+ */
+ void setUnicode() {
+ final String Win95 = "windows 95";
+ final String Win98 = "windows 98";
+ final String WinME = "windows me";
+ final String WinNT = "windows nt";
+ String osName = System.getProperty("os.name").toLowerCase();
+ String osVersion = System.getProperty("os.version");
+ int majorVersion = 0;
+
+ if (osName.startsWith(WinNT) && osVersion != null) {
+ int majorIndex = osVersion.indexOf('.');
+ if (majorIndex != -1) {
+ osVersion = osVersion.substring(0, majorIndex);
+ try {
+ majorVersion = Integer.parseInt(osVersion);
+ }
+ catch (NumberFormatException exception) {
+ // ignore exception. version number remains unknown.
+ // will write without Unicode
+ }
+ }
+ }
+ if (osName != null &&
+ osName.startsWith(Win95) == false &&
+ osName.startsWith(Win98) == false &&
+ osName.startsWith(WinME) == false &&
+ (osName.startsWith(WinNT) == false || majorVersion > 4)) {
+ WriteUnicode = true;
+ }
+ else {
+ WriteUnicode = false;
+ }
+ }
+ /**
+ * Appends the specified segment of "string" to the RTF data.
+ * Copy from start
up to, but excluding, end
.
+ *
+ * + * @param string string to copy a segment from. Must not contain + * line breaks. Line breaks should be written using writeLineDelimiter() + * @param start start offset of segment. 0 based. + * @param end end offset of segment + */ + void write(String string, int start, int end) { + for (int index = start; index < end; index++) { + char ch = string.charAt(index); + if (ch > 0xFF && WriteUnicode) { + // write the sub string from the last escaped character + // to the current one. Fixes bug 21698. + if (index > start) { + write(string.substring(start, index)); + } + write("\\u"); + write(Integer.toString((short) ch)); + write(' '); // control word delimiter + start = index + 1; + } + else + if (ch == '}' || ch == '{' || ch == '\\') { + // write the sub string from the last escaped character + // to the current one. Fixes bug 21698. + if (index > start) { + write(string.substring(start, index)); + } + write('\\'); + write(ch); + start = index + 1; + } + } + // write from the last escaped character to the end. + // Fixes bug 21698. + if (start < end) { + write(string.substring(start, end)); + } + } + /** + * Writes the RTF header including font table and color table. + */ + void writeHeader() { + StringBuffer header = new StringBuffer(); + FontData fontData = getFont().getFontData()[0]; + header.append("{\\rtf1\\ansi"); + // specify code page, necessary for copy to work in bidi + // systems that don't support Unicode RTF. + String cpg = System.getProperty("file.encoding").toLowerCase(); + if (cpg.startsWith("cp") || cpg.startsWith("ms")) { + cpg = cpg.substring(2, cpg.length()); + header.append("\\ansicpg"); + header.append(cpg); + } + header.append("\\uc0\\deff0{\\fonttbl{\\f0\\fnil "); + header.append(fontData.getName()); + header.append(";}}\n{\\colortbl"); + for (int i = 0; i < colorTable.size(); i++) { + Color color = (Color) colorTable.elementAt(i); + header.append("\\red"); + header.append(color.getRed()); + header.append("\\green"); + header.append(color.getGreen()); + header.append("\\blue"); + header.append(color.getBlue()); + header.append(";"); + } + // some RTF readers ignore the deff0 font tag. Explicitly + // set the font for the whole document to work around this. + header.append("}\n{\\f0\\fs"); + // font size is specified in half points + header.append(fontData.getHeight() * 2); + header.append(" "); + write(header.toString(), 0); + } + /** + * Appends the specified line text to the RTF data. Lines will be formatted + * using the styles queried from the LineStyleListener, if set, or those set + * directly in the widget. + *
+ * + * @param line line text to write as RTF. Must not contain line breaks + * Line breaks should be written using writeLineDelimiter() + * @param lineOffset offset of the line. 0 based from the start of the + * widget document. Any text occurring before the start offset or after the + * end offset specified during object creation is ignored. + * @exception SWTException
+ * + * @param lineDelimiter line delimiter to write as RTF. + * @exception SWTException
+ *
+ * @param line line text to write as RTF. Must not contain line breaks
+ * Line breaks should be written using writeLineDelimiter()
+ * @param lineOffset offset of the line. 0 based from the start of the
+ * widget document. Any text occurring before the start offset or after the
+ * end offset specified during object creation is ignored.
+ * @param styles styles to use for formatting. Must not be null.
+ * @param linebackground line background color to use for formatting.
+ * May be null.
+ */
+ void writeStyledLine(String line, int lineOffset, StyleRange[] styles, Color lineBackground) {
+ int lineLength = line.length();
+ int lineIndex;
+ int copyEnd;
+ int startOffset = getStart();
+ int endOffset = startOffset + super.getCharCount();
+ int lineEndOffset = Math.min(lineLength, endOffset - lineOffset);
+ int writeOffset = startOffset - lineOffset;
+
+ if (writeOffset >= line.length()) {
+ return; // whole line is outside write range
+ }
+ else
+ if (writeOffset > 0) {
+ lineIndex = writeOffset; // line starts before RTF write start
+ }
+ else {
+ lineIndex = 0;
+ }
+ if (lineBackground != null) {
+ write("{\\highlight");
+ write(getColorIndex(lineBackground, DEFAULT_BACKGROUND));
+ write(" ");
+ }
+ for (int i = 0; i < styles.length; i++) {
+ StyleRange style = styles[i];
+ int start = style.start - lineOffset;
+ int end = start + style.length;
+ int colorIndex;
+ // skip over partial first line
+ if (end < writeOffset) {
+ continue;
+ }
+ // style starts beyond line end or RTF write end
+ if (start >= lineEndOffset) {
+ break;
+ }
+ // write any unstyled text
+ if (lineIndex < start) {
+ // copy to start of style
+ // style starting betond end of write range or end of line
+ // is guarded against above.
+ write(line, lineIndex, start);
+ lineIndex = start;
+ }
+ // write styled text
+ colorIndex = getColorIndex(style.background, DEFAULT_BACKGROUND);
+ write("{\\cf");
+ write(getColorIndex(style.foreground, DEFAULT_FOREGROUND));
+ if (colorIndex != DEFAULT_BACKGROUND) {
+ write("\\highlight");
+ write(colorIndex);
+ }
+ if (style.fontStyle == SWT.BOLD) {
+ write("\\b");
+ }
+ write(" ");
+ // copy to end of style or end of write range or end of line
+ copyEnd = Math.min(end, lineEndOffset);
+ // guard against invalid styles and let style processing continue
+ copyEnd = Math.max(copyEnd, lineIndex);
+ write(line, lineIndex, copyEnd);
+ if (style.fontStyle == SWT.BOLD) {
+ write("\\b0");
+ }
+ write("}");
+ lineIndex = copyEnd;
+ }
+ // write unstyled text at the end of the line
+ if (lineIndex < lineEndOffset) {
+ write(line, lineIndex, lineEndOffset);
+ }
+ if (lineBackground != null) {
+ write("}");
+ }
+ }
+ }
+ /**
+ * The TextWriter
class is used to write widget content to
+ * a string. Whole and partial lines and line breaks can be written. To write
+ * partial lines, specify the start and length of the desired segment
+ * during object creation.
+ *
+ * NOTE: toString()
is guaranteed to return a valid string only after close()
+ * has been called.
+ */
+ class TextWriter {
+ private StringBuffer buffer;
+ private int startOffset; // offset of first character that will be written
+ private int endOffset; // offset of last character that will be written.
+ // 0 based from the beginning of the widget text.
+ private boolean isClosed = false;
+
+ /**
+ * Creates a writer that writes content starting at offset "start"
+ * in the document. start
and length
can be set to specify partial lines.
+ *
+ *
+ * @param start start offset of content to write, 0 based from beginning of document
+ * @param length length of content to write
+ */
+ public TextWriter(int start, int length) {
+ buffer = new StringBuffer(length);
+ startOffset = start;
+ endOffset = start + length;
+ }
+ /**
+ * Closes the writer. Once closed no more content can be written.
+ * NOTE: toString()
is not guaranteed to return a valid string unless
+ * the writer is closed.
+ */
+ public void close() {
+ if (isClosed == false) {
+ isClosed = true;
+ }
+ }
+ /**
+ * Returns the number of characters to write.
+ */
+ public int getCharCount() {
+ return endOffset - startOffset;
+ }
+ /**
+ * Returns the offset where writing starts. 0 based from the start of
+ * the widget text. Used to write partial lines.
+ */
+ public int getStart() {
+ return startOffset;
+ }
+ /**
+ * Returns whether the writer is closed.
+ */
+ public boolean isClosed() {
+ return isClosed;
+ }
+ /**
+ * Returns the string. close()
must be called before toString()
+ * is guaranteed to return a valid string.
+ *
+ * + * @return the string + */ + public String toString() { + return buffer.toString(); + } + /** + * Appends the given string to the data. + */ + void write(String string) { + buffer.append(string); + } + /** + * Inserts the given string to the data at the specified offset. + * Do nothing if "offset" is < 0 or > getCharCount() + *
+ * + * @param string text to insert + * @param offset offset in the existing data to insert "string" at. + */ + void write(String string, int offset) { + if (offset < 0 || offset > buffer.length()) { + return; + } + buffer.insert(offset, string); + } + /** + * Appends the given int to the data. + */ + void write(int i) { + buffer.append(i); + } + /** + * Appends the given character to the data. + */ + void write(char i) { + buffer.append(i); + } + /** + * Appends the specified line text to the data. + *
+ * + * @param line line text to write. Must not contain line breaks + * Line breaks should be written using writeLineDelimiter() + * @param lineOffset offset of the line. 0 based from the start of the + * widget document. Any text occurring before the start offset or after the + * end offset specified during object creation is ignored. + * @exception SWTException
+ * + * @param lineDelimiter line delimiter to write + * @exception SWTException
getWidth
.
+ */
+ interface LineCache {
+ /**
+ * Calculates the lines in the specified range.
+ *
+ *
+ * @param startLine first line to calculate
+ * @param lineCount number of lines to calculate
+ */
+ public void calculate(int startLine, int lineCount);
+ /**
+ * Returns a width that will be used by the StyledText
+ * widget to size a horizontal scroll bar.
+ *
+ *
+ * @return the line width
+ */
+ public int getWidth();
+ /**
+ * Resets the lines in the specified range.
+ * This method is called in StyledText.redraw()
+ * and allows implementors to call redraw themselves during reset.
+ *
+ * + * @param startLine the first line to reset + * @param lineCount the number of lines to reset + * @param calculateMaxWidth true=implementors should retain a + * valid width even if it is affected by the reset operation. + * false=the width may be set to 0 + */ + public void redrawReset(int startLine, int lineCount, boolean calculateMaxWidth); + /** + * Resets the lines in the specified range. + *
+ * + * @param startLine the first line to reset + * @param lineCount the number of lines to reset + * @param calculateMaxWidth true=implementors should retain a + * valid width even if it is affected by the reset operation. + * false=the width may be set to 0 + */ + public void reset(int startLine, int lineCount, boolean calculateMaxWidth); + /** + * Called when a text change occurred. + *
+ *
+ * @param startOffset the start offset of the text change
+ * @param newLineCount the number of inserted lines
+ * @param replaceLineCount the number of deleted lines
+ * @param newCharCount the number of new characters
+ * @param replaceCharCount the number of deleted characters
+ */
+ public void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount);
+ }
+ /**
+ * Keeps track of line widths and the longest line in the
+ * StyledText document.
+ * Line widths are calculated when requested by a call to
+ * calculate
and cached until reset by a call
+ * to redrawReset
or reset
.
+ */
+ class ContentWidthCache implements LineCache {
+ StyledText parent; // parent widget, used to create a GC for line measuring
+ int[] lineWidth; // width in pixel of each line in the document, -1 for unknown width
+ int lineCount; // number of lines in lineWidth array
+ int maxWidth; // maximum line width of all measured lines
+ int maxWidthLineIndex; // index of the widest line
+
+ /**
+ * Creates a new ContentWidthCache
and allocates space
+ * for the given number of lines.
+ *
+ * + * @param parent the StyledText widget used to create a GC for + * line measuring + * @param lineCount initial number of lines to allocate space for + */ + public ContentWidthCache(StyledText parent, int lineCount) { + this.lineCount = lineCount; + this.parent = parent; + lineWidth = new int[lineCount]; + reset(0, lineCount, false); + } + /** + * Calculates the width of each line in the given range if it has + * not been calculated yet. + * If any line in the given range is wider than the currently widest + * line, the maximum line width is updated, + *
+ * + * @param startLine first line to calculate the line width of + * @param lineCount number of lines to calculate the line width for + */ + public void calculate(int startLine, int lineCount) { + GC gc = null; + int caretWidth = 0; + int stopLine = startLine + lineCount; + + for (int i = startLine; i < stopLine; i++) { + if (lineWidth[i] == -1) { + String line = content.getLine(i); + int lineOffset = content.getOffsetAtLine(i); + + if (gc == null) { + gc = parent.getGC(); + caretWidth = getCaretWidth(); + } + lineWidth[i] = contentWidth(line, lineOffset, gc) + caretWidth; + } + if (lineWidth[i] > maxWidth) { + maxWidth = lineWidth[i]; + maxWidthLineIndex = i; + } + } + if (gc != null) { + gc.dispose(); + } + } + /** + * Calculates the width of the visible lines in the specified + * range. + *
+ * + * @param startLine the first changed line + * @param newLineCount the number of inserted lines + */ + void calculateVisible(int startLine, int newLineCount) { + int topIndex = parent.getTopIndex(); + int bottomLine = Math.min(getPartialBottomIndex(), startLine + newLineCount); + + startLine = Math.max(startLine, topIndex); + calculate(startLine, bottomLine - startLine + 1); + } + /** + * Measures the width of the given line. + *
+ *
+ * @param line the line to measure
+ * @param lineOffset start offset of the line to measure, relative
+ * to the start of the document
+ * @param gc the GC to use for measuring the line
+ * @param currentFont the font currently set in gc. Cached for better
+ * performance. Null when running in a bidi locale.
+ * @return the width of the given line
+ */
+ int contentWidth(String line, int lineOffset, GC gc) {
+ int width;
+
+ if (isBidi()) {
+ StyledTextBidi bidi = getStyledTextBidi(line, lineOffset, gc);
+ width = bidi.getTextWidth();
+ }
+ else {
+ StyledTextEvent event = renderer.getLineStyleData(lineOffset, line);
+ StyleRange[] styles = null;
+ if (event != null) {
+ styles = renderer.filterLineStyles(event.styles);
+ }
+ width = renderer.getTextWidth(line, lineOffset, 0, line.length(), styles, 0, gc);
+ }
+ return width + leftMargin;
+ }
+ /**
+ * Grows the lineWidth
array to accomodate new line width
+ * information.
+ *
+ * + * @param numLines the number of elements to increase the array by + */ + void expandLines(int numLines) { + int size = lineWidth.length; + if (size - lineCount >= numLines) { + return; + } + int[] newLines = new int[Math.max(size * 2, size + numLines)]; + System.arraycopy(lineWidth, 0, newLines, 0, size); + lineWidth = newLines; + reset(size, lineWidth.length - size, false); + } + /** + * Returns the width of the longest measured line. + *
+ * + * @return the width of the longest measured line. + */ + public int getWidth() { + return maxWidth; + } + /** + * Updates the line width array to reflect inserted or deleted lines. + *
+ * + * @param start the starting line of the change that took place + * @param delta the number of lines in the change, > 0 indicates lines inserted, + * < 0 indicates lines deleted + */ + void linesChanged(int startLine, int delta) { + boolean inserting = delta > 0; + + if (delta == 0) { + return; + } + if (inserting) { + // shift the lines down to make room for new lines + expandLines(delta); + for (int i = lineCount - 1; i >= startLine; i--) { + lineWidth[i + delta] = lineWidth[i]; + } + // reset the new lines + for (int i = startLine + 1; i <= startLine + delta && i < lineWidth.length; i++) { + lineWidth[i] = -1; + } + // have new lines been inserted above the longest line? + if (maxWidthLineIndex >= startLine) { + maxWidthLineIndex += delta; + } + } + else { + // shift up the lines + for (int i = startLine - delta; i < lineCount; i++) { + lineWidth[i+delta] = lineWidth[i]; + } + // has the longest line been removed? + if (maxWidthLineIndex > startLine && maxWidthLineIndex <= startLine - delta) { + maxWidth = 0; + maxWidthLineIndex = -1; + } + else + if (maxWidthLineIndex >= startLine - delta) { + maxWidthLineIndex += delta; + } + } + lineCount += delta; + } + /** + * Resets the line width of the lines in the specified range. + *
+ * + * @param startLine the first line to reset + * @param lineCount the number of lines to reset + * @param calculateMaxWidth true=if the widest line is being + * reset the maximum width of all remaining cached lines is + * calculated. false=the maximum width is set to 0 if the + * widest line is being reset. + */ + public void redrawReset(int startLine, int lineCount, boolean calculateMaxWidth) { + reset(startLine, lineCount, calculateMaxWidth); + } + /** + * Resets the line width of the lines in the specified range. + *
+ * + * @param startLine the first line to reset + * @param lineCount the number of lines to reset + * @param calculateMaxWidth true=if the widest line is being + * reset the maximum width of all remaining cached lines is + * calculated. false=the maximum width is set to 0 if the + * widest line is being reset. + */ + public void reset(int startLine, int lineCount, boolean calculateMaxWidth) { + int endLine = startLine + lineCount; + + if (startLine < 0 || endLine > lineWidth.length) { + return; + } + for (int i = startLine; i < endLine; i++) { + lineWidth[i] = -1; + } + // if the longest line is one of the reset lines, the maximum line + // width is no longer valid + if (maxWidthLineIndex >= startLine && maxWidthLineIndex < endLine) { + maxWidth = 0; + maxWidthLineIndex = -1; + if (calculateMaxWidth) { + for (int i = 0; i < lineCount; i++) { + if (lineWidth[i] > maxWidth) { + maxWidth = lineWidth[i]; + maxWidthLineIndex = i; + } + } + } + } + } + /** + * Updates the line width array to reflect a text change. + * Lines affected by the text change will be reset. + *
+ *
+ * @param startOffset the start offset of the text change
+ * @param newLineCount the number of inserted lines
+ * @param replaceLineCount the number of deleted lines
+ * @param newCharCount the number of new characters
+ * @param replaceCharCount the number of deleted characters
+ */
+ public void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount) {
+ int startLine = parent.getLineAtOffset(startOffset);
+ boolean removedMaxLine = (maxWidthLineIndex > startLine && maxWidthLineIndex <= startLine + replaceLineCount);
+ // entire text deleted?
+ if (startLine == 0 && replaceLineCount == lineCount) {
+ lineCount = newLineCount;
+ lineWidth = new int[lineCount];
+ reset(0, lineCount, false);
+ maxWidth = 0;
+ }
+ else {
+ linesChanged(startLine, -replaceLineCount);
+ linesChanged(startLine, newLineCount);
+ lineWidth[startLine] = -1;
+ }
+ // only calculate the visible lines. otherwise measurements of changed lines
+ // outside the visible area may subsequently change again without the
+ // lines ever being visible.
+ calculateVisible(startLine, newLineCount);
+ // maxWidthLineIndex will be -1 (i.e., unknown line width) if the widget has
+ // not been visible yet and the changed lines have therefore not been
+ // calculated above.
+ if (removedMaxLine ||
+ (maxWidthLineIndex != -1 && lineWidth[maxWidthLineIndex] < maxWidth)) {
+ // longest line has been removed or changed and is now shorter.
+ // need to recalculate maximum content width for all lines
+ maxWidth = 0;
+ for (int i = 0; i < lineCount; i++) {
+ if (lineWidth[i] > maxWidth) {
+ maxWidth = lineWidth[i];
+ maxWidthLineIndex = i;
+ }
+ }
+ }
+ }
+ }
+ /**
+ * Updates the line wrapping of the content.
+ * The line wrapping must always be in a consistent state.
+ * Therefore, when reset
or redrawReset
+ * is called, the line wrapping is recalculated immediately
+ * instead of in calculate
.
+ */
+ class WordWrapCache implements LineCache {
+ StyledText parent;
+ WrappedContent visualContent;
+
+ /**
+ * Creates a new WordWrapCache
and calculates an initial
+ * line wrapping.
+ *
+ * + * @param parent the StyledText widget to wrap content in. + * @param content the content provider that does the actual line wrapping. + */ + public WordWrapCache(StyledText parent, WrappedContent content) { + this.parent = parent; + visualContent = content; + visualContent.wrapLines(); + } + /** + * Do nothing. Lines are wrapped immediately after reset. + *
+ * + * @param startLine first line to calculate + * @param lineCount number of lines to calculate + */ + public void calculate(int startLine, int lineCount) { + } + /** + * Returns the client area width. Lines are wrapped so there + * is no horizontal scroll bar. + *
+ *
+ * @return the line width
+ */
+ public int getWidth() {
+ return parent.getClientArea().width;
+ }
+ /**
+ * Wraps the lines in the specified range.
+ * This method is called in StyledText.redraw()
.
+ * A redraw is therefore not necessary.
+ *
+ * + * @param startLine the first line to reset + * @param lineCount the number of lines to reset + * @param calculateMaxWidth true=implementors should retain a + * valid width even if it is affected by the reset operation. + * false=the width may be set to 0 + */ + public void redrawReset(int startLine, int lineCount, boolean calculateMaxWidth) { + if (lineCount == visualContent.getLineCount()) { + // do a full rewrap if all lines are reset + visualContent.wrapLines(); + } + else { + visualContent.reset(startLine, lineCount); + } + } + /** + * Rewraps the lines in the specified range and redraws + * the widget if the line wrapping has changed. + *
+ * + * @param startLine the first line to reset + * @param lineCount the number of lines to reset + * @param calculateMaxWidth true=implementors should retain a + * valid width even if it is affected by the reset operation. + * false=the width may be set to 0 + */ + public void reset(int startLine, int lineCount, boolean calculateMaxWidth) { + int itemCount = getPartialBottomIndex() - topIndex + 1; + int[] oldLineOffsets = new int[itemCount]; + + for (int i = 0; i < itemCount; i++) { + oldLineOffsets[i] = visualContent.getOffsetAtLine(i + topIndex); + } + redrawReset(startLine, lineCount, calculateMaxWidth); + // check for cases which will require a full redraw + if (getPartialBottomIndex() - topIndex + 1 != itemCount) { + // number of visible lines has changed + parent.internalRedraw(); + } + else { + for (int i = 0; i < itemCount; i++) { + if (visualContent.getOffsetAtLine(i + topIndex) != oldLineOffsets[i]) { + // wrapping of one of the visible lines has changed + parent.internalRedraw(); + break; + } + } + } + } + /** + * Passes the text change notification to the line wrap content. + *
+ * + * @param startOffset the start offset of the text change + * @param newLineCount the number of inserted lines + * @param replaceLineCount the number of deleted lines + * @param newCharCount the number of new characters + * @param replaceCharCount the number of deleted characters + */ + public void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount) { + int startLine = visualContent.getLineAtOffset(startOffset); + + visualContent.textChanged(startOffset, newLineCount, replaceLineCount, newCharCount, replaceCharCount); + if (startLine <= getPartialBottomIndex()) { + // only redraw if the text change is inside or above the + // visible lines. if it is below the visible lines it will + // not affect the word wrapping. fixes bug 14047. + parent.internalRedraw(); + } + } + } /** * Constructs a new instance of this class given its parent @@ -1552,7 +1558,7 @@ *
* The style value is either one of the style constants defined in
* class SWT
which is applicable to instances of this
- * class, or must be built by bitwise OR'ing together
+ * class, or must be built by bitwise OR'ing together
* (that is, using the int
"|" operator) two or more
* of those SWT
style constants. The class description
* lists the style constants that are applicable to the class.
@@ -1577,60 +1583,64 @@
* @see #getStyle
*/
public StyledText(Composite parent, int style) {
- super(parent, checkStyle(style | SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND));
- // set the bg/fg in the OS to ensure that these are the same as StyledText, necessary
- // for ensuring that the bg/fg the IME box uses is the same as what StyledText uses
- super.setForeground(getForeground());
- super.setBackground(getBackground());
- Display display = getDisplay();
- isBidi = StyledTextBidi.isBidiPlatform();
- if ((style & SWT.READ_ONLY) != 0) {
- setEditable(false);
- }
- if ((style & SWT.BORDER) == 0 || (style & SWT.SINGLE) == 0) {
- leftMargin = topMargin = rightMargin = bottomMargin = 0;
- }
- clipboard = new Clipboard(display);
- installDefaultContent();
- initializeRenderer();
- if ((style & SWT.WRAP) != 0) {
- setWordWrap(true);
- }
- else {
- lineCache = new ContentWidthCache(this, content.getLineCount());
- }
- if (isBidi() == false) {
- Caret caret = new Caret(this, SWT.NULL);
- caret.setSize(1, caret.getSize().y);
- }
- else {
- createCaretBitmaps();
- new Caret(this, SWT.NULL);
- setBidiCaretDirection();
- Runnable runnable = new Runnable() {
- public void run() {
- // setBidiCaretLocation calculates caret location like during
- // cursor movement and takes keyboard language into account.
- // Fixes 1GKPYMK
- setBidiCaretLocation(null);
- }
- };
- StyledTextBidi.addLanguageListener(this, runnable);
- }
-
- String platform= SWT.getPlatform();
- isCarbon = "carbon".equals(platform);
-
- // set the caret width, the height of the caret will default to the line height
- calculateScrollBars();
- createKeyBindings();
- ibeamCursor = new Cursor(display, SWT.CURSOR_IBEAM);
- setCursor(ibeamCursor);
- installListeners();
- installDefaultLineStyler();
+ super(parent, checkStyle(style | SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND));
+ // set the bg/fg in the OS to ensure that these are the same as StyledText, necessary
+ // for ensuring that the bg/fg the IME box uses is the same as what StyledText uses
+ super.setForeground(getForeground());
+ super.setBackground(getBackground());
+ Display display = getDisplay();
+ isBidi = StyledTextBidi.isBidiPlatform();
+ if ((style & SWT.READ_ONLY) != 0) {
+ setEditable(false);
+ }
+ if ((style & SWT.BORDER) == 0 || (style & SWT.SINGLE) == 0) {
+ leftMargin = topMargin = rightMargin = bottomMargin = 0;
+ }
+ clipboard = new Clipboard(display);
+ installDefaultContent();
+ initializeRenderer();
+ if ((style & SWT.WRAP) != 0) {
+ setWordWrap(true);
+ }
+ else {
+ lineCache = new ContentWidthCache(this, content.getLineCount());
+ }
+ if (isBidi() == false) {
+ Caret caret = new Caret(this, SWT.NULL);
+ caret.setSize(1, caret.getSize().y);
+ }
+ else {
+ createCaretBitmaps();
+ new Caret(this, SWT.NULL);
+ setBidiCaretDirection();
+ Runnable runnable = new Runnable() {
+ public void run() {
+ // setBidiCaretLocation calculates caret location like during
+ // cursor movement and takes keyboard language into account.
+ // Fixes 1GKPYMK
+ setBidiCaretLocation(null);
+ }
+ };
+ StyledTextBidi.addLanguageListener(this, runnable);
+ }
+
+ String platform= SWT.getPlatform();
+ isCarbon = "carbon".equals(platform);
+
+ // set the caret width, the height of the caret will default to the line height
+ calculateScrollBars();
+ createKeyBindings();
+
+ ibeamCursor = new Cursor(display, SWT.CURSOR_IBEAM);
+ arrowCursor = new Cursor(display, SWT.CURSOR_ARROW);
+ currentCursor = ibeamCursor;
+ super.setCursor(currentCursor);
+
+ installListeners();
+ installDefaultLineStyler();
}
-/**
- * Adds an extended modify listener. An ExtendedModify event is sent by the
+/**
+ * Adds an extended modify listener. An ExtendedModify event is sent by the
* widget when the widget text has changed.
*
* @@ -1644,75 +1654,75 @@ *
* - * @param key a key code defined in SWT.java or a character. - * Optionally ORd with a state mask. Preferred state masks are one or more of - * SWT.MOD1, SWT.MOD2, SWT.MOD3, since these masks account for modifier platform + * @param key a key code defined in SWT.java or a character. + * Optionally ORd with a state mask. Preferred state masks are one or more of + * SWT.MOD1, SWT.MOD2, SWT.MOD3, since these masks account for modifier platform * differences. However, there may be cases where using the specific state masks * (i.e., SWT.CTRL, SWT.SHIFT, SWT.ALT, SWT.COMMAND) makes sense. - * @param action one of the predefined actions defined in ST.java. - * Use SWT.NULL to remove a key binding. + * @param action one of the predefined actions defined in ST.java. + * Use SWT.NULL to remove a key binding. * @exception SWTException
* * @param listener the listener @@ -1727,15 +1737,15 @@ * @since 2.0 */ public void addBidiSegmentListener(BidiSegmentListener listener) { - checkWidget(); - if (listener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - StyledTextListener typedListener = new StyledTextListener(listener); - addListener(LineGetSegments, typedListener); + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + StyledTextListener typedListener = new StyledTextListener(listener); + addListener(LineGetSegments, typedListener); } /** - * Adds a line background listener. A LineGetBackground event is sent by the + * Adds a line background listener. A LineGetBackground event is sent by the * widget to determine the background color for a line. *
* @@ -1749,18 +1759,18 @@ *
* @@ -1774,20 +1784,20 @@ * */ public void addLineStyleListener(LineStyleListener listener) { - checkWidget(); - if (listener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - if (userLineStyle == false) { - removeLineStyleListener(defaultLineStyler); - defaultLineStyler.setStyleRange(null); - userLineStyle = true; - } - StyledTextListener typedListener = new StyledTextListener(listener); - addListener(LineGetStyle, typedListener); + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + if (userLineStyle == false) { + removeLineStyleListener(defaultLineStyler); + defaultLineStyler.setStyleRange(null); + userLineStyle = true; + } + StyledTextListener typedListener = new StyledTextListener(listener); + addListener(LineGetStyle, typedListener); } -/** - * Adds a modify listener. A Modify event is sent by the widget when the widget text +/** + * Adds a modify listener. A Modify event is sent by the widget when the widget text * has changed. *
* @@ -1801,15 +1811,15 @@ * */ public void addModifyListener(ModifyListener modifyListener) { - checkWidget(); - if (modifyListener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - TypedListener typedListener = new TypedListener(modifyListener); - addListener(SWT.Modify, typedListener); + checkWidget(); + if (modifyListener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(modifyListener); + addListener(SWT.Modify, typedListener); } -/** - * Adds a selection listener. A Selection event is sent by the widget when the +/** + * Adds a selection listener. A Selection event is sent by the widget when the * selection has changed. *
* @@ -1823,17 +1833,17 @@ * */ public void addSelectionListener(SelectionListener listener) { - checkWidget(); - if (listener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - TypedListener typedListener = new TypedListener(listener); - addListener(SWT.Selection, typedListener); -} -/** - * Adds a verify key listener. A VerifyKey event is sent by the widget when a key - * is pressed. The widget ignores the key press if the listener sets the doit field - * of the event to false. + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); +} +/** + * Adds a verify key listener. A VerifyKey event is sent by the widget when a key + * is pressed. The widget ignores the key press if the listener sets the doit field + * of the event to false. *
* * @param listener the listener @@ -1846,17 +1856,17 @@ * */ public void addVerifyKeyListener(VerifyKeyListener listener) { - checkWidget(); - if (listener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - StyledTextListener typedListener = new StyledTextListener(listener); - addListener(VerifyKey, typedListener); -} -/** - * Adds a verify listener. A Verify event is sent by the widget when the widget text - * is about to change. The listener can set the event text and the doit field to - * change the text that is set in the widget or to force the widget to ignore the + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + StyledTextListener typedListener = new StyledTextListener(listener); + addListener(VerifyKey, typedListener); +} +/** + * Adds a verify listener. A Verify event is sent by the widget when the widget text + * is about to change. The listener can set the event text and the doit field to + * change the text that is set in the widget or to force the widget to ignore the * text change. *
* @@ -1870,14 +1880,14 @@ * */ public void addVerifyListener(VerifyListener verifyListener) { - checkWidget(); - if (verifyListener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - TypedListener typedListener = new TypedListener(verifyListener); - addListener(SWT.Verify, typedListener); + checkWidget(); + if (verifyListener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(verifyListener); + addListener(SWT.Verify, typedListener); } -/** +/** * Appends a string to the text at the end of the widget. *
* @@ -1892,36 +1902,36 @@ * */ public void append(String string) { - checkWidget(); - if (string == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - int lastChar = Math.max(getCharCount(), 0); - replaceTextRange(lastChar, 0, string); + checkWidget(); + if (string == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + int lastChar = Math.max(getCharCount(), 0); + replaceTextRange(lastChar, 0, string); } /** * Calculates the width of the widest visible line. */ void calculateContentWidth() { - if (lineHeight != 0) { - lineCache = getLineCache(content); - lineCache.calculate(topIndex, getPartialBottomIndex() - topIndex + 1); - } + if (lineHeight != 0) { + lineCache = getLineCache(content); + lineCache.calculate(topIndex, getPartialBottomIndex() - topIndex + 1); + } } /** * Calculates the scroll bars */ void calculateScrollBars() { - ScrollBar horizontalBar = getHorizontalBar(); - ScrollBar verticalBar = getVerticalBar(); - - setScrollBars(); - if (verticalBar != null) { - verticalBar.setIncrement(getVerticalIncrement()); - } - if (horizontalBar != null) { - horizontalBar.setIncrement(getHorizontalIncrement()); - } + ScrollBar horizontalBar = getHorizontalBar(); + ScrollBar verticalBar = getVerticalBar(); + + setScrollBars(); + if (verticalBar != null) { + verticalBar.setIncrement(getVerticalIncrement()); + } + if (horizontalBar != null) { + horizontalBar.setIncrement(getHorizontalIncrement()); + } } /** * Calculates the top index based on the current vertical scroll offset. @@ -1930,97 +1940,97 @@ * The top index starts at 0. */ void calculateTopIndex() { - int oldTopIndex = topIndex; - int verticalIncrement = getVerticalIncrement(); - int clientAreaHeight = getClientArea().height; - - if (verticalIncrement == 0) { - return; - } - topIndex = Compatibility.ceil(verticalScrollOffset, verticalIncrement); - // Set top index to partially visible top line if no line is fully - // visible but at least some of the widget client area is visible. - // Fixes bug 15088. - if (topIndex > 0) { - if (clientAreaHeight > 0) { - int bottomPixel = verticalScrollOffset + clientAreaHeight; - int fullLineTopPixel = topIndex * verticalIncrement; - int fullLineVisibleHeight = bottomPixel - fullLineTopPixel; - // set top index to partially visible line if no line fully fits in - // client area or if space is available but not used (the latter should - // never happen because we use claimBottomFreeSpace) - if (fullLineVisibleHeight < verticalIncrement) { - topIndex--; - } - } - else - if (topIndex >= content.getLineCount()) { - topIndex = content.getLineCount() - 1; - } - } - if (topIndex != oldTopIndex) { - topOffset = content.getOffsetAtLine(topIndex); - lineCache.calculate(topIndex, getPartialBottomIndex() - topIndex + 1); - setHorizontalScrollBar(); - } + int oldTopIndex = topIndex; + int verticalIncrement = getVerticalIncrement(); + int clientAreaHeight = getClientArea().height; + + if (verticalIncrement == 0) { + return; + } + topIndex = Compatibility.ceil(verticalScrollOffset, verticalIncrement); + // Set top index to partially visible top line if no line is fully + // visible but at least some of the widget client area is visible. + // Fixes bug 15088. + if (topIndex > 0) { + if (clientAreaHeight > 0) { + int bottomPixel = verticalScrollOffset + clientAreaHeight; + int fullLineTopPixel = topIndex * verticalIncrement; + int fullLineVisibleHeight = bottomPixel - fullLineTopPixel; + // set top index to partially visible line if no line fully fits in + // client area or if space is available but not used (the latter should + // never happen because we use claimBottomFreeSpace) + if (fullLineVisibleHeight < verticalIncrement) { + topIndex--; + } + } + else + if (topIndex >= content.getLineCount()) { + topIndex = content.getLineCount() - 1; + } + } + if (topIndex != oldTopIndex) { + topOffset = content.getOffsetAtLine(topIndex); + lineCache.calculate(topIndex, getPartialBottomIndex() - topIndex + 1); + setHorizontalScrollBar(); + } } /** * Hides the scroll bars if widget is created in single line mode. */ static int checkStyle(int style) { - if ((style & SWT.SINGLE) != 0) { - style &= ~(SWT.H_SCROLL | SWT.V_SCROLL); - } - return style; + if ((style & SWT.SINGLE) != 0) { + style &= ~(SWT.H_SCROLL | SWT.V_SCROLL); + } + return style; } /** - * Scrolls down the text to use new space made available by a resize or by + * Scrolls down the text to use new space made available by a resize or by * deleted lines. */ void claimBottomFreeSpace() { - int newVerticalOffset = Math.max(0, content.getLineCount() * lineHeight - getClientArea().height); - - if (newVerticalOffset < verticalScrollOffset) { - // Scroll up so that empty lines below last text line are used. - // Fixes 1GEYJM0 - setVerticalScrollOffset(newVerticalOffset, true); - } + int newVerticalOffset = Math.max(0, content.getLineCount() * lineHeight - getClientArea().height); + + if (newVerticalOffset < verticalScrollOffset) { + // Scroll up so that empty lines below last text line are used. + // Fixes 1GEYJM0 + setVerticalScrollOffset(newVerticalOffset, true); + } } /** * Scrolls text to the right to use new space made available by a resize. */ void claimRightFreeSpace() { - int newHorizontalOffset = Math.max(0, lineCache.getWidth() - (getClientArea().width - leftMargin - rightMargin)); - - if (newHorizontalOffset < horizontalScrollOffset) { - // item is no longer drawn past the right border of the client area - // align the right end of the item with the right border of the - // client area (window is scrolled right). - scrollHorizontalBar(newHorizontalOffset - horizontalScrollOffset); - } + int newHorizontalOffset = Math.max(0, lineCache.getWidth() - (getClientArea().width - leftMargin - rightMargin)); + + if (newHorizontalOffset < horizontalScrollOffset) { + // item is no longer drawn past the right border of the client area + // align the right end of the item with the right border of the + // client area (window is scrolled right). + scrollHorizontalBar(newHorizontalOffset - horizontalScrollOffset); + } } /** * Clears the widget margin. - * + * * @param gc GC to render on * @param background background color to use for clearing the margin * @param clientArea widget client area dimensions * @param renderHeight height in pixel of the rendered lines */ void clearMargin(GC gc, Color background, Rectangle clientArea, int renderHeight) { - if (renderHeight + topMargin <= 0) { - return; - } - // clear the margin background - gc.setBackground(background); - gc.fillRectangle(0, 0, clientArea.width, topMargin); - gc.fillRectangle(0, 0, leftMargin, renderHeight + topMargin); - gc.fillRectangle( - 0, clientArea.height - bottomMargin, - clientArea.width, bottomMargin); - gc.fillRectangle( - clientArea.width - rightMargin, 0, - rightMargin, renderHeight + topMargin); + if (renderHeight + topMargin <= 0) { + return; + } + // clear the margin background + gc.setBackground(background); + gc.fillRectangle(0, 0, clientArea.width, topMargin); + gc.fillRectangle(0, 0, leftMargin, renderHeight + topMargin); + gc.fillRectangle( + 0, clientArea.height - bottomMargin, + clientArea.width, bottomMargin); + gc.fillRectangle( + clientArea.width - rightMargin, 0, + rightMargin, renderHeight + topMargin); } /** * Removes the widget selection. @@ -2029,24 +2039,24 @@ * @param sendEvent a Selection event is sent when set to true and when the selection is actually reset. */ void clearSelection(boolean sendEvent) { - int selectionStart = selection.x; - int selectionEnd = selection.y; - int length = content.getCharCount(); - - resetSelection(); - // redraw old selection, if any - if (selectionEnd - selectionStart > 0) { - // called internally to remove selection after text is removed - // therefore make sure redraw range is valid. - int redrawStart = Math.min(selectionStart, length); - int redrawEnd = Math.min(selectionEnd, length); - if (redrawEnd - redrawStart > 0) { - internalRedrawRange(redrawStart, redrawEnd - redrawStart, true); - } - if (sendEvent == true) { - sendSelectionEvent(); - } - } + int selectionStart = selection.x; + int selectionEnd = selection.y; + int length = content.getCharCount(); + + resetSelection(); + // redraw old selection, if any + if (selectionEnd - selectionStart > 0) { + // called internally to remove selection after text is removed + // therefore make sure redraw range is valid. + int redrawStart = Math.min(selectionStart, length); + int redrawEnd = Math.min(selectionEnd, length); + if (redrawEnd - redrawStart > 0) { + internalRedrawRange(redrawStart, redrawEnd - redrawStart, true); + } + if (sendEvent == true) { + sendSelectionEvent(); + } + } } /** * Computes the preferred size. @@ -2057,77 +2067,77 @@ * */ public Point computeSize (int wHint, int hHint, boolean changed) { - checkWidget(); - int count, width, height; - boolean singleLine = (getStyle() & SWT.SINGLE) != 0; - - if (singleLine) { - count = 1; - } else { - count = content.getLineCount(); - } - if (wHint != SWT.DEFAULT) { - width = wHint; - } - else { - width = DEFAULT_WIDTH; - } - - if (wordWrap) { - if (((WrappedContent) content).getVisualLineCount() != 0) { - // lines have already been wrapped to a specific width. - // use existing line count. fixes bug 9191 - if (wHint == SWT.DEFAULT) { - width = lineCache.getWidth(); - } else { - ((WrappedContent) content).wrapLines(width); - // caret may be on a different line after a rewrap - setCaretLocation(); - } - if (singleLine == false) { - count = content.getLineCount(); - } - } - else { - if (singleLine == false) { - ((WrappedContent) content).wrapLines(width); - // caret may be on a different line after a rewrap - setCaretLocation(); - count = content.getLineCount(); - } - } - } - else if (wHint == SWT.DEFAULT) { - // Only calculate what can actually be displayed. - // Do this because measuring each text line is a - // time-consuming process. - int visibleCount = Math.min (count, getDisplay().getBounds().height / lineHeight); - lineCache.calculate(0, visibleCount); - width = lineCache.getWidth() + leftMargin + rightMargin; - } - if (hHint != SWT.DEFAULT) { - height = hHint; - } - else { - height = count * lineHeight + topMargin + bottomMargin; - } - // Use default values if no text is defined. - if (width == 0) { - width = DEFAULT_WIDTH; - } - if (height == 0) { - if (singleLine) { - height = lineHeight; - } - else { - height = DEFAULT_HEIGHT; - } - } - Rectangle rect = computeTrim(0, 0, width, height); - return new Point (rect.width, rect.height); + checkWidget(); + int count, width, height; + boolean singleLine = (getStyle() & SWT.SINGLE) != 0; + + if (singleLine) { + count = 1; + } else { + count = content.getLineCount(); + } + if (wHint != SWT.DEFAULT) { + width = wHint; + } + else { + width = DEFAULT_WIDTH; + } + + if (wordWrap) { + if (((WrappedContent) content).getVisualLineCount() != 0) { + // lines have already been wrapped to a specific width. + // use existing line count. fixes bug 9191 + if (wHint == SWT.DEFAULT) { + width = lineCache.getWidth(); + } else { + ((WrappedContent) content).wrapLines(width); + // caret may be on a different line after a rewrap + setCaretLocation(); + } + if (singleLine == false) { + count = content.getLineCount(); + } + } + else { + if (singleLine == false) { + ((WrappedContent) content).wrapLines(width); + // caret may be on a different line after a rewrap + setCaretLocation(); + count = content.getLineCount(); + } + } + } + else if (wHint == SWT.DEFAULT) { + // Only calculate what can actually be displayed. + // Do this because measuring each text line is a + // time-consuming process. + int visibleCount = Math.min (count, getDisplay().getBounds().height / lineHeight); + lineCache.calculate(0, visibleCount); + width = lineCache.getWidth() + leftMargin + rightMargin; + } + if (hHint != SWT.DEFAULT) { + height = hHint; + } + else { + height = count * lineHeight + topMargin + bottomMargin; + } + // Use default values if no text is defined. + if (width == 0) { + width = DEFAULT_WIDTH; + } + if (height == 0) { + if (singleLine) { + height = lineHeight; + } + else { + height = DEFAULT_HEIGHT; + } + } + Rectangle rect = computeTrim(0, 0, width, height); + return new Point (rect.width, rect.height); } /** - * Copies the selected text to the clipboard. The text will be put in the + * Copies the selected text to the clipboard. The text will be put in the * clipboard in plain text format and RTF format. *
* @@ -2137,135 +2147,135 @@ * */ public void copy() { - checkWidget(); - int length = selection.y - selection.x; - if (length > 0) { - try { - setClipboardContent(selection.x, length); - } - catch (SWTError error) { - // Copy to clipboard failed. This happens when another application - // is accessing the clipboard while we copy. Ignore the error. - // Fixes 1GDQAVN - // Rethrow all other errors. Fixes bug 17578. - if (error.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { - throw error; - } - } - } + checkWidget(); + int length = selection.y - selection.x; + if (length > 0) { + try { + setClipboardContent(selection.x, length); + } + catch (SWTError error) { + // Copy to clipboard failed. This happens when another application + // is accessing the clipboard while we copy. Ignore the error. + // Fixes 1GDQAVN + // Rethrow all other errors. Fixes bug 17578. + if (error.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { + throw error; + } + } + } } /** - * Returns a string that uses only the line delimiter specified by the + * Returns a string that uses only the line delimiter specified by the * StyledTextContent implementation. * Returns only the first line if the widget has the SWT.SINGLE style. *
* - * @param text the text that may have line delimiters that don't - * match the model line delimiter. Possible line delimiters - * are CR ('\r'), LF ('\n'), CR/LF ("\r\n") - * @return the converted text that only uses the line delimiter - * specified by the model. Returns only the first line if the widget - * has the SWT.SINGLE style. + * @param text the text that may have line delimiters that don't + * match the model line delimiter. Possible line delimiters + * are CR ('\r'), LF ('\n'), CR/LF ("\r\n") + * @return the converted text that only uses the line delimiter + * specified by the model. Returns only the first line if the widget + * has the SWT.SINGLE style. */ String getModelDelimitedText(String text) { - StringBuffer convertedText; - String delimiter = getLineDelimiter(); - int length = text.length(); - int crIndex = 0; - int lfIndex = 0; - int i = 0; - - if (length == 0) { - return text; - } - convertedText = new StringBuffer(length); - while (i < length) { - if (crIndex != -1) { - crIndex = text.indexOf(SWT.CR, i); - } - if (lfIndex != -1) { - lfIndex = text.indexOf(SWT.LF, i); - } - if (lfIndex == -1 && crIndex == -1) { // no more line breaks? - break; - } - else // CR occurs before LF or no LF present? - if ((crIndex < lfIndex && crIndex != -1) || lfIndex == -1) { - convertedText.append(text.substring(i, crIndex)); - if (lfIndex == crIndex + 1) { // CR/LF combination? - i = lfIndex + 1; - } - else { - i = crIndex + 1; - } - } - else { // LF occurs before CR! - convertedText.append(text.substring(i, lfIndex)); - i = lfIndex + 1; - } - if (isSingleLine()) { - break; - } - convertedText.append(delimiter); - } - // copy remaining text if any and if not in single line mode or no - // text copied thus far (because there only is one line) - if (i < length && (isSingleLine() == false || convertedText.length() == 0)) { - convertedText.append(text.substring(i)); - } - return convertedText.toString(); + StringBuffer convertedText; + String delimiter = getLineDelimiter(); + int length = text.length(); + int crIndex = 0; + int lfIndex = 0; + int i = 0; + + if (length == 0) { + return text; + } + convertedText = new StringBuffer(length); + while (i < length) { + if (crIndex != -1) { + crIndex = text.indexOf(SWT.CR, i); + } + if (lfIndex != -1) { + lfIndex = text.indexOf(SWT.LF, i); + } + if (lfIndex == -1 && crIndex == -1) { // no more line breaks? + break; + } + else // CR occurs before LF or no LF present? + if ((crIndex < lfIndex && crIndex != -1) || lfIndex == -1) { + convertedText.append(text.substring(i, crIndex)); + if (lfIndex == crIndex + 1) { // CR/LF combination? + i = lfIndex + 1; + } + else { + i = crIndex + 1; + } + } + else { // LF occurs before CR! + convertedText.append(text.substring(i, lfIndex)); + i = lfIndex + 1; + } + if (isSingleLine()) { + break; + } + convertedText.append(delimiter); + } + // copy remaining text if any and if not in single line mode or no + // text copied thus far (because there only is one line) + if (i < length && (isSingleLine() == false || convertedText.length() == 0)) { + convertedText.append(text.substring(i)); + } + return convertedText.toString(); } /** * Creates default key bindings. */ void createKeyBindings() { - // Navigation - setKeyBinding(SWT.ARROW_UP, ST.LINE_UP); - setKeyBinding(SWT.ARROW_DOWN, ST.LINE_DOWN); - setKeyBinding(SWT.HOME, ST.LINE_START); - setKeyBinding(SWT.END, ST.LINE_END); - setKeyBinding(SWT.ARROW_LEFT, ST.COLUMN_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT, ST.COLUMN_NEXT); - setKeyBinding(SWT.PAGE_UP, ST.PAGE_UP); - setKeyBinding(SWT.PAGE_DOWN, ST.PAGE_DOWN); - setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1, ST.WORD_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1, ST.WORD_NEXT); - setKeyBinding(SWT.HOME | SWT.MOD1, ST.TEXT_START); - setKeyBinding(SWT.END | SWT.MOD1, ST.TEXT_END); - setKeyBinding(SWT.PAGE_UP | SWT.MOD1, ST.WINDOW_START); - setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1, ST.WINDOW_END); - // Selection - setKeyBinding(SWT.ARROW_UP | SWT.MOD2, ST.SELECT_LINE_UP); - setKeyBinding(SWT.ARROW_DOWN | SWT.MOD2, ST.SELECT_LINE_DOWN); - setKeyBinding(SWT.HOME | SWT.MOD2, ST.SELECT_LINE_START); - setKeyBinding(SWT.END | SWT.MOD2, ST.SELECT_LINE_END); - setKeyBinding(SWT.ARROW_LEFT | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD2, ST.SELECT_COLUMN_NEXT); - setKeyBinding(SWT.PAGE_UP | SWT.MOD2, ST.SELECT_PAGE_UP); - setKeyBinding(SWT.PAGE_DOWN | SWT.MOD2, ST.SELECT_PAGE_DOWN); - setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_NEXT); - setKeyBinding(SWT.HOME | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_START); - setKeyBinding(SWT.END | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_END); - setKeyBinding(SWT.PAGE_UP | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_START); - setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_END); - - // Modification - // Cut, Copy, Paste - setKeyBinding('X' | SWT.MOD1, ST.CUT); - setKeyBinding('C' | SWT.MOD1, ST.COPY); - setKeyBinding('V' | SWT.MOD1, ST.PASTE); - // Cut, Copy, Paste Wordstar style - setKeyBinding(SWT.DEL | SWT.MOD2, ST.CUT); - setKeyBinding(SWT.INSERT | SWT.MOD1, ST.COPY); - setKeyBinding(SWT.INSERT | SWT.MOD2, ST.PASTE); - setKeyBinding(SWT.BS | SWT.MOD2, ST.DELETE_PREVIOUS); - - setKeyBinding(SWT.BS, ST.DELETE_PREVIOUS); - setKeyBinding(SWT.DEL, ST.DELETE_NEXT); - - // Miscellaneous - setKeyBinding(SWT.INSERT, ST.TOGGLE_OVERWRITE); + // Navigation + setKeyBinding(SWT.ARROW_UP, ST.LINE_UP); + setKeyBinding(SWT.ARROW_DOWN, ST.LINE_DOWN); + setKeyBinding(SWT.HOME, ST.LINE_START); + setKeyBinding(SWT.END, ST.LINE_END); + setKeyBinding(SWT.ARROW_LEFT, ST.COLUMN_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT, ST.COLUMN_NEXT); + setKeyBinding(SWT.PAGE_UP, ST.PAGE_UP); + setKeyBinding(SWT.PAGE_DOWN, ST.PAGE_DOWN); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1, ST.WORD_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1, ST.WORD_NEXT); + setKeyBinding(SWT.HOME | SWT.MOD1, ST.TEXT_START); + setKeyBinding(SWT.END | SWT.MOD1, ST.TEXT_END); + setKeyBinding(SWT.PAGE_UP | SWT.MOD1, ST.WINDOW_START); + setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1, ST.WINDOW_END); + // Selection + setKeyBinding(SWT.ARROW_UP | SWT.MOD2, ST.SELECT_LINE_UP); + setKeyBinding(SWT.ARROW_DOWN | SWT.MOD2, ST.SELECT_LINE_DOWN); + setKeyBinding(SWT.HOME | SWT.MOD2, ST.SELECT_LINE_START); + setKeyBinding(SWT.END | SWT.MOD2, ST.SELECT_LINE_END); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD2, ST.SELECT_COLUMN_NEXT); + setKeyBinding(SWT.PAGE_UP | SWT.MOD2, ST.SELECT_PAGE_UP); + setKeyBinding(SWT.PAGE_DOWN | SWT.MOD2, ST.SELECT_PAGE_DOWN); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_NEXT); + setKeyBinding(SWT.HOME | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_START); + setKeyBinding(SWT.END | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_END); + setKeyBinding(SWT.PAGE_UP | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_START); + setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_END); + + // Modification + // Cut, Copy, Paste + setKeyBinding('X' | SWT.MOD1, ST.CUT); + setKeyBinding('C' | SWT.MOD1, ST.COPY); + setKeyBinding('V' | SWT.MOD1, ST.PASTE); + // Cut, Copy, Paste Wordstar style + setKeyBinding(SWT.DEL | SWT.MOD2, ST.CUT); + setKeyBinding(SWT.INSERT | SWT.MOD1, ST.COPY); + setKeyBinding(SWT.INSERT | SWT.MOD2, ST.PASTE); + setKeyBinding(SWT.BS | SWT.MOD2, ST.DELETE_PREVIOUS); + + setKeyBinding(SWT.BS, ST.DELETE_PREVIOUS); + setKeyBinding(SWT.DEL, ST.DELETE_NEXT); + + // Miscellaneous + setKeyBinding(SWT.INSERT, ST.TOGGLE_OVERWRITE); } /** * Create the bitmaps to use for the caret in bidi mode. This @@ -2273,37 +2283,37 @@ * font changes (the caret bitmap height needs to match font height). */ void createCaretBitmaps() { - int caretWidth = BIDI_CARET_WIDTH; - - Display display = getDisplay(); - if (caretPalette == null) { - caretPalette = new PaletteData(new RGB[] {new RGB (0,0,0), new RGB (255,255,255)}); - } - if (leftCaretBitmap != null) { - leftCaretBitmap.dispose(); - } - ImageData imageData = new ImageData(caretWidth, lineHeight, 1, caretPalette); - leftCaretBitmap = new Image(display, imageData); - GC gc = new GC (leftCaretBitmap); - gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); - gc.drawLine(0,0,0,lineHeight); - gc.drawLine(0,0,caretWidth-1,0); - gc.drawLine(0,1,1,1); - gc.dispose(); - - if (rightCaretBitmap != null) { - rightCaretBitmap.dispose(); - } - rightCaretBitmap = new Image(display, imageData); - gc = new GC (rightCaretBitmap); - gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); - gc.drawLine(caretWidth-1,0,caretWidth-1,lineHeight); - gc.drawLine(0,0,caretWidth-1,0); - gc.drawLine(caretWidth-1,1,1,1); - gc.dispose(); + int caretWidth = BIDI_CARET_WIDTH; + + Display display = getDisplay(); + if (caretPalette == null) { + caretPalette = new PaletteData(new RGB[] {new RGB (0,0,0), new RGB (255,255,255)}); + } + if (leftCaretBitmap != null) { + leftCaretBitmap.dispose(); + } + ImageData imageData = new ImageData(caretWidth, lineHeight, 1, caretPalette); + leftCaretBitmap = new Image(display, imageData); + GC gc = new GC (leftCaretBitmap); + gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.drawLine(0,0,0,lineHeight); + gc.drawLine(0,0,caretWidth-1,0); + gc.drawLine(0,1,1,1); + gc.dispose(); + + if (rightCaretBitmap != null) { + rightCaretBitmap.dispose(); + } + rightCaretBitmap = new Image(display, imageData); + gc = new GC (rightCaretBitmap); + gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.drawLine(caretWidth-1,0,caretWidth-1,lineHeight); + gc.drawLine(0,0,caretWidth-1,0); + gc.drawLine(caretWidth-1,1,1,1); + gc.dispose(); } /** - * Moves the selected text to the clipboard. The text will be put in the + * Moves the selected text to the clipboard. The text will be put in the * clipboard in plain text format and RTF format. *
* @@ -2313,564 +2323,564 @@ * */ public void cut(){ - checkWidget(); - int length = selection.y - selection.x; - - if (length > 0) { - try { - setClipboardContent(selection.x, length); - } - catch (SWTError error) { - // Copy to clipboard failed. This happens when another application - // is accessing the clipboard while we copy. Ignore the error. - // Fixes 1GDQAVN - // Rethrow all other errors. Fixes bug 17578. - if (error.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { - throw error; - } - // Abort cut operation if copy to clipboard fails. - // Fixes bug 21030. - return; - } - doDelete(); - } + checkWidget(); + int length = selection.y - selection.x; + + if (length > 0) { + try { + setClipboardContent(selection.x, length); + } + catch (SWTError error) { + // Copy to clipboard failed. This happens when another application + // is accessing the clipboard while we copy. Ignore the error. + // Fixes 1GDQAVN + // Rethrow all other errors. Fixes bug 17578. + if (error.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { + throw error; + } + // Abort cut operation if copy to clipboard fails. + // Fixes bug 21030. + return; + } + doDelete(); + } } -/** +/** * A mouse move event has occurred. See if we should start autoscrolling. If - * the move position is outside of the client area, initiate autoscrolling. + * the move position is outside of the client area, initiate autoscrolling. * Otherwise, we've moved back into the widget so end autoscrolling. */ void doAutoScroll(Event event) { - Rectangle area = getClientArea(); - - if (event.y > area.height) { - doAutoScroll(SWT.DOWN); - } - else - if (event.y < 0) { - doAutoScroll(SWT.UP); - } - else - if (event.x < leftMargin && wordWrap == false) { - doAutoScroll(SWT.LEFT); - } - else - if (event.x > area.width - leftMargin - rightMargin && wordWrap == false) { - doAutoScroll(SWT.RIGHT); - } - else { - endAutoScroll(); - } + Rectangle area = getClientArea(); + + if (event.y > area.height) { + doAutoScroll(SWT.DOWN); + } + else + if (event.y < 0) { + doAutoScroll(SWT.UP); + } + else + if (event.x < leftMargin && wordWrap == false) { + doAutoScroll(SWT.LEFT); + } + else + if (event.x > area.width - leftMargin - rightMargin && wordWrap == false) { + doAutoScroll(SWT.RIGHT); + } + else { + endAutoScroll(); + } } -/** +/** * Initiates autoscrolling. *
* * @param direction SWT.UP, SWT.DOWN, SWT.RIGHT, SWT.LEFT */ void doAutoScroll(int direction) { - Runnable timer = null; - final int TIMER_INTERVAL = 5; - - // If we're already autoscrolling in the given direction do nothing - if (autoScrollDirection == direction) { - return; - } - - final Display display = getDisplay(); - // Set a timer that will simulate the user pressing and holding - // down a cursor key (i.e., arrowUp, arrowDown). - if (direction == SWT.UP) { - timer = new Runnable() { - public void run() { - if (autoScrollDirection == SWT.UP) { - doSelectionLineUp(); - display.timerExec(TIMER_INTERVAL, this); - } - } - }; - } else if (direction == SWT.DOWN) { - timer = new Runnable() { - public void run() { - if (autoScrollDirection == SWT.DOWN) { - doSelectionLineDown(); - display.timerExec(TIMER_INTERVAL, this); - } - } - }; - } else if (direction == SWT.RIGHT) { - timer = new Runnable() { - public void run() { - if (autoScrollDirection == SWT.RIGHT) { - doColumnRight(); - setMouseWordSelectionAnchor(); - doSelection(SWT.RIGHT); - display.timerExec(TIMER_INTERVAL, this); - } - } - }; - } else if (direction == SWT.LEFT) { - timer = new Runnable() { - public void run() { - if (autoScrollDirection == SWT.LEFT) { - doColumnLeft(); - setMouseWordSelectionAnchor(); - doSelection(SWT.LEFT); - display.timerExec(TIMER_INTERVAL, this); - } - } - }; - } - if (timer != null) { - autoScrollDirection = direction; - display.timerExec(TIMER_INTERVAL, timer); - } + Runnable timer = null; + final int TIMER_INTERVAL = 5; + + // If we're already autoscrolling in the given direction do nothing + if (autoScrollDirection == direction) { + return; + } + + final Display display = getDisplay(); + // Set a timer that will simulate the user pressing and holding + // down a cursor key (i.e., arrowUp, arrowDown). + if (direction == SWT.UP) { + timer = new Runnable() { + public void run() { + if (autoScrollDirection == SWT.UP) { + doSelectionLineUp(); + display.timerExec(TIMER_INTERVAL, this); + } + } + }; + } else if (direction == SWT.DOWN) { + timer = new Runnable() { + public void run() { + if (autoScrollDirection == SWT.DOWN) { + doSelectionLineDown(); + display.timerExec(TIMER_INTERVAL, this); + } + } + }; + } else if (direction == SWT.RIGHT) { + timer = new Runnable() { + public void run() { + if (autoScrollDirection == SWT.RIGHT) { + doColumnRight(); + setMouseWordSelectionAnchor(); + doSelection(SWT.RIGHT); + display.timerExec(TIMER_INTERVAL, this); + } + } + }; + } else if (direction == SWT.LEFT) { + timer = new Runnable() { + public void run() { + if (autoScrollDirection == SWT.LEFT) { + doColumnLeft(); + setMouseWordSelectionAnchor(); + doSelection(SWT.LEFT); + display.timerExec(TIMER_INTERVAL, this); + } + } + }; + } + if (timer != null) { + autoScrollDirection = direction; + display.timerExec(TIMER_INTERVAL, timer); + } } /** * Deletes the previous character. Delete the selected text if any. * Move the caret in front of the deleted text. */ void doBackspace() { - Event event = new Event(); - event.text = ""; - if (selection.x != selection.y) { - event.start = selection.x; - event.end = selection.y; - sendKeyEvent(event); - } - else - if (caretOffset > 0) { - int line = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(line); - - if (caretOffset == lineOffset) { - lineOffset = content.getOffsetAtLine(line - 1); - event.start = lineOffset + content.getLine(line - 1).length(); - event.end = caretOffset; - } - else { - event.start = caretOffset - 1; - event.end = caretOffset; - } - sendKeyEvent(event); - } + Event event = new Event(); + event.text = ""; + if (selection.x != selection.y) { + event.start = selection.x; + event.end = selection.y; + sendKeyEvent(event); + } + else + if (caretOffset > 0) { + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + + if (caretOffset == lineOffset) { + lineOffset = content.getOffsetAtLine(line - 1); + event.start = lineOffset + content.getLine(line - 1).length(); + event.end = caretOffset; + } + else { + event.start = caretOffset - 1; + event.end = caretOffset; + } + sendKeyEvent(event); + } } /** * Moves the caret one character to the left. Do not go to the previous line. - * When in a bidi locale and at a R2L character the caret is moved to the - * beginning of the R2L segment (visually right) and then one character to the + * When in a bidi locale and at a R2L character the caret is moved to the + * beginning of the R2L segment (visually right) and then one character to the * left (visually left because it's now in a L2R segment). */ void doColumnLeft() { - int line = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = caretOffset - lineOffset; - - if (isBidi()) { - String lineText = content.getLine(line); - int lineLength = lineText.length(); - GC gc = getGC(); - StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); - - if (horizontalScrollOffset > 0 || offsetInLine > 0) { - if (offsetInLine < lineLength && bidi.isRightToLeft(offsetInLine)) { - // advance caret logically if in R2L segment (move visually left) - caretOffset++; - doSelection(SWT.RIGHT); - if (caretOffset - lineOffset == lineLength) { - // if the line end is reached in a R2L segment, make the - // caret position (visual left border) visible before - // jumping to segment start - showCaret(); - } - // end of R2L segment reached (visual left side)? - if (bidi.isRightToLeft(caretOffset - lineOffset) == false) { - if (bidi.getTextPosition(caretOffset - lineOffset) < horizontalScrollOffset) { - // make beginning of R2L segment visible before going - // left, to L2R segment important if R2L segment ends - // at visual left in order to scroll all the way to the - // left. Fixes 1GKM3XS - showCaret(); - } - // go to beginning of R2L segment (visually end of next L2R - // segment)/beginning of line - caretOffset--; - while (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset--; - } - } - } - else - if (offsetInLine == lineLength && - bidi.getTextPosition(lineLength) != XINSET) { - // at logical line end in R2L segment but there's more text (a - // L2R segment) go to end of R2L segment (visually left of next - // L2R segment)/end of line - caretOffset--; - while (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset--; - } - } - else - if (offsetInLine > 0 && bidi.isRightToLeft(offsetInLine) == false) { - // decrease caret logically if in L2R segment (move visually left) - caretOffset--; - doSelection(SWT.LEFT); - // end of L2R segment reached (visual left side of preceeding R2L - // segment)? - if (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset - 1)) { - // go to beginning of R2L segment (visually start of next L2R - // segment)/beginning of line - caretOffset--; - while (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset - 1)) { - caretOffset--; - } - } - } - // if new caret position is to the left of the client area - if (bidi.getTextPosition(caretOffset - lineOffset) < horizontalScrollOffset) { - // scroll to the caret position - showCaret(); - } - else { - // otherwise just update caret position without scrolling it into view - setBidiCaretLocation(null); - setBidiKeyboardLanguage(); - } - // Beginning of line reached (auto scroll finished) but not scrolled - // completely to the left? Fixes 1GKM193 - if (caretOffset - lineOffset == 0 && horizontalScrollOffset > 0 && - horizontalScrollOffset <= XINSET) { - scrollHorizontalBar(-horizontalScrollOffset); - } - } - gc.dispose(); - } - else - if (offsetInLine > 0) { - caretOffset--; - showCaret(); - } + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = caretOffset - lineOffset; + + if (isBidi()) { + String lineText = content.getLine(line); + int lineLength = lineText.length(); + GC gc = getGC(); + StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); + + if (horizontalScrollOffset > 0 || offsetInLine > 0) { + if (offsetInLine < lineLength && bidi.isRightToLeft(offsetInLine)) { + // advance caret logically if in R2L segment (move visually left) + caretOffset++; + doSelection(SWT.RIGHT); + if (caretOffset - lineOffset == lineLength) { + // if the line end is reached in a R2L segment, make the + // caret position (visual left border) visible before + // jumping to segment start + showCaret(); + } + // end of R2L segment reached (visual left side)? + if (bidi.isRightToLeft(caretOffset - lineOffset) == false) { + if (bidi.getTextPosition(caretOffset - lineOffset) < horizontalScrollOffset) { + // make beginning of R2L segment visible before going + // left, to L2R segment important if R2L segment ends + // at visual left in order to scroll all the way to the + // left. Fixes 1GKM3XS + showCaret(); + } + // go to beginning of R2L segment (visually end of next L2R + // segment)/beginning of line + caretOffset--; + while (caretOffset - lineOffset > 0 && + bidi.isRightToLeft(caretOffset - lineOffset)) { + caretOffset--; + } + } + } + else + if (offsetInLine == lineLength && + bidi.getTextPosition(lineLength) != XINSET) { + // at logical line end in R2L segment but there's more text (a + // L2R segment) go to end of R2L segment (visually left of next + // L2R segment)/end of line + caretOffset--; + while (caretOffset - lineOffset > 0 && + bidi.isRightToLeft(caretOffset - lineOffset)) { + caretOffset--; + } + } + else + if (offsetInLine > 0 && bidi.isRightToLeft(offsetInLine) == false) { + // decrease caret logically if in L2R segment (move visually left) + caretOffset--; + doSelection(SWT.LEFT); + // end of L2R segment reached (visual left side of preceeding R2L + // segment)? + if (caretOffset - lineOffset > 0 && + bidi.isRightToLeft(caretOffset - lineOffset - 1)) { + // go to beginning of R2L segment (visually start of next L2R + // segment)/beginning of line + caretOffset--; + while (caretOffset - lineOffset > 0 && + bidi.isRightToLeft(caretOffset - lineOffset - 1)) { + caretOffset--; + } + } + } + // if new caret position is to the left of the client area + if (bidi.getTextPosition(caretOffset - lineOffset) < horizontalScrollOffset) { + // scroll to the caret position + showCaret(); + } + else { + // otherwise just update caret position without scrolling it into view + setBidiCaretLocation(null); + setBidiKeyboardLanguage(); + } + // Beginning of line reached (auto scroll finished) but not scrolled + // completely to the left? Fixes 1GKM193 + if (caretOffset - lineOffset == 0 && horizontalScrollOffset > 0 && + horizontalScrollOffset <= XINSET) { + scrollHorizontalBar(-horizontalScrollOffset); + } + } + gc.dispose(); + } + else + if (offsetInLine > 0) { + caretOffset--; + showCaret(); + } } /** * Moves the caret one character to the right. Do not go to the next line. - * When in a bidi locale and at a R2L character the caret is moved to the - * end of the R2L segment (visually left) and then one character to the + * When in a bidi locale and at a R2L character the caret is moved to the + * end of the R2L segment (visually left) and then one character to the * right (visually right because it's now in a L2R segment). */ void doColumnRight() { - int line = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = caretOffset - lineOffset; - String lineText = content.getLine(line); - int lineLength = lineText.length(); - - if (isBidi()) { - GC gc = getGC(); - StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); - if (bidi.getTextWidth() + leftMargin > horizontalScrollOffset + getClientArea().width || - offsetInLine < lineLength) { - if (bidi.isRightToLeft(offsetInLine) == false && - offsetInLine < lineLength) { - // advance caret logically if in L2R segment (move visually right) - caretOffset++; - doSelection(SWT.RIGHT); - // end of L2R segment reached (visual right side)? - if (bidi.isRightToLeft(caretOffset - lineOffset)) { - // go to end of R2L segment (visually left of next R2L segment)/ - // end of line - caretOffset++; - while (caretOffset < lineOffset + lineLength && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset++; - } - } - } - else - if (offsetInLine > 0 && - (bidi.isRightToLeft(offsetInLine) || - bidi.getTextWidth() + leftMargin > horizontalScrollOffset + getClientArea().width || - offsetInLine < lineLength)) { - // advance caret visually if in R2L segment or logically at line end - // but right end of line is not fully visible yet - caretOffset--; - doSelection(SWT.LEFT); - offsetInLine = caretOffset - lineOffset; - // end of R2L segment reached (visual right side)? - if (offsetInLine > 0 && bidi.isRightToLeft(offsetInLine) == false) { - // go to end of R2L segment (visually left of next L2R segment)/ - // end of line - caretOffset++; - while (caretOffset < lineOffset + lineLength && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset++; - } - } - } - else - if (offsetInLine == 0 && bidi.getTextPosition(0) != bidi.getTextWidth()) { - // at logical line start in R2L segment but there's more text (a L2R - // segment) go to end of R2L segment (visually left of next L2R - // segment)/end of line - caretOffset++; - while (caretOffset < lineOffset + lineLength && - bidi.isRightToLeft(caretOffset - lineOffset - 1)) { - caretOffset++; - } - } - offsetInLine = caretOffset - lineOffset; - // if new caret position is to the right of the client area - if (bidi.getTextPosition(offsetInLine) >= horizontalScrollOffset) { - // scroll to the caret position - showCaret(); - } - else { - // otherwise just update caret position without scrolling it into view - setBidiCaretLocation(null); - setBidiKeyboardLanguage(); - } - if (offsetInLine > 0 && offsetInLine < lineLength - 1) { - int clientAreaEnd = horizontalScrollOffset + getClientArea().width; - boolean directionChange = bidi.isRightToLeft(offsetInLine - 1) == false && bidi.isRightToLeft(offsetInLine); - int textWidth = bidi.getTextWidth() + leftMargin; - // between L2R and R2L segment and second character of R2L segment is - // left of right border and logical line end is left of right border - // but visual line end is not left of right border - if (directionChange && - bidi.isRightToLeft(offsetInLine + 1) && - bidi.getTextPosition(offsetInLine + 1) + leftMargin < clientAreaEnd && - bidi.getTextPosition(lineLength) + leftMargin < clientAreaEnd && textWidth > clientAreaEnd) { - // make visual line end visible - scrollHorizontalBar(textWidth - clientAreaEnd); - } - } - } - gc.dispose(); - } - else - if (offsetInLine < lineLength) { - caretOffset++; - showCaret(); - } + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = caretOffset - lineOffset; + String lineText = content.getLine(line); + int lineLength = lineText.length(); + + if (isBidi()) { + GC gc = getGC(); + StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); + if (bidi.getTextWidth() + leftMargin > horizontalScrollOffset + getClientArea().width || + offsetInLine < lineLength) { + if (bidi.isRightToLeft(offsetInLine) == false && + offsetInLine < lineLength) { + // advance caret logically if in L2R segment (move visually right) + caretOffset++; + doSelection(SWT.RIGHT); + // end of L2R segment reached (visual right side)? + if (bidi.isRightToLeft(caretOffset - lineOffset)) { + // go to end of R2L segment (visually left of next R2L segment)/ + // end of line + caretOffset++; + while (caretOffset < lineOffset + lineLength && + bidi.isRightToLeft(caretOffset - lineOffset)) { + caretOffset++; + } + } + } + else + if (offsetInLine > 0 && + (bidi.isRightToLeft(offsetInLine) || + bidi.getTextWidth() + leftMargin > horizontalScrollOffset + getClientArea().width || + offsetInLine < lineLength)) { + // advance caret visually if in R2L segment or logically at line end + // but right end of line is not fully visible yet + caretOffset--; + doSelection(SWT.LEFT); + offsetInLine = caretOffset - lineOffset; + // end of R2L segment reached (visual right side)? + if (offsetInLine > 0 && bidi.isRightToLeft(offsetInLine) == false) { + // go to end of R2L segment (visually left of next L2R segment)/ + // end of line + caretOffset++; + while (caretOffset < lineOffset + lineLength && + bidi.isRightToLeft(caretOffset - lineOffset)) { + caretOffset++; + } + } + } + else + if (offsetInLine == 0 && bidi.getTextPosition(0) != bidi.getTextWidth()) { + // at logical line start in R2L segment but there's more text (a L2R + // segment) go to end of R2L segment (visually left of next L2R + // segment)/end of line + caretOffset++; + while (caretOffset < lineOffset + lineLength && + bidi.isRightToLeft(caretOffset - lineOffset - 1)) { + caretOffset++; + } + } + offsetInLine = caretOffset - lineOffset; + // if new caret position is to the right of the client area + if (bidi.getTextPosition(offsetInLine) >= horizontalScrollOffset) { + // scroll to the caret position + showCaret(); + } + else { + // otherwise just update caret position without scrolling it into view + setBidiCaretLocation(null); + setBidiKeyboardLanguage(); + } + if (offsetInLine > 0 && offsetInLine < lineLength - 1) { + int clientAreaEnd = horizontalScrollOffset + getClientArea().width; + boolean directionChange = bidi.isRightToLeft(offsetInLine - 1) == false && bidi.isRightToLeft(offsetInLine); + int textWidth = bidi.getTextWidth() + leftMargin; + // between L2R and R2L segment and second character of R2L segment is + // left of right border and logical line end is left of right border + // but visual line end is not left of right border + if (directionChange && + bidi.isRightToLeft(offsetInLine + 1) && + bidi.getTextPosition(offsetInLine + 1) + leftMargin < clientAreaEnd && + bidi.getTextPosition(lineLength) + leftMargin < clientAreaEnd && textWidth > clientAreaEnd) { + // make visual line end visible + scrollHorizontalBar(textWidth - clientAreaEnd); + } + } + } + gc.dispose(); + } + else + if (offsetInLine < lineLength) { + caretOffset++; + showCaret(); + } } /** - * Replaces the selection with the character or insert the character at the + * Replaces the selection with the character or insert the character at the * current caret position if no selection exists. - * If a carriage return was typed replace it with the line break character + * If a carriage return was typed replace it with the line break character * used by the widget on this platform. *
* * @param key the character typed by the user */ void doContent(char key) { - Event event; - - if (textLimit > 0 && - content.getCharCount() - (selection.y - selection.x) >= textLimit) { - return; - } - event = new Event(); - event.start = selection.x; - event.end = selection.y; - // replace a CR line break with the widget line break - // CR does not make sense on Windows since most (all?) applications - // don't recognize CR as a line break. - if (key == SWT.CR || key == SWT.LF) { - if (isSingleLine() == false) { - event.text = getLineDelimiter(); - } - } - // no selection and overwrite mode is on and the typed key is not a - // tab character (tabs are always inserted without overwriting)? - else - if (selection.x == selection.y && overwrite == true && key != TAB) { - int lineIndex = content.getLineAtOffset(event.end); - int lineOffset = content.getOffsetAtLine(lineIndex); - String line = content.getLine(lineIndex); - // replace character at caret offset if the caret is not at the - // end of the line - if (event.end < lineOffset + line.length()) { - event.end++; - } - event.text = new String(new char[] {key}); - } - else { - event.text = new String(new char[] {key}); - } - if (event.text != null) { - sendKeyEvent(event); - } + Event event; + + if (textLimit > 0 && + content.getCharCount() - (selection.y - selection.x) >= textLimit) { + return; + } + event = new Event(); + event.start = selection.x; + event.end = selection.y; + // replace a CR line break with the widget line break + // CR does not make sense on Windows since most (all?) applications + // don't recognize CR as a line break. + if (key == SWT.CR || key == SWT.LF) { + if (isSingleLine() == false) { + event.text = getLineDelimiter(); + } + } + // no selection and overwrite mode is on and the typed key is not a + // tab character (tabs are always inserted without overwriting)? + else + if (selection.x == selection.y && overwrite == true && key != TAB) { + int lineIndex = content.getLineAtOffset(event.end); + int lineOffset = content.getOffsetAtLine(lineIndex); + String line = content.getLine(lineIndex); + // replace character at caret offset if the caret is not at the + // end of the line + if (event.end < lineOffset + line.length()) { + event.end++; + } + event.text = new String(new char[] {key}); + } + else { + event.text = new String(new char[] {key}); + } + if (event.text != null) { + sendKeyEvent(event); + } } /** * Moves the caret after the last character of the widget content. */ void doContentEnd() { - // place caret at end of first line if receiver is in single - // line mode. fixes 4820. - if (isSingleLine()) { - doLineEnd(); - } - else { - int length = content.getCharCount(); - if (caretOffset < length) { - caretOffset = length; - showCaret(); - } - } + // place caret at end of first line if receiver is in single + // line mode. fixes 4820. + if (isSingleLine()) { + doLineEnd(); + } + else { + int length = content.getCharCount(); + if (caretOffset < length) { + caretOffset = length; + showCaret(); + } + } } /** * Moves the caret in front of the first character of the widget content. */ void doContentStart() { - if (caretOffset > 0) { - caretOffset = 0; - showCaret(); - } + if (caretOffset > 0) { + caretOffset = 0; + showCaret(); + } } /** * Moves the caret to the start of the selection if a selection exists. - * Otherwise, if no selection exists move the cursor according to the + * Otherwise, if no selection exists move the cursor according to the * cursor selection rules. *
* * @see #doSelectionCursorPrevious */ void doCursorPrevious() { - if (selection.y - selection.x > 0) { - int caretLine; - - caretOffset = selection.x; - caretLine = getCaretLine(); - showCaret(caretLine); - } - else { - doSelectionCursorPrevious(); - } + if (selection.y - selection.x > 0) { + int caretLine; + + caretOffset = selection.x; + caretLine = getCaretLine(); + showCaret(caretLine); + } + else { + doSelectionCursorPrevious(); + } } /** * Moves the caret to the end of the selection if a selection exists. - * Otherwise, if no selection exists move the cursor according to the + * Otherwise, if no selection exists move the cursor according to the * cursor selection rules. *
* * @see #doSelectionCursorNext */ void doCursorNext() { - if (selection.y - selection.x > 0) { - int caretLine; + if (selection.y - selection.x > 0) { + int caretLine; - caretOffset = selection.y; - caretLine = getCaretLine(); - showCaret(caretLine); - } - else { - doSelectionCursorNext(); - } + caretOffset = selection.y; + caretLine = getCaretLine(); + showCaret(caretLine); + } + else { + doSelectionCursorNext(); + } } /** * Deletes the next character. Delete the selected text if any. */ void doDelete() { - Event event = new Event(); - - event.text = ""; - if (selection.x != selection.y) { - event.start = selection.x; - event.end = selection.y; - sendKeyEvent(event); - } - else - if (caretOffset < content.getCharCount()) { - int line = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(line); - int lineLength = content.getLine(line).length(); - - if (caretOffset == lineOffset + lineLength) { - event.start = caretOffset; - event.end = content.getOffsetAtLine(line + 1); - } - else { - event.start = caretOffset; - event.end = caretOffset + 1; - } - sendKeyEvent(event); - } + Event event = new Event(); + + event.text = ""; + if (selection.x != selection.y) { + event.start = selection.x; + event.end = selection.y; + sendKeyEvent(event); + } + else + if (caretOffset < content.getCharCount()) { + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + int lineLength = content.getLine(line).length(); + + if (caretOffset == lineOffset + lineLength) { + event.start = caretOffset; + event.end = content.getOffsetAtLine(line + 1); + } + else { + event.start = caretOffset; + event.end = caretOffset + 1; + } + sendKeyEvent(event); + } } /** - * Moves the caret one line down and to the same character offset relative - * to the beginning of the line. Move the caret to the end of the new line + * Moves the caret one line down and to the same character offset relative + * to the beginning of the line. Move the caret to the end of the new line * if the new line is shorter than the character offset. - * + * * @return index of the new line relative to the first line in the document */ int doLineDown() { - if (isSingleLine()) { - return 0; - } - // allow line down action only if receiver is not in single line mode. - // fixes 4820. - int caretLine = getCaretLine(); - if (caretLine < content.getLineCount() - 1) { - caretLine++; - if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); - } - else { - caretOffset = getOffsetAtMouseLocation(columnX, caretLine); - } - } - return caretLine; + if (isSingleLine()) { + return 0; + } + // allow line down action only if receiver is not in single line mode. + // fixes 4820. + int caretLine = getCaretLine(); + if (caretLine < content.getLineCount() - 1) { + caretLine++; + if (isBidi()) { + caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + } + else { + caretOffset = getOffsetAtMouseLocation(columnX, caretLine); + } + } + return caretLine; } /** * Moves the caret to the end of the line. */ void doLineEnd() { - int caretLine = getCaretLine(); - int lineOffset = content.getOffsetAtLine(caretLine); - int lineLength = content.getLine(caretLine).length(); - int lineEndOffset = lineOffset + lineLength; - - if (caretOffset < lineEndOffset) { - caretOffset = lineEndOffset; - showCaret(); - } + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + int lineLength = content.getLine(caretLine).length(); + int lineEndOffset = lineOffset + lineLength; + + if (caretOffset < lineEndOffset) { + caretOffset = lineEndOffset; + showCaret(); + } } /** * Moves the caret to the beginning of the line. */ void doLineStart() { - int caretLine = getCaretLine(); - int lineOffset = content.getOffsetAtLine(caretLine); - - if (caretOffset > lineOffset) { - caretOffset = lineOffset; - showCaret(caretLine); - } + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + + if (caretOffset > lineOffset) { + caretOffset = lineOffset; + showCaret(caretLine); + } } /** - * Moves the caret one line up and to the same character offset relative - * to the beginning of the line. Move the caret to the end of the new line + * Moves the caret one line up and to the same character offset relative + * to the beginning of the line. Move the caret to the end of the new line * if the new line is shorter than the character offset. - * + * * @return index of the new line relative to the first line in the document */ int doLineUp() { - int caretLine = getCaretLine(); + int caretLine = getCaretLine(); - if (caretLine > 0) { - caretLine--; - if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); - } - else { - caretOffset = getOffsetAtMouseLocation(columnX, caretLine); - } - } - return caretLine; + if (caretLine > 0) { + caretLine--; + if (isBidi()) { + caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + } + else { + caretOffset = getOffsetAtMouseLocation(columnX, caretLine); + } + } + return caretLine; } /** * Moves the caret to the specified location. @@ -2879,370 +2889,370 @@ * @param x x location of the new caret position * @param y y location of the new caret position * @param select the location change is a selection operation. - * include the line delimiter in the selection + * include the line delimiter in the selection */ void doMouseLocationChange(int x, int y, boolean select) { - int line = (y + verticalScrollOffset) / lineHeight; - int lineCount = content.getLineCount(); - int newCaretOffset; - int newCaretLine; - - if (line > lineCount - 1) { - line = lineCount - 1; - } - // allow caret to be placed below first line only if receiver is - // not in single line mode. fixes 4820. - if (line < 0 || (isSingleLine() && line > 0)) { - return; - } - if (isBidi()) { - newCaretOffset = getBidiOffsetAtMouseLocation(x, line); - } - else { - newCaretOffset = getOffsetAtMouseLocation(x, line); - } - if (mouseDoubleClick) { - // double click word select the previous/next word. fixes bug 15610 - newCaretOffset = doMouseWordSelect(x, newCaretOffset, line); - } - newCaretLine = content.getLineAtOffset(newCaretOffset); - // Is the mouse within the left client area border or on - // a different line? If not the autoscroll selection - // could be incorrectly reset. Fixes 1GKM3XS - if (y >= 0 && y < getClientArea().height && - (x >= 0 || newCaretLine != content.getLineAtOffset(caretOffset))) { - if (newCaretOffset != caretOffset) { - caretOffset = newCaretOffset; - if (select) { - doMouseSelection(); - } - showCaret(); - } - } - if (select == false) { - clearSelection(true); - } + int line = (y + verticalScrollOffset) / lineHeight; + int lineCount = content.getLineCount(); + int newCaretOffset; + int newCaretLine; + + if (line > lineCount - 1) { + line = lineCount - 1; + } + // allow caret to be placed below first line only if receiver is + // not in single line mode. fixes 4820. + if (line < 0 || (isSingleLine() && line > 0)) { + return; + } + if (isBidi()) { + newCaretOffset = getBidiOffsetAtMouseLocation(x, line); + } + else { + newCaretOffset = getOffsetAtMouseLocation(x, line); + } + if (mouseDoubleClick) { + // double click word select the previous/next word. fixes bug 15610 + newCaretOffset = doMouseWordSelect(x, newCaretOffset, line); + } + newCaretLine = content.getLineAtOffset(newCaretOffset); + // Is the mouse within the left client area border or on + // a different line? If not the autoscroll selection + // could be incorrectly reset. Fixes 1GKM3XS + if (y >= 0 && y < getClientArea().height && + (x >= 0 || newCaretLine != content.getLineAtOffset(caretOffset))) { + if (newCaretOffset != caretOffset) { + caretOffset = newCaretOffset; + if (select) { + doMouseSelection(); + } + showCaret(); + } + } + if (select == false) { + clearSelection(true); + } } /** * Updates the selection based on the caret position */ void doMouseSelection() { - if (caretOffset <= selection.x || - (caretOffset > selection.x && - caretOffset < selection.y && selectionAnchor == selection.x)) { - doSelection(SWT.LEFT); - } - else { - doSelection(SWT.RIGHT); - } + if (caretOffset <= selection.x || + (caretOffset > selection.x && + caretOffset < selection.y && selectionAnchor == selection.x)) { + doSelection(SWT.LEFT); + } + else { + doSelection(SWT.RIGHT); + } } /** - * Returns the offset of the word at the specified offset. - * If the current selection extends from high index to low index - * (i.e., right to left, or caret is at left border of selecton on + * Returns the offset of the word at the specified offset. + * If the current selection extends from high index to low index + * (i.e., right to left, or caret is at left border of selecton on * non-bidi platforms) the start offset of the word preceeding the - * selection is returned. If the current selection extends from - * low index to high index the end offset of the word following + * selection is returned. If the current selection extends from + * low index to high index the end offset of the word following * the selection is returned. - * + * * @param x mouse x location * @param newCaretOffset caret offset of the mouse cursor location * @param line line index of the mouse cursor location */ int doMouseWordSelect(int x, int newCaretOffset, int line) { - int wordOffset; + int wordOffset; - // flip selection anchor based on word selection direction from - // base double click. Always do this here (and don't rely on doAutoScroll) - // because auto scroll only does not cover all possible mouse selections - // (e.g., mouse x < 0 && mouse y > caret line y) - if (newCaretOffset < selectionAnchor && selectionAnchor == selection.x) { - selectionAnchor = doubleClickSelection.y; - } - else - if (newCaretOffset > selectionAnchor && selectionAnchor == selection.y) { - selectionAnchor = doubleClickSelection.x; - } - if (x >= 0 && x < getClientArea().width) { - // find the previous/next word - if (caretOffset == selection.x) { - wordOffset = getWordStart(newCaretOffset); - } - else { - wordOffset = getWordEndNoSpaces(newCaretOffset); - } - // mouse word select only on same line mouse cursor is on - if (content.getLineAtOffset(wordOffset) == line) { - newCaretOffset = wordOffset; - } - } - return newCaretOffset; + // flip selection anchor based on word selection direction from + // base double click. Always do this here (and don't rely on doAutoScroll) + // because auto scroll only does not cover all possible mouse selections + // (e.g., mouse x < 0 && mouse y > caret line y) + if (newCaretOffset < selectionAnchor && selectionAnchor == selection.x) { + selectionAnchor = doubleClickSelection.y; + } + else + if (newCaretOffset > selectionAnchor && selectionAnchor == selection.y) { + selectionAnchor = doubleClickSelection.x; + } + if (x >= 0 && x < getClientArea().width) { + // find the previous/next word + if (caretOffset == selection.x) { + wordOffset = getWordStart(newCaretOffset); + } + else { + wordOffset = getWordEndNoSpaces(newCaretOffset); + } + // mouse word select only on same line mouse cursor is on + if (content.getLineAtOffset(wordOffset) == line) { + newCaretOffset = wordOffset; + } + } + return newCaretOffset; } /** * Scrolls one page down so that the last line (truncated or whole) * of the current page becomes the fully visible top line. - * The caret is scrolled the same number of lines so that its location - * relative to the top line remains the same. The exception is the end - * of the text where a full page scroll is not possible. In this case + * The caret is scrolled the same number of lines so that its location + * relative to the top line remains the same. The exception is the end + * of the text where a full page scroll is not possible. In this case * the caret is moved after the last character. *
* * @param select whether or not to select the page */ void doPageDown(boolean select) { - int lineCount = content.getLineCount(); - int oldColumnX = columnX; - int caretLine; - - // do nothing if in single line mode. fixes 5673 - if (isSingleLine()) { - return; - } - caretLine = getCaretLine(); - if (caretLine < lineCount - 1) { - int verticalMaximum = lineCount * getVerticalIncrement(); - int pageSize = getClientArea().height; - int scrollLines = Math.min(lineCount - caretLine - 1, getLineCountWhole()); - int scrollOffset; - - // ensure that scrollLines never gets negative and at leat one - // line is scrolled. fixes bug 5602. - scrollLines = Math.max(1, scrollLines); - caretLine += scrollLines; - if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); - } - else { - caretOffset = getOffsetAtMouseLocation(columnX, caretLine); - } - if (select) { - doSelection(SWT.RIGHT); - } - // scroll one page down or to the bottom - scrollOffset = verticalScrollOffset + scrollLines * getVerticalIncrement(); - if (scrollOffset + pageSize > verticalMaximum) { - scrollOffset = verticalMaximum - pageSize; - } - if (scrollOffset > verticalScrollOffset) { - setVerticalScrollOffset(scrollOffset, true); - } - } - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - // save the original horizontal caret position - columnX = oldColumnX; + int lineCount = content.getLineCount(); + int oldColumnX = columnX; + int caretLine; + + // do nothing if in single line mode. fixes 5673 + if (isSingleLine()) { + return; + } + caretLine = getCaretLine(); + if (caretLine < lineCount - 1) { + int verticalMaximum = lineCount * getVerticalIncrement(); + int pageSize = getClientArea().height; + int scrollLines = Math.min(lineCount - caretLine - 1, getLineCountWhole()); + int scrollOffset; + + // ensure that scrollLines never gets negative and at leat one + // line is scrolled. fixes bug 5602. + scrollLines = Math.max(1, scrollLines); + caretLine += scrollLines; + if (isBidi()) { + caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + } + else { + caretOffset = getOffsetAtMouseLocation(columnX, caretLine); + } + if (select) { + doSelection(SWT.RIGHT); + } + // scroll one page down or to the bottom + scrollOffset = verticalScrollOffset + scrollLines * getVerticalIncrement(); + if (scrollOffset + pageSize > verticalMaximum) { + scrollOffset = verticalMaximum - pageSize; + } + if (scrollOffset > verticalScrollOffset) { + setVerticalScrollOffset(scrollOffset, true); + } + } + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + // save the original horizontal caret position + columnX = oldColumnX; } /** * Moves the cursor to the end of the last fully visible line. */ void doPageEnd() { - // go to end of line if in single line mode. fixes 5673 - if (isSingleLine()) { - doLineEnd(); - } - else { - int line = getBottomIndex(); - int bottomCaretOffset = content.getOffsetAtLine(line) + content.getLine(line).length(); - - if (caretOffset < bottomCaretOffset) { - caretOffset = bottomCaretOffset; - showCaret(); - } - } + // go to end of line if in single line mode. fixes 5673 + if (isSingleLine()) { + doLineEnd(); + } + else { + int line = getBottomIndex(); + int bottomCaretOffset = content.getOffsetAtLine(line) + content.getLine(line).length(); + + if (caretOffset < bottomCaretOffset) { + caretOffset = bottomCaretOffset; + showCaret(); + } + } } /** * Moves the cursor to the beginning of the first fully visible line. */ void doPageStart() { - int topCaretOffset = content.getOffsetAtLine(topIndex); - - if (caretOffset > topCaretOffset) { - caretOffset = topCaretOffset; - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(topIndex); - } + int topCaretOffset = content.getOffsetAtLine(topIndex); + + if (caretOffset > topCaretOffset) { + caretOffset = topCaretOffset; + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(topIndex); + } } /** * Scrolls one page up so that the first line (truncated or whole) * of the current page becomes the fully visible last line. - * The caret is scrolled the same number of lines so that its location - * relative to the top line remains the same. The exception is the beginning + * The caret is scrolled the same number of lines so that its location + * relative to the top line remains the same. The exception is the beginning * of the text where a full page scroll is not possible. In this case the * caret is moved in front of the first character. */ void doPageUp() { - int oldColumnX = columnX; - int caretLine = getCaretLine(); - - if (caretLine > 0) { - int scrollLines = Math.max(1, Math.min(caretLine, getLineCountWhole())); - int scrollOffset; - - caretLine -= scrollLines; - if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); - } - else { - caretOffset = getOffsetAtMouseLocation(columnX, caretLine); - } - // scroll one page up or to the top - scrollOffset = Math.max(0, verticalScrollOffset - scrollLines * getVerticalIncrement()); - if (scrollOffset < verticalScrollOffset) { - setVerticalScrollOffset(scrollOffset, true); - } - } - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - // save the original horizontal caret position - columnX = oldColumnX; + int oldColumnX = columnX; + int caretLine = getCaretLine(); + + if (caretLine > 0) { + int scrollLines = Math.max(1, Math.min(caretLine, getLineCountWhole())); + int scrollOffset; + + caretLine -= scrollLines; + if (isBidi()) { + caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + } + else { + caretOffset = getOffsetAtMouseLocation(columnX, caretLine); + } + // scroll one page up or to the top + scrollOffset = Math.max(0, verticalScrollOffset - scrollLines * getVerticalIncrement()); + if (scrollOffset < verticalScrollOffset) { + setVerticalScrollOffset(scrollOffset, true); + } + } + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + // save the original horizontal caret position + columnX = oldColumnX; } /** * Updates the selection to extend to the current caret position. */ void doSelection(int direction) { - int redrawStart = -1; - int redrawEnd = -1; - - if (selectionAnchor == -1) { - selectionAnchor = selection.x; - } - if (direction == SWT.LEFT) { - if (caretOffset < selection.x) { - // grow selection - redrawEnd = selection.x; - redrawStart = selection.x = caretOffset; - // check if selection has reversed direction - if (selection.y != selectionAnchor) { - redrawEnd = selection.y; - selection.y = selectionAnchor; - } - } - else // test whether selection actually changed. Fixes 1G71EO1 - if (selectionAnchor == selection.x && caretOffset < selection.y) { - // caret moved towards selection anchor (left side of selection). - // shrink selection - redrawEnd = selection.y; - redrawStart = selection.y = caretOffset; - } - } - else { - if (caretOffset > selection.y) { - // grow selection - redrawStart = selection.y; - redrawEnd = selection.y = caretOffset; - // check if selection has reversed direction - if (selection.x != selectionAnchor) { - redrawStart = selection.x; - selection.x = selectionAnchor; - } - } - else // test whether selection actually changed. Fixes 1G71EO1 - if (selectionAnchor == selection.y && caretOffset > selection.x) { - // caret moved towards selection anchor (right side of selection). - // shrink selection - redrawStart = selection.x; - redrawEnd = selection.x = caretOffset; - } - } - if (redrawStart != -1 && redrawEnd != -1) { - internalRedrawRange(redrawStart, redrawEnd - redrawStart, true); - sendSelectionEvent(); - } + int redrawStart = -1; + int redrawEnd = -1; + + if (selectionAnchor == -1) { + selectionAnchor = selection.x; + } + if (direction == SWT.LEFT) { + if (caretOffset < selection.x) { + // grow selection + redrawEnd = selection.x; + redrawStart = selection.x = caretOffset; + // check if selection has reversed direction + if (selection.y != selectionAnchor) { + redrawEnd = selection.y; + selection.y = selectionAnchor; + } + } + else // test whether selection actually changed. Fixes 1G71EO1 + if (selectionAnchor == selection.x && caretOffset < selection.y) { + // caret moved towards selection anchor (left side of selection). + // shrink selection + redrawEnd = selection.y; + redrawStart = selection.y = caretOffset; + } + } + else { + if (caretOffset > selection.y) { + // grow selection + redrawStart = selection.y; + redrawEnd = selection.y = caretOffset; + // check if selection has reversed direction + if (selection.x != selectionAnchor) { + redrawStart = selection.x; + selection.x = selectionAnchor; + } + } + else // test whether selection actually changed. Fixes 1G71EO1 + if (selectionAnchor == selection.y && caretOffset > selection.x) { + // caret moved towards selection anchor (right side of selection). + // shrink selection + redrawStart = selection.x; + redrawEnd = selection.x = caretOffset; + } + } + if (redrawStart != -1 && redrawEnd != -1) { + internalRedrawRange(redrawStart, redrawEnd - redrawStart, true); + sendSelectionEvent(); + } } /** - * Moves the caret to the next character or to the beginning of the + * Moves the caret to the next character or to the beginning of the * next line if the cursor is at the end of a line. */ void doSelectionCursorNext() { - int caretLine = getCaretLine(); - int lineOffset = content.getOffsetAtLine(caretLine); - int offsetInLine = caretOffset - lineOffset; - - if (offsetInLine < content.getLine(caretLine).length()) { - // Remember the last direction. Always update lastCaretDirection, - // even though it's not used in non-bidi mode in order to avoid - // extra methods. - lastCaretDirection = ST.COLUMN_NEXT; - caretOffset++; - showCaret(); - } - else - if (caretLine < content.getLineCount() - 1 && isSingleLine() == false) { - // only go to next line if not in single line mode. fixes 5673 - caretLine++; - caretOffset = content.getOffsetAtLine(caretLine); - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - } + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + + if (offsetInLine < content.getLine(caretLine).length()) { + // Remember the last direction. Always update lastCaretDirection, + // even though it's not used in non-bidi mode in order to avoid + // extra methods. + lastCaretDirection = ST.COLUMN_NEXT; + caretOffset++; + showCaret(); + } + else + if (caretLine < content.getLineCount() - 1 && isSingleLine() == false) { + // only go to next line if not in single line mode. fixes 5673 + caretLine++; + caretOffset = content.getOffsetAtLine(caretLine); + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + } } /** - * Moves the caret to the previous character or to the end of the previous + * Moves the caret to the previous character or to the end of the previous * line if the cursor is at the beginning of a line. */ void doSelectionCursorPrevious() { - int caretLine = getCaretLine(); - int lineOffset = content.getOffsetAtLine(caretLine); - int offsetInLine = caretOffset - lineOffset; - - if (offsetInLine > 0) { - // Remember the last direction. Always update lastCaretDirection, - // even though it's not used in non-bidi mode in order to avoid - // extra methods. - lastCaretDirection = ST.COLUMN_PREVIOUS; - caretOffset--; - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - } - else - if (caretLine > 0) { - caretLine--; - lineOffset = content.getOffsetAtLine(caretLine); - caretOffset = lineOffset + content.getLine(caretLine).length(); - showCaret(); - } + int caretLine = getCaretLine(); + int lineOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + + if (offsetInLine > 0) { + // Remember the last direction. Always update lastCaretDirection, + // even though it's not used in non-bidi mode in order to avoid + // extra methods. + lastCaretDirection = ST.COLUMN_PREVIOUS; + caretOffset--; + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + } + else + if (caretLine > 0) { + caretLine--; + lineOffset = content.getOffsetAtLine(caretLine); + caretOffset = lineOffset + content.getLine(caretLine).length(); + showCaret(); + } } /** - * Moves the caret one line down and to the same character offset relative - * to the beginning of the line. Moves the caret to the end of the new line + * Moves the caret one line down and to the same character offset relative + * to the beginning of the line. Moves the caret to the end of the new line * if the new line is shorter than the character offset. - * Moves the caret to the end of the text if the caret already is on the + * Moves the caret to the end of the text if the caret already is on the * last line. * Adjusts the selection according to the caret change. This can either add * to or subtract from the old selection, depending on the previous selection * direction. */ void doSelectionLineDown() { - int oldColumnX = columnX; - int caretLine; - - if (isSingleLine()) { - return; - } - caretLine = getCaretLine(); - if (caretLine == content.getLineCount() - 1) { - caretOffset = content.getCharCount(); - } - else { - caretLine = doLineDown(); - } - setMouseWordSelectionAnchor(); - // select first and then scroll to reduce flash when key - // repeat scrolls lots of lines - doSelection(SWT.RIGHT); - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - // save the original horizontal caret position - columnX = oldColumnX; + int oldColumnX = columnX; + int caretLine; + + if (isSingleLine()) { + return; + } + caretLine = getCaretLine(); + if (caretLine == content.getLineCount() - 1) { + caretOffset = content.getCharCount(); + } + else { + caretLine = doLineDown(); + } + setMouseWordSelectionAnchor(); + // select first and then scroll to reduce flash when key + // repeat scrolls lots of lines + doSelection(SWT.RIGHT); + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + // save the original horizontal caret position + columnX = oldColumnX; } /** - * Moves the caret one line up and to the same character offset relative - * to the beginning of the line. Moves the caret to the end of the new line + * Moves the caret one line up and to the same character offset relative + * to the beginning of the line. Moves the caret to the end of the new line * if the new line is shorter than the character offset. * Moves the caret to the beginning of the document if it is already on the * first line. @@ -3251,54 +3261,54 @@ * direction. */ void doSelectionLineUp() { - int oldColumnX = columnX; - int caretLine = getCaretLine(); - - if (caretLine == 0) { - caretOffset = 0; - } - else { - caretLine = doLineUp(); - } - setMouseWordSelectionAnchor(); - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - doSelection(SWT.LEFT); - // save the original horizontal caret position - columnX = oldColumnX; + int oldColumnX = columnX; + int caretLine = getCaretLine(); + + if (caretLine == 0) { + caretOffset = 0; + } + else { + caretLine = doLineUp(); + } + setMouseWordSelectionAnchor(); + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + doSelection(SWT.LEFT); + // save the original horizontal caret position + columnX = oldColumnX; } /** * Moves the caret to the end of the next word . */ void doSelectionWordNext() { - int newCaretOffset = getWordEnd(caretOffset); - - // don't change caret position if in single line mode and the cursor - // would be on a different line. fixes 5673 - if (isSingleLine() == false || - content.getLineAtOffset(caretOffset) == content.getLineAtOffset(newCaretOffset)) { - lastCaretDirection = ST.COLUMN_NEXT; - caretOffset = newCaretOffset; - showCaret(); - } + int newCaretOffset = getWordEnd(caretOffset); + + // don't change caret position if in single line mode and the cursor + // would be on a different line. fixes 5673 + if (isSingleLine() == false || + content.getLineAtOffset(caretOffset) == content.getLineAtOffset(newCaretOffset)) { + lastCaretDirection = ST.COLUMN_NEXT; + caretOffset = newCaretOffset; + showCaret(); + } } /** * Moves the caret to the start of the previous word. */ void doSelectionWordPrevious() { - int caretLine; - - lastCaretDirection = ST.COLUMN_PREVIOUS; - caretOffset = getWordStart(caretOffset); - caretLine = content.getLineAtOffset(caretOffset); - // word previous always comes from bottom line. when - // wrapping lines, stay on bottom line when on line boundary - if (wordWrap && caretLine < content.getLineCount() - 1 && - caretOffset == content.getOffsetAtLine(caretLine + 1)) { - caretLine++; - } - showCaret(caretLine); + int caretLine; + + lastCaretDirection = ST.COLUMN_PREVIOUS; + caretOffset = getWordStart(caretOffset); + caretLine = content.getLineAtOffset(caretOffset); + // word previous always comes from bottom line. when + // wrapping lines, stay on bottom line when on line boundary + if (wordWrap && caretLine < content.getLineCount() - 1 && + caretOffset == content.getOffsetAtLine(caretLine + 1)) { + caretLine++; + } + showCaret(caretLine); } /** * Moves the caret to the end of the next word. @@ -3306,16 +3316,16 @@ * and remove the selection. */ void doWordNext() { - if (selection.y - selection.x > 0) { - int caretLine; - - caretOffset = selection.y; - caretLine = getCaretLine(); - showCaret(caretLine); - } - else { - doSelectionWordNext(); - } + if (selection.y - selection.x > 0) { + int caretLine; + + caretOffset = selection.y; + caretLine = getCaretLine(); + showCaret(caretLine); + } + else { + doSelectionWordNext(); + } } /** * Moves the caret to the start of the previous word. @@ -3323,20 +3333,20 @@ * and remove the selection. */ void doWordPrevious() { - if (selection.y - selection.x > 0) { - int caretLine; - - caretOffset = selection.x; - caretLine = getCaretLine(); - showCaret(caretLine); - } - else { - doSelectionWordPrevious(); - } + if (selection.y - selection.x > 0) { + int caretLine; + + caretOffset = selection.x; + caretLine = getCaretLine(); + showCaret(caretLine); + } + else { + doSelectionWordPrevious(); + } } /** * Draws the specified rectangle. - * Draw directly without invalidating the affected area when clearBackground is + * Draw directly without invalidating the affected area when clearBackground is * false. *
* @@ -3344,53 +3354,53 @@ * @param y the y position * @param width the width * @param height the height - * @param clearBackground true=clear the background by invalidating the requested - * redraw area, false=draw the foreground directly without invalidating the - * redraw area. + * @param clearBackground true=clear the background by invalidating the requested + * redraw area, false=draw the foreground directly without invalidating the + * redraw area. */ void draw(int x, int y, int width, int height, boolean clearBackground) { - if (clearBackground) { - redraw(x + leftMargin, y + topMargin, width, height, true); - } - else { - int startLine = (y + verticalScrollOffset) / lineHeight; - int endY = y + height; - int paintYFromTopLine = (startLine - topIndex) * lineHeight; - int topLineOffset = (topIndex * lineHeight - verticalScrollOffset); - int paintY = paintYFromTopLine + topLineOffset + topMargin; // adjust y position for pixel based scrolling - int lineCount = content.getLineCount(); - Color background = getBackground(); - Color foreground = getForeground(); - GC gc = getGC(); - - if (isSingleLine()) { - lineCount = 1; - if (startLine > 1) { - startLine = 1; - } - } - for (int i = startLine; paintY < endY && i < lineCount; i++, paintY += lineHeight) { - String line = content.getLine(i); - renderer.drawLine(line, i, paintY, gc, background, foreground, clearBackground); - } - gc.dispose(); - } + if (clearBackground) { + redraw(x + leftMargin, y + topMargin, width, height, true); + } + else { + int startLine = (y + verticalScrollOffset) / lineHeight; + int endY = y + height; + int paintYFromTopLine = (startLine - topIndex) * lineHeight; + int topLineOffset = (topIndex * lineHeight - verticalScrollOffset); + int paintY = paintYFromTopLine + topLineOffset + topMargin; // adjust y position for pixel based scrolling + int lineCount = content.getLineCount(); + Color background = getBackground(); + Color foreground = getForeground(); + GC gc = getGC(); + + if (isSingleLine()) { + lineCount = 1; + if (startLine > 1) { + startLine = 1; + } + } + for (int i = startLine; paintY < endY && i < lineCount; i++, paintY += lineHeight) { + String line = content.getLine(i); + renderer.drawLine(line, i, paintY, gc, background, foreground, clearBackground); + } + gc.dispose(); + } } -/** +/** * Ends the autoscroll process. */ void endAutoScroll() { - autoScrollDirection = SWT.NULL; + autoScrollDirection = SWT.NULL; } /** * @see org.eclipse.swt.widgets.Control#getBackground */ public Color getBackground() { - checkWidget(); - if (background == null) { - return getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); - } - return background; + checkWidget(); + if (background == null) { + return getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); + } + return background; } /** * Gets the BIDI coloring mode. When true the BIDI text display @@ -3407,70 +3417,70 @@ *
*/ public boolean getBidiColoring() { - checkWidget(); - return bidiColoring; + checkWidget(); + return bidiColoring; } /** * Returns the offset at the specified x location in the specified line. - * Also sets the caret direction so that the caret is placed correctly + * Also sets the caret direction so that the caret is placed correctly * depending on whether the mouse location is in a R2L or L2R segment. ** - * @param x x location of the mouse location - * @param line line the mouse location is in + * @param x x location of the mouse location + * @param line line the mouse location is in * @return the offset at the specified x location in the specified line, - * relative to the beginning of the document + * relative to the beginning of the document */ int getBidiOffsetAtMouseLocation(int x, int line) { - String lineText = content.getLine(line); - int lineOffset = content.getOffsetAtLine(line); - GC gc = getGC(); - StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); - int[] values; - int offsetInLine; - x += horizontalScrollOffset; - values = bidi.getCaretOffsetAndDirectionAtX(x - leftMargin); - offsetInLine = values[0]; - lastCaretDirection = values[1]; - gc.dispose(); - - return lineOffset + offsetInLine; + String lineText = content.getLine(line); + int lineOffset = content.getOffsetAtLine(line); + GC gc = getGC(); + StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); + int[] values; + int offsetInLine; + x += horizontalScrollOffset; + values = bidi.getCaretOffsetAndDirectionAtX(x - leftMargin); + offsetInLine = values[0]; + lastCaretDirection = values[1]; + gc.dispose(); + + return lineOffset + offsetInLine; } /** - * Returns the x position of the character at the specified offset + * Returns the x position of the character at the specified offset * relative to the first character in the line. *
* * @param text text to be measured. * @param endOffset offset of the character * @param bidi the bidi object to use for measuring text in bidi - * locales. - * @return x position of the character at the specified offset. - * 0 if the length is outside the specified text. + * locales. + * @return x position of the character at the specified offset. + * 0 if the length is outside the specified text. */ int getBidiTextPosition(String text, int endOffset, StyledTextBidi bidi) { - if (endOffset > text.length()) { - return 0; - } - // Use lastCaretDirection in order to get same results as during - // caret positioning (setBidiCaretLocation). Fixes 1GKU4C5. - return bidi.getTextPosition(endOffset, lastCaretDirection); + if (endOffset > text.length()) { + return 0; + } + // Use lastCaretDirection in order to get same results as during + // caret positioning (setBidiCaretLocation). Fixes 1GKU4C5. + return bidi.getTextPosition(endOffset, lastCaretDirection); } -/** +/** * Returns the index of the last fully visible line. ** * @return index of the last fully visible line. */ int getBottomIndex() { - int lineCount = 1; - - if (lineHeight != 0) { - // calculate the number of lines that are fully visible - int partialTopLineHeight = topIndex * lineHeight - verticalScrollOffset; - lineCount = (getClientArea().height - partialTopLineHeight) / lineHeight; - } - return Math.min(content.getLineCount() - 1, topIndex + Math.max(0, lineCount - 1)); + int lineCount = 1; + + if (lineHeight != 0) { + // calculate the number of lines that are fully visible + int partialTopLineHeight = topIndex * lineHeight - verticalScrollOffset; + lineCount = (getClientArea().height - partialTopLineHeight) / lineHeight; + } + return Math.min(content.getLineCount() - 1, topIndex + Math.max(0, lineCount - 1)); } /** * Returns the caret position relative to the start of the text. @@ -3483,53 +3493,53 @@ * */ public int getCaretOffset() { - checkWidget(); - - return caretOffset; + checkWidget(); + + return caretOffset; } /** * Returns the caret offset at the given x location in the line. * The caret offset is the offset of the character where the caret will be - * placed when a mouse click occurs. The caret offset will be the offset of - * the character after the clicked one if the mouse click occurs at the second + * placed when a mouse click occurs. The caret offset will be the offset of + * the character after the clicked one if the mouse click occurs at the second * half of a character. - * Doesn't properly handle ligatures and other context dependent characters - * unless the current locale is a bidi locale. + * Doesn't properly handle ligatures and other context dependent characters + * unless the current locale is a bidi locale. * Ligatures are handled properly as long as they don't occur at lineXOffset. *
* * @param line text of the line to calculate the offset in - * @param lineOffset offset of the first character in the line. - * 0 based from the beginning of the document. + * @param lineOffset offset of the first character in the line. + * 0 based from the beginning of the document. * @param lineXOffset x location in the line * @return caret offset at the x location relative to the start of the line. */ int getCaretOffsetAtX(String line, int lineOffset, int lineXOffset) { - int offset = 0; - GC gc = getGC(); - StyleRange[] styles = null; - StyledTextEvent event = renderer.getLineStyleData(lineOffset, line); - - lineXOffset += horizontalScrollOffset; - if (event != null) { - styles = renderer.filterLineStyles(event.styles); - } - int low = -1; - int high = line.length(); - while (high - low > 1) { - offset = (high + low) / 2; - int x = renderer.getTextPosition(line, lineOffset, offset, styles, gc) + leftMargin; - int charWidth = renderer.getTextPosition(line, lineOffset, offset + 1, styles, gc) + leftMargin - x; - if (lineXOffset <= x + charWidth / 2) { - high = offset; - } - else { - low = offset; - } - } - offset = high; - gc.dispose(); - return offset; + int offset = 0; + GC gc = getGC(); + StyleRange[] styles = null; + StyledTextEvent event = renderer.getLineStyleData(lineOffset, line); + + lineXOffset += horizontalScrollOffset; + if (event != null) { + styles = renderer.filterLineStyles(event.styles); + } + int low = -1; + int high = line.length(); + while (high - low > 1) { + offset = (high + low) / 2; + int x = renderer.getTextPosition(line, lineOffset, offset, styles, gc) + leftMargin; + int charWidth = renderer.getTextPosition(line, lineOffset, offset + 1, styles, gc) + leftMargin - x; + if (lineXOffset <= x + charWidth / 2) { + high = offset; + } + else { + low = offset; + } + } + offset = high; + gc.dispose(); + return offset; } /** * Returns the caret width. @@ -3538,16 +3548,16 @@ * @return the caret width, 0 if caret is null. */ int getCaretWidth() { - Caret caret = getCaret(); - if (caret == null) return 0; - return caret.getSize().x; + Caret caret = getCaret(); + if (caret == null) return 0; + return caret.getSize().x; } /** * Returns the content implementation that is used for text storage * or null if no user defined content implementation has been set. *
* - * @return content implementation that is used for text storage or null + * @return content implementation that is used for text storage or null * if no user defined content implementation has been set. * @exception SWTException
* @@ -3571,8 +3581,8 @@ * */ public boolean getDoubleClickEnabled() { - checkWidget(); - return doubleClickEnabled; + checkWidget(); + return doubleClickEnabled; } /** * Returns whether the widget content can be edited. @@ -3585,20 +3595,20 @@ * */ public boolean getEditable() { - checkWidget(); - return editable; + checkWidget(); + return editable; } /** * @see org.eclipse.swt.widgets.Control#getForeground */ public Color getForeground() { - checkWidget(); - if (foreground == null) { - return getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND); - } - return foreground; + checkWidget(); + if (foreground == null) { + return getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND); + } + return foreground; } -/** +/** * Return a GC to use for rendering and update the cached font style to * represent the current style. *
@@ -3606,23 +3616,23 @@ * @return GC. */ GC getGC() { - renderer.setCurrentFontStyle(SWT.NORMAL); - return new GC(this); + renderer.setCurrentFontStyle(SWT.NORMAL); + return new GC(this); } -/** +/** * Returns the horizontal scroll increment. *
* * @return horizontal scroll increment. */ int getHorizontalIncrement() { - GC gc = getGC(); - int increment = gc.getFontMetrics().getAverageCharWidth(); - - gc.dispose(); - return increment; + GC gc = getGC(); + int increment = gc.getFontMetrics().getAverageCharWidth(); + + gc.dispose(); + return increment; } -/** +/** * Returns the horizontal scroll offset relative to the start of the line. *
* @@ -3633,11 +3643,11 @@ *
* @@ -3648,39 +3658,39 @@ *
* - * @param key a key code defined in SWT.java or a character. - * Optionally ORd with a state mask. Preferred state masks are one or more of - * SWT.MOD1, SWT.MOD2, SWT.MOD3, since these masks account for modifier platform + * @param key a key code defined in SWT.java or a character. + * Optionally ORd with a state mask. Preferred state masks are one or more of + * SWT.MOD1, SWT.MOD2, SWT.MOD3, since these masks account for modifier platform * differences. However, there may be cases where using the specific state masks * (i.e., SWT.CTRL, SWT.SHIFT, SWT.ALT, SWT.COMMAND) makes sense. - * @return one of the predefined actions defined in ST.java or SWT.NULL - * if there is no action associated with the key. + * @return one of the predefined actions defined in ST.java or SWT.NULL + * if there is no action associated with the key. * @exception SWTException
* @param lineOffset offset of the line start relative to the start - * of the content. + * of the content. * @param line line to get line background data for * @return line background data for the given line. */ StyledTextEvent getLineBackgroundData(int lineOffset, String line) { - return sendLineEvent(LineGetBackground, lineOffset, line); + return sendLineEvent(LineGetBackground, lineOffset, line); } -/** +/** * Gets the number of text lines. *
* @@ -3748,27 +3758,27 @@ * */ public int getLineCount() { - checkWidget(); - return getLineAtOffset(getCharCount()) + 1; + checkWidget(); + return getLineAtOffset(getCharCount()) + 1; } /** - * Returns the number of lines that can be completely displayed in the + * Returns the number of lines that can be completely displayed in the * widget client area. *
* - * @return number of lines that can be completely displayed in the widget - * client area. + * @return number of lines that can be completely displayed in the widget + * client area. */ int getLineCountWhole() { - int lineCount; - - if (lineHeight != 0) { - lineCount = getClientArea().height / lineHeight; - } - else { - lineCount = 1; - } - return lineCount; + int lineCount; + + if (lineHeight != 0) { + lineCount = getClientArea().height / lineHeight; + } + else { + lineCount = 1; + } + return lineCount; } /** * Returns the line at the specified offset in the text. @@ -3776,24 +3786,24 @@ * returns the line of the insert location. *
* - * @param offset offset relative to the start of the content. - * 0 <= offset <= getCharCount() + * @param offset offset relative to the start of the content. + * 0 <= offset <= getCharCount() * @return line at the specified offset in the text * @exception SWTException
* * @param lineOffset offset of the line. This may be the offset of - * a visual line if the widget is in word wrap mode. - * @param line line text. This may be the text of a visualline if - * the widget is in word wrap mode. - * @return StyledTextEvent that can be used to request line data - * for the given line. + * a visual line if the widget is in word wrap mode. + * @param line line text. This may be the text of a visualline if + * the widget is in word wrap mode. + * @return StyledTextEvent that can be used to request line data + * for the given line. */ StyledTextEvent sendLineEvent(int eventType, int lineOffset, String line) { - StyledTextEvent event = null; - - if (isListening(eventType)) { - event = new StyledTextEvent(logicalContent); - if (wordWrap) { - // if word wrap is on, the line offset and text may be visual (wrapped) - int lineIndex = logicalContent.getLineAtOffset(lineOffset); - - event.detail = logicalContent.getOffsetAtLine(lineIndex); - event.text = logicalContent.getLine(lineIndex); - } - else { - event.detail = lineOffset; - event.text = line; - } - notifyListeners(eventType, event); - } - return event; + StyledTextEvent event = null; + + if (isListening(eventType)) { + event = new StyledTextEvent(logicalContent); + if (wordWrap) { + // if word wrap is on, the line offset and text may be visual (wrapped) + int lineIndex = logicalContent.getLineAtOffset(lineOffset); + + event.detail = logicalContent.getOffsetAtLine(lineIndex); + event.text = logicalContent.getLine(lineIndex); + } + else { + event.detail = lineOffset; + event.text = line; + } + notifyListeners(eventType, event); + } + return event; } /** * Returns the line height. @@ -3857,108 +3867,108 @@ * */ public int getLineHeight() { - checkWidget(); - return lineHeight; + checkWidget(); + return lineHeight; } /** * Returns a LineCache implementation. Depending on whether or not - * word wrap is on this may be a line wrapping or line width + * word wrap is on this may be a line wrapping or line width * calculating implementaiton. *
- * + * * @param content StyledTextContent to create the LineCache on. * @return a LineCache implementation */ LineCache getLineCache(StyledTextContent content) { LineCache lineCache; - - if (wordWrap) { - lineCache = new WordWrapCache(this, (WrappedContent) content); - } - else { - lineCache = new ContentWidthCache(this, content.getLineCount()); - } - return lineCache; + + if (wordWrap) { + lineCache = new WordWrapCache(this, (WrappedContent) content); + } + else { + lineCache = new ContentWidthCache(this, content.getLineCount()); + } + return lineCache; } /** - * Returns the line style data for the given line or null if there is - * none. If there is a LineStyleListener but it does not set any styles, - * the StyledTextEvent.styles field will be initialized to an empty + * Returns the line style data for the given line or null if there is + * none. If there is a LineStyleListener but it does not set any styles, + * the StyledTextEvent.styles field will be initialized to an empty * array. *
- * - * @param lineOffset offset of the line start relative to the start of - * the content. + * + * @param lineOffset offset of the line start relative to the start of + * the content. * @param line line to get line styles for - * @return line style data for the given line. Styles may start before - * line start and end after line end + * @return line style data for the given line. Styles may start before + * line start and end after line end */ StyledTextEvent getLineStyleData(int lineOffset, String line) { - return sendLineEvent(LineGetStyle, lineOffset, line); + return sendLineEvent(LineGetStyle, lineOffset, line); } /** - * Returns the x, y location of the upper left corner of the character - * bounding box at the specified offset in the text. The point is + * Returns the x, y location of the upper left corner of the character + * bounding box at the specified offset in the text. The point is * relative to the upper left corner of the widget client area. *
* - * @param offset offset relative to the start of the content. - * 0 <= offset <= getCharCount() - * @return x, y location of the upper left corner of the character - * bounding box at the specified offset in the text. + * @param offset offset relative to the start of the content. + * 0 <= offset <= getCharCount() + * @return x, y location of the upper left corner of the character + * bounding box at the specified offset in the text. * @exception SWTException
* - * @param lineIndex index of the line, 0 based relative to the first - * line in the content. 0 <= lineIndex < getLineCount(), except - * lineIndex may always be 0 + * @param lineIndex index of the line, 0 based relative to the first + * line in the content. 0 <= lineIndex < getLineCount(), except + * lineIndex may always be 0 * @return offset offset of the first character of the line, relative to - * the beginning of the document. The first character of the document is - * at offset 0. - * When there are not any lines, getOffsetAtLine(0) is a valid call that - * answers 0. + * the beginning of the document. The first character of the document is + * at offset 0. + * When there are not any lines, getOffsetAtLine(0) is a valid call that + * answers 0. * @exception SWTException
* - * @param point the origin of character bounding box relative to - * the origin of the widget client area. - * @return offset of the character at the given location relative - * to the first character in the document. + * @param point the origin of character bounding box relative to + * the origin of the widget client area. + * @return offset of the character at the given location relative + * to the first character in the document. * @exception SWTException
* - * @param x x location of the mouse location - * @param line line the mouse location is in + * @param x x location of the mouse location + * @param line line the mouse location is in * @return the offset at the specified x location in the specified line, - * relative to the beginning of the document + * relative to the beginning of the document */ int getOffsetAtMouseLocation(int x, int line) { - String lineText = content.getLine(line); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = getCaretOffsetAtX(lineText, lineOffset, x); - return lineOffset + offsetInLine; + String lineText = content.getLine(line); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = getCaretOffsetAtX(lineText, lineOffset, x); + return lineOffset + offsetInLine; } /** * Returns the offset of the character at the given x location in the line. *
* * @param line text of the line to calculate the offset in - * @param lineOffset offset of the first character in the line. - * 0 based from the beginning of the document. + * @param lineOffset offset of the first character in the line. + * 0 based from the beginning of the document. * @param lineXOffset x location in the line - * @return offset of the character at the x location relative to the start - * of the line. -1 if the x location is past the end if the line. + * @return offset of the character at the x location relative to the start + * of the line. -1 if the x location is past the end if the line. */ int getOffsetAtX(String line, int lineOffset, int lineXOffset) { - GC gc = getGC(); - int offset; - - lineXOffset += (horizontalScrollOffset - leftMargin); - if (isBidi()) { - StyledTextBidi bidi = getStyledTextBidi(line, lineOffset, gc); - offset = bidi.getOffsetAtX(lineXOffset); - } - else { - StyleRange[] styles = null; - StyledTextEvent event = renderer.getLineStyleData(lineOffset, line); - - if (event != null) { - styles = renderer.filterLineStyles(event.styles); - } - int low = -1; - int high = line.length(); - while (high - low > 1) { - offset = (high + low) / 2; - // Restrict right/high search boundary only if x is within searched text segment. - // Fixes 1GL4ZVE. - if (lineXOffset < renderer.getTextPosition(line, lineOffset, offset + 1, styles, gc)) { - high = offset; - } - else - if (high == line.length() && high - offset == 1) { - // requested x location is past end of line - high = -1; - } - else { - low = offset; - } - } - offset = high; - } - gc.dispose(); - return offset; + GC gc = getGC(); + int offset; + + lineXOffset += (horizontalScrollOffset - leftMargin); + if (isBidi()) { + StyledTextBidi bidi = getStyledTextBidi(line, lineOffset, gc); + offset = bidi.getOffsetAtX(lineXOffset); + } + else { + StyleRange[] styles = null; + StyledTextEvent event = renderer.getLineStyleData(lineOffset, line); + + if (event != null) { + styles = renderer.filterLineStyles(event.styles); + } + int low = -1; + int high = line.length(); + while (high - low > 1) { + offset = (high + low) / 2; + // Restrict right/high search boundary only if x is within searched text segment. + // Fixes 1GL4ZVE. + if (lineXOffset < renderer.getTextPosition(line, lineOffset, offset + 1, styles, gc)) { + high = offset; + } + else + if (high == line.length() && high - offset == 1) { + // requested x location is past end of line + high = -1; + } + else { + low = offset; + } + } + offset = high; + } + gc.dispose(); + return offset; } -/** +/** * Returns the index of the last partially visible line. * * @return index of the last partially visible line. */ int getPartialBottomIndex() { - int partialLineCount = Compatibility.ceil(getClientArea().height, lineHeight); - return Math.min(content.getLineCount(), topIndex + partialLineCount) - 1; + int partialLineCount = Compatibility.ceil(getClientArea().height, lineHeight); + return Math.min(content.getLineCount(), topIndex + partialLineCount) - 1; } /** - * Returns the content in the specified range using the platform line + * Returns the content in the specified range using the platform line * delimiter to separate lines. *
* * @param writer the TextWriter to write line text into - * @return the content in the specified range using the platform line - * delimiter to separate lines as written by the specified TextWriter. + * @return the content in the specified range using the platform line + * delimiter to separate lines as written by the specified TextWriter. */ String getPlatformDelimitedText(TextWriter writer) { - int end = writer.getStart() + writer.getCharCount(); - int startLine = logicalContent.getLineAtOffset(writer.getStart()); - int endLine = logicalContent.getLineAtOffset(end); - String endLineText = logicalContent.getLine(endLine); - int endLineOffset = logicalContent.getOffsetAtLine(endLine); - - for (int i = startLine; i <= endLine; i++) { - writer.writeLine(logicalContent.getLine(i), logicalContent.getOffsetAtLine(i)); - if (i < endLine) { - writer.writeLineDelimiter(PlatformLineDelimiter); - } - } - if (end > endLineOffset + endLineText.length()) { - writer.writeLineDelimiter(PlatformLineDelimiter); - } - writer.close(); - return writer.toString(); + int end = writer.getStart() + writer.getCharCount(); + int startLine = logicalContent.getLineAtOffset(writer.getStart()); + int endLine = logicalContent.getLineAtOffset(end); + String endLineText = logicalContent.getLine(endLine); + int endLineOffset = logicalContent.getOffsetAtLine(endLine); + + for (int i = startLine; i <= endLine; i++) { + writer.writeLine(logicalContent.getLine(i), logicalContent.getOffsetAtLine(i)); + if (i < endLine) { + writer.writeLineDelimiter(PlatformLineDelimiter); + } + } + if (end > endLineOffset + endLineText.length()) { + writer.writeLineDelimiter(PlatformLineDelimiter); + } + writer.close(); + return writer.toString(); } /** * Returns the selection. *
* Text selections are specified in terms of caret positions. In a text - * widget that contains N characters, there are N+1 caret positions, + * widget that contains N characters, there are N+1 caret positions, * ranging from 0..N *
* - * @return start and end of the selection, x is the offset of the first - * selected character, y is the offset after the last selected character. - * The selection values returned are visual (i.e., x will always always be - * <= y). To determine if a selection is right-to-left (RtoL) vs. left-to-right - * (LtoR), compare the caretOffset to the start and end of the selection + * @return start and end of the selection, x is the offset of the first + * selected character, y is the offset after the last selected character. + * The selection values returned are visual (i.e., x will always always be + * <= y). To determine if a selection is right-to-left (RtoL) vs. left-to-right + * (LtoR), compare the caretOffset to the start and end of the selection * (e.g., caretOffset == start of selection implies that the selection is RtoL). * @see #getSelectionRange * @exception SWTException
* - * @return start and length of the selection, x is the offset of the - * first selected character, relative to the first character of the - * widget content. y is the length of the selection. - * The selection values returned are visual (i.e., length will always always be - * positive). To determine if a selection is right-to-left (RtoL) vs. left-to-right - * (LtoR), compare the caretOffset to the start and end of the selection + * @return start and length of the selection, x is the offset of the + * first selected character, relative to the first character of the + * widget content. y is the length of the selection. + * The selection values returned are visual (i.e., length will always always be + * positive). To determine if a selection is right-to-left (RtoL) vs. left-to-right + * (LtoR), compare the caretOffset to the start and end of the selection * (e.g., caretOffset == start of selection implies that the selection is RtoL). * @exception SWTException
* - * @param lineOffset offset of the first character in the line. - * 0 based from the beginning of the document. + * @param lineOffset offset of the first character in the line. + * 0 based from the beginning of the document. * @param line text of the line to specify bidi segments for * @return text segments that should be treated as if they had a - * different direction than the surrounding text. Only the start - * index of a segment is specified, relative to the start of the - * line. Always starts with 0 and ends with the line length. - * @exception IllegalArgumentException
* - * @param offset the offset to return the style for. - * 0 <= offset < getCharCount() must be true. + * @param offset the offset to return the style for. + * 0 <= offset < getCharCount() must be true. * @return a StyleRange with start == offset and length == 1, indicating - * the style at the given offset. null if a LineStyleListener has been set - * or if a style is not set for the given offset. + * the style at the given offset. null if a LineStyleListener has been set + * or if a style is not set for the given offset. * @exception SWTException
* @@ -4369,47 +4379,47 @@ *
- * - * @param lineText the line that the StyledTextBidi object should - * work on. - * @param lineOffset offset of the beginning of the line, relative - * to the beginning of the document + * + * @param lineText the line that the StyledTextBidi object should + * work on. + * @param lineOffset offset of the beginning of the line, relative + * to the beginning of the document * @param gc GC to use when creating a new StyledTextBidi object. * @return a StyledTextBidi object for the specified line. */ StyledTextBidi getStyledTextBidi(String lineText, int lineOffset, GC gc) { - return getStyledTextBidi(lineText, lineOffset, gc, null); + return getStyledTextBidi(lineText, lineOffset, gc, null); } /** * Returns a StyledTextBidi object for the specified line. *
- * - * @param lineText the line that the StyledTextBidi object should - * work on. - * @param lineOffset offset of the beginning of the line, relative - * to the beginning of the document + * + * @param lineText the line that the StyledTextBidi object should + * work on. + * @param lineOffset offset of the beginning of the line, relative + * to the beginning of the document * @param gc GC to use when creating a new StyledTextBidi object. - * @param styles StyleRanges to use when creating a new StyledTextBidi - * object. + * @param styles StyleRanges to use when creating a new StyledTextBidi + * object. * @return a StyledTextBidi object for the specified line. */ StyledTextBidi getStyledTextBidi(String lineText, int lineOffset, GC gc, StyleRange[] styles) { - return renderer.getStyledTextBidi(lineText, lineOffset, gc, styles); -} + return renderer.getStyledTextBidi(lineText, lineOffset, gc, styles); +} /** * Returns the tab width measured in characters. * @@ -4420,8 +4430,8 @@ * */ public int getTabs() { - checkWidget(); - return tabLength; + checkWidget(); + return tabLength; } /** * Returns a copy of the widget content. @@ -4434,15 +4444,15 @@ * */ public String getText() { - checkWidget(); - return content.getTextRange(0, getCharCount()); -} + checkWidget(); + return content.getTextRange(0, getCharCount()); +} /** * Returns the widget content between the two offsets. *
* * @param start offset of the first character in the returned String - * @param end offset of the last character in the returned String + * @param end offset of the last character in the returned String * @return widget content starting at start and ending at end * @see #getTextRange(int,int) * @exception SWTException
* * @param start offset of the first character in the returned String - * @param length number of characters to return + * @param length number of characters to return * @return widget content starting at start and extending length characters. * @exception SWTException
* @@ -4498,51 +4508,51 @@ * */ public int getTextLimit() { - checkWidget(); - - return textLimit; + checkWidget(); + + return textLimit; } /** - * Returns the x position of the character at the specified offset + * Returns the x position of the character at the specified offset * relative to the first character in the line. * Expands tabs to tab stops using the widget tab width. *
* * @param line line to be measured. - * @param lineIndex index of the line relative to the first kine of the - * document - * @param length number of characters to measure. Tabs are counted - * as one character in this parameter. + * @param lineIndex index of the line relative to the first kine of the + * document + * @param length number of characters to measure. Tabs are counted + * as one character in this parameter. * @param gc GC to use for measuring text - * @return x position of the character at the specified offset - * with tabs expanded to tab stops. 0 if the length is outside the - * specified text. + * @return x position of the character at the specified offset + * with tabs expanded to tab stops. 0 if the length is outside the + * specified text. */ int getTextPosition(String line, int lineIndex, int length, GC gc) { - int lineOffset = content.getOffsetAtLine(lineIndex); - int lineLength = line.length(); - int width; - if (lineLength == 0 || length > lineLength) { - return 0; - } - if (isBidi()) { - StyledTextBidi bidi = getStyledTextBidi(line, lineOffset, gc, null); - width = getBidiTextPosition(line, length, bidi); - } - else { - StyledTextEvent event = renderer.getLineStyleData(lineOffset, line); - StyleRange[] styles = null; - if (event != null) { - styles = renderer.filterLineStyles(event.styles); - } - width = renderer.getTextPosition(line, lineOffset, length, styles, gc); - } - return width; + int lineOffset = content.getOffsetAtLine(lineIndex); + int lineLength = line.length(); + int width; + if (lineLength == 0 || length > lineLength) { + return 0; + } + if (isBidi()) { + StyledTextBidi bidi = getStyledTextBidi(line, lineOffset, gc, null); + width = getBidiTextPosition(line, length, bidi); + } + else { + StyledTextEvent event = renderer.getLineStyleData(lineOffset, line); + StyleRange[] styles = null; + if (event != null) { + styles = renderer.filterLineStyles(event.styles); + } + width = renderer.getTextPosition(line, lineOffset, length, styles, gc); + } + return width; } /** * Gets the top index. The top index is the index of the fully visible line that - * is currently at the top of the widget or the topmost partially visible line if - * no line is fully visible. + * is currently at the top of the widget or the topmost partially visible line if + * no line is fully visible. * The top index changes when the widget is scrolled. Indexing is zero based. *
* @@ -4553,20 +4563,20 @@ * */ public int getTopIndex() { - checkWidget(); - int logicalTopIndex = topIndex; - - if (wordWrap) { - int visualLineOffset = content.getOffsetAtLine(topIndex); - logicalTopIndex = logicalContent.getLineAtOffset(visualLineOffset); - } - return logicalTopIndex; + checkWidget(); + int logicalTopIndex = topIndex; + + if (wordWrap) { + int visualLineOffset = content.getOffsetAtLine(topIndex); + logicalTopIndex = logicalContent.getLineAtOffset(visualLineOffset); + } + return logicalTopIndex; } /** - * Gets the top pixel. The top pixel is the pixel position of the line that is - * currently at the top of the widget.The text widget can be scrolled by pixels - * by dragging the scroll thumb so that a partial line may be displayed at the top - * the widget. The top pixel changes when the widget is scrolled. The top pixel + * Gets the top pixel. The top pixel is the pixel position of the line that is + * currently at the top of the widget.The text widget can be scrolled by pixels + * by dragging the scroll thumb so that a partial line may be displayed at the top + * the widget. The top pixel changes when the widget is scrolled. The top pixel * does not include the widget trimming. *
* @@ -4577,39 +4587,39 @@ * */ public int getTopPixel() { - checkWidget(); - return verticalScrollOffset; + checkWidget(); + return verticalScrollOffset; } -/** +/** * Returns the vertical scroll increment. *
* * @return vertical scroll increment. */ int getVerticalIncrement() { - return lineHeight; + return lineHeight; } /** * Returns the index of the line the caret is on. - * When in word wrap mode and at the end of one wrapped line/ + * When in word wrap mode and at the end of one wrapped line/ * beginning of the continuing wrapped line the caret offset * is not sufficient to determine the caret line. - * + * * @return the index of the line the caret is on. */ int getCaretLine() { - int caretLine = content.getLineAtOffset(caretOffset); - int leftColumnX = 0; - - if (isBidi()) { - leftColumnX = XINSET; - } - if (wordWrap && columnX <= leftColumnX && - caretLine < content.getLineCount() - 1 && - caretOffset == content.getOffsetAtLine(caretLine + 1)) { - caretLine++; - } - return caretLine; + int caretLine = content.getLineAtOffset(caretOffset); + int leftColumnX = 0; + + if (isBidi()) { + leftColumnX = XINSET; + } + if (wordWrap && columnX <= leftColumnX && + caretLine < content.getLineCount() - 1 && + caretOffset == content.getOffsetAtLine(caretLine + 1)) { + caretLine++; + } + return caretLine; } /** * Returns the offset of the character after the word at the specified @@ -4623,42 +4633,42 @@ *
** Space characters ' ' (ASCII 20) are special as they are treated as - * part of the word leading up to the space character. Line breaks are + * part of the word leading up to the space character. Line breaks are * treated as one word. *
*/ int getWordEnd(int offset) { - int line = logicalContent.getLineAtOffset(offset); - int lineOffset = logicalContent.getOffsetAtLine(line); - String lineText = logicalContent.getLine(line); - int lineLength = lineText.length(); - - if (offset >= getCharCount()) { - return offset; - } - if (offset == lineOffset + lineLength) { - line++; - offset = logicalContent.getOffsetAtLine(line); - } - else { - offset -= lineOffset; - char ch = lineText.charAt(offset); - boolean letterOrDigit = Compatibility.isLetterOrDigit(ch); - while (offset < lineLength - 1 && Compatibility.isLetterOrDigit(ch) == letterOrDigit) { - offset++; - ch = lineText.charAt(offset); - } - // skip over trailing whitespace - while (offset < lineLength - 1 && Compatibility.isSpaceChar(ch)) { - offset++; - ch = lineText.charAt(offset); - } - if (offset == lineLength - 1 && (Compatibility.isLetterOrDigit(ch) == letterOrDigit || Compatibility.isSpaceChar(ch))) { - offset++; - } - offset += lineOffset; - } - return offset; + int line = logicalContent.getLineAtOffset(offset); + int lineOffset = logicalContent.getOffsetAtLine(line); + String lineText = logicalContent.getLine(line); + int lineLength = lineText.length(); + + if (offset >= getCharCount()) { + return offset; + } + if (offset == lineOffset + lineLength) { + line++; + offset = logicalContent.getOffsetAtLine(line); + } + else { + offset -= lineOffset; + char ch = lineText.charAt(offset); + boolean letterOrDigit = Compatibility.isLetterOrDigit(ch); + while (offset < lineLength - 1 && Compatibility.isLetterOrDigit(ch) == letterOrDigit) { + offset++; + ch = lineText.charAt(offset); + } + // skip over trailing whitespace + while (offset < lineLength - 1 && Compatibility.isSpaceChar(ch)) { + offset++; + ch = lineText.charAt(offset); + } + if (offset == lineLength - 1 && (Compatibility.isLetterOrDigit(ch) == letterOrDigit || Compatibility.isSpaceChar(ch))) { + offset++; + } + offset += lineOffset; + } + return offset; } /** * Returns the offset of the character after the word at the specified @@ -4671,38 +4681,38 @@ * * *- * Spaces are ignored and do not represent a word. Line breaks are treated + * Spaces are ignored and do not represent a word. Line breaks are treated * as one word. *
*/ int getWordEndNoSpaces(int offset) { - int line = logicalContent.getLineAtOffset(offset); - int lineOffset = logicalContent.getOffsetAtLine(line); - String lineText = logicalContent.getLine(line); - int lineLength = lineText.length(); - - if (offset >= getCharCount()) { - return offset; - } - if (offset == lineOffset + lineLength) { - line++; - offset = logicalContent.getOffsetAtLine(line); - } - else { - offset -= lineOffset; - char ch = lineText.charAt(offset); - boolean letterOrDigit = Compatibility.isLetterOrDigit(ch); - - while (offset < lineLength - 1 && Compatibility.isLetterOrDigit(ch) == letterOrDigit && Compatibility.isSpaceChar(ch) == false) { - offset++; - ch = lineText.charAt(offset); - } - if (offset == lineLength - 1 && Compatibility.isLetterOrDigit(ch) == letterOrDigit && Compatibility.isSpaceChar(ch) == false) { - offset++; - } - offset += lineOffset; - } - return offset; + int line = logicalContent.getLineAtOffset(offset); + int lineOffset = logicalContent.getOffsetAtLine(line); + String lineText = logicalContent.getLine(line); + int lineLength = lineText.length(); + + if (offset >= getCharCount()) { + return offset; + } + if (offset == lineOffset + lineLength) { + line++; + offset = logicalContent.getOffsetAtLine(line); + } + else { + offset -= lineOffset; + char ch = lineText.charAt(offset); + boolean letterOrDigit = Compatibility.isLetterOrDigit(ch); + + while (offset < lineLength - 1 && Compatibility.isLetterOrDigit(ch) == letterOrDigit && Compatibility.isSpaceChar(ch) == false) { + offset++; + ch = lineText.charAt(offset); + } + if (offset == lineLength - 1 && Compatibility.isLetterOrDigit(ch) == letterOrDigit && Compatibility.isSpaceChar(ch) == false) { + offset++; + } + offset += lineOffset; + } + return offset; } /** * Returns the start offset of the word at the specified offset. @@ -4715,44 +4725,44 @@ * ** Space characters ' ' (ASCII 20) are special as they are treated as - * part of the word leading up to the space character. Line breaks are treated + * part of the word leading up to the space character. Line breaks are treated * as one word. *
*/ int getWordStart(int offset) { - int line = logicalContent.getLineAtOffset(offset); - int lineOffset = logicalContent.getOffsetAtLine(line); - String lineText = logicalContent.getLine(line); - - if (offset <= 0) { - return offset; - } - if (offset == lineOffset) { - line--; - lineText = logicalContent.getLine(line); - offset = logicalContent.getOffsetAtLine(line) + lineText.length(); - } - else { - char ch; - boolean letterOrDigit; - - offset -= lineOffset; - // skip over trailing whitespace - do { - offset--; - ch = lineText.charAt(offset); - } while (offset > 0 && Compatibility.isSpaceChar(ch)); - letterOrDigit = Compatibility.isLetterOrDigit(ch); - while (offset > 0 && Compatibility.isLetterOrDigit(ch) == letterOrDigit && Compatibility.isSpaceChar(ch) == false) { - offset--; - ch = lineText.charAt(offset); - } - if (offset > 0 || Compatibility.isLetterOrDigit(ch) != letterOrDigit) { - offset++; - } - offset += lineOffset; - } - return offset; + int line = logicalContent.getLineAtOffset(offset); + int lineOffset = logicalContent.getOffsetAtLine(line); + String lineText = logicalContent.getLine(line); + + if (offset <= 0) { + return offset; + } + if (offset == lineOffset) { + line--; + lineText = logicalContent.getLine(line); + offset = logicalContent.getOffsetAtLine(line) + lineText.length(); + } + else { + char ch; + boolean letterOrDigit; + + offset -= lineOffset; + // skip over trailing whitespace + do { + offset--; + ch = lineText.charAt(offset); + } while (offset > 0 && Compatibility.isSpaceChar(ch)); + letterOrDigit = Compatibility.isLetterOrDigit(ch); + while (offset > 0 && Compatibility.isLetterOrDigit(ch) == letterOrDigit && Compatibility.isSpaceChar(ch) == false) { + offset--; + ch = lineText.charAt(offset); + } + if (offset > 0 || Compatibility.isLetterOrDigit(ch) != letterOrDigit) { + offset++; + } + offset += lineOffset; + } + return offset; } /** * Returns whether the widget wraps lines. @@ -4762,10 +4772,10 @@ * @since 2.0 */ public boolean getWordWrap() { - checkWidget(); - return wordWrap; + checkWidget(); + return wordWrap; } -/** +/** * Returns the x location of the character at the give offset in the line. * NOTE: Does not return correct values for true italic fonts (vs. slanted fonts). *@@ -4773,24 +4783,24 @@ * @return x location of the character at the given offset in the line. */ int getXAtOffset(String line, int lineIndex, int lineOffset) { - int x; - if (lineOffset == 0 && isBidi() == false) { - x = leftMargin; - } - else { - GC gc = getGC(); - x = getTextPosition(line, lineIndex, Math.min(line.length(), lineOffset), gc) + leftMargin; - gc.dispose(); - if (lineOffset > line.length()) { - // offset is not on the line. return an x location one character - // after the line to indicate the line delimiter. - x += lineEndSpaceWidth; - } - } - return x - horizontalScrollOffset; + int x; + if (lineOffset == 0 && isBidi() == false) { + x = leftMargin; + } + else { + GC gc = getGC(); + x = getTextPosition(line, lineIndex, Math.min(line.length(), lineOffset), gc) + leftMargin; + gc.dispose(); + if (lineOffset > line.length()) { + // offset is not on the line. return an x location one character + // after the line to indicate the line delimiter. + x += lineEndSpaceWidth; + } + } + return x - horizontalScrollOffset; } -/** - * Inserts a string. The old selection is replaced with the new text. +/** + * Inserts a string. The old selection is replaced with the new text. *
* * @param string the string @@ -4804,30 +4814,30 @@ * */ public void insert(String string) { - checkWidget(); - if (string == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - Point sel = getSelectionRange(); - replaceTextRange(sel.x, sel.y, string); + checkWidget(); + if (string == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + Point sel = getSelectionRange(); + replaceTextRange(sel.x, sel.y, string); } /** * Creates content change listeners and set the default content model. */ void installDefaultContent() { - textChangeListener = new TextChangeListener() { - public void textChanging(TextChangingEvent event) { - handleTextChanging(event); - } - public void textChanged(TextChangedEvent event) { - handleTextChanged(event); - } - public void textSet(TextChangedEvent event) { - handleTextSet(event); - } - }; - logicalContent = content = new DefaultContent(); - content.addTextChangeListener(textChangeListener); + textChangeListener = new TextChangeListener() { + public void textChanging(TextChangingEvent event) { + handleTextChanging(event); + } + public void textChanged(TextChangedEvent event) { + handleTextChanged(event); + } + public void textSet(TextChangedEvent event) { + handleTextSet(event); + } + }; + logicalContent = content = new DefaultContent(); + content.addTextChangeListener(textChangeListener); } /** * Creates a default line style listener. @@ -4838,159 +4848,159 @@ * @see #addLineStyleListener */ void installDefaultLineStyler() { - defaultLineStyler = new DefaultLineStyler(logicalContent); - StyledTextListener typedListener = new StyledTextListener(defaultLineStyler); - if (userLineStyle == false) { - addListener(LineGetStyle, typedListener); - } - if (userLineBackground == false) { - addListener(LineGetBackground, typedListener); - } + defaultLineStyler = new DefaultLineStyler(logicalContent); + StyledTextListener typedListener = new StyledTextListener(defaultLineStyler); + if (userLineStyle == false) { + addListener(LineGetStyle, typedListener); + } + if (userLineBackground == false) { + addListener(LineGetBackground, typedListener); + } } -/** +/** * Adds event listeners */ void installListeners() { - ScrollBar verticalBar = getVerticalBar(); - ScrollBar horizontalBar = getHorizontalBar(); - - addListener(SWT.Dispose, new Listener() { - public void handleEvent(Event event) { - handleDispose(); - } - }); - addListener(SWT.KeyDown, new Listener() { - public void handleEvent(Event event) { - handleKeyDown(event); - } - }); - addListener(SWT.MouseDown, new Listener() { - public void handleEvent(Event event) { - handleMouseDown(event); - } - }); - addListener(SWT.MouseUp, new Listener() { - public void handleEvent(Event event) { - handleMouseUp(event); - } - }); - addListener(SWT.MouseDoubleClick, new Listener() { - public void handleEvent(Event event) { - handleMouseDoubleClick(event); - } - }); - addListener(SWT.MouseMove, new Listener() { - public void handleEvent(Event event) { - handleMouseMove(event); - } - }); - addListener(SWT.Paint, new Listener() { - public void handleEvent(Event event) { - handlePaint(event); - } - }); - addListener(SWT.Resize, new Listener() { - public void handleEvent(Event event) { - handleResize(event); - } - }); - addListener(SWT.Traverse, new Listener() { - public void handleEvent(Event event) { - handleTraverse(event); - } - }); - if (verticalBar != null) { - verticalBar.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - handleVerticalScroll(event); - } - }); - } - if (horizontalBar != null) { - horizontalBar.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - handleHorizontalScroll(event); - } - }); - } + ScrollBar verticalBar = getVerticalBar(); + ScrollBar horizontalBar = getHorizontalBar(); + + addListener(SWT.Dispose, new Listener() { + public void handleEvent(Event event) { + handleDispose(); + } + }); + addListener(SWT.KeyDown, new Listener() { + public void handleEvent(Event event) { + handleKeyDown(event); + } + }); + addListener(SWT.MouseDown, new Listener() { + public void handleEvent(Event event) { + handleMouseDown(event); + } + }); + addListener(SWT.MouseUp, new Listener() { + public void handleEvent(Event event) { + handleMouseUp(event); + } + }); + addListener(SWT.MouseDoubleClick, new Listener() { + public void handleEvent(Event event) { + handleMouseDoubleClick(event); + } + }); + addListener(SWT.MouseMove, new Listener() { + public void handleEvent(Event event) { + handleMouseMove(event); + } + }); + addListener(SWT.Paint, new Listener() { + public void handleEvent(Event event) { + handlePaint(event); + } + }); + addListener(SWT.Resize, new Listener() { + public void handleEvent(Event event) { + handleResize(event); + } + }); + addListener(SWT.Traverse, new Listener() { + public void handleEvent(Event event) { + handleTraverse(event); + } + }); + if (verticalBar != null) { + verticalBar.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + handleVerticalScroll(event); + } + }); + } + if (horizontalBar != null) { + horizontalBar.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + handleHorizontalScroll(event); + } + }); + } } StyledTextContent internalGetContent() { - return content; + return content; } int internalGetHorizontalPixel() { - return horizontalScrollOffset; + return horizontalScrollOffset; } LineCache internalGetLineCache() { - return lineCache; + return lineCache; } Point internalGetSelection() { - return selection; + return selection; } boolean internalGetWordWrap() { - return wordWrap; + return wordWrap; } /** * Used by WordWrapCache to bypass StyledText.redraw which does * an unwanted cache reset. */ void internalRedraw() { - super.redraw(); + super.redraw(); } -/** +/** * Redraws the specified text range. *
* * @param start offset of the first character to redraw * @param length number of characters to redraw - * @param clearBackground true if the background should be cleared as - * part of the redraw operation. If true, the entire redraw range will + * @param clearBackground true if the background should be cleared as + * part of the redraw operation. If true, the entire redraw range will * be cleared before anything is redrawn. If the redraw range includes - * the last character of a line (i.e., the entire line is redrawn) the - * line is cleared all the way to the right border of the widget. - * The redraw operation will be faster and smoother if clearBackground is - * set to false. Whether or not the flag can be set to false depends on - * the type of change that has taken place. If font styles or background - * colors for the redraw range have changed, clearBackground should be - * set to true. If only foreground colors have changed for the redraw - * range, clearBackground can be set to false. + * the last character of a line (i.e., the entire line is redrawn) the + * line is cleared all the way to the right border of the widget. + * The redraw operation will be faster and smoother if clearBackground is + * set to false. Whether or not the flag can be set to false depends on + * the type of change that has taken place. If font styles or background + * colors for the redraw range have changed, clearBackground should be + * set to true. If only foreground colors have changed for the redraw + * range, clearBackground can be set to false. */ void internalRedrawRange(int start, int length, boolean clearBackground) { - int end = start + length; - int firstLine = content.getLineAtOffset(start); - int lastLine = content.getLineAtOffset(end); - int offsetInFirstLine; - int partialBottomIndex = getPartialBottomIndex(); - int partialTopIndex = verticalScrollOffset / lineHeight; - // do nothing if redraw range is completely invisible - if (firstLine > partialBottomIndex || lastLine < partialTopIndex) { - return; - } - // only redraw visible lines - if (partialTopIndex > firstLine) { - firstLine = partialTopIndex; - offsetInFirstLine = 0; - } - else { - offsetInFirstLine = start - content.getOffsetAtLine(firstLine); - } - if (partialBottomIndex + 1 < lastLine) { - lastLine = partialBottomIndex + 1; // + 1 to redraw whole bottom line, including line break - end = content.getOffsetAtLine(lastLine); - } - // redraw first and last lines - if (isBidi()) { - redrawBidiLines(firstLine, offsetInFirstLine, lastLine, end, clearBackground); - } - else { - redrawLines(firstLine, offsetInFirstLine, lastLine, end, clearBackground); - } - // redraw entire center lines if redraw range includes more than two lines - if (lastLine - firstLine > 1) { - Rectangle clientArea = getClientArea(); - int redrawStopY = lastLine * lineHeight - verticalScrollOffset; - int redrawY = (firstLine + 1) * lineHeight - verticalScrollOffset; - draw(0, redrawY, clientArea.width, redrawStopY - redrawY, clearBackground); - } + int end = start + length; + int firstLine = content.getLineAtOffset(start); + int lastLine = content.getLineAtOffset(end); + int offsetInFirstLine; + int partialBottomIndex = getPartialBottomIndex(); + int partialTopIndex = verticalScrollOffset / lineHeight; + // do nothing if redraw range is completely invisible + if (firstLine > partialBottomIndex || lastLine < partialTopIndex) { + return; + } + // only redraw visible lines + if (partialTopIndex > firstLine) { + firstLine = partialTopIndex; + offsetInFirstLine = 0; + } + else { + offsetInFirstLine = start - content.getOffsetAtLine(firstLine); + } + if (partialBottomIndex + 1 < lastLine) { + lastLine = partialBottomIndex + 1; // + 1 to redraw whole bottom line, including line break + end = content.getOffsetAtLine(lastLine); + } + // redraw first and last lines + if (isBidi()) { + redrawBidiLines(firstLine, offsetInFirstLine, lastLine, end, clearBackground); + } + else { + redrawLines(firstLine, offsetInFirstLine, lastLine, end, clearBackground); + } + // redraw entire center lines if redraw range includes more than two lines + if (lastLine - firstLine > 1) { + Rectangle clientArea = getClientArea(); + int redrawStopY = lastLine * lineHeight - verticalScrollOffset; + int redrawY = (firstLine + 1) * lineHeight - verticalScrollOffset; + draw(0, redrawY, clientArea.width, redrawStopY - redrawY, clearBackground); + } } /** * Returns the widget text with style information encoded using RTF format @@ -5003,41 +5013,41 @@ * */ String getRtf(){ - checkWidget(); - RTFWriter rtfWriter = new RTFWriter(0, getCharCount()); - return getPlatformDelimitedText(rtfWriter); + checkWidget(); + RTFWriter rtfWriter = new RTFWriter(0, getCharCount()); + return getPlatformDelimitedText(rtfWriter); } -/** +/** * Frees resources. */ void handleDispose() { - clipboard.dispose(); - ibeamCursor.dispose(); - if (renderer != null) { - renderer.dispose(); - renderer = null; - } - if (content != null) { - content.removeTextChangeListener(textChangeListener); - } - if (leftCaretBitmap != null) { - leftCaretBitmap.dispose(); - leftCaretBitmap = null; - } - if (rightCaretBitmap != null) { - rightCaretBitmap.dispose(); - rightCaretBitmap = null; - } - if (isBidi()) { - StyledTextBidi.removeLanguageListener(this); - } + clipboard.dispose(); + ibeamCursor.dispose(); + if (renderer != null) { + renderer.dispose(); + renderer = null; + } + if (content != null) { + content.removeTextChangeListener(textChangeListener); + } + if (leftCaretBitmap != null) { + leftCaretBitmap.dispose(); + leftCaretBitmap = null; + } + if (rightCaretBitmap != null) { + rightCaretBitmap.dispose(); + rightCaretBitmap = null; + } + if (isBidi()) { + StyledTextBidi.removeLanguageListener(this); + } } -/** +/** * Scrolls the widget horizontally. */ void handleHorizontalScroll(Event event) { - int scrollPixel = getHorizontalBar().getSelection() - horizontalScrollOffset; - scrollHorizontal(scrollPixel); + int scrollPixel = getHorizontalBar().getSelection() - horizontalScrollOffset; + scrollHorizontal(scrollPixel); } /** * If an action has been registered for the key stroke execute the action. @@ -5047,56 +5057,56 @@ * @param event keyboard event */ void handleKey(Event event) { - int action; - - if (event.keyCode != 0) { - // special key pressed (e.g., F1) - action = getKeyBinding(event.keyCode | event.stateMask); - } - else { - // character key pressed - action = getKeyBinding(event.character | event.stateMask); - if (action == SWT.NULL) { - // see if we have a control character - if ((event.stateMask & SWT.CTRL) != 0 && (event.character >= 0) && event.character <= 31) { - // get the character from the CTRL+char sequence, the control - // key subtracts 64 from the value of the key that it modifies - int c = event.character + 64; - action = getKeyBinding(c | event.stateMask); - } - } - } - if (action == SWT.NULL) { - boolean ignore = false; - - if (isCarbon) { - // Ignore acclerator key combinations (we do not want to - // insert a character in the text in this instance). Do not - // ignore COMMAND+ALT combinations since that key sequence - // produces characters on the mac. - ignore = (event.stateMask ^ SWT.COMMAND) == 0 || - (event.stateMask ^ (SWT.COMMAND | SWT.SHIFT)) == 0; - } else { - // Ignore acclerator key combinations (we do not want to - // insert a character in the text in this instance). Don't - // ignore CTRL+ALT combinations since that is the Alt Gr - // key on some keyboards. See bug 20953. - ignore = (event.stateMask ^ SWT.ALT) == 0 || - (event.stateMask ^ SWT.CTRL) == 0 || - (event.stateMask ^ (SWT.ALT | SWT.SHIFT)) == 0 || - (event.stateMask ^ (SWT.CTRL | SWT.SHIFT)) == 0; - } - // -ignore anything below SPACE except for line delimiter keys and tab. - // -ignore DEL - if (!ignore && event.character > 31 && event.character != SWT.DEL || - event.character == SWT.CR || event.character == SWT.LF || - event.character == TAB) { - doContent(event.character); - } - } - else { - invokeAction(action); - } + int action; + + if (event.keyCode != 0) { + // special key pressed (e.g., F1) + action = getKeyBinding(event.keyCode | event.stateMask); + } + else { + // character key pressed + action = getKeyBinding(event.character | event.stateMask); + if (action == SWT.NULL) { + // see if we have a control character + if ((event.stateMask & SWT.CTRL) != 0 && (event.character >= 0) && event.character <= 31) { + // get the character from the CTRL+char sequence, the control + // key subtracts 64 from the value of the key that it modifies + int c = event.character + 64; + action = getKeyBinding(c | event.stateMask); + } + } + } + if (action == SWT.NULL) { + boolean ignore = false; + + if (isCarbon) { + // Ignore acclerator key combinations (we do not want to + // insert a character in the text in this instance). Do not + // ignore COMMAND+ALT combinations since that key sequence + // produces characters on the mac. + ignore = (event.stateMask ^ SWT.COMMAND) == 0 || + (event.stateMask ^ (SWT.COMMAND | SWT.SHIFT)) == 0; + } else { + // Ignore acclerator key combinations (we do not want to + // insert a character in the text in this instance). Don't + // ignore CTRL+ALT combinations since that is the Alt Gr + // key on some keyboards. See bug 20953. + ignore = (event.stateMask ^ SWT.ALT) == 0 || + (event.stateMask ^ SWT.CTRL) == 0 || + (event.stateMask ^ (SWT.ALT | SWT.SHIFT)) == 0 || + (event.stateMask ^ (SWT.CTRL | SWT.SHIFT)) == 0; + } + // -ignore anything below SPACE except for line delimiter keys and tab. + // -ignore DEL + if (!ignore && event.character > 31 && event.character != SWT.DEL || + event.character == SWT.CR || event.character == SWT.LF || + event.character == TAB) { + doContent(event.character); + } + } + else { + invokeAction(action); + } } /** * If a VerifyKey listener exists, verify that the key that was entered @@ -5106,66 +5116,71 @@ * @param event keyboard event */ void handleKeyDown(Event event) { - Event verifyEvent = new Event(); - - verifyEvent.character = event.character; - verifyEvent.keyCode = event.keyCode; - verifyEvent.stateMask = event.stateMask; - verifyEvent.doit = true; - notifyListeners(VerifyKey, verifyEvent); - if (verifyEvent.doit == true) { - handleKey(event); - } + Event verifyEvent = new Event(); + + verifyEvent.character = event.character; + verifyEvent.keyCode = event.keyCode; + verifyEvent.stateMask = event.stateMask; + verifyEvent.doit = true; + notifyListeners(VerifyKey, verifyEvent); + if (verifyEvent.doit == true) { + handleKey(event); + } } /** - * Updates the caret location and selection if mouse button 1 has been + * Updates the caret location and selection if mouse button 1 has been * pressed. */ void handleMouseDoubleClick(Event event) { - if (event.button != 1 || doubleClickEnabled == false) { - return; - } - event.y -= topMargin; - mouseDoubleClick = true; - caretOffset = getWordStart(caretOffset); - resetSelection(); - caretOffset = getWordEndNoSpaces(caretOffset); - showCaret(); - doMouseSelection(); - doubleClickSelection = new Point(selection.x, selection.y); + if (event.button != 1 || doubleClickEnabled == false) { + return; + } + event.y -= topMargin; + mouseDoubleClick = true; + caretOffset = getWordStart(caretOffset); + resetSelection(); + caretOffset = getWordEndNoSpaces(caretOffset); + showCaret(); + doMouseSelection(); + doubleClickSelection = new Point(selection.x, selection.y); } -/** - * Updates the caret location and selection if mouse button 1 has been +/** + * Updates the caret location and selection if mouse button 1 has been * pressed. */ void handleMouseDown(Event event) { - boolean select = (event.stateMask & SWT.MOD2) != 0; - - if (event.button != 1) { - return; - } - mouseDoubleClick = false; - event.y -= topMargin; - doMouseLocationChange(event.x, event.y, select); + boolean select = (event.stateMask & SWT.MOD2) != 0; + + if ((event.button == 1) || (event.button == 3)) { + if ((event.button == 3) && (isMouseOverSelection(event.x, event.y))) { + // we have a right click over a selection, so don't alter the selection + return; + } + mouseDoubleClick = false; + event.y -= topMargin; + doMouseLocationChange(event.x, event.y, select); + } } -/** - * Updates the caret location and selection if mouse button 1 is pressed +/** + * Updates the caret location and selection if mouse button 1 is pressed * during the mouse move. */ void handleMouseMove(Event event) { - if ((event.stateMask & SWT.BUTTON1) == 0) { - return; - } - event.y -= topMargin; - doMouseLocationChange(event.x, event.y, true); - doAutoScroll(event); + if ((event.stateMask & SWT.BUTTON1) != 0) { + event.y -= topMargin; + doMouseLocationChange(event.x, event.y, true); + doAutoScroll(event); + } else if (event.stateMask == 0) { + // changes the mouse pointer based on whether or not it is over a selection + internalSetCursor(event.x, event.y); + } } -/** +/** * Autoscrolling ends when the mouse button is released. */ void handleMouseUp(Event event) { - event.y -= topMargin; - endAutoScroll(); + event.y -= topMargin; + endAutoScroll(); } /** * Renders the invalidated area specified in the paint event. @@ -5174,204 +5189,204 @@ * @param event paint event */ void handlePaint(Event event) { - int startLine = Math.max(0, (event.y - topMargin + verticalScrollOffset) / lineHeight); - int paintYFromTopLine = (startLine - topIndex) * lineHeight; - int topLineOffset = topIndex * lineHeight - verticalScrollOffset; - int startY = paintYFromTopLine + topLineOffset + topMargin; // adjust y position for pixel based scrolling and top margin - int renderHeight = event.y + event.height - startY; - Rectangle clientArea = getClientArea(); - - // Check if there is work to do. clientArea.width should never be 0 - // if we receive a paint event but we never want to try and create - // an Image with 0 width. - if (clientArea.width == 0 || event.height == 0) { - return; - } - performPaint(event.gc, startLine, startY, renderHeight); -} + int startLine = Math.max(0, (event.y - topMargin + verticalScrollOffset) / lineHeight); + int paintYFromTopLine = (startLine - topIndex) * lineHeight; + int topLineOffset = topIndex * lineHeight - verticalScrollOffset; + int startY = paintYFromTopLine + topLineOffset + topMargin; // adjust y position for pixel based scrolling and top margin + int renderHeight = event.y + event.height - startY; + Rectangle clientArea = getClientArea(); + + // Check if there is work to do. clientArea.width should never be 0 + // if we receive a paint event but we never want to try and create + // an Image with 0 width. + if (clientArea.width == 0 || event.height == 0) { + return; + } + performPaint(event.gc, startLine, startY, renderHeight); +} /** - * Recalculates the scroll bars. Rewraps all lines when in word + * Recalculates the scroll bars. Rewraps all lines when in word * wrap mode. *
* * @param event resize event */ void handleResize(Event event) { - int oldHeight = clientAreaHeight; - int oldWidth = clientAreaWidth; - - clientAreaHeight = getClientArea().height; - clientAreaWidth = getClientArea().width; - if (wordWrap) { - if (oldWidth != clientAreaWidth) { - wordWrapResize(oldWidth); - } - } - else - if (clientAreaHeight > oldHeight) { - int lineCount = content.getLineCount(); - int oldBottomIndex = topIndex + oldHeight / lineHeight; - int newItemCount = Compatibility.ceil(clientAreaHeight - oldHeight, lineHeight); - - oldBottomIndex = Math.min(oldBottomIndex, lineCount); - newItemCount = Math.min(newItemCount, lineCount - oldBottomIndex); - lineCache.calculate(oldBottomIndex, newItemCount); - } - setScrollBars(); - claimBottomFreeSpace(); - claimRightFreeSpace(); - if (oldHeight != clientAreaHeight) { - calculateTopIndex(); - } + int oldHeight = clientAreaHeight; + int oldWidth = clientAreaWidth; + + clientAreaHeight = getClientArea().height; + clientAreaWidth = getClientArea().width; + if (wordWrap) { + if (oldWidth != clientAreaWidth) { + wordWrapResize(oldWidth); + } + } + else + if (clientAreaHeight > oldHeight) { + int lineCount = content.getLineCount(); + int oldBottomIndex = topIndex + oldHeight / lineHeight; + int newItemCount = Compatibility.ceil(clientAreaHeight - oldHeight, lineHeight); + + oldBottomIndex = Math.min(oldBottomIndex, lineCount); + newItemCount = Math.min(newItemCount, lineCount - oldBottomIndex); + lineCache.calculate(oldBottomIndex, newItemCount); + } + setScrollBars(); + claimBottomFreeSpace(); + claimRightFreeSpace(); + if (oldHeight != clientAreaHeight) { + calculateTopIndex(); + } } /** - * Updates the caret position and selection and the scroll bars to reflect + * Updates the caret position and selection and the scroll bars to reflect * the content change. *
*/ void handleTextChanged(TextChangedEvent event) { - lineCache.textChanged(lastTextChangeStart, - lastTextChangeNewLineCount, - lastTextChangeReplaceLineCount, - lastTextChangeNewCharCount, - lastTextChangeReplaceCharCount); - setScrollBars(); - // update selection/caret location after styles have been changed. - // otherwise any text measuring could be incorrect - // - // also, this needs to be done after all scrolling. Otherwise, - // selection redraw would be flushed during scroll which is wrong. - // in some cases new text would be drawn in scroll source area even - // though the intent is to scroll it. - // fixes 1GB93QT - updateSelection( - lastTextChangeStart, - lastTextChangeReplaceCharCount, - lastTextChangeNewCharCount); - - if (lastTextChangeReplaceLineCount > 0) { - // Only check for unused space when lines are deleted. - // Fixes 1GFL4LY - // Scroll up so that empty lines below last text line are used. - // Fixes 1GEYJM0 - claimBottomFreeSpace(); - } - if (lastTextChangeReplaceCharCount > 0) { - // fixes bug 8273 - claimRightFreeSpace(); - } - // do direct drawing if the text change is confined to a single line. - // optimization and fixes bug 13999. see also handleTextChanging. - if (lastTextChangeNewLineCount == 0 && lastTextChangeReplaceLineCount == 0) { - int startLine = content.getLineAtOffset(lastTextChangeStart); - int startY = startLine * lineHeight - verticalScrollOffset + topMargin; - - GC gc = getGC(); - Caret caret = getCaret(); - boolean caretVisible = false; - - if (caret != null) { - caretVisible = caret.getVisible(); - caret.setVisible(false); - } - performPaint(gc, startLine, startY, lineHeight); - if (caret != null) { - caret.setVisible(caretVisible); - } - gc.dispose(); - } + lineCache.textChanged(lastTextChangeStart, + lastTextChangeNewLineCount, + lastTextChangeReplaceLineCount, + lastTextChangeNewCharCount, + lastTextChangeReplaceCharCount); + setScrollBars(); + // update selection/caret location after styles have been changed. + // otherwise any text measuring could be incorrect + // + // also, this needs to be done after all scrolling. Otherwise, + // selection redraw would be flushed during scroll which is wrong. + // in some cases new text would be drawn in scroll source area even + // though the intent is to scroll it. + // fixes 1GB93QT + updateSelection( + lastTextChangeStart, + lastTextChangeReplaceCharCount, + lastTextChangeNewCharCount); + + if (lastTextChangeReplaceLineCount > 0) { + // Only check for unused space when lines are deleted. + // Fixes 1GFL4LY + // Scroll up so that empty lines below last text line are used. + // Fixes 1GEYJM0 + claimBottomFreeSpace(); + } + if (lastTextChangeReplaceCharCount > 0) { + // fixes bug 8273 + claimRightFreeSpace(); + } + // do direct drawing if the text change is confined to a single line. + // optimization and fixes bug 13999. see also handleTextChanging. + if (lastTextChangeNewLineCount == 0 && lastTextChangeReplaceLineCount == 0) { + int startLine = content.getLineAtOffset(lastTextChangeStart); + int startY = startLine * lineHeight - verticalScrollOffset + topMargin; + + GC gc = getGC(); + Caret caret = getCaret(); + boolean caretVisible = false; + + if (caret != null) { + caretVisible = caret.getVisible(); + caret.setVisible(false); + } + performPaint(gc, startLine, startY, lineHeight); + if (caret != null) { + caret.setVisible(caretVisible); + } + gc.dispose(); + } } /** * Updates the screen to reflect a pending content change. *
* * @param event.start the start offset of the change - * @param event.newText text that is going to be inserted or empty String - * if no text will be inserted + * @param event.newText text that is going to be inserted or empty String + * if no text will be inserted * @param event.replaceCharCount length of text that is going to be replaced * @param event.newCharCount length of text that is going to be inserted * @param event.replaceLineCount number of lines that are going to be replaced * @param event.newLineCount number of new lines that are going to be inserted */ void handleTextChanging(TextChangingEvent event) { - int firstLine; - int textChangeY; - boolean isMultiLineChange = event.replaceLineCount > 0 || event.newLineCount > 0; - - if (event.replaceCharCount < 0) { - event.start += event.replaceCharCount; - event.replaceCharCount *= -1; - } - lastTextChangeStart = event.start; - lastTextChangeNewLineCount = event.newLineCount; - lastTextChangeNewCharCount = event.newCharCount; - lastTextChangeReplaceLineCount = event.replaceLineCount; - lastTextChangeReplaceCharCount = event.replaceCharCount; - firstLine = content.getLineAtOffset(event.start); - textChangeY = firstLine * lineHeight - verticalScrollOffset + topMargin; - if (isMultiLineChange) { - redrawMultiLineChange(textChangeY, event.newLineCount, event.replaceLineCount); - } - // notify default line styler about text change - if (defaultLineStyler != null) { - defaultLineStyler.textChanging(event); - } - - // Update the caret offset if it is greater than the length of the content. - // This is necessary since style range API may be called between the - // handleTextChanging and handleTextChanged events and this API sets the - // caretOffset. - int newEndOfText = content.getCharCount() - event.replaceCharCount + event.newCharCount; - if (caretOffset > newEndOfText) caretOffset = newEndOfText; + int firstLine; + int textChangeY; + boolean isMultiLineChange = event.replaceLineCount > 0 || event.newLineCount > 0; + + if (event.replaceCharCount < 0) { + event.start += event.replaceCharCount; + event.replaceCharCount *= -1; + } + lastTextChangeStart = event.start; + lastTextChangeNewLineCount = event.newLineCount; + lastTextChangeNewCharCount = event.newCharCount; + lastTextChangeReplaceLineCount = event.replaceLineCount; + lastTextChangeReplaceCharCount = event.replaceCharCount; + firstLine = content.getLineAtOffset(event.start); + textChangeY = firstLine * lineHeight - verticalScrollOffset + topMargin; + if (isMultiLineChange) { + redrawMultiLineChange(textChangeY, event.newLineCount, event.replaceLineCount); + } + // notify default line styler about text change + if (defaultLineStyler != null) { + defaultLineStyler.textChanging(event); + } + + // Update the caret offset if it is greater than the length of the content. + // This is necessary since style range API may be called between the + // handleTextChanging and handleTextChanged events and this API sets the + // caretOffset. + int newEndOfText = content.getCharCount() - event.replaceCharCount + event.newCharCount; + if (caretOffset > newEndOfText) caretOffset = newEndOfText; } /** - * Called when the widget content is set programatically, overwriting - * the old content. Resets the caret position, selection and scroll offsets. + * Called when the widget content is set programatically, overwriting + * the old content. Resets the caret position, selection and scroll offsets. * Recalculates the content width and scroll bars. Redraws the widget. *
* - * @param event text change event. + * @param event text change event. */ void handleTextSet(TextChangedEvent event) { - reset(); + reset(); } /** * Called when a traversal key is pressed. - * Allow tab next traversal to occur when the widget is in single - * line mode or in multi line and non-editable mode . - * When in editable multi line mode we want to prevent the tab + * Allow tab next traversal to occur when the widget is in single + * line mode or in multi line and non-editable mode . + * When in editable multi line mode we want to prevent the tab * traversal and receive the tab key event instead. *
* * @param event the event */ void handleTraverse(Event event) { - int style = getStyle(); - boolean ignoreTab = (style & SWT.MULTI) != 0 && !editable || isSingleLine(); - - if ((event.detail == SWT.TRAVERSE_TAB_NEXT || - event.detail == SWT.TRAVERSE_RETURN) && ignoreTab) { - event.doit = true; - } + int style = getStyle(); + boolean ignoreTab = (style & SWT.MULTI) != 0 && !editable || isSingleLine(); + + if ((event.detail == SWT.TRAVERSE_TAB_NEXT || + event.detail == SWT.TRAVERSE_RETURN) && ignoreTab) { + event.doit = true; + } } -/** +/** * Scrolls the widget vertically. */ void handleVerticalScroll(Event event) { - setVerticalScrollOffset(getVerticalBar().getSelection(), false); + setVerticalScrollOffset(getVerticalBar().getSelection(), false); } -/** +/** * Initializes the fonts used to render font styles. * Presently only regular and bold fonts are supported. */ void initializeRenderer() { - if (renderer != null) { - renderer.dispose(); - } - renderer = new DisplayRenderer( - getDisplay(), getFont(), isBidi(), leftMargin, this, tabLength); - lineHeight = renderer.getLineHeight(); - lineEndSpaceWidth = renderer.getLineEndSpaceWidth(); + if (renderer != null) { + renderer.dispose(); + } + renderer = new DisplayRenderer( + getDisplay(), getFont(), isBidi(), leftMargin, this, tabLength); + lineHeight = renderer.getLineHeight(); + lineEndSpaceWidth = renderer.getLineEndSpaceWidth(); } /** * Executes the action. @@ -5380,178 +5395,178 @@ * @param action one of the actions defined in ST.java */ public void invokeAction(int action) { - int oldColumnX; - int caretLine; - - checkWidget(); - switch (action) { - // Navigation - case ST.LINE_UP: - caretLine = doLineUp(); - oldColumnX = columnX; - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - // save the original horizontal caret position - columnX = oldColumnX; - clearSelection(true); - break; - case ST.LINE_DOWN: - caretLine = doLineDown(); - oldColumnX = columnX; - // explicitly go to the calculated caret line. may be different - // from content.getLineAtOffset(caretOffset) when in word wrap mode - showCaret(caretLine); - // save the original horizontal caret position - columnX = oldColumnX; - clearSelection(true); - break; - case ST.LINE_START: - doLineStart(); - clearSelection(true); - break; - case ST.LINE_END: - doLineEnd(); - clearSelection(true); - break; - case ST.COLUMN_PREVIOUS: - doCursorPrevious(); - clearSelection(true); - break; - case ST.COLUMN_NEXT: - doCursorNext(); - clearSelection(true); - break; - case ST.PAGE_UP: - doPageUp(); - clearSelection(true); - break; - case ST.PAGE_DOWN: - doPageDown(false); - clearSelection(true); - break; - case ST.WORD_PREVIOUS: - doWordPrevious(); - clearSelection(true); - break; - case ST.WORD_NEXT: - doWordNext(); - clearSelection(true); - break; - case ST.TEXT_START: - doContentStart(); - clearSelection(true); - break; - case ST.TEXT_END: - doContentEnd(); - clearSelection(true); - break; - case ST.WINDOW_START: - doPageStart(); - clearSelection(true); - break; - case ST.WINDOW_END: - doPageEnd(); - clearSelection(true); - break; - // Selection - case ST.SELECT_LINE_UP: - doSelectionLineUp(); - break; - case ST.SELECT_LINE_DOWN: - doSelectionLineDown(); - break; - case ST.SELECT_LINE_START: - doLineStart(); - doSelection(SWT.LEFT); - break; - case ST.SELECT_LINE_END: - doLineEnd(); - doSelection(SWT.RIGHT); - break; - case ST.SELECT_COLUMN_PREVIOUS: - doSelectionCursorPrevious(); - doSelection(SWT.LEFT); - break; - case ST.SELECT_COLUMN_NEXT: - doSelectionCursorNext(); - doSelection(SWT.RIGHT); - break; - case ST.SELECT_PAGE_UP: - doPageUp(); - doSelection(SWT.LEFT); - break; - case ST.SELECT_PAGE_DOWN: - doPageDown(true); - break; - case ST.SELECT_WORD_PREVIOUS: - doSelectionWordPrevious(); - doSelection(SWT.LEFT); - break; - case ST.SELECT_WORD_NEXT: - doSelectionWordNext(); - doSelection(SWT.RIGHT); - break; - case ST.SELECT_TEXT_START: - doContentStart(); - doSelection(SWT.LEFT); - break; - case ST.SELECT_TEXT_END: - doContentEnd(); - doSelection(SWT.RIGHT); - break; - case ST.SELECT_WINDOW_START: - doPageStart(); - doSelection(SWT.LEFT); - break; - case ST.SELECT_WINDOW_END: - doPageEnd(); - doSelection(SWT.RIGHT); - break; - // Modification - case ST.CUT: - cut(); - break; - case ST.COPY: - copy(); - break; - case ST.PASTE: - paste(); - break; - case ST.DELETE_PREVIOUS: - doBackspace(); - break; - case ST.DELETE_NEXT: - doDelete(); - break; - // Miscellaneous - case ST.TOGGLE_OVERWRITE: - overwrite = !overwrite; // toggle insert/overwrite mode - break; - } + int oldColumnX; + int caretLine; + + checkWidget(); + switch (action) { + // Navigation + case ST.LINE_UP: + caretLine = doLineUp(); + oldColumnX = columnX; + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + // save the original horizontal caret position + columnX = oldColumnX; + clearSelection(true); + break; + case ST.LINE_DOWN: + caretLine = doLineDown(); + oldColumnX = columnX; + // explicitly go to the calculated caret line. may be different + // from content.getLineAtOffset(caretOffset) when in word wrap mode + showCaret(caretLine); + // save the original horizontal caret position + columnX = oldColumnX; + clearSelection(true); + break; + case ST.LINE_START: + doLineStart(); + clearSelection(true); + break; + case ST.LINE_END: + doLineEnd(); + clearSelection(true); + break; + case ST.COLUMN_PREVIOUS: + doCursorPrevious(); + clearSelection(true); + break; + case ST.COLUMN_NEXT: + doCursorNext(); + clearSelection(true); + break; + case ST.PAGE_UP: + doPageUp(); + clearSelection(true); + break; + case ST.PAGE_DOWN: + doPageDown(false); + clearSelection(true); + break; + case ST.WORD_PREVIOUS: + doWordPrevious(); + clearSelection(true); + break; + case ST.WORD_NEXT: + doWordNext(); + clearSelection(true); + break; + case ST.TEXT_START: + doContentStart(); + clearSelection(true); + break; + case ST.TEXT_END: + doContentEnd(); + clearSelection(true); + break; + case ST.WINDOW_START: + doPageStart(); + clearSelection(true); + break; + case ST.WINDOW_END: + doPageEnd(); + clearSelection(true); + break; + // Selection + case ST.SELECT_LINE_UP: + doSelectionLineUp(); + break; + case ST.SELECT_LINE_DOWN: + doSelectionLineDown(); + break; + case ST.SELECT_LINE_START: + doLineStart(); + doSelection(SWT.LEFT); + break; + case ST.SELECT_LINE_END: + doLineEnd(); + doSelection(SWT.RIGHT); + break; + case ST.SELECT_COLUMN_PREVIOUS: + doSelectionCursorPrevious(); + doSelection(SWT.LEFT); + break; + case ST.SELECT_COLUMN_NEXT: + doSelectionCursorNext(); + doSelection(SWT.RIGHT); + break; + case ST.SELECT_PAGE_UP: + doPageUp(); + doSelection(SWT.LEFT); + break; + case ST.SELECT_PAGE_DOWN: + doPageDown(true); + break; + case ST.SELECT_WORD_PREVIOUS: + doSelectionWordPrevious(); + doSelection(SWT.LEFT); + break; + case ST.SELECT_WORD_NEXT: + doSelectionWordNext(); + doSelection(SWT.RIGHT); + break; + case ST.SELECT_TEXT_START: + doContentStart(); + doSelection(SWT.LEFT); + break; + case ST.SELECT_TEXT_END: + doContentEnd(); + doSelection(SWT.RIGHT); + break; + case ST.SELECT_WINDOW_START: + doPageStart(); + doSelection(SWT.LEFT); + break; + case ST.SELECT_WINDOW_END: + doPageEnd(); + doSelection(SWT.RIGHT); + break; + // Modification + case ST.CUT: + cut(); + break; + case ST.COPY: + copy(); + break; + case ST.PASTE: + paste(); + break; + case ST.DELETE_PREVIOUS: + doBackspace(); + break; + case ST.DELETE_NEXT: + doDelete(); + break; + // Miscellaneous + case ST.TOGGLE_OVERWRITE: + overwrite = !overwrite; // toggle insert/overwrite mode + break; + } } /** * Temporary until SWT provides this */ boolean isBidi() { - return isBidi; + return isBidi; } /** * Returns whether the given offset is inside a multi byte line delimiter. - * Example: + * Example: * "Line1\r\n" isLineDelimiter(5) == false but isLineDelimiter(6) == true - * + * * @return true if the given offset is inside a multi byte line delimiter. * false if the given offset is before or after a line delimiter. */ boolean isLineDelimiter(int offset) { - int line = content.getLineAtOffset(offset); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = offset - lineOffset; - // offsetInLine will be greater than line length if the line - // delimiter is longer than one character and the offset is set - // in between parts of the line delimiter. - return offsetInLine > content.getLine(line).length(); + int line = content.getLineAtOffset(offset); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = offset - lineOffset; + // offsetInLine will be greater than line length if the line + // delimiter is longer than one character and the offset is set + // in between parts of the line delimiter. + return offsetInLine > content.getLine(line).length(); } /** * Returns whether or not the given lines are visible. @@ -5561,190 +5576,243 @@ * false if none of the lines is visible */ boolean isAreaVisible(int firstLine, int lastLine) { - int partialBottomIndex = getPartialBottomIndex(); - int partialTopIndex = verticalScrollOffset / lineHeight; - boolean notVisible = firstLine > partialBottomIndex || lastLine < partialTopIndex; - return !notVisible; + int partialBottomIndex = getPartialBottomIndex(); + int partialTopIndex = verticalScrollOffset / lineHeight; + boolean notVisible = firstLine > partialBottomIndex || lastLine < partialTopIndex; + return !notVisible; +} +/** + * Tests whether the mouse pointer is over a selection. + * + * @param x mouse x position in client coordinates + * @param y mouse y position in client coordinates + */ +private boolean isMouseOverSelection(int x, int y) { + if (selectionAnchor == -1) { + // no selection + return false; + } else { + // there is a selection + int mouseLineIndex = (y + verticalScrollOffset) / lineHeight; + int mouseCharOffset; + int selLineIndexX; + int selLineIndexY; + int selLineOffset; + String lineContent = null; + + selLineIndexX = content.getLineAtOffset(selection.x); + selLineIndexY = content.getLineAtOffset(selection.y); + + if ((mouseLineIndex < selLineIndexX) || (mouseLineIndex > selLineIndexY)) { + // mouse is before the first or after the last line of the selection + return false; + } + + if (mouseLineIndex == selLineIndexX) { + // the mouse is on the first line of the selection + selLineOffset = content.getOffsetAtLine(selLineIndexX); + lineContent = content.getLine(selLineIndexX); + if (x < getXAtOffset(lineContent, selLineIndexX, selection.x - selLineOffset)) { + // mouse is before the start of the selection + return false; + } + } + + if (mouseLineIndex == selLineIndexY) { + // the mouse is on the last line of the selection + selLineOffset = content.getOffsetAtLine(selLineIndexY); + if (selLineIndexY != selLineIndexX) { + lineContent = content.getLine(selLineIndexY); + } + if (x > getXAtOffset(lineContent, selLineIndexY, selection.y - selLineOffset)) { + // mouse is after the end of the selection + return false; + } + } + + // mouse is over the selection + return true; + } } /** - * Returns whether or not the given styles will necessitate a redraw for the given start line. - * A redraw is necessary when font style changes after the start of a style will take place. + * Returns whether or not the given styles will necessitate a redraw for the given start line. + * A redraw is necessary when font style changes after the start of a style will take place. * This method assumes ranges is in order and non-overlapping. *
*
* @return true if a redraw of the given line is necessary, false otherwise
*/
boolean isRedrawFirstLine(StyleRange[] ranges, int firstLine, int firstLineOffset) {
- int lineEnd = firstLineOffset + content.getLine(firstLine).length();
- for (int i=0; i
*
- * @return true if widget can have only one line, false if widget can have
- * multiple lines
+ * @return true if widget can have only one line, false if widget can have
+ * multiple lines
*/
boolean isSingleLine() {
- return (getStyle() & SWT.SINGLE) != 0;
+ return (getStyle() & SWT.SINGLE) != 0;
}
-/**
- * Returns whether the font style in the given style range is changing
+/**
+ * Returns whether the font style in the given style range is changing
* from SWT.NORMAL to SWT.BOLD or vice versa.
*
*
* @param range StyleRange to compare current font style with.
- * @param start offset of the first font style to compare
+ * @param start offset of the first font style to compare
* @param end offset behind the last font style to compare
* @return true if the font style is changing in the given style range,
- * false if the font style is not changing in the given style range.
+ * false if the font style is not changing in the given style range.
* @exception SWTException
*
- * @param event the text change event.
- *
*
@@ -5754,73 +5822,73 @@
*
*/
public void paste(){
- checkWidget();
- TextTransfer transfer = TextTransfer.getInstance();
- String text;
- text = (String) clipboard.getContents(transfer);
- if (text != null && text.length() > 0) {
- Event event = new Event();
- event.start = selection.x;
- event.end = selection.y;
- event.text = getModelDelimitedText(text);
- sendKeyEvent(event);
- }
+ checkWidget();
+ TextTransfer transfer = TextTransfer.getInstance();
+ String text;
+ text = (String) clipboard.getContents(transfer);
+ if (text != null && text.length() > 0) {
+ Event event = new Event();
+ event.start = selection.x;
+ event.end = selection.y;
+ event.text = getModelDelimitedText(text);
+ sendKeyEvent(event);
+ }
}
/**
* Render the specified area. Broken out as its own method to support
* direct drawing.
*
*
- * @param gc GC to render on
+ * @param gc GC to render on
* @param startLine first line to render
* @param startY y pixel location to start rendering at
* @param renderHeight renderHeight widget area that needs to be filled with lines
*/
-void performPaint(GC gc,int startLine,int startY, int renderHeight) {
- Rectangle clientArea = getClientArea();
- Color background = getBackground();
-
- // Check if there is work to do. We never want to try and create
- // an Image with 0 width or 0 height.
- if (clientArea.width == 0) {
- return;
- }
- if (renderHeight > 0) {
- // renderHeight will be negative when only top margin needs redrawing
- Color foreground = getForeground();
- int lineCount = content.getLineCount();
- int paintY = 0;
-
- if (isSingleLine()) {
- lineCount = 1;
- if (startLine > 1) {
- startLine = 1;
- }
- }
- Image lineBuffer = new Image(getDisplay(), clientArea.width, renderHeight);
- GC lineGC = new GC(lineBuffer);
-
- lineGC.setFont(getFont());
- renderer.setCurrentFontStyle(SWT.NORMAL);
- lineGC.setForeground(foreground);
- lineGC.setBackground(background);
-
- for (int i = startLine; paintY < renderHeight && i < lineCount; i++, paintY += lineHeight) {
- String line = content.getLine(i);
- renderer.drawLine(line, i, paintY, lineGC, background, foreground, true);
- }
- if (paintY < renderHeight) {
- lineGC.setBackground(background);
- lineGC.setForeground(background);
- lineGC.fillRectangle(0, paintY, clientArea.width, renderHeight - paintY);
- }
- gc.drawImage(lineBuffer, 0, startY);
- lineGC.dispose();
- lineBuffer.dispose();
- }
- clearMargin(gc, background, clientArea, renderHeight);
+void performPaint(GC gc,int startLine,int startY, int renderHeight) {
+ Rectangle clientArea = getClientArea();
+ Color background = getBackground();
+
+ // Check if there is work to do. We never want to try and create
+ // an Image with 0 width or 0 height.
+ if (clientArea.width == 0) {
+ return;
+ }
+ if (renderHeight > 0) {
+ // renderHeight will be negative when only top margin needs redrawing
+ Color foreground = getForeground();
+ int lineCount = content.getLineCount();
+ int paintY = 0;
+
+ if (isSingleLine()) {
+ lineCount = 1;
+ if (startLine > 1) {
+ startLine = 1;
+ }
+ }
+ Image lineBuffer = new Image(getDisplay(), clientArea.width, renderHeight);
+ GC lineGC = new GC(lineBuffer);
+
+ lineGC.setFont(getFont());
+ renderer.setCurrentFontStyle(SWT.NORMAL);
+ lineGC.setForeground(foreground);
+ lineGC.setBackground(background);
+
+ for (int i = startLine; paintY < renderHeight && i < lineCount; i++, paintY += lineHeight) {
+ String line = content.getLine(i);
+ renderer.drawLine(line, i, paintY, lineGC, background, foreground, true);
+ }
+ if (paintY < renderHeight) {
+ lineGC.setBackground(background);
+ lineGC.setForeground(background);
+ lineGC.fillRectangle(0, paintY, clientArea.width, renderHeight - paintY);
+ }
+ gc.drawImage(lineBuffer, 0, startY);
+ lineGC.dispose();
+ lineBuffer.dispose();
+ }
+ clearMargin(gc, background, clientArea, renderHeight);
}
-/**
+/**
* Prints the widget's text to the default printer.
*
* @exception SWTException
* The runnable may be run in a non-UI thread.
*
* The runnable may be run in a non-UI thread.
*
* Recalculates the content width for all lines in the bounds.
- * When a
* Marks the content width of all lines in the specified rectangle
* as unknown. Recalculates the content width of all visible lines.
- * When a
*
@@ -5982,53 +6050,53 @@
* without invalidating the redraw range.
*/
void redrawBidiLines(int firstLine, int offsetInFirstLine, int lastLine, int endOffset, boolean clearBackground) {
- int lineCount = lastLine - firstLine + 1;
- int redrawY = firstLine * lineHeight - verticalScrollOffset;
- int firstLineOffset = content.getOffsetAtLine(firstLine);
- String line = content.getLine(firstLine);
- GC gc = getGC();
- StyledTextBidi bidi = getStyledTextBidi(line, firstLineOffset, gc);
-
- bidi.redrawRange(
- this, offsetInFirstLine,
- Math.min(line.length(), endOffset) - offsetInFirstLine,
- leftMargin - horizontalScrollOffset, redrawY + topMargin, lineHeight);
- // redraw line break marker (either space or full client area width)
- // if redraw range extends over more than one line and background should be redrawn
- if (lastLine > firstLine && clearBackground) {
- int lineBreakWidth;
- int lineBreakStartX = bidi.getTextWidth();
- // handle empty line case
- if (lineBreakStartX == leftMargin) {
- lineBreakStartX += XINSET;
- }
- lineBreakStartX = lineBreakStartX - horizontalScrollOffset;
- if ((getStyle() & SWT.FULL_SELECTION) != 0) {
- lineBreakWidth = getClientArea().width - lineBreakStartX;
- }
- else {
- lineBreakWidth = lineEndSpaceWidth;
- }
- draw(lineBreakStartX, redrawY, lineBreakWidth, lineHeight, clearBackground);
- }
- // redraw last line if more than one line needs redrawing
- if (lineCount > 1) {
- int lastLineOffset = content.getOffsetAtLine(lastLine);
- int offsetInLastLine = endOffset - lastLineOffset;
- // no redraw necessary if redraw offset is 0
- if (offsetInLastLine > 0) {
- line = content.getLine(lastLine);
- redrawY = lastLine * lineHeight - verticalScrollOffset;
- bidi = getStyledTextBidi(line, lastLineOffset, gc);
- bidi.redrawRange(
- this, 0, offsetInLastLine,
- leftMargin - horizontalScrollOffset,
- redrawY + topMargin, lineHeight);
- }
- }
- gc.dispose();
+ int lineCount = lastLine - firstLine + 1;
+ int redrawY = firstLine * lineHeight - verticalScrollOffset;
+ int firstLineOffset = content.getOffsetAtLine(firstLine);
+ String line = content.getLine(firstLine);
+ GC gc = getGC();
+ StyledTextBidi bidi = getStyledTextBidi(line, firstLineOffset, gc);
+
+ bidi.redrawRange(
+ this, offsetInFirstLine,
+ Math.min(line.length(), endOffset) - offsetInFirstLine,
+ leftMargin - horizontalScrollOffset, redrawY + topMargin, lineHeight);
+ // redraw line break marker (either space or full client area width)
+ // if redraw range extends over more than one line and background should be redrawn
+ if (lastLine > firstLine && clearBackground) {
+ int lineBreakWidth;
+ int lineBreakStartX = bidi.getTextWidth();
+ // handle empty line case
+ if (lineBreakStartX == leftMargin) {
+ lineBreakStartX += XINSET;
+ }
+ lineBreakStartX = lineBreakStartX - horizontalScrollOffset;
+ if ((getStyle() & SWT.FULL_SELECTION) != 0) {
+ lineBreakWidth = getClientArea().width - lineBreakStartX;
+ }
+ else {
+ lineBreakWidth = lineEndSpaceWidth;
+ }
+ draw(lineBreakStartX, redrawY, lineBreakWidth, lineHeight, clearBackground);
+ }
+ // redraw last line if more than one line needs redrawing
+ if (lineCount > 1) {
+ int lastLineOffset = content.getOffsetAtLine(lastLine);
+ int offsetInLastLine = endOffset - lastLineOffset;
+ // no redraw necessary if redraw offset is 0
+ if (offsetInLastLine > 0) {
+ line = content.getLine(lastLine);
+ redrawY = lastLine * lineHeight - verticalScrollOffset;
+ bidi = getStyledTextBidi(line, lastLineOffset, gc);
+ bidi.redrawRange(
+ this, 0, offsetInLastLine,
+ leftMargin - horizontalScrollOffset,
+ redrawY + topMargin, lineHeight);
+ }
+ }
+ gc.dispose();
}
-/**
+/**
* Redraw the given line.
*
*
@@ -6036,17 +6104,17 @@
* @param offset offset in line to start redrawing
*/
void redrawLine(int line, int offset) {
- int redrawX = 0;
- if (offset > 0) {
- String lineText = content.getLine(line);
- redrawX = getXAtOffset(lineText, line, offset);
- }
- int redrawY = line * lineHeight - verticalScrollOffset;
- super.redraw(
- redrawX + leftMargin, redrawY + topMargin,
- getClientArea().width, lineHeight, true);
+ int redrawX = 0;
+ if (offset > 0) {
+ String lineText = content.getLine(line);
+ redrawX = getXAtOffset(lineText, line, offset);
+ }
+ int redrawY = line * lineHeight - verticalScrollOffset;
+ super.redraw(
+ redrawX + leftMargin, redrawY + topMargin,
+ getClientArea().width, lineHeight, true);
}
-/**
+/**
* Redraws a text range in the specified lines
*
*
@@ -6055,55 +6123,55 @@
* @param lastLine last line to redraw
* @param endOffset offset in the last where redrawing should stop
* @param clearBackground true=clear the background by invalidating
- * the requested redraw range. If the redraw range includes the
- * last character of a line (i.e., the entire line is redrawn) the
- * line is cleared all the way to the right border of the widget.
- * false=draw the foreground directly without invalidating the
- * redraw range.
+ * the requested redraw range. If the redraw range includes the
+ * last character of a line (i.e., the entire line is redrawn) the
+ * line is cleared all the way to the right border of the widget.
+ * false=draw the foreground directly without invalidating the
+ * redraw range.
*/
void redrawLines(int firstLine, int offsetInFirstLine, int lastLine, int endOffset, boolean clearBackground) {
- String line = content.getLine(firstLine);
- int lineCount = lastLine - firstLine + 1;
- int redrawX = getXAtOffset(line, firstLine, offsetInFirstLine) - leftMargin;
- int redrawStopX;
- int redrawY = firstLine * lineHeight - verticalScrollOffset;
- int firstLineOffset = content.getOffsetAtLine(firstLine);
- boolean fullLineRedraw = ((getStyle() & SWT.FULL_SELECTION) != 0 && lastLine > firstLine);
-
- // if redraw range includes last character on the first line,
- // clear background to right widget border. fixes bug 19595.
- if (clearBackground && endOffset - firstLineOffset >= line.length()) {
- fullLineRedraw = true;
- }
- // calculate redraw stop location
- if (fullLineRedraw) {
- redrawStopX = getClientArea().width - leftMargin;
- }
- else {
- redrawStopX = getXAtOffset(line, firstLine, endOffset - firstLineOffset) - leftMargin;
- }
- draw(redrawX, redrawY, redrawStopX - redrawX, lineHeight, clearBackground);
- // redraw last line if more than one line needs redrawing
- if (lineCount > 1) {
- int offsetInLastLine = endOffset - content.getOffsetAtLine(lastLine);
- // no redraw necessary if redraw offset is 0
- if (offsetInLastLine > 0) {
- line = content.getLine(lastLine);
- // if redraw range includes last character on the last line,
- // clear background to right widget border. fixes bug 19595.
- if (clearBackground && offsetInLastLine >= line.length()) {
- fullLineRedraw = true;
- }
- if (fullLineRedraw) {
- redrawStopX = getClientArea().width - leftMargin;
- }
- else {
- redrawStopX = getXAtOffset(line, lastLine, offsetInLastLine) - leftMargin;
- }
- redrawY = lastLine * lineHeight - verticalScrollOffset;
- draw(0, redrawY, redrawStopX, lineHeight, clearBackground);
- }
- }
+ String line = content.getLine(firstLine);
+ int lineCount = lastLine - firstLine + 1;
+ int redrawX = getXAtOffset(line, firstLine, offsetInFirstLine) - leftMargin;
+ int redrawStopX;
+ int redrawY = firstLine * lineHeight - verticalScrollOffset;
+ int firstLineOffset = content.getOffsetAtLine(firstLine);
+ boolean fullLineRedraw = ((getStyle() & SWT.FULL_SELECTION) != 0 && lastLine > firstLine);
+
+ // if redraw range includes last character on the first line,
+ // clear background to right widget border. fixes bug 19595.
+ if (clearBackground && endOffset - firstLineOffset >= line.length()) {
+ fullLineRedraw = true;
+ }
+ // calculate redraw stop location
+ if (fullLineRedraw) {
+ redrawStopX = getClientArea().width - leftMargin;
+ }
+ else {
+ redrawStopX = getXAtOffset(line, firstLine, endOffset - firstLineOffset) - leftMargin;
+ }
+ draw(redrawX, redrawY, redrawStopX - redrawX, lineHeight, clearBackground);
+ // redraw last line if more than one line needs redrawing
+ if (lineCount > 1) {
+ int offsetInLastLine = endOffset - content.getOffsetAtLine(lastLine);
+ // no redraw necessary if redraw offset is 0
+ if (offsetInLastLine > 0) {
+ line = content.getLine(lastLine);
+ // if redraw range includes last character on the last line,
+ // clear background to right widget border. fixes bug 19595.
+ if (clearBackground && offsetInLastLine >= line.length()) {
+ fullLineRedraw = true;
+ }
+ if (fullLineRedraw) {
+ redrawStopX = getClientArea().width - leftMargin;
+ }
+ else {
+ redrawStopX = getXAtOffset(line, lastLine, offsetInLastLine) - leftMargin;
+ }
+ redrawY = lastLine * lineHeight - verticalScrollOffset;
+ draw(0, redrawY, redrawStopX, lineHeight, clearBackground);
+ }
+ }
}
/**
* Fixes the widget to display a text change.
@@ -6115,50 +6183,50 @@
* @param replacedLineCount number of replaced lines.
*/
void redrawMultiLineChange(int y, int newLineCount, int replacedLineCount) {
- Rectangle clientArea = getClientArea();
- int lineCount = newLineCount - replacedLineCount;
- int sourceY;
- int destinationY;
-
- if (lineCount > 0) {
- sourceY = Math.max(0, y + lineHeight);
- destinationY = sourceY + lineCount * lineHeight;
- }
- else {
- destinationY = Math.max(0, y + lineHeight);
- sourceY = destinationY - lineCount * lineHeight;
- }
- scroll(
- 0, destinationY, // destination x, y
- 0, sourceY, // source x, y
- clientArea.width, clientArea.height, true);
- // Always redrawing causes the bottom line to flash when a line is
- // deleted. This is because SWT merges the paint area of the scroll
- // with the paint area of the redraw call below.
- // To prevent this we could call update after the scroll. However,
- // adding update can cause even more flash if the client does other
- // redraw/update calls (ie. for syntax highlighting).
- // We could also redraw only when a line has been added or when
- // contents has been added to a line. This would require getting
- // line index info from the content and is not worth the trouble
- // (the flash is only on the bottom line and minor).
- // Specifying the NO_MERGE_PAINTS style bit prevents the merged
- // redraw but could cause flash/slowness elsewhere.
- if (y + lineHeight > 0 && y <= clientArea.height) {
- // redraw first changed line in case a line was split/joined
- super.redraw(0, y, clientArea.width, lineHeight, true);
- }
- if (newLineCount > 0) {
- int redrawStartY = y + lineHeight;
- int redrawHeight = newLineCount * lineHeight;
-
- if (redrawStartY + redrawHeight > 0 && redrawStartY <= clientArea.height) {
- // display new text
- super.redraw(0, redrawStartY, clientArea.width, redrawHeight, true);
- }
- }
+ Rectangle clientArea = getClientArea();
+ int lineCount = newLineCount - replacedLineCount;
+ int sourceY;
+ int destinationY;
+
+ if (lineCount > 0) {
+ sourceY = Math.max(0, y + lineHeight);
+ destinationY = sourceY + lineCount * lineHeight;
+ }
+ else {
+ destinationY = Math.max(0, y + lineHeight);
+ sourceY = destinationY - lineCount * lineHeight;
+ }
+ scroll(
+ 0, destinationY, // destination x, y
+ 0, sourceY, // source x, y
+ clientArea.width, clientArea.height, true);
+ // Always redrawing causes the bottom line to flash when a line is
+ // deleted. This is because SWT merges the paint area of the scroll
+ // with the paint area of the redraw call below.
+ // To prevent this we could call update after the scroll. However,
+ // adding update can cause even more flash if the client does other
+ // redraw/update calls (ie. for syntax highlighting).
+ // We could also redraw only when a line has been added or when
+ // contents has been added to a line. This would require getting
+ // line index info from the content and is not worth the trouble
+ // (the flash is only on the bottom line and minor).
+ // Specifying the NO_MERGE_PAINTS style bit prevents the merged
+ // redraw but could cause flash/slowness elsewhere.
+ if (y + lineHeight > 0 && y <= clientArea.height) {
+ // redraw first changed line in case a line was split/joined
+ super.redraw(0, y, clientArea.width, lineHeight, true);
+ }
+ if (newLineCount > 0) {
+ int redrawStartY = y + lineHeight;
+ int redrawHeight = newLineCount * lineHeight;
+
+ if (redrawStartY + redrawHeight > 0 && redrawStartY <= clientArea.height) {
+ // display new text
+ super.redraw(0, redrawStartY, clientArea.width, redrawHeight, true);
+ }
+ }
}
-/**
+/**
* Redraws the specified text range.
*
*
@@ -6167,38 +6235,38 @@
* @param clearBackground true if the background should be cleared as
* part of the redraw operation. If true, the entire redraw range will
* be cleared before anything is redrawn. If the redraw range includes
- * the last character of a line (i.e., the entire line is redrawn) the
- * line is cleared all the way to the right border of the widget.
- * The redraw operation will be faster and smoother if clearBackground
- * is set to false. Whether or not the flag can be set to false depends
- * on the type of change that has taken place. If font styles or
- * background colors for the redraw range have changed, clearBackground
- * should be set to true. If only foreground colors have changed for
- * the redraw range, clearBackground can be set to false.
+ * the last character of a line (i.e., the entire line is redrawn) the
+ * line is cleared all the way to the right border of the widget.
+ * The redraw operation will be faster and smoother if clearBackground
+ * is set to false. Whether or not the flag can be set to false depends
+ * on the type of change that has taken place. If font styles or
+ * background colors for the redraw range have changed, clearBackground
+ * should be set to true. If only foreground colors have changed for
+ * the redraw range, clearBackground can be set to false.
* @exception SWTException
- * Should not be called if a LineStyleListener has been set since the
+ * Should not be called if a LineStyleListener has been set since the
* listener maintains the styles.
*
* NOTE: During the replace operation the current selection is
* changed as follows:
- *
*
* @param pixels number of pixels to scroll, > 0 = scroll left,
- * < 0 scroll right
+ * < 0 scroll right
*/
void scrollHorizontal(int pixels) {
- Rectangle clientArea;
-
- if (pixels == 0) {
- return;
- }
- clientArea = getClientArea();
- if (pixels > 0) {
- int sourceX = leftMargin + pixels;
- int scrollWidth = clientArea.width - sourceX - rightMargin;
- int scrollHeight = clientArea.height - topMargin - bottomMargin;
- scroll(
- leftMargin, topMargin, // destination x, y
- sourceX, topMargin, // source x, y
- scrollWidth, scrollHeight, true);
- if (sourceX > scrollWidth) {
- // redraw from end of scrolled area to beginning of scroll
- // invalidated area
- super.redraw(
- leftMargin + scrollWidth, topMargin,
- pixels - scrollWidth, scrollHeight, true);
- }
- }
- else {
- int destinationX = leftMargin - pixels;
- int scrollWidth = clientArea.width - destinationX - rightMargin;
- int scrollHeight = clientArea.height - topMargin - bottomMargin;
- scroll(
- destinationX, topMargin, // destination x, y
- leftMargin, topMargin, // source x, y
- scrollWidth, scrollHeight, true);
- if (destinationX > scrollWidth) {
- // redraw from end of scroll invalidated area to scroll
- // destination
- super.redraw(
- leftMargin + scrollWidth, topMargin,
- -pixels - scrollWidth, scrollHeight, true);
- }
- }
- horizontalScrollOffset += pixels;
- setCaretLocation();
+ Rectangle clientArea;
+
+ if (pixels == 0) {
+ return;
+ }
+ clientArea = getClientArea();
+ if (pixels > 0) {
+ int sourceX = leftMargin + pixels;
+ int scrollWidth = clientArea.width - sourceX - rightMargin;
+ int scrollHeight = clientArea.height - topMargin - bottomMargin;
+ scroll(
+ leftMargin, topMargin, // destination x, y
+ sourceX, topMargin, // source x, y
+ scrollWidth, scrollHeight, true);
+ if (sourceX > scrollWidth) {
+ // redraw from end of scrolled area to beginning of scroll
+ // invalidated area
+ super.redraw(
+ leftMargin + scrollWidth, topMargin,
+ pixels - scrollWidth, scrollHeight, true);
+ }
+ }
+ else {
+ int destinationX = leftMargin - pixels;
+ int scrollWidth = clientArea.width - destinationX - rightMargin;
+ int scrollHeight = clientArea.height - topMargin - bottomMargin;
+ scroll(
+ destinationX, topMargin, // destination x, y
+ leftMargin, topMargin, // source x, y
+ scrollWidth, scrollHeight, true);
+ if (destinationX > scrollWidth) {
+ // redraw from end of scroll invalidated area to scroll
+ // destination
+ super.redraw(
+ leftMargin + scrollWidth, topMargin,
+ -pixels - scrollWidth, scrollHeight, true);
+ }
+ }
+ horizontalScrollOffset += pixels;
+ setCaretLocation();
}
/**
* Scrolls the widget horizontally and adjust the horizontal scroll
@@ -6601,23 +6671,23 @@
*
*
* @param pixels number of pixels to scroll, > 0 = scroll left,
- * < 0 scroll right
+ * < 0 scroll right
* @return
- * true=the widget was scrolled
- * false=the widget was not scrolled, the given offset is not valid.
+ * true=the widget was scrolled
+ * false=the widget was not scrolled, the given offset is not valid.
*/
boolean scrollHorizontalBar(int pixels) {
- if (pixels == 0) {
- return false;
- }
- ScrollBar horizontalBar = getHorizontalBar();
- if (horizontalBar != null) {
- horizontalBar.setSelection(horizontalScrollOffset + pixels);
- }
- scrollHorizontal(pixels);
- return true;
+ if (pixels == 0) {
+ return false;
+ }
+ ScrollBar horizontalBar = getHorizontalBar();
+ if (horizontalBar != null) {
+ horizontalBar.setSelection(horizontalScrollOffset + pixels);
+ }
+ scrollHorizontal(pixels);
+ return true;
}
-/**
+/**
* Selects all the text.
*
*
@@ -6627,34 +6697,34 @@
*
*
- * @param event the text change event.
- *
*
*/
boolean isStyleChanging(StyleRange range, int start, int end) {
- checkWidget();
- StyleRange[] styles = defaultLineStyler.getStyleRangesFor(start, end - start);
-
- if (styles == null) {
- return (range.fontStyle != SWT.NORMAL);
- }
- for (int i = 0; i < styles.length; i++) {
- StyleRange newStyle = styles[i];
- if (newStyle.fontStyle != range.fontStyle) {
- return true;
- }
- }
- return false;
+ checkWidget();
+ StyleRange[] styles = defaultLineStyler.getStyleRangesFor(start, end - start);
+
+ if (styles == null) {
+ return (range.fontStyle != SWT.NORMAL);
+ }
+ for (int i = 0; i < styles.length; i++) {
+ StyleRange newStyle = styles[i];
+ if (newStyle.fontStyle != range.fontStyle) {
+ return true;
+ }
+ }
+ return false;
}
/**
- * Sends the specified verify event, replace/insert text as defined by
+ * Sends the specified verify event, replace/insert text as defined by
* the event and send a modify event.
*
- *
+ * @param event the text change event.
+ *
+ *
* @param updateCaret whether or not he caret should be set behind
- * the new text
+ * the new text
*/
void modifyContent(Event event, boolean updateCaret) {
- event.doit = true;
- notifyListeners(SWT.Verify, event);
- if (event.doit) {
- StyledTextEvent styledTextEvent = null;
- int replacedLength = event.end - event.start;
- boolean isCharacterRemove = replacedLength == 1 && event.text.length() == 0;
- boolean isBackspace = event.start < caretOffset;
- boolean isDirectionBoundary = false;
-
- if (updateCaret && isBidi() && isCharacterRemove) {
- // set the keyboard language to the language of the deleted character.
- // determine direction boundary so that caret location can be updated
- // properly.
- int line = content.getLineAtOffset(caretOffset);
- int lineStartOffset = content.getOffsetAtLine(line);
- int offsetInLine = caretOffset - lineStartOffset;
- String lineText = content.getLine(line);
- GC gc = getGC();
- StyledTextBidi bidi = new StyledTextBidi(gc, lineText, getBidiSegments(lineStartOffset, lineText));
- if (isBackspace) {
- if (offsetInLine > 0) {
- // the line start/end does not represent a direction boundary
- // even if the previous/next line has a different direction.
- isDirectionBoundary =
- offsetInLine < lineText.length() &&
- (bidi.isRightToLeft(offsetInLine) != bidi.isRightToLeft(offsetInLine - 1) ||
- bidi.isLocalNumber(offsetInLine) != bidi.isLocalNumber(offsetInLine - 1));
- bidi.setKeyboardLanguage(offsetInLine - 1);
- }
- }
- else {
- if (offsetInLine < lineText.length()) {
- // the line start/end does not represent a direction boundary
- // even if the previous/next line has a different direction.
- isDirectionBoundary =
- offsetInLine > 0 &&
- (bidi.isRightToLeft(offsetInLine) != bidi.isRightToLeft(offsetInLine - 1) ||
- bidi.isLocalNumber(offsetInLine) != bidi.isLocalNumber(offsetInLine - 1));
- bidi.setKeyboardLanguage(offsetInLine);
- }
- }
- gc.dispose();
- }
- if (isListening(ExtendedModify)) {
- styledTextEvent = new StyledTextEvent(logicalContent);
- styledTextEvent.start = event.start;
- styledTextEvent.end = event.start + event.text.length();
- styledTextEvent.text = content.getTextRange(event.start, replacedLength);
- }
- content.replaceTextRange(event.start, replacedLength, event.text);
- // set the caret position prior to sending the modify event.
- // fixes 1GBB8NJ
- if (updateCaret) {
- // always update the caret location. fixes 1G8FODP
- internalSetSelection(event.start + event.text.length(), 0, true);
- if (isBidi()) {
- // Update the caret direction so that the caret moves to the
- // typed/deleted character. Fixes 1GJLQ16.
- if (isCharacterRemove) {
- updateBidiDirection(isBackspace, isDirectionBoundary);
- }
- else {
- lastCaretDirection = ST.COLUMN_NEXT;
- }
- showBidiCaret();
- }
- else {
- showCaret();
- }
- }
- notifyListeners(SWT.Modify, event);
- if (isListening(ExtendedModify)) {
- notifyListeners(ExtendedModify, styledTextEvent);
- }
- }
-}
-/**
- * Replaces the selection with the clipboard text or insert the text at
- * the current caret offset if there is no selection.
+ event.doit = true;
+ notifyListeners(SWT.Verify, event);
+ if (event.doit) {
+ StyledTextEvent styledTextEvent = null;
+ int replacedLength = event.end - event.start;
+ boolean isCharacterRemove = replacedLength == 1 && event.text.length() == 0;
+ boolean isBackspace = event.start < caretOffset;
+ boolean isDirectionBoundary = false;
+
+ if (updateCaret && isBidi() && isCharacterRemove) {
+ // set the keyboard language to the language of the deleted character.
+ // determine direction boundary so that caret location can be updated
+ // properly.
+ int line = content.getLineAtOffset(caretOffset);
+ int lineStartOffset = content.getOffsetAtLine(line);
+ int offsetInLine = caretOffset - lineStartOffset;
+ String lineText = content.getLine(line);
+ GC gc = getGC();
+ StyledTextBidi bidi = new StyledTextBidi(gc, lineText, getBidiSegments(lineStartOffset, lineText));
+ if (isBackspace) {
+ if (offsetInLine > 0) {
+ // the line start/end does not represent a direction boundary
+ // even if the previous/next line has a different direction.
+ isDirectionBoundary =
+ offsetInLine < lineText.length() &&
+ (bidi.isRightToLeft(offsetInLine) != bidi.isRightToLeft(offsetInLine - 1) ||
+ bidi.isLocalNumber(offsetInLine) != bidi.isLocalNumber(offsetInLine - 1));
+ bidi.setKeyboardLanguage(offsetInLine - 1);
+ }
+ }
+ else {
+ if (offsetInLine < lineText.length()) {
+ // the line start/end does not represent a direction boundary
+ // even if the previous/next line has a different direction.
+ isDirectionBoundary =
+ offsetInLine > 0 &&
+ (bidi.isRightToLeft(offsetInLine) != bidi.isRightToLeft(offsetInLine - 1) ||
+ bidi.isLocalNumber(offsetInLine) != bidi.isLocalNumber(offsetInLine - 1));
+ bidi.setKeyboardLanguage(offsetInLine);
+ }
+ }
+ gc.dispose();
+ }
+ if (isListening(ExtendedModify)) {
+ styledTextEvent = new StyledTextEvent(logicalContent);
+ styledTextEvent.start = event.start;
+ styledTextEvent.end = event.start + event.text.length();
+ styledTextEvent.text = content.getTextRange(event.start, replacedLength);
+ }
+ content.replaceTextRange(event.start, replacedLength, event.text);
+ // set the caret position prior to sending the modify event.
+ // fixes 1GBB8NJ
+ if (updateCaret) {
+ // always update the caret location. fixes 1G8FODP
+ internalSetSelection(event.start + event.text.length(), 0, true);
+ if (isBidi()) {
+ // Update the caret direction so that the caret moves to the
+ // typed/deleted character. Fixes 1GJLQ16.
+ if (isCharacterRemove) {
+ updateBidiDirection(isBackspace, isDirectionBoundary);
+ }
+ else {
+ lastCaretDirection = ST.COLUMN_NEXT;
+ }
+ showBidiCaret();
+ }
+ else {
+ showCaret();
+ }
+ }
+ notifyListeners(SWT.Modify, event);
+ if (isListening(ExtendedModify)) {
+ notifyListeners(ExtendedModify, styledTextEvent);
+ }
+ }
+}
+/**
+ * Replaces the selection with the clipboard text or insert the text at
+ * the current caret offset if there is no selection.
* If the widget has the SWT.SINGLE style and the clipboard text contains
- * more than one line, only the first line without line delimiters is
+ * more than one line, only the first line without line delimiters is
* inserted in the widget.
*
@@ -5829,24 +5897,24 @@
*
*/
public void print() {
- checkWidget();
- Printer printer = new Printer();
- StyledTextPrintOptions options = new StyledTextPrintOptions();
-
- options.printTextForeground = true;
- options.printTextBackground = true;
- options.printTextFontStyle = true;
- options.printLineBackground = true;
- new Printing(this, printer, options).run();
- printer.dispose();
+ checkWidget();
+ Printer printer = new Printer();
+ StyledTextPrintOptions options = new StyledTextPrintOptions();
+
+ options.printTextForeground = true;
+ options.printTextBackground = true;
+ options.printTextFontStyle = true;
+ options.printLineBackground = true;
+ new Printing(this, printer, options).run();
+ printer.dispose();
}
-/**
+/**
* Returns a runnable that will print the widget's text
* to the specified printer.
*
*
*/
public Runnable print(Printer printer) {
- StyledTextPrintOptions options = new StyledTextPrintOptions();
+ StyledTextPrintOptions options = new StyledTextPrintOptions();
- checkWidget();
- options.printTextForeground = true;
- options.printTextBackground = true;
- options.printTextFontStyle = true;
- options.printLineBackground = true;
- if (printer == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- return print(printer, options);
+ checkWidget();
+ options.printTextForeground = true;
+ options.printTextBackground = true;
+ options.printTextFontStyle = true;
+ options.printLineBackground = true;
+ if (printer == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ return print(printer, options);
}
-/**
+/**
* Returns a runnable that will print the widget's text
* to the specified printer.
*
@@ -5888,11 +5956,11 @@
* @since 2.1
*/
public Runnable print(Printer printer, StyledTextPrintOptions options) {
- checkWidget();
- if (printer == null || options == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- return new Printing(this, printer, options);
+ checkWidget();
+ if (printer == null || options == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ return new Printing(this, printer, options);
}
/**
* Causes the entire bounds of the receiver to be marked
@@ -5900,8 +5968,8 @@
* is processed, the control will be completely painted.
*
*/
public void removeExtendedModifyListener(ExtendedModifyListener extendedModifyListener) {
- checkWidget();
- if (extendedModifyListener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- removeListener(ExtendedModify, extendedModifyListener);
+ checkWidget();
+ if (extendedModifyListener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ removeListener(ExtendedModify, extendedModifyListener);
}
/**
* Removes the specified line background listener.
@@ -6251,15 +6319,15 @@
*
*/
public void removeLineBackgroundListener(LineBackgroundListener listener) {
- checkWidget();
- if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- removeListener(LineGetBackground, listener);
- // use default line styler if last user line styler was removed.
- if (isListening(LineGetBackground) == false && userLineBackground) {
- StyledTextListener typedListener = new StyledTextListener(defaultLineStyler);
- addListener(LineGetBackground, typedListener);
- userLineBackground = false;
- }
+ checkWidget();
+ if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ removeListener(LineGetBackground, listener);
+ // use default line styler if last user line styler was removed.
+ if (isListening(LineGetBackground) == false && userLineBackground) {
+ StyledTextListener typedListener = new StyledTextListener(defaultLineStyler);
+ addListener(LineGetBackground, typedListener);
+ userLineBackground = false;
+ }
}
/**
* Removes the specified line style listener.
@@ -6275,17 +6343,17 @@
*
*/
public void removeLineStyleListener(LineStyleListener listener) {
- checkWidget();
- if (listener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- removeListener(LineGetStyle, listener);
- // use default line styler if last user line styler was removed. Fixes 1G7B1X2
- if (isListening(LineGetStyle) == false && userLineStyle) {
- StyledTextListener typedListener = new StyledTextListener(defaultLineStyler);
- addListener(LineGetStyle, typedListener);
- userLineStyle = false;
- }
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ removeListener(LineGetStyle, listener);
+ // use default line styler if last user line styler was removed. Fixes 1G7B1X2
+ if (isListening(LineGetStyle) == false && userLineStyle) {
+ StyledTextListener typedListener = new StyledTextListener(defaultLineStyler);
+ addListener(LineGetStyle, typedListener);
+ userLineStyle = false;
+ }
}
/**
* Removes the specified modify listener.
@@ -6301,11 +6369,11 @@
*
*/
public void removeModifyListener(ModifyListener modifyListener) {
- checkWidget();
- if (modifyListener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- removeListener(SWT.Modify, modifyListener);
+ checkWidget();
+ if (modifyListener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ removeListener(SWT.Modify, modifyListener);
}
/**
* Removes the specified selection listener.
@@ -6321,11 +6389,11 @@
*
*/
public void removeSelectionListener(SelectionListener listener) {
- checkWidget();
- if (listener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- removeListener(SWT.Selection, listener);
+ checkWidget();
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ removeListener(SWT.Selection, listener);
}
/**
* Removes the specified verify listener.
@@ -6341,11 +6409,11 @@
*
*/
public void removeVerifyListener(VerifyListener verifyListener) {
- checkWidget();
- if (verifyListener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- removeListener(SWT.Verify, verifyListener);
+ checkWidget();
+ if (verifyListener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ removeListener(SWT.Verify, verifyListener);
}
/**
* Removes the specified key verify listener.
@@ -6361,22 +6429,22 @@
*
*/
public void removeVerifyKeyListener(VerifyKeyListener listener) {
- if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- removeListener(VerifyKey, listener);
+ if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ removeListener(VerifyKey, listener);
}
-/**
+/**
* Replaces the styles in the given range with new styles. This method
* effectively deletes the styles in the given range and then adds the
- * the new styles.
+ * the new styles.
* LineStyleListener
is used a redraw call
- * is the only notification to the widget that styles have changed
+ * When a LineStyleListener
is used a redraw call
+ * is the only notification to the widget that styles have changed
* and that the content width may have changed.
* all
flag
* is true
, any children of the receiver which
* intersect with the specified area will also paint their
- * intersecting areas. If the all
flag is
+ * intersecting areas. If the all
flag is
* false
, the children will not be painted.
* LineStyleListener
is used a redraw call
- * is the only notification to the widget that styles have changed
+ * When a LineStyleListener
is used a redraw call
+ * is the only notification to the widget that styles have changed
* and that the content width may have changed.
*
*
* @exception IllegalArgumentException
- *
*/
public void redrawRange(int start, int length, boolean clearBackground) {
- checkWidget();
- int end = start + length;
- int contentLength = content.getCharCount();
- int firstLine;
- int lastLine;
-
- if (start > end || start < 0 || end > contentLength) {
- SWT.error(SWT.ERROR_INVALID_RANGE);
- }
- firstLine = content.getLineAtOffset(start);
- lastLine = content.getLineAtOffset(end);
- // reset all affected lines but let the redraw recalculate only
- // those that are visible.
- lineCache.reset(firstLine, lastLine - firstLine + 1, true);
- internalRedrawRange(start, length, clearBackground);
+ checkWidget();
+ int end = start + length;
+ int contentLength = content.getCharCount();
+ int firstLine;
+ int lastLine;
+
+ if (start > end || start < 0 || end > contentLength) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ firstLine = content.getLineAtOffset(start);
+ lastLine = content.getLineAtOffset(end);
+ // reset all affected lines but let the redraw recalculate only
+ // those that are visible.
+ lineCache.reset(firstLine, lastLine - firstLine + 1, true);
+ internalRedrawRange(start, length, clearBackground);
}
/**
* Removes the specified bidirectional segment listener.
@@ -6215,9 +6283,9 @@
* @since 2.0
*/
public void removeBidiSegmentListener(BidiSegmentListener listener) {
- checkWidget();
- if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- removeListener(LineGetSegments, listener);
+ checkWidget();
+ if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ removeListener(LineGetSegments, listener);
}
/**
* Removes the specified extended modify listener.
@@ -6233,9 +6301,9 @@
*
@@ -6384,93 +6452,93 @@
*
* @exception IllegalArgumentException
- *
* @since 2.0
*/
public void replaceStyleRanges(int start, int length, StyleRange[] ranges) {
- checkWidget();
- if (userLineStyle) {
- return;
- }
- if (ranges == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- if (ranges.length == 0) {
- setStyleRange(new StyleRange(start, length, null, null));
- return;
- }
- int end = start + length;
- if (start > end || start < 0 || end > getCharCount()) {
- SWT.error(SWT.ERROR_INVALID_RANGE);
- }
-
- int firstLine = content.getLineAtOffset(start);
- int lastLine = content.getLineAtOffset(end);
-
- // if the area is not visible, there is no need to redraw
- boolean redrawLines = isAreaVisible(firstLine, lastLine);
-
- if (!redrawLines) {
- defaultLineStyler.replaceStyleRanges(start, length, ranges);
- lineCache.reset(firstLine, lastLine - firstLine + 1, true);
- } else {
- boolean redrawFirstLine = false;
- boolean redrawLastLine = false;
- // the first and last line needs to be redrawn completely if the
- // font style is changing from SWT.NORMAL to something else or
- // vice versa. fixes 1G7M5WE.
- int firstLineOffset = content.getOffsetAtLine(firstLine);
- if (isBidi()) {
- redrawFirstLine = true;
- redrawLastLine = true;
- } else {
- int firstLineEnd = firstLineOffset + content.getLine(firstLine).length();
- redrawFirstLine = isRedrawFirstLine(ranges, firstLine, firstLineOffset);
- // check if any bold styles will be cleared
- StyleRange clearRange = new StyleRange(firstLineOffset, firstLineEnd - firstLineOffset, null, null);
- redrawFirstLine = redrawFirstLine || isRedrawFirstLine(new StyleRange[] {clearRange}, firstLine, firstLineOffset);
- if (lastLine != firstLine) {
- int lastLineOffset = content.getOffsetAtLine(lastLine);
- int lastLineEnd = lastLineOffset + content.getLine(lastLine).length();
- redrawLastLine = isRedrawLastLine(ranges, lastLine, lastLineOffset);
- // check if any bold styles will be cleared
- clearRange = new StyleRange(lastLineOffset, lastLineEnd - lastLineOffset, null, null);
- redrawLastLine = redrawLastLine || isRedrawLastLine(new StyleRange[] {clearRange}, lastLine, lastLineOffset);
- }
- }
- defaultLineStyler.replaceStyleRanges(start, length, ranges);
- // reset all lines affected by the style change but let the redraw
- // recalculate only those that are visible.
- lineCache.reset(firstLine, lastLine - firstLine + 1, true);
- internalRedrawRange(start, length, true);
- if (redrawFirstLine) {
- redrawLine(firstLine, start - firstLineOffset);
- }
- if (redrawLastLine) {
- redrawLine(lastLine, 0);
- }
- }
-
- // make sure that the caret is positioned correctly.
- // caret location may change if font style changes.
- // fixes 1G8FODP
- setCaretLocation();
+ checkWidget();
+ if (userLineStyle) {
+ return;
+ }
+ if (ranges == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (ranges.length == 0) {
+ setStyleRange(new StyleRange(start, length, null, null));
+ return;
+ }
+ int end = start + length;
+ if (start > end || start < 0 || end > getCharCount()) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+
+ int firstLine = content.getLineAtOffset(start);
+ int lastLine = content.getLineAtOffset(end);
+
+ // if the area is not visible, there is no need to redraw
+ boolean redrawLines = isAreaVisible(firstLine, lastLine);
+
+ if (!redrawLines) {
+ defaultLineStyler.replaceStyleRanges(start, length, ranges);
+ lineCache.reset(firstLine, lastLine - firstLine + 1, true);
+ } else {
+ boolean redrawFirstLine = false;
+ boolean redrawLastLine = false;
+ // the first and last line needs to be redrawn completely if the
+ // font style is changing from SWT.NORMAL to something else or
+ // vice versa. fixes 1G7M5WE.
+ int firstLineOffset = content.getOffsetAtLine(firstLine);
+ if (isBidi()) {
+ redrawFirstLine = true;
+ redrawLastLine = true;
+ } else {
+ int firstLineEnd = firstLineOffset + content.getLine(firstLine).length();
+ redrawFirstLine = isRedrawFirstLine(ranges, firstLine, firstLineOffset);
+ // check if any bold styles will be cleared
+ StyleRange clearRange = new StyleRange(firstLineOffset, firstLineEnd - firstLineOffset, null, null);
+ redrawFirstLine = redrawFirstLine || isRedrawFirstLine(new StyleRange[] {clearRange}, firstLine, firstLineOffset);
+ if (lastLine != firstLine) {
+ int lastLineOffset = content.getOffsetAtLine(lastLine);
+ int lastLineEnd = lastLineOffset + content.getLine(lastLine).length();
+ redrawLastLine = isRedrawLastLine(ranges, lastLine, lastLineOffset);
+ // check if any bold styles will be cleared
+ clearRange = new StyleRange(lastLineOffset, lastLineEnd - lastLineOffset, null, null);
+ redrawLastLine = redrawLastLine || isRedrawLastLine(new StyleRange[] {clearRange}, lastLine, lastLineOffset);
+ }
+ }
+ defaultLineStyler.replaceStyleRanges(start, length, ranges);
+ // reset all lines affected by the style change but let the redraw
+ // recalculate only those that are visible.
+ lineCache.reset(firstLine, lastLine - firstLine + 1, true);
+ internalRedrawRange(start, length, true);
+ if (redrawFirstLine) {
+ redrawLine(firstLine, start - firstLineOffset);
+ }
+ if (redrawLastLine) {
+ redrawLine(lastLine, 0);
+ }
+ }
+
+ // make sure that the caret is positioned correctly.
+ // caret location may change if font style changes.
+ // fixes 1G8FODP
+ setCaretLocation();
}
/**
* Replaces the given text range with new text.
- * If the widget has the SWT.SINGLE style and "text" contains more than
- * one line, only the first line is rendered but the text is stored
- * unchanged. A subsequent call to getText will return the same text
- * that was set. Note that only a single line of text should be set when
+ * If the widget has the SWT.SINGLE style and "text" contains more than
+ * one line, only the first line is rendered but the text is stored
+ * unchanged. A subsequent call to getText will return the same text
+ * that was set. Note that only a single line of text should be set when
* the SWT.SINGLE style is used.
*
+ *
*/
public void selectAll() {
- checkWidget();
- setSelection(new Point(0, Math.max(getCharCount(),0)));
+ checkWidget();
+ setSelection(new Point(0, Math.max(getCharCount(),0)));
}
/**
* Replaces/inserts text as defined by the event.
*
*
* @exception IllegalArgumentException
- *
*/
public void replaceTextRange(int start, int length, String text) {
- checkWidget();
- int contentLength = getCharCount();
- int end = start + length;
- Event event = new Event();
-
- if (start > end || start < 0 || end > contentLength) {
- SWT.error(SWT.ERROR_INVALID_RANGE);
- }
- if (text == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- event.start = start;
- event.end = end;
- event.text = text;
- modifyContent(event, false);
+ checkWidget();
+ int contentLength = getCharCount();
+ int end = start + length;
+ Event event = new Event();
+
+ if (start > end || start < 0 || end > contentLength) {
+ SWT.error(SWT.ERROR_INVALID_RANGE);
+ }
+ if (text == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ event.start = start;
+ event.end = end;
+ event.text = text;
+ modifyContent(event, false);
}
/**
* Resets the caret position, selection and scroll offsets. Recalculate
* the content width and scroll bars. Redraw the widget.
*/
void reset() {
- ScrollBar verticalBar = getVerticalBar();
- ScrollBar horizontalBar = getHorizontalBar();
- caretOffset = 0;
- topIndex = 0;
- topOffset = 0;
- verticalScrollOffset = 0;
- horizontalScrollOffset = 0;
- resetSelection();
- // discard any styles that may have been set by creating a
- // new default line styler
- if (defaultLineStyler != null) {
- removeLineBackgroundListener(defaultLineStyler);
- removeLineStyleListener(defaultLineStyler);
- installDefaultLineStyler();
- }
- calculateContentWidth();
- if (verticalBar != null) {
- verticalBar.setSelection(0);
- }
- if (horizontalBar != null) {
- horizontalBar.setSelection(0);
- }
- setScrollBars();
- setCaretLocation();
- super.redraw();
+ ScrollBar verticalBar = getVerticalBar();
+ ScrollBar horizontalBar = getHorizontalBar();
+ caretOffset = 0;
+ topIndex = 0;
+ topOffset = 0;
+ verticalScrollOffset = 0;
+ horizontalScrollOffset = 0;
+ resetSelection();
+ // discard any styles that may have been set by creating a
+ // new default line styler
+ if (defaultLineStyler != null) {
+ removeLineBackgroundListener(defaultLineStyler);
+ removeLineStyleListener(defaultLineStyler);
+ installDefaultLineStyler();
+ }
+ calculateContentWidth();
+ if (verticalBar != null) {
+ verticalBar.setSelection(0);
+ }
+ if (horizontalBar != null) {
+ horizontalBar.setSelection(0);
+ }
+ setScrollBars();
+ setCaretLocation();
+ super.redraw();
}
/**
* Resets the selection.
*/
void resetSelection() {
- selection.x = selection.y = caretOffset;
- selectionAnchor = -1;
+ selection.x = selection.y = caretOffset;
+ selectionAnchor = -1;
+ // see if we need to update the mouse pointer
+ internalSetCursor();
}
/**
* Scrolls the widget horizontally.
*
- *
+ * @param event the text change event.
+ *
+ *
*/
void sendKeyEvent(Event event) {
- if (editable == false) {
- return;
- }
- modifyContent(event, true);
+ if (editable == false) {
+ return;
+ }
+ modifyContent(event, true);
}
/**
* Sends the specified selection event.
*/
void sendSelectionEvent() {
- Event event = new Event();
- event.x = selection.x;
- event.y = selection.y;
- notifyListeners(SWT.Selection, event);
+ Event event = new Event();
+ event.x = selection.x;
+ event.y = selection.y;
+ notifyListeners(SWT.Selection, event);
}
/**
* Sets whether the widget wraps lines.
@@ -6665,59 +6735,59 @@
* @since 2.0
*/
public void setWordWrap(boolean wrap) {
- checkWidget();
-
- if (wrap != wordWrap) {
- ScrollBar horizontalBar = getHorizontalBar();
-
- wordWrap = wrap;
- if (wordWrap) {
- logicalContent = content;
- content = new WrappedContent(renderer, logicalContent);
- }
- else {
- content = logicalContent;
- }
- calculateContentWidth();
- horizontalScrollOffset = 0;
- if (horizontalBar != null) {
- horizontalBar.setVisible(!wordWrap);
- }
- setScrollBars();
- setCaretLocation();
- super.redraw();
- }
+ checkWidget();
+
+ if (wrap != wordWrap) {
+ ScrollBar horizontalBar = getHorizontalBar();
+
+ wordWrap = wrap;
+ if (wordWrap) {
+ logicalContent = content;
+ content = new WrappedContent(renderer, logicalContent);
+ }
+ else {
+ content = logicalContent;
+ }
+ calculateContentWidth();
+ horizontalScrollOffset = 0;
+ if (horizontalBar != null) {
+ horizontalBar.setVisible(!wordWrap);
+ }
+ setScrollBars();
+ setCaretLocation();
+ super.redraw();
+ }
}
/**
* Sets the caret location and scrolls the caret offset into view.
*/
void showBidiCaret() {
- int line = content.getLineAtOffset(caretOffset);
- int lineOffset = content.getOffsetAtLine(line);
- int offsetInLine = caretOffset - lineOffset;
- String lineText = content.getLine(line);
- int xAtOffset = 0;
- boolean scrolled = false;
- GC gc = getGC();
- StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc);
- // getXAtOffset, inlined for better performance
- xAtOffset = getBidiTextPosition(lineText, offsetInLine, bidi) + leftMargin;
- if (offsetInLine > lineText.length()) {
- // offset is not on the line. return an x location one character
- // after the line to indicate the line delimiter.
- xAtOffset += lineEndSpaceWidth;
- }
- xAtOffset -= horizontalScrollOffset;
- //
- scrolled = showLocation(xAtOffset, line);
- if (scrolled == false) {
- setBidiCaretLocation(bidi);
- }
- gc.dispose();
+ int line = content.getLineAtOffset(caretOffset);
+ int lineOffset = content.getOffsetAtLine(line);
+ int offsetInLine = caretOffset - lineOffset;
+ String lineText = content.getLine(line);
+ int xAtOffset = 0;
+ boolean scrolled = false;
+ GC gc = getGC();
+ StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc);
+ // getXAtOffset, inlined for better performance
+ xAtOffset = getBidiTextPosition(lineText, offsetInLine, bidi) + leftMargin;
+ if (offsetInLine > lineText.length()) {
+ // offset is not on the line. return an x location one character
+ // after the line to indicate the line delimiter.
+ xAtOffset += lineEndSpaceWidth;
+ }
+ xAtOffset -= horizontalScrollOffset;
+ //
+ scrolled = showLocation(xAtOffset, line);
+ if (scrolled == false) {
+ setBidiCaretLocation(bidi);
+ }
+ gc.dispose();
}
/**
* Sets the receiver's caret. Set the caret's height and location.
- *
+ *
*
- * + * * @param bidi StyledTextBidi object to use for measuring. - * May be left null in which case a new object will be created. + * May be left null in which case a new object will be created. */ void setBidiCaretLocation(StyledTextBidi bidi) { - int caretLine = getCaretLine(); - - setBidiCaretLocation(bidi, caretLine); + int caretLine = getCaretLine(); + + setBidiCaretLocation(bidi, caretLine); } /** * Moves the Caret to the current caret offset. *
- * + * * @param bidi StyledTextBidi object to use for measuring. - * May be left null in which case a new object will be created. + * May be left null in which case a new object will be created. * @param caretLine line the caret should be placed on. Relative to - * first line in document + * first line in document */ void setBidiCaretLocation(StyledTextBidi bidi, int caretLine) { - Caret caret = getCaret(); - String lineText = content.getLine(caretLine); - int lineStartOffset = content.getOffsetAtLine(caretLine); - int offsetInLine = caretOffset - lineStartOffset; - GC gc = null; - - if (bidi == null) { - gc = getGC(); - bidi = getStyledTextBidi(lineText, lineStartOffset, gc); - } - if (lastCaretDirection == SWT.NULL) { - columnX = bidi.getTextPosition(offsetInLine) + leftMargin - horizontalScrollOffset; - } else { - columnX = bidi.getTextPosition(offsetInLine, lastCaretDirection) + leftMargin - horizontalScrollOffset; - } - if (StyledTextBidi.getKeyboardLanguageDirection() == SWT.RIGHT) { - columnX -= (getCaretWidth() - 1); - } - if (caret != null) { - setBidiCaretDirection(); - caret.setLocation( - columnX, - caretLine * lineHeight - verticalScrollOffset + topMargin); - } - if (gc != null) { - gc.dispose(); - } + Caret caret = getCaret(); + String lineText = content.getLine(caretLine); + int lineStartOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineStartOffset; + GC gc = null; + + if (bidi == null) { + gc = getGC(); + bidi = getStyledTextBidi(lineText, lineStartOffset, gc); + } + if (lastCaretDirection == SWT.NULL) { + columnX = bidi.getTextPosition(offsetInLine) + leftMargin - horizontalScrollOffset; + } else { + columnX = bidi.getTextPosition(offsetInLine, lastCaretDirection) + leftMargin - horizontalScrollOffset; + } + if (StyledTextBidi.getKeyboardLanguageDirection() == SWT.RIGHT) { + columnX -= (getCaretWidth() - 1); + } + if (caret != null) { + setBidiCaretDirection(); + caret.setLocation( + columnX, + caretLine * lineHeight - verticalScrollOffset + topMargin); + } + if (gc != null) { + gc.dispose(); + } } /** * Sets the BIDI coloring mode. When true the BIDI text display @@ -6837,87 +6907,87 @@ *
*/ public void setBidiColoring(boolean mode) { - checkWidget(); - bidiColoring = mode; + checkWidget(); + bidiColoring = mode; } /** - * Switches the keyboard language according to the current editing + * Switches the keyboard language according to the current editing * position and cursor direction. */ void setBidiKeyboardLanguage() { - int caretLine = getCaretLine(); - int lineStartOffset = content.getOffsetAtLine(caretLine); - int offsetInLine = caretOffset - lineStartOffset; - String lineText = content.getLine(caretLine); - GC gc = getGC(); - StyledTextBidi bidi; - int lineLength = lineText.length(); - - // Don't supply the bold styles/font since we don't want to measure anything - bidi = new StyledTextBidi(gc, lineText, getBidiSegments(lineStartOffset, lineText)); - if (offsetInLine == 0) { - bidi.setKeyboardLanguage(offsetInLine); - } - else - if (offsetInLine >= lineLength) { - offsetInLine = Math.min(offsetInLine, lineLength - 1); - bidi.setKeyboardLanguage(offsetInLine); - } - else - if (lastCaretDirection == ST.COLUMN_NEXT) { - // continue with previous character type - bidi.setKeyboardLanguage(offsetInLine - 1); - } - else { - bidi.setKeyboardLanguage(offsetInLine); - } - gc.dispose(); + int caretLine = getCaretLine(); + int lineStartOffset = content.getOffsetAtLine(caretLine); + int offsetInLine = caretOffset - lineStartOffset; + String lineText = content.getLine(caretLine); + GC gc = getGC(); + StyledTextBidi bidi; + int lineLength = lineText.length(); + + // Don't supply the bold styles/font since we don't want to measure anything + bidi = new StyledTextBidi(gc, lineText, getBidiSegments(lineStartOffset, lineText)); + if (offsetInLine == 0) { + bidi.setKeyboardLanguage(offsetInLine); + } + else + if (offsetInLine >= lineLength) { + offsetInLine = Math.min(offsetInLine, lineLength - 1); + bidi.setKeyboardLanguage(offsetInLine); + } + else + if (lastCaretDirection == ST.COLUMN_NEXT) { + // continue with previous character type + bidi.setKeyboardLanguage(offsetInLine - 1); + } + else { + bidi.setKeyboardLanguage(offsetInLine); + } + gc.dispose(); } /** * Moves the Caret to the current caret offset. *- * + * * @param newCaretX the new x location of the caret. - * passed in for better performance when it has already been - * calculated outside this method. - * @param line index of the line the caret is on. Relative to - * the first line in the document. + * passed in for better performance when it has already been + * calculated outside this method. + * @param line index of the line the caret is on. Relative to + * the first line in the document. */ void setCaretLocation(int newCaretX, int line) { - if (isBidi()) { - setBidiCaretLocation(null, line); - } - else { - Caret caret = getCaret(); - - columnX = newCaretX; - if (caret != null) { - caret.setLocation( - newCaretX, - line * lineHeight - verticalScrollOffset + topMargin); - } - } + if (isBidi()) { + setBidiCaretLocation(null, line); + } + else { + Caret caret = getCaret(); + + columnX = newCaretX; + if (caret != null) { + caret.setLocation( + newCaretX, + line * lineHeight - verticalScrollOffset + topMargin); + } + } } /** * Moves the Caret to the current caret offset. */ void setCaretLocation() { - if (isBidi()) { - setBidiCaretLocation(null); - } - else { - Caret caret = getCaret(); - int caretLine = getCaretLine(); - int lineStartOffset = content.getOffsetAtLine(caretLine); - - columnX = getXAtOffset( - content.getLine(caretLine), caretLine, caretOffset - lineStartOffset); - if (caret != null) { - caret.setLocation( - columnX, - caretLine * lineHeight - verticalScrollOffset + topMargin); - } - } + if (isBidi()) { + setBidiCaretLocation(null); + } + else { + Caret caret = getCaret(); + int caretLine = getCaretLine(); + int lineStartOffset = content.getOffsetAtLine(caretLine); + + columnX = getXAtOffset( + content.getLine(caretLine), caretLine, caretOffset - lineStartOffset); + if (caret != null) { + caret.setLocation( + columnX, + caretLine * lineHeight - verticalScrollOffset + topMargin); + } + } } /** * Sets the caret offset. @@ -6928,40 +6998,40 @@ *
- * NOTE: The horizontal index is reset to 0 when new text is set in the + * NOTE: The horizontal index is reset to 0 when new text is set in the * widget. *
* - * @param offset horizontal scroll offset relative to the start - * of the line, measured in character increments starting at 0, if - * equal to 0 the content is not scrolled, if > 0 = the content is scrolled. + * @param offset horizontal scroll offset relative to the start + * of the line, measured in character increments starting at 0, if + * equal to 0 the content is not scrolled, if > 0 = the content is scrolled. * @exception SWTException- * NOTE: The horizontal pixel offset is reset to 0 when new text + * NOTE: The horizontal pixel offset is reset to 0 when new text * is set in the widget. *
* - * @param pixel horizontal pixel offset relative to the start - * of the line. + * @param pixel horizontal pixel offset relative to the start + * of the line. * @exception SWTException- * Line background colors are maintained relative to the line text, not the + * Line background colors are maintained relative to the line text, not the * line index that is specified in this method call. - * During text changes, when entire lines are inserted or removed, the line - * background colors that are associated with the lines after the change - * will "move" with their respective text. An entire line is defined as - * extending from the first character on a line to the last and including the - * line delimiter. + * During text changes, when entire lines are inserted or removed, the line + * background colors that are associated with the lines after the change + * will "move" with their respective text. An entire line is defined as + * extending from the first character on a line to the last and including the + * line delimiter. *
*- * When two lines are joined by deleting a line delimiter, the top line - * background takes precedence and the color of the bottom line is deleted. - * For all other text changes line background colors will remain unchanged. + * When two lines are joined by deleting a line delimiter, the top line + * background takes precedence and the color of the bottom line is deleted. + * For all other text changes line background colors will remain unchanged. *
- * + * * @param startLine first line the color is applied to, 0 based * @param lineCount number of lines the color applies to. * @param background line background color @@ -7259,87 +7330,87 @@ ** @@ -7351,24 +7422,24 @@ * * @exception IllegalArgumentException
* Indexing is zero based. Text selections are specified in terms of - * caret positions. In a text widget that contains N characters, there are + * caret positions. In a text widget that contains N characters, there are * N+1 caret positions, ranging from 0..N *
* * @param point x=selection start offset, y=selection end offset - * The caret will be placed at the selection start when x > y. + * The caret will be placed at the selection start when x > y. * @see #setSelection(int,int) * @exception SWTException* Indexing is zero based. Text selections are specified in terms of - * caret positions. In a text widget that contains N characters, there are + * caret positions. In a text widget that contains N characters, there are * N+1 caret positions, ranging from 0..N *
* - * @param start selection start offset. The caret will be placed at the - * selection start when start > end. + * @param start selection start offset. The caret will be placed at the + * selection start when start > end. * @param end selection end offset * @see #setSelectionRange(int,int) * @exception SWTException* * @param start offset of the first selected character, start >= 0 must be true. - * @param length number of characters to select, 0 <= start + length <= getCharCount() - * must be true. - * A negative length places the caret at the visual start of the selection. + * @param length number of characters to select, 0 <= start + length <= getCharCount() + * must be true. + * A negative length places the caret at the visual start of the selection. * @exception SWTException
* * @param start offset of the first selected character, start >= 0 must be true. - * @param length number of characters to select, 0 <= start + length - * <= getCharCount() must be true. - * A negative length places the caret at the selection start. - * @param sendEvent a Selection event is sent when set to true and when - * the selection is reset. + * @param length number of characters to select, 0 <= start + length + * <= getCharCount() must be true. + * A negative length places the caret at the selection start. + * @param sendEvent a Selection event is sent when set to true and when + * the selection is reset. */ void internalSetSelection(int start, int length, boolean sendEvent) { - int end = start + length; - - if (start > end) { - int temp = end; - end = start; - start = temp; - } - // is the selection range different or is the selection direction - // different? - if (selection.x != start || selection.y != end || - (length > 0 && selectionAnchor != selection.x) || - (length < 0 && selectionAnchor != selection.y)) { - clearSelection(sendEvent); - if (length < 0) { - selectionAnchor = selection.y = end; - caretOffset = selection.x = start; - } - else { - selectionAnchor = selection.x = start; - caretOffset = selection.y = end; - } - internalRedrawRange(selection.x, selection.y - selection.x, true); - } + int end = start + length; + + if (start > end) { + int temp = end; + end = start; + start = temp; + } + // is the selection range different or is the selection direction + // different? + if (selection.x != start || selection.y != end || + (length > 0 && selectionAnchor != selection.x) || + (length < 0 && selectionAnchor != selection.y)) { + clearSelection(sendEvent); + if (length < 0) { + selectionAnchor = selection.y = end; + caretOffset = selection.x = start; + } + else { + selectionAnchor = selection.x = start; + caretOffset = selection.y = end; + } + internalRedrawRange(selection.x, selection.y - selection.x, true); + } + // see if we need to update the mouse pointer + internalSetCursor(); +} +/** + * Sets the mouse pointer based on whether it is over a selection and whether + * a custom cursor has been set. + */ +void internalSetCursor() { + Point pos = this.toControl(getDisplay().getCursorLocation()); + internalSetCursor(pos.x, pos.y); +} +/** + * Sets the mouse pointer based on whether it is over a selection and whether + * a custom cursor has been set. + * + * @param x mouse x position in client coordinates + * @param y mouse y position in client coordinates + */ +void internalSetCursor(int x, int y) { + int mouseLineIndex = (y + verticalScrollOffset) / lineHeight; + + if (mouseLineIndex < 0 || mouseLineIndex > content.getLineCount() - 1) { + // mouse is above or below content, set ibeam/custom cursor + Cursor cursor = (customCursor != null) ? customCursor : ibeamCursor; + if (!currentCursor.equals(cursor)) { + currentCursor = cursor; + super.setCursor(cursor); + } + } else { + if (isMouseOverSelection(x, y)) { + // mouse is over a selection, set arrow cursor + if (!currentCursor.equals(arrowCursor)) { + currentCursor = arrowCursor; + super.setCursor(arrowCursor); + } + } else { + Cursor cursor = (customCursor != null) ? customCursor : ibeamCursor; + // mouse is not over a selection, set ibeam/custom cursor + if (!currentCursor.equals(cursor)) { + currentCursor = cursor; + super.setCursor(cursor); + } + } + } } -/** +/** * Adds the specified style. The new style overwrites existing styles for the - * specified range. Existing style ranges are adjusted if they partially - * overlap with the new style, To clear an individual style, call setStyleRange - * with a StyleRange that has null attributes. + * specified range. Existing style ranges are adjusted if they partially + * overlap with the new style, To clear an individual style, call setStyleRange + * with a StyleRange that has null attributes. *
- * Should not be called if a LineStyleListener has been set since the + * Should not be called if a LineStyleListener has been set since the * listener maintains the styles. *
* @@ -7557,84 +7672,84 @@ *- * Should not be called if a LineStyleListener has been set since the + * Should not be called if a LineStyleListener has been set since the * listener maintains the styles. *
* * @param ranges StyleRange objects containing the style information. - * The ranges should not overlap. The style rendering is undefined if + * The ranges should not overlap. The style rendering is undefined if * the ranges do overlap. Must not be null. * @exception SWTException* * @param tabs tab width measured in characters. @@ -7690,37 +7805,37 @@ *
- * Note: Only a single line of text should be set when the SWT.SINGLE + * Note: Only a single line of text should be set when the SWT.SINGLE * style is used. *
* - * @param text new widget content. Replaces existing content. Line styles - * that were set using StyledText API are discarded. The - * current selection is also discarded. + * @param text new widget content. Replaces existing content. Line styles + * that were set using StyledText API are discarded. The + * current selection is also discarded. * @exception SWTException- * The top index is the index of the line that is currently at the top + * The top index is the index of the line that is currently at the top * of the widget. The top index changes when the widget is scrolled. * Indexing starts from zero. * Note: The top index is reset to 0 when new text is set in the widget. *
* - * @param index new top index. Must be between 0 and - * getLineCount() - fully visible lines per page. If no lines are fully - * visible the maximum value is getLineCount() - 1. An out of range - * index will be adjusted accordingly. + * @param index new top index. Must be between 0 and + * getLineCount() - fully visible lines per page. If no lines are fully + * visible the maximum value is getLineCount() - 1. An out of range + * index will be adjusted accordingly. * @exception SWTException* * @param pixelOffset the new vertical scroll offset - * @param adjustScrollBar - * true= the scroll thumb will be moved to reflect the new scroll offset. - * false = the scroll thumb will not be moved - * @return - * true=the widget was scrolled - * false=the widget was not scrolled, the given offset is not valid. + * @param adjustScrollBar + * true= the scroll thumb will be moved to reflect the new scroll offset. + * false = the scroll thumb will not be moved + * @return + * true=the widget was scrolled + * false=the widget was not scrolled, the given offset is not valid. */ boolean setVerticalScrollOffset(int pixelOffset, boolean adjustScrollBar) { - Rectangle clientArea; - ScrollBar verticalBar = getVerticalBar(); - - if (pixelOffset == verticalScrollOffset) { - return false; - } - if (verticalBar != null && adjustScrollBar) { - verticalBar.setSelection(pixelOffset); - } - clientArea = getClientArea(); - scroll( - 0, 0, // destination x, y - 0, pixelOffset - verticalScrollOffset, // source x, y - clientArea.width, clientArea.height, true); - - verticalScrollOffset = pixelOffset; - calculateTopIndex(); - setCaretLocation(); - return true; + Rectangle clientArea; + ScrollBar verticalBar = getVerticalBar(); + + if (pixelOffset == verticalScrollOffset) { + return false; + } + if (verticalBar != null && adjustScrollBar) { + verticalBar.setSelection(pixelOffset); + } + clientArea = getClientArea(); + scroll( + 0, 0, // destination x, y + 0, pixelOffset - verticalScrollOffset, // source x, y + clientArea.width, clientArea.height, true); + + verticalScrollOffset = pixelOffset; + calculateTopIndex(); + setCaretLocation(); + return true; } /** * Scrolls the specified location into view. *
- * + * * @param x the x coordinate that should be made visible. * @param line the line that should be made visible. Relative to the - * first line in the document. - * @return - * true=the widget was scrolled to make the specified location visible. - * false=the specified location is already visible, the widget was - * not scrolled. + * first line in the document. + * @return + * true=the widget was scrolled to make the specified location visible. + * false=the specified location is already visible, the widget was + * not scrolled. */ boolean showLocation(int x, int line) { - int clientAreaWidth = getClientArea().width - leftMargin - rightMargin; - int verticalIncrement = getVerticalIncrement(); - int horizontalIncrement = clientAreaWidth / 4; - boolean scrolled = false; - - if (x < leftMargin) { - // always make 1/4 of a page visible - x = Math.max(horizontalScrollOffset * -1, x - horizontalIncrement); - scrolled = scrollHorizontalBar(x); - } - else - if (x >= clientAreaWidth) { - // always make 1/4 of a page visible - x = Math.min(lineCache.getWidth() - horizontalScrollOffset, x + horizontalIncrement); - scrolled = scrollHorizontalBar(x - clientAreaWidth); - } - if (line < topIndex) { - scrolled = setVerticalScrollOffset(line * verticalIncrement, true); - } - else - if (line > getBottomIndex()) { - scrolled = setVerticalScrollOffset((line + 1) * verticalIncrement - getClientArea().height, true); - } - return scrolled; + int clientAreaWidth = getClientArea().width - leftMargin - rightMargin; + int verticalIncrement = getVerticalIncrement(); + int horizontalIncrement = clientAreaWidth / 4; + boolean scrolled = false; + + if (x < leftMargin) { + // always make 1/4 of a page visible + x = Math.max(horizontalScrollOffset * -1, x - horizontalIncrement); + scrolled = scrollHorizontalBar(x); + } + else + if (x >= clientAreaWidth) { + // always make 1/4 of a page visible + x = Math.min(lineCache.getWidth() - horizontalScrollOffset, x + horizontalIncrement); + scrolled = scrollHorizontalBar(x - clientAreaWidth); + } + if (line < topIndex) { + scrolled = setVerticalScrollOffset(line * verticalIncrement, true); + } + else + if (line > getBottomIndex()) { + scrolled = setVerticalScrollOffset((line + 1) * verticalIncrement - getClientArea().height, true); + } + return scrolled; } /** * Sets the caret location and scrolls the caret offset into view. */ void showCaret() { - int caretLine = content.getLineAtOffset(caretOffset); - - showCaret(caretLine); + int caretLine = content.getLineAtOffset(caretOffset); + + showCaret(caretLine); } /** * Sets the caret location and scrolls the caret offset into view. */ void showCaret(int caretLine) { - int lineOffset = content.getOffsetAtLine(caretLine); - String lineText = content.getLine(caretLine); - int offsetInLine = caretOffset - lineOffset; - int xAtOffset = getXAtOffset(lineText, caretLine, offsetInLine); - boolean scrolled = showLocation(xAtOffset, caretLine); - boolean setWrapCaretLocation = false; - Caret caret = getCaret(); - - if (wordWrap && caret != null) { - int caretY = caret.getLocation().y; - if ((caretY + verticalScrollOffset) / getVerticalIncrement() - 1 != caretLine) { - setWrapCaretLocation = true; - } - } - if (scrolled == false || setWrapCaretLocation) { - // set the caret location if a scroll operation did not set it (as a - // sideeffect of scrolling) or when in word wrap mode and the caret - // line was explicitly specified (i.e., because getWrapCaretLine does - // not return the desired line causing scrolling to not set it correctly) - setCaretLocation(xAtOffset, caretLine); - } - if (isBidi()) { - setBidiKeyboardLanguage(); - } + int lineOffset = content.getOffsetAtLine(caretLine); + String lineText = content.getLine(caretLine); + int offsetInLine = caretOffset - lineOffset; + int xAtOffset = getXAtOffset(lineText, caretLine, offsetInLine); + boolean scrolled = showLocation(xAtOffset, caretLine); + boolean setWrapCaretLocation = false; + Caret caret = getCaret(); + + if (wordWrap && caret != null) { + int caretY = caret.getLocation().y; + if ((caretY + verticalScrollOffset) / getVerticalIncrement() - 1 != caretLine) { + setWrapCaretLocation = true; + } + } + if (scrolled == false || setWrapCaretLocation) { + // set the caret location if a scroll operation did not set it (as a + // sideeffect of scrolling) or when in word wrap mode and the caret + // line was explicitly specified (i.e., because getWrapCaretLine does + // not return the desired line causing scrolling to not set it correctly) + setCaretLocation(xAtOffset, caretLine); + } + if (isBidi()) { + setBidiKeyboardLanguage(); + } } /** * Scrolls the specified offset into view. @@ -7970,13 +8085,13 @@ * @param offset offset that should be scolled into view */ void showOffset(int offset) { - int line = content.getLineAtOffset(offset); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = offset - lineOffset; - String lineText = content.getLine(line); - int xAtOffset = getXAtOffset(lineText, line, offsetInLine); - - showLocation(xAtOffset, line); + int line = content.getLineAtOffset(offset); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = offset - lineOffset; + String lineText = content.getLine(line); + int xAtOffset = getXAtOffset(lineText, line, offsetInLine); + + showLocation(xAtOffset, line); } /** /** @@ -7991,92 +8106,92 @@ *
- * - * @param isBackspace true=the previous character was deleted, false=the - * character next to the caret location was deleted + * + * @param isBackspace true=the previous character was deleted, false=the + * character next to the caret location was deleted * @param isDirectionBoundary true=the caret is between a R2L and L2R segment, - * false=the caret is within a direction segment + * false=the caret is within a direction segment */ void updateBidiDirection(boolean isBackspace, boolean isDirectionBoundary) { - if (isDirectionBoundary) { - if (isBackspace) { - // Deleted previous character (backspace) at a direction boundary - // Go to direction segment of deleted character - lastCaretDirection = ST.COLUMN_NEXT; - } - else { - // Deleted next character. Go to direction segment of deleted character - lastCaretDirection = ST.COLUMN_PREVIOUS; - } - } - else { - if (isBackspace) { - // Delete previous character inside direction segment (i.e., not at a direction boundary) - lastCaretDirection = ST.COLUMN_PREVIOUS; - } - else { - // Deleted next character. - lastCaretDirection = ST.COLUMN_NEXT; - } - } + if (isDirectionBoundary) { + if (isBackspace) { + // Deleted previous character (backspace) at a direction boundary + // Go to direction segment of deleted character + lastCaretDirection = ST.COLUMN_NEXT; + } + else { + // Deleted next character. Go to direction segment of deleted character + lastCaretDirection = ST.COLUMN_PREVIOUS; + } + } + else { + if (isBackspace) { + // Delete previous character inside direction segment (i.e., not at a direction boundary) + lastCaretDirection = ST.COLUMN_PREVIOUS; + } + else { + // Deleted next character. + lastCaretDirection = ST.COLUMN_NEXT; + } + } } /** * Updates the selection and caret position depending on the text change. - * If the selection intersects with the replaced text, the selection is + * If the selection intersects with the replaced text, the selection is * reset and the caret moved to the end of the new text. * If the selection is behind the replaced text it is moved so that the - * same text remains selected. If the selection is before the replaced text + * same text remains selected. If the selection is before the replaced text * it is left unchanged. *
* @@ -8085,86 +8200,86 @@ * @param newLength length of new text */ void updateSelection(int startOffset, int replacedLength, int newLength) { - if (selection.y <= startOffset) { - // selection ends before text change - return; - } - if (selection.x < startOffset) { - // clear selection fragment before text change - internalRedrawRange(selection.x, startOffset - selection.x, true); - } - if (selection.y > startOffset + replacedLength && selection.x < startOffset + replacedLength) { - // clear selection fragment after text change. - // do this only when the selection is actually affected by the - // change. Selection is only affected if it intersects the change (1GDY217). - int netNewLength = newLength - replacedLength; - int redrawStart = startOffset + newLength; - internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart, true); - } - if (selection.y > startOffset && selection.x < startOffset + replacedLength) { - // selection intersects replaced text. set caret behind text change - internalSetSelection(startOffset + newLength, 0, true); - // always update the caret location. fixes 1G8FODP - setCaretLocation(); - } - else { - // move selection to keep same text selected - internalSetSelection(selection.x + newLength - replacedLength, selection.y - selection.x, true); - // always update the caret location. fixes 1G8FODP - setCaretLocation(); - } + if (selection.y <= startOffset) { + // selection ends before text change + return; + } + if (selection.x < startOffset) { + // clear selection fragment before text change + internalRedrawRange(selection.x, startOffset - selection.x, true); + } + if (selection.y > startOffset + replacedLength && selection.x < startOffset + replacedLength) { + // clear selection fragment after text change. + // do this only when the selection is actually affected by the + // change. Selection is only affected if it intersects the change (1GDY217). + int netNewLength = newLength - replacedLength; + int redrawStart = startOffset + newLength; + internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart, true); + } + if (selection.y > startOffset && selection.x < startOffset + replacedLength) { + // selection intersects replaced text. set caret behind text change + internalSetSelection(startOffset + newLength, 0, true); + // always update the caret location. fixes 1G8FODP + setCaretLocation(); + } + else { + // move selection to keep same text selected + internalSetSelection(selection.x + newLength - replacedLength, selection.y - selection.x, true); + // always update the caret location. fixes 1G8FODP + setCaretLocation(); + } } /** * Rewraps all lines *
- * - * @param oldClientAreaWidth client area width before resize - * occurred + * + * @param oldClientAreaWidth client area width before resize + * occurred */ void wordWrapResize(int oldClientAreaWidth) { - WrappedContent wrappedContent = (WrappedContent) content; - int newTopIndex; + WrappedContent wrappedContent = (WrappedContent) content; + int newTopIndex; - // all lines are wrapped and no rewrap required if widget has already - // been visible, client area is now wider and visual (wrapped) line - // count equals logical line count. - if (oldClientAreaWidth != 0 && clientAreaWidth > oldClientAreaWidth && - wrappedContent.getLineCount() == logicalContent.getLineCount()) { - return; - } + // all lines are wrapped and no rewrap required if widget has already + // been visible, client area is now wider and visual (wrapped) line + // count equals logical line count. + if (oldClientAreaWidth != 0 && clientAreaWidth > oldClientAreaWidth && + wrappedContent.getLineCount() == logicalContent.getLineCount()) { + return; + } wrappedContent.wrapLines(); - + // adjust the top index so that top line remains the same - newTopIndex = content.getLineAtOffset(topOffset); - // topOffset is the beginning of the top line. therefore it - // needs to be adjusted because in a wrapped line this is also - // the end of the preceeding line. - if (newTopIndex < content.getLineCount() - 1 && - topOffset == content.getOffsetAtLine(newTopIndex + 1)) { - newTopIndex++; - } + newTopIndex = content.getLineAtOffset(topOffset); + // topOffset is the beginning of the top line. therefore it + // needs to be adjusted because in a wrapped line this is also + // the end of the preceeding line. + if (newTopIndex < content.getLineCount() - 1 && + topOffset == content.getOffsetAtLine(newTopIndex + 1)) { + newTopIndex++; + } if (newTopIndex != topIndex) { - ScrollBar verticalBar = getVerticalBar(); - // adjust index and pixel offset manually instead of calling - // setVerticalScrollOffset because the widget does not actually need - // to be scrolled. causes flash otherwise. - verticalScrollOffset += (newTopIndex - topIndex) * getVerticalIncrement(); - // verticalScrollOffset may become negative if first line was - // partially visible and second line was top line. prevent this from - // happening to fix 8503. - if (verticalScrollOffset < 0) { - verticalScrollOffset = 0; - } - topIndex = newTopIndex; - topOffset = content.getOffsetAtLine(topIndex); - if (verticalBar != null) { - verticalBar.setSelection(verticalScrollOffset); - } + ScrollBar verticalBar = getVerticalBar(); + // adjust index and pixel offset manually instead of calling + // setVerticalScrollOffset because the widget does not actually need + // to be scrolled. causes flash otherwise. + verticalScrollOffset += (newTopIndex - topIndex) * getVerticalIncrement(); + // verticalScrollOffset may become negative if first line was + // partially visible and second line was top line. prevent this from + // happening to fix 8503. + if (verticalScrollOffset < 0) { + verticalScrollOffset = 0; + } + topIndex = newTopIndex; + topOffset = content.getOffsetAtLine(topIndex); + if (verticalBar != null) { + verticalBar.setSelection(verticalScrollOffset); + } } - // caret may be on a different line after a rewrap. - // call setCaretLocation after fixing vertical scroll offset. - setCaretLocation(); - // word wrap may have changed on one of the visible lines + // caret may be on a different line after a rewrap. + // call setCaretLocation after fixing vertical scroll offset. + setCaretLocation(); + // word wrap may have changed on one of the visible lines super.redraw(); } }