📄 styledtext.java
字号:
*/ 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 StyledTextContent content; // content to use for line width calculation 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 <code>ContentWidthCache</code> and allocates space * for the given number of lines. * <p> * * @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, StyledTextContent content) { this.parent = parent; this.content = content; this.lineCount = content.getLineCount(); 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, * <p> * * @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) { int caretWidth = 0; int endLine = startLine + lineCount; if (startLine < 0 || endLine > lineWidth.length) { return; } caretWidth = getCaretWidth(); for (int i = startLine; i < endLine; i++) { if (lineWidth[i] == -1) { String line = content.getLine(i); int lineOffset = content.getOffsetAtLine(i); lineWidth[i] = contentWidth(line, lineOffset) + caretWidth; } if (lineWidth[i] > maxWidth) { maxWidth = lineWidth[i]; maxWidthLineIndex = i; } } } /** * Calculates the width of the visible lines in the specified * range. * <p> * * @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. * <p> * * @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) { TextLayout layout = renderer.getTextLayout(line, lineOffset); Rectangle rect = layout.getLineBounds(0); renderer.disposeTextLayout(layout); return rect.x + rect.width + leftMargin + rightMargin; } /** * Grows the <code>lineWidth</code> array to accomodate new line width * information. * <p> * * @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. * <p> * * @return the width of the longest measured line. */ public int getWidth() { return maxWidth; } /** * Updates the line width array to reflect inserted or deleted lines. * <p> * * @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. * <p> * * @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. * <p> * * @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. * <p> * * @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 <code>reset</code> or <code>redrawReset</code> * is called, the line wrapping is recalculated immediately * instead of in <code>calculate</code>. */ class WordWrapCache implements LineCache { StyledText parent; WrappedContent visualContent; /** * Creates a new <code>WordWrapCache</code> and calculates an initial * line wrapping. * <p> * * @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. * <p> * * @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. * <p> * * @return the line width */ public int getWidth() { return parent.getClientArea().width; } /** * Wraps the lines in the specified range. * This method is called in <code>StyledText.redraw()</code>. * A redraw is therefore not necessary. * <p> * * @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. * <p> * * @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. * <p> * * @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 we are wrapping then it is possible for a deletion on the last // line of text to shorten the total text length by a line. If this // occurs then the startIndex must be adjusted such that a redraw will // be performed if a visible region is affected. fixes bug 42947. if (wordWrap) { int lineCount = content.getLineCount(); if (startLine >= lineCount) startLine = lineCount - 1; } if (startLine <= getPartialBottomIndex()) { // only redraw if the text change affects text 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 * and a style value describing its behavior and appearance. * <p> * The style value is either one of the style constants defined in * class <code>SWT</code> which is applicable to instances of this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -