1 11 package org.eclipse.swt.custom; 12 13 14 import org.eclipse.swt.*; 15 import org.eclipse.swt.graphics.*; 16 17 33 class WrappedContent implements StyledTextContent { 34 final static int LINE_OFFSET = 0; final static int LINE_LENGTH = 1; 37 StyledTextRenderer renderer; 38 StyledTextContent logicalContent; 39 int[][] visualLines; int visualLineCount = 0; 41 42 50 WrappedContent(StyledTextRenderer renderer, StyledTextContent logicalContent) { 51 this.renderer = renderer; 52 this.logicalContent = logicalContent; 53 } 54 57 public void addTextChangeListener(TextChangeListener listener) { 58 logicalContent.addTextChangeListener(listener); 59 } 60 67 private void ensureSize(int numLines) { 68 int size = visualLines.length; 69 if (size >= numLines) { 70 return; 71 } 72 int[][] newLines = new int[Math.max(size * 2, numLines)][2]; 73 System.arraycopy(visualLines, 0, newLines, 0, size); 74 visualLines = newLines; 75 resetVisualLines(size, visualLines.length - size); 76 } 77 80 public int getCharCount() { 81 return logicalContent.getCharCount(); 82 } 83 87 public String getLine(int lineIndex) { 88 String line; 89 90 if (visualLineCount == 0) { 92 line = logicalContent.getLine(lineIndex); 93 } 94 else { 95 if (lineIndex >= visualLineCount || lineIndex < 0) { 96 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 97 } 98 line = logicalContent.getTextRange(visualLines[lineIndex][LINE_OFFSET], visualLines[lineIndex][LINE_LENGTH]); 99 } 100 return line; 101 } 102 118 public int getLineAtOffset(int offset) { 119 int lastLine = visualLineCount - 1; 120 int lastChar; 121 122 if (visualLineCount == 0) { 124 return logicalContent.getLineAtOffset(offset); 125 } 126 lastChar = visualLines[lastLine][LINE_OFFSET] + visualLines[lastLine][LINE_LENGTH]; 132 if (offset < 0 || (offset > 0 && offset > lastChar)) { 133 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 134 } 135 if (offset == lastChar) { 139 return lastLine; 140 } 141 142 int high = visualLineCount; 143 int low = -1; 144 int index = visualLineCount; 145 while (high - low > 1) { 146 index = (high + low) / 2; 147 int lineStart = visualLines[index][LINE_OFFSET]; 148 if (offset >= lineStart) { 149 int lineEnd = lineStart + visualLines[index][LINE_LENGTH]; 150 low = index; 151 if (offset <= lineEnd) { 152 break; 153 } 154 } 155 else { 156 high = index; 157 } 158 } 159 if (low > 0 && offset == visualLines[low - 1][LINE_OFFSET] + visualLines[low - 1][LINE_LENGTH]) { 160 low--; 163 } 164 return low; 165 } 166 170 public int getLineCount() { 171 int lineCount = visualLineCount; 172 173 if (visualLineCount == 0) { 175 lineCount = logicalContent.getLineCount(); 176 } 177 return lineCount; 178 } 179 182 public String getLineDelimiter() { 183 return logicalContent.getLineDelimiter(); 184 } 185 190 public int getOffsetAtLine(int lineIndex) { 191 int offset; 192 193 if (visualLineCount == 0) { 195 offset = logicalContent.getOffsetAtLine(lineIndex); 196 } 197 else { 198 if (lineIndex >= visualLineCount || lineIndex < 0) { 199 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 200 } 201 offset = visualLines[lineIndex][LINE_OFFSET]; 202 } 203 return offset; 204 } 205 208 public String getTextRange(int start, int length) { 209 return logicalContent.getTextRange(start, length); 210 } 211 216 int getVisualLineCount() { 217 return visualLineCount; 218 } 219 222 public void removeTextChangeListener(TextChangeListener listener) { 223 logicalContent.removeTextChangeListener(listener); 224 } 225 237 void reset(int startLine, int lineCount) { 238 if (lineCount <= 0 || visualLineCount == 0) { 239 return; 240 } 241 reset(startLine, lineCount, true); 242 } 243 257 private int reset(int startLine, int lineCount, boolean wrap) { 258 if (lineCount <= 0) { 259 return startLine; 260 } 261 int visualFirstLineOffset = getOffsetAtLine(startLine); 265 int logicalFirstLine = logicalContent.getLineAtOffset(visualFirstLineOffset); 266 int logicalFirstLineOffset = logicalContent.getOffsetAtLine(logicalFirstLine); 267 int visualFirstLine = getLineAtOffset(logicalFirstLineOffset); 268 269 lineCount += startLine - visualFirstLine; 270 startLine = visualFirstLine; 271 272 int lastLine = startLine + lineCount - 1; 275 int lastLineEnd = visualLines[lastLine][LINE_OFFSET] + visualLines[lastLine][LINE_LENGTH]; 276 int logicalEndLine = 0; 277 278 while (lastLine < visualLineCount - 1 && lastLineEnd == visualLines[lastLine + 1][LINE_OFFSET]) { 279 lastLine++; 280 lastLineEnd = visualLines[lastLine][LINE_OFFSET] + visualLines[lastLine][LINE_LENGTH]; 281 } 282 if (wrap) { 283 if (lastLine == visualLineCount - 1) { 284 logicalEndLine = logicalContent.getLineCount(); 285 } 286 else { 287 logicalEndLine = logicalContent.getLineAtOffset(visualLines[lastLine + 1][LINE_OFFSET]); 288 } 289 } 290 lineCount = lastLine - startLine + 1; 291 resetVisualLines(startLine, lineCount); 292 visualLineCount -= lineCount; 293 if (wrap) { 294 wrapLineRange(logicalFirstLine, logicalEndLine, startLine); 298 } 299 return startLine; 300 } 301 308 private void resetVisualLines(int startLine, int lineCount) { 309 int endLine = startLine + lineCount; 310 311 for (int i = startLine; i < endLine; i++) { 312 visualLines[i] = new int[] {-1, -1}; 313 } 314 } 315 318 public void replaceTextRange(int start, int replaceLength, String text) { 319 logicalContent.replaceTextRange(start, replaceLength, text); 320 } 321 324 public void setText(String text) { 325 logicalContent.setText(text); 326 } 327 336 private void setVisualLine(int visualLineIndex, int visualLineOffset, int visualLineLength) { 337 ensureSize(visualLineCount + 1); 338 if (visualLines[visualLineIndex][LINE_OFFSET] != -1) { 341 System.arraycopy(visualLines, visualLineIndex, visualLines, visualLineIndex + 1, visualLineCount - visualLineIndex); 342 visualLines[visualLineIndex] = new int[2]; 343 } 344 visualLines[visualLineIndex][LINE_OFFSET] = visualLineOffset; 345 visualLines[visualLineIndex][LINE_LENGTH] = visualLineLength; 346 visualLineCount++; 347 } 348 359 void textChanged(int startOffset, int newLineCount, int replaceLineCount, int newCharCount, int replaceCharCount) { 360 if (visualLineCount == 0) { 362 return; 363 } 364 int logicalStartLine = logicalContent.getLineAtOffset(startOffset); 365 int visualStartLine = getLineAtOffset(startOffset); 366 int visualReplaceLastLine = visualLineCount - 1; 367 int textChangeDelta = newCharCount - replaceCharCount; 368 369 if (replaceLineCount > 0) { 370 visualReplaceLastLine = getLineAtOffset(startOffset + replaceCharCount); 371 if ((visualReplaceLastLine == 0 || 373 visualLines[visualReplaceLastLine][LINE_OFFSET] == visualLines[visualReplaceLastLine - 1][LINE_OFFSET] + visualLines[visualReplaceLastLine - 1][LINE_LENGTH]) && 374 visualReplaceLastLine != visualLineCount - 1) { 375 visualReplaceLastLine++; 376 } 377 visualStartLine = reset(visualStartLine, visualReplaceLastLine - visualStartLine + 1, false); 378 } 379 else { 380 visualStartLine = reset(visualStartLine, 1, false); 381 } 382 visualReplaceLastLine = wrapLineRange(logicalStartLine, logicalStartLine + 1 + newLineCount, visualStartLine); 383 for (int i = visualReplaceLastLine; i < visualLineCount; i++) { 384 visualLines[i][LINE_OFFSET] += textChangeDelta; 385 } 386 } 387 398 private int wrapLineRange(int startLine, int endLine, int visualLineIndex) { 399 int emptyLineCount = 0; 400 401 int width = renderer.getClientArea().width - renderer.getLeftMargin() - renderer.getRightMargin(); 402 visualLineIndex = wrapLineRange(startLine, endLine, visualLineIndex, width); 403 for (int i = visualLineIndex; i < visualLines.length; i++, emptyLineCount++) { 406 if (visualLines[i][LINE_OFFSET] != -1) { 407 break; 408 } 409 } 410 if (emptyLineCount > 0) { 411 int copyLineCount = visualLineCount - visualLineIndex; 412 System.arraycopy(visualLines, visualLineIndex + emptyLineCount, visualLines, visualLineIndex, copyLineCount); 413 resetVisualLines(visualLineIndex + copyLineCount, emptyLineCount); 414 } 415 return visualLineIndex; 416 } 417 429 private int wrapLineRange(int startLine, int endLine, int visualLineIndex, int width) { 430 if (visualLineCount == 0 && width == 0) { 434 return visualLineIndex; 435 } 436 437 for (int i = startLine; i < endLine; i++) { 438 String line = logicalContent.getLine(i); 439 int lineOffset = logicalContent.getOffsetAtLine(i); 440 int lineLength = line.length(); 441 if (lineLength == 0) { 442 setVisualLine(visualLineIndex, lineOffset, 0); 443 visualLineIndex++; 444 continue; 445 } 446 TextLayout layout = renderer.getTextLayout(line, lineOffset); 447 layout.setWidth(Math.max(1, width)); 448 int[] offsets = layout.getLineOffsets(); 449 for (int j = 0; j < offsets.length - 1; j++) { 450 setVisualLine(visualLineIndex++, lineOffset + offsets[j], offsets[j+1] - offsets[j]); 451 } 452 renderer.disposeTextLayout(layout); 453 } 454 return visualLineIndex; 455 } 456 460 void wrapLines() { 461 int width = renderer.getClientArea().width - renderer.getLeftMargin() - renderer.getRightMargin(); 462 wrapLines(width); 463 } 464 470 void wrapLines(int width) { 471 int lineCount = logicalContent.getLineCount(); 472 473 visualLineCount = 0; 474 visualLines = new int[lineCount][2]; 475 resetVisualLines(0, visualLines.length); 476 wrapLineRange(0, lineCount, 0, width); 477 } 478 } 479 | Popular Tags |