1 11 12 package org.eclipse.ui.console; 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.core.runtime.IProgressMonitor; 18 import org.eclipse.core.runtime.IStatus; 19 import org.eclipse.core.runtime.Status; 20 import org.eclipse.jface.preference.JFacePreferences; 21 import org.eclipse.jface.resource.ColorRegistry; 22 import org.eclipse.jface.resource.JFaceColors; 23 import org.eclipse.jface.resource.JFaceResources; 24 import org.eclipse.jface.text.BadPositionCategoryException; 25 import org.eclipse.jface.text.DocumentEvent; 26 import org.eclipse.jface.text.IDocument; 27 import org.eclipse.jface.text.IDocumentAdapter; 28 import org.eclipse.jface.text.IDocumentListener; 29 import org.eclipse.jface.text.IPositionUpdater; 30 import org.eclipse.jface.text.IRegion; 31 import org.eclipse.jface.text.Position; 32 import org.eclipse.jface.text.source.SourceViewer; 33 import org.eclipse.jface.util.IPropertyChangeListener; 34 import org.eclipse.jface.util.PropertyChangeEvent; 35 import org.eclipse.swt.SWT; 36 import org.eclipse.swt.custom.LineBackgroundEvent; 37 import org.eclipse.swt.custom.LineBackgroundListener; 38 import org.eclipse.swt.custom.LineStyleEvent; 39 import org.eclipse.swt.custom.LineStyleListener; 40 import org.eclipse.swt.custom.StyleRange; 41 import org.eclipse.swt.custom.StyledText; 42 import org.eclipse.swt.events.MouseEvent; 43 import org.eclipse.swt.events.MouseListener; 44 import org.eclipse.swt.events.MouseMoveListener; 45 import org.eclipse.swt.events.MouseTrackListener; 46 import org.eclipse.swt.graphics.Color; 47 import org.eclipse.swt.graphics.Cursor; 48 import org.eclipse.swt.graphics.Font; 49 import org.eclipse.swt.graphics.Point; 50 import org.eclipse.swt.widgets.Composite; 51 import org.eclipse.swt.widgets.Control; 52 import org.eclipse.swt.widgets.Display; 53 import org.eclipse.swt.widgets.Event; 54 import org.eclipse.swt.widgets.Listener; 55 import org.eclipse.ui.internal.console.ConsoleDocumentAdapter; 56 import org.eclipse.ui.internal.console.ConsoleHyperlinkPosition; 57 import org.eclipse.ui.progress.WorkbenchJob; 58 59 67 public class TextConsoleViewer extends SourceViewer implements LineStyleListener, LineBackgroundListener, MouseTrackListener, MouseMoveListener, MouseListener { 68 71 private ConsoleDocumentAdapter documentAdapter; 72 73 private IHyperlink hyperlink; 74 75 private Cursor handCursor; 76 77 private Cursor textCursor; 78 79 private int consoleWidth = -1; 80 81 private TextConsole console; 82 83 private IPropertyChangeListener propertyChangeListener; 84 85 private IDocumentListener documentListener = new IDocumentListener() { 86 public void documentAboutToBeChanged(DocumentEvent event) { 87 } 88 89 public void documentChanged(DocumentEvent event) { 90 updateLinks(event.fOffset); 91 } 92 }; 93 private Listener mouseUpListener = new Listener() { 95 public void handleEvent(Event event) { 96 if (hyperlink != null) { 97 String selection = getTextWidget().getSelectionText(); 98 if (selection.length() <= 0) { 99 if (event.button == 1) { 100 if (hyperlink instanceof IHyperlink2) { 101 ((IHyperlink2) hyperlink).linkActivated(event); 102 } else { 103 hyperlink.linkActivated(); 104 } 105 } 106 } 107 } 108 } 109 }; 110 111 WorkbenchJob revealJob = new WorkbenchJob("Reveal End of Document") { public IStatus runInUIThread(IProgressMonitor monitor) { 113 StyledText textWidget = getTextWidget(); 114 if (textWidget != null && !textWidget.isDisposed()) { 115 int lineCount = textWidget.getLineCount(); 116 textWidget.setTopIndex(lineCount - 1); 117 } 118 return Status.OK_STATUS; 119 } 120 }; 121 122 private IPositionUpdater positionUpdater = new IPositionUpdater() { 123 public void update(DocumentEvent event) { 124 try { 125 IDocument document = getDocument(); 126 if (document != null) { 127 Position[] positions = document.getPositions(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY); 128 for (int i = 0; i < positions.length; i++) { 129 Position position = positions[i]; 130 if (position.offset == event.fOffset && position.length<=event.fLength) { 131 position.delete(); 132 } 133 if (position.isDeleted) { 134 document.removePosition(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY, position); 135 } 136 } 137 } 138 } catch (BadPositionCategoryException e) { 139 } 140 } 141 }; 142 143 151 public TextConsoleViewer(Composite parent, TextConsole console) { 152 super(parent, null, SWT.V_SCROLL | SWT.H_SCROLL); 153 this.console = console; 154 155 IDocument document = console.getDocument(); 156 setDocument(document); 157 158 StyledText styledText = getTextWidget(); 159 styledText.setDoubleClickEnabled(true); 160 styledText.addLineStyleListener(this); 161 styledText.addLineBackgroundListener(this); 162 styledText.setEditable(true); 163 setFont(console.getFont()); 164 styledText.addMouseTrackListener(this); 165 styledText.addListener(SWT.MouseUp, mouseUpListener); 166 167 ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); 168 propertyChangeListener = new HyperlinkColorChangeListener(); 169 colorRegistry.addListener(propertyChangeListener); 170 171 revealJob.setSystem(true); 172 document.addDocumentListener(documentListener); 173 document.addPositionUpdater(positionUpdater); 174 } 175 176 182 public void setTabWidth(int tabWidth) { 183 StyledText styledText = getTextWidget(); 184 int oldWidth = styledText.getTabs(); 185 if (tabWidth != oldWidth) { 186 styledText.setTabs(tabWidth); 187 } 188 } 189 190 196 public void setFont(Font font) { 197 StyledText styledText = getTextWidget(); 198 Font oldFont = styledText.getFont(); 199 if (oldFont == font) { 200 return; 201 } 202 if (font == null || !(font.equals(oldFont))) { 203 styledText.setFont(font); 204 } 205 } 206 207 210 protected void revealEndOfDocument() { 211 revealJob.schedule(50); 212 } 213 214 219 public void lineGetStyle(LineStyleEvent event) { 220 IDocument document = getDocument(); 221 if (document != null && document.getLength() > 0) { 222 ArrayList ranges = new ArrayList (); 223 int offset = event.lineOffset; 224 int length = event.lineText.length(); 225 226 StyleRange[] partitionerStyles = ((IConsoleDocumentPartitioner) document.getDocumentPartitioner()).getStyleRanges(event.lineOffset, event.lineText.length()); 227 if (partitionerStyles != null) { 228 for (int i = 0; i < partitionerStyles.length; i++) { 229 ranges.add(partitionerStyles[i]); 230 } 231 } else { 232 ranges.add(new StyleRange(offset, length, null, null)); 233 } 234 235 try { 236 Position[] positions = getDocument().getPositions(ConsoleHyperlinkPosition.HYPER_LINK_CATEGORY); 237 Position[] overlap = findPosition(offset, length, positions); 238 Color color = JFaceColors.getHyperlinkText(Display.getCurrent()); 239 if (overlap != null) { 240 for (int i = 0; i < overlap.length; i++) { 241 Position position = overlap[i]; 242 StyleRange linkRange = new StyleRange(position.offset, position.length, color, null); 243 linkRange.underline = true; 244 override(ranges, linkRange); 245 } 246 } 247 } catch (BadPositionCategoryException e) { 248 } 249 250 if (ranges.size() > 0) { 251 event.styles = (StyleRange[]) ranges.toArray(new StyleRange[ranges.size()]); 252 } 253 } 254 } 255 256 private void override(List ranges, StyleRange newRange) { 257 if (ranges.isEmpty()) { 258 ranges.add(newRange); 259 return; 260 } 261 262 int start = newRange.start; 263 int end = start + newRange.length; 264 for (int i = 0; i < ranges.size(); i++) { 265 StyleRange existingRange = (StyleRange) ranges.get(i); 266 int rEnd = existingRange.start + existingRange.length; 267 if (end <= existingRange.start || start >= rEnd) { 268 continue; 269 } 270 271 if (start < existingRange.start && end > existingRange.start) { 272 start = existingRange.start; 273 } 274 275 if (start >= existingRange.start && end <= rEnd) { 276 existingRange.length = start - existingRange.start; 277 ranges.add(++i, newRange); 278 if (end != rEnd) { 279 ranges.add(++i, new StyleRange(end, rEnd - end - 1, existingRange.foreground, existingRange.background)); 280 } 281 return; 282 } else if (start >= existingRange.start && start < rEnd) { 283 existingRange.length = start - existingRange.start; 284 ranges.add(++i, newRange); 285 } else if (end >= rEnd) { 286 ranges.remove(i); 287 } else { 288 ranges.add(++i, new StyleRange(end + 1, rEnd - end + 1, existingRange.foreground, existingRange.background)); 289 } 290 } 291 } 292 293 304 private Position[] findPosition(int offset, int length, Position[] positions) { 305 306 if (positions.length == 0) 307 return null; 308 309 int rangeEnd = offset + length; 310 int left = 0; 311 int right = positions.length - 1; 312 int mid = 0; 313 Position position = null; 314 315 while (left < right) { 316 317 mid = (left + right) / 2; 318 319 position = positions[mid]; 320 if (rangeEnd < position.getOffset()) { 321 if (left == mid) 322 right = left; 323 else 324 right = mid - 1; 325 } else if (offset > (position.getOffset() + position.getLength() - 1)) { 326 if (right == mid) 327 left = right; 328 else 329 left = mid + 1; 330 } else { 331 left = right = mid; 332 } 333 } 334 335 List list = new ArrayList (); 336 int index = left - 1; 337 if (index >= 0) { 338 position = positions[index]; 339 while (index >= 0 && (position.getOffset() + position.getLength()) > offset) { 340 index--; 341 if (index > 0) { 342 position = positions[index]; 343 } 344 } 345 } 346 index++; 347 position = positions[index]; 348 while (index < positions.length && (position.getOffset() < rangeEnd)) { 349 list.add(position); 350 index++; 351 if (index < positions.length) { 352 position = positions[index]; 353 } 354 } 355 356 if (list.isEmpty()) { 357 return null; 358 } 359 return (Position[]) list.toArray(new Position[list.size()]); 360 } 361 362 367 public void lineGetBackground(LineBackgroundEvent event) { 368 event.lineBackground = null; 369 } 370 371 376 protected Cursor getHandCursor() { 377 if (handCursor == null) { 378 handCursor = new Cursor(ConsolePlugin.getStandardDisplay(), SWT.CURSOR_HAND); 379 } 380 return handCursor; 381 } 382 383 388 protected Cursor getTextCursor() { 389 if (textCursor == null) { 390 textCursor = new Cursor(ConsolePlugin.getStandardDisplay(), SWT.CURSOR_IBEAM); 391 } 392 return textCursor; 393 } 394 395 401 protected void linkEntered(IHyperlink link) { 402 Control control = getTextWidget(); 403 if (hyperlink != null) { 404 linkExited(hyperlink); 405 } 406 hyperlink = link; 407 hyperlink.linkEntered(); 408 control.setCursor(getHandCursor()); 409 control.redraw(); 410 control.addMouseListener(this); 411 } 412 413 419 protected void linkExited(IHyperlink link) { 420 link.linkExited(); 421 hyperlink = null; 422 Control control = getTextWidget(); 423 control.setCursor(getTextCursor()); 424 control.redraw(); 425 control.removeMouseListener(this); 426 } 427 428 433 public void mouseEnter(MouseEvent e) { 434 getTextWidget().addMouseMoveListener(this); 435 } 436 437 442 public void mouseExit(MouseEvent e) { 443 getTextWidget().removeMouseMoveListener(this); 444 if (hyperlink != null) { 445 linkExited(hyperlink); 446 } 447 } 448 449 454 public void mouseHover(MouseEvent e) { 455 } 456 457 462 public void mouseMove(MouseEvent e) { 463 int offset = -1; 464 try { 465 Point p = new Point(e.x, e.y); 466 offset = getTextWidget().getOffsetAtLocation(p); 467 } catch (IllegalArgumentException ex) { 468 } 470 updateLinks(offset); 471 } 472 473 479 protected void updateLinks(int offset) { 480 if (offset >= 0) { 481 IHyperlink link = getHyperlink(offset); 482 if (link != null) { 483 if (link.equals(hyperlink)) { 484 return; 485 } 486 linkEntered(link); 487 return; 488 } 489 } 490 if (hyperlink != null) { 491 linkExited(hyperlink); 492 } 493 } 494 495 500 public IHyperlink getHyperlink() { 501 return hyperlink; 502 } 503 504 512 public IHyperlink getHyperlink(int offset) { 513 if (offset >= 0 && console != null) { 514 return console.getHyperlink(offset); 515 } 516 return null; 517 } 518 519 524 public void mouseDoubleClick(MouseEvent e) { 525 } 526 527 532 public void mouseDown(MouseEvent e) { 533 } 534 535 540 public void mouseUp(MouseEvent e) { 541 } 542 543 548 protected IDocumentAdapter createDocumentAdapter() { 549 if (documentAdapter == null) { 550 documentAdapter = new ConsoleDocumentAdapter(consoleWidth = -1); 551 } 552 return documentAdapter; 553 } 554 555 562 public void setConsoleWidth(int width) { 563 if (consoleWidth != width) { 564 consoleWidth = width; 565 ConsolePlugin.getStandardDisplay().asyncExec(new Runnable () { 566 public void run() { 567 if (documentAdapter != null) { 568 documentAdapter.setWidth(consoleWidth); 569 } 570 } 571 }); 572 } 573 } 574 575 580 protected void handleDispose() { 581 IDocument document = getDocument(); 582 if (document != null) { 583 document.removeDocumentListener(documentListener); 584 document.removePositionUpdater(positionUpdater); 585 } 586 587 StyledText styledText = getTextWidget(); 588 styledText.removeLineStyleListener(this); 589 styledText.removeLineBackgroundListener(this); 590 styledText.removeMouseTrackListener(this); 591 592 handCursor = null; 593 textCursor = null; 594 hyperlink = null; 595 console = null; 596 597 ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); 598 colorRegistry.removeListener(propertyChangeListener); 599 600 super.handleDispose(); 601 } 602 603 class HyperlinkColorChangeListener implements IPropertyChangeListener { 604 public void propertyChange(PropertyChangeEvent event) { 605 if (event.getProperty().equals(JFacePreferences.ACTIVE_HYPERLINK_COLOR) || event.getProperty().equals(JFacePreferences.HYPERLINK_COLOR)) { 606 getTextWidget().redraw(); 607 } 608 } 609 610 } 611 612 615 protected void updateTextListeners(WidgetCommand cmd) { 616 super.updateTextListeners(cmd); 617 cmd.preservedText = null; 618 cmd.event = null; 619 cmd.text = null; 620 } 621 622 protected void internalRevealRange(int start, int end) { 623 StyledText textWidget = getTextWidget(); 624 int startLine = documentAdapter.getLineAtOffset(start); 625 int endLine = documentAdapter.getLineAtOffset(end); 626 627 int top = textWidget.getTopIndex(); 628 if (top > -1) { 629 int lines = getVisibleLinesInViewport(); 631 int bottom = top + lines; 632 633 int bufferZone = 2; 637 if (startLine >= top + bufferZone && startLine <= bottom - bufferZone && endLine >= top + bufferZone && endLine <= bottom - bufferZone) { 638 639 } else { 641 int delta = Math.max(0, lines - (endLine - startLine)); 642 textWidget.setTopIndex(startLine - delta / 3); 643 updateViewportListeners(INTERNAL); 644 } 645 646 if (endLine < startLine) { 648 endLine += startLine; 649 startLine = endLine - startLine; 650 endLine -= startLine; 651 } 652 653 int startPixel = -1; 654 int endPixel = -1; 655 656 if (endLine > startLine) { 657 IRegion extent = getExtent(start, start); 659 startPixel = extent.getOffset() + textWidget.getHorizontalPixel(); 660 endPixel = startPixel; 661 } else { 662 IRegion extent = getExtent(start, end); 663 startPixel = extent.getOffset() + textWidget.getHorizontalPixel(); 664 endPixel = startPixel + extent.getLength(); 665 } 666 667 int visibleStart = textWidget.getHorizontalPixel(); 668 int visibleEnd = visibleStart + textWidget.getClientArea().width; 669 670 if (startPixel < visibleStart || visibleEnd < endPixel) { 672 bufferZone = 10; 674 int newOffset = visibleStart; 675 int visibleWidth = visibleEnd - visibleStart; 676 int selectionPixelWidth = endPixel - startPixel; 677 678 if (startPixel < visibleStart) 679 newOffset = startPixel; 680 else if (selectionPixelWidth + bufferZone < visibleWidth) 681 newOffset = endPixel + bufferZone - visibleWidth; 682 else 683 newOffset = startPixel; 684 685 float index = ((float) newOffset) / ((float) getAverageCharWidth()); 686 687 textWidget.setHorizontalIndex(Math.round(index)); 688 } 689 690 } 691 } 692 693 } 694 | Popular Tags |