1 11 12 package org.eclipse.jdt.internal.ui.javaeditor; 13 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.List ; 17 18 import org.eclipse.swt.custom.StyleRange; 19 20 import org.eclipse.jface.text.BadLocationException; 21 import org.eclipse.jface.text.BadPositionCategoryException; 22 import org.eclipse.jface.text.DocumentEvent; 23 import org.eclipse.jface.text.IDocument; 24 import org.eclipse.jface.text.IDocumentListener; 25 import org.eclipse.jface.text.IPositionUpdater; 26 import org.eclipse.jface.text.IRegion; 27 import org.eclipse.jface.text.ISynchronizable; 28 import org.eclipse.jface.text.ITextInputListener; 29 import org.eclipse.jface.text.ITextPresentationListener; 30 import org.eclipse.jface.text.Position; 31 import org.eclipse.jface.text.Region; 32 import org.eclipse.jface.text.TextPresentation; 33 34 import org.eclipse.jdt.internal.ui.JavaPlugin; 35 import org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingManager.HighlightedPosition; 36 import org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingManager.Highlighting; 37 import org.eclipse.jdt.internal.ui.text.JavaPresentationReconciler; 38 39 40 45 public class SemanticHighlightingPresenter implements ITextPresentationListener, ITextInputListener, IDocumentListener { 46 47 50 private class HighlightingPositionUpdater implements IPositionUpdater { 51 52 53 private final String fCategory; 54 55 60 public HighlightingPositionUpdater(String category) { 61 fCategory= category; 62 } 63 64 67 public void update(DocumentEvent event) { 68 69 int eventOffset= event.getOffset(); 70 int eventOldLength= event.getLength(); 71 int eventEnd= eventOffset + eventOldLength; 72 73 try { 74 Position[] positions= event.getDocument().getPositions(fCategory); 75 76 for (int i= 0; i != positions.length; i++) { 77 78 HighlightedPosition position= (HighlightedPosition) positions[i]; 79 80 84 int offset= position.getOffset(); 85 int length= position.getLength(); 86 int end= offset + length; 87 88 if (offset > eventEnd) 89 updateWithPrecedingEvent(position, event); 90 else if (end < eventOffset) 91 updateWithSucceedingEvent(position, event); 92 else if (offset <= eventOffset && end >= eventEnd) 93 updateWithIncludedEvent(position, event); 94 else if (offset <= eventOffset) 95 updateWithOverEndEvent(position, event); 96 else if (end >= eventEnd) 97 updateWithOverStartEvent(position, event); 98 else 99 updateWithIncludingEvent(position, event); 100 } 101 } catch (BadPositionCategoryException e) { 102 } 104 } 105 106 112 private void updateWithPrecedingEvent(HighlightedPosition position, DocumentEvent event) { 113 String newText= event.getText(); 114 int eventNewLength= newText != null ? newText.length() : 0; 115 int deltaLength= eventNewLength - event.getLength(); 116 117 position.setOffset(position.getOffset() + deltaLength); 118 } 119 120 126 private void updateWithSucceedingEvent(HighlightedPosition position, DocumentEvent event) { 127 } 128 129 135 private void updateWithIncludedEvent(HighlightedPosition position, DocumentEvent event) { 136 int eventOffset= event.getOffset(); 137 String newText= event.getText(); 138 if (newText == null) 139 newText= ""; int eventNewLength= newText.length(); 141 142 int deltaLength= eventNewLength - event.getLength(); 143 144 int offset= position.getOffset(); 145 int length= position.getLength(); 146 int end= offset + length; 147 148 int includedLength= 0; 149 while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength))) 150 includedLength++; 151 if (includedLength == eventNewLength) 152 position.setLength(length + deltaLength); 153 else { 154 int newLeftLength= eventOffset - offset + includedLength; 155 156 int excludedLength= eventNewLength; 157 while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1))) 158 excludedLength--; 159 int newRightOffset= eventOffset + excludedLength; 160 int newRightLength= end + deltaLength - newRightOffset; 161 162 if (newRightLength == 0) { 163 position.setLength(newLeftLength); 164 } else { 165 if (newLeftLength == 0) { 166 position.update(newRightOffset, newRightLength); 167 } else { 168 position.setLength(newLeftLength); 169 addPositionFromUI(newRightOffset, newRightLength, position.getHighlighting()); 170 } 171 } 172 } 173 } 174 175 181 private void updateWithOverEndEvent(HighlightedPosition position, DocumentEvent event) { 182 String newText= event.getText(); 183 if (newText == null) 184 newText= ""; int eventNewLength= newText.length(); 186 187 int includedLength= 0; 188 while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength))) 189 includedLength++; 190 position.setLength(event.getOffset() - position.getOffset() + includedLength); 191 } 192 193 199 private void updateWithOverStartEvent(HighlightedPosition position, DocumentEvent event) { 200 int eventOffset= event.getOffset(); 201 int eventEnd= eventOffset + event.getLength(); 202 203 String newText= event.getText(); 204 if (newText == null) 205 newText= ""; int eventNewLength= newText.length(); 207 208 int excludedLength= eventNewLength; 209 while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1))) 210 excludedLength--; 211 int deleted= eventEnd - position.getOffset(); 212 int inserted= eventNewLength - excludedLength; 213 position.update(eventOffset + excludedLength, position.getLength() - deleted + inserted); 214 } 215 216 222 private void updateWithIncludingEvent(HighlightedPosition position, DocumentEvent event) { 223 position.delete(); 224 position.update(event.getOffset(), 0); 225 } 226 } 227 228 229 private IPositionUpdater fPositionUpdater= new HighlightingPositionUpdater(getPositionCategory()); 230 231 232 private JavaSourceViewer fSourceViewer; 233 234 private JavaPresentationReconciler fPresentationReconciler; 235 236 237 private List fPositions= new ArrayList (); 238 239 private Object fPositionLock= new Object (); 240 241 242 private boolean fIsCanceled= false; 243 244 255 public HighlightedPosition createHighlightedPosition(int offset, int length, Highlighting highlighting) { 256 return new HighlightedPosition(offset, length, highlighting, fPositionUpdater); 258 } 259 260 268 public void addAllPositions(List list) { 269 synchronized (fPositionLock) { 270 list.addAll(fPositions); 271 } 272 } 273 274 284 public TextPresentation createPresentation(List addedPositions, List removedPositions) { 285 JavaSourceViewer sourceViewer= fSourceViewer; 286 JavaPresentationReconciler presentationReconciler= fPresentationReconciler; 287 if (sourceViewer == null || presentationReconciler == null) 288 return null; 289 290 if (isCanceled()) 291 return null; 292 293 IDocument document= sourceViewer.getDocument(); 294 if (document == null) 295 return null; 296 297 int minStart= Integer.MAX_VALUE; 298 int maxEnd= Integer.MIN_VALUE; 299 for (int i= 0, n= removedPositions.size(); i < n; i++) { 300 Position position= (Position) removedPositions.get(i); 301 int offset= position.getOffset(); 302 minStart= Math.min(minStart, offset); 303 maxEnd= Math.max(maxEnd, offset + position.getLength()); 304 } 305 for (int i= 0, n= addedPositions.size(); i < n; i++) { 306 Position position= (Position) addedPositions.get(i); 307 int offset= position.getOffset(); 308 minStart= Math.min(minStart, offset); 309 maxEnd= Math.max(maxEnd, offset + position.getLength()); 310 } 311 312 if (minStart < maxEnd) 313 try { 314 return presentationReconciler.createRepairDescription(new Region(minStart, maxEnd - minStart), document); 315 } catch (RuntimeException e) { 316 } 318 319 return null; 320 } 321 322 332 public Runnable createUpdateRunnable(final TextPresentation textPresentation, List addedPositions, List removedPositions) { 333 if (fSourceViewer == null || textPresentation == null) 334 return null; 335 336 final HighlightedPosition[] added= new SemanticHighlightingManager.HighlightedPosition[addedPositions.size()]; 338 addedPositions.toArray(added); 339 final SemanticHighlightingManager.HighlightedPosition[] removed= new SemanticHighlightingManager.HighlightedPosition[removedPositions.size()]; 340 removedPositions.toArray(removed); 341 342 if (isCanceled()) 343 return null; 344 345 Runnable runnable= new Runnable () { 346 public void run() { 347 updatePresentation(textPresentation, added, removed); 348 } 349 }; 350 return runnable; 351 } 352 353 363 public void updatePresentation(TextPresentation textPresentation, HighlightedPosition[] addedPositions, HighlightedPosition[] removedPositions) { 364 if (fSourceViewer == null) 365 return; 366 367 371 if (isCanceled()) 374 return; 375 376 IDocument document= fSourceViewer.getDocument(); 377 if (document == null) 378 return; 379 380 String positionCategory= getPositionCategory(); 381 382 List removedPositionsList= Arrays.asList(removedPositions); 383 384 try { 385 synchronized (fPositionLock) { 386 List oldPositions= fPositions; 387 int newSize= Math.max(fPositions.size() + addedPositions.length - removedPositions.length, 10); 388 389 396 List newPositions= new ArrayList (newSize); 397 Position position= null; 398 Position addedPosition= null; 399 for (int i= 0, j= 0, n= oldPositions.size(), m= addedPositions.length; i < n || position != null || j < m || addedPosition != null;) { 400 402 while (position == null && i < n) { 404 position= (Position) oldPositions.get(i++); 405 if (position.isDeleted() || contain(removedPositionsList, position)) { 406 document.removePosition(positionCategory, position); 407 position= null; 408 } 409 } 410 411 if (addedPosition == null && j < m) { 413 addedPosition= addedPositions[j++]; 414 document.addPosition(positionCategory, addedPosition); 415 } 416 417 if (position != null) { 419 if (addedPosition != null) 420 if (position.getOffset() <= addedPosition.getOffset()) { 421 newPositions.add(position); 422 position= null; 423 } else { 424 newPositions.add(addedPosition); 425 addedPosition= null; 426 } 427 else { 428 newPositions.add(position); 429 position= null; 430 } 431 } else if (addedPosition != null) { 432 newPositions.add(addedPosition); 433 addedPosition= null; 434 } 435 } 436 fPositions= newPositions; 437 } 438 } catch (BadPositionCategoryException e) { 439 JavaPlugin.log(e); 441 } catch (BadLocationException e) { 442 JavaPlugin.log(e); 444 } 445 447 if (textPresentation != null) 448 fSourceViewer.changeTextPresentation(textPresentation, false); 449 else 450 fSourceViewer.invalidateTextPresentation(); 451 } 452 453 462 468 private boolean contain(List positions, Position position) { 469 return indexOf(positions, position) != -1; 470 } 471 472 478 private int indexOf(List positions, Position position) { 479 int index= computeIndexAtOffset(positions, position.getOffset()); 480 int size= positions.size(); 481 while (index < size) { 482 if (positions.get(index) == position) 483 return index; 484 index++; 485 } 486 return -1; 487 } 488 489 494 private void insertPosition(Position position) { 495 int i= computeIndexAfterOffset(fPositions, position.getOffset()); 496 fPositions.add(i, position); 497 } 498 499 506 private int computeIndexAfterOffset(List positions, int offset) { 507 int i= -1; 508 int j= positions.size(); 509 while (j - i > 1) { 510 int k= (i + j) >> 1; 511 Position position= (Position) positions.get(k); 512 if (position.getOffset() > offset) 513 j= k; 514 else 515 i= k; 516 } 517 return j; 518 } 519 520 527 private int computeIndexAtOffset(List positions, int offset) { 528 int i= -1; 529 int j= positions.size(); 530 while (j - i > 1) { 531 int k= (i + j) >> 1; 532 Position position= (Position) positions.get(k); 533 if (position.getOffset() >= offset) 534 j= k; 535 else 536 i= k; 537 } 538 return j; 539 } 540 541 544 public void applyTextPresentation(TextPresentation textPresentation) { 545 IRegion region= textPresentation.getExtent(); 546 int i= computeIndexAtOffset(fPositions, region.getOffset()), n= computeIndexAtOffset(fPositions, region.getOffset() + region.getLength()); 547 if (n - i > 2) { 548 List ranges= new ArrayList (n - i); 549 for (; i < n; i++) { 550 HighlightedPosition position= (HighlightedPosition) fPositions.get(i); 551 if (!position.isDeleted()) 552 ranges.add(position.createStyleRange()); 553 } 554 StyleRange[] array= new StyleRange[ranges.size()]; 555 array= (StyleRange[]) ranges.toArray(array); 556 textPresentation.replaceStyleRanges(array); 557 } else { 558 for (; i < n; i++) { 559 HighlightedPosition position= (HighlightedPosition) fPositions.get(i); 560 if (!position.isDeleted()) 561 textPresentation.replaceStyleRange(position.createStyleRange()); 562 } 563 } 564 } 565 566 569 public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { 570 setCanceled(true); 571 releaseDocument(oldInput); 572 resetState(); 573 } 574 575 578 public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { 579 manageDocument(newInput); 580 } 581 582 585 public void documentAboutToBeChanged(DocumentEvent event) { 586 setCanceled(true); 587 } 588 589 592 public void documentChanged(DocumentEvent event) { 593 } 594 595 601 public boolean isCanceled() { 602 IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null; 603 if (document == null) 604 return fIsCanceled; 605 606 synchronized (getLockObject(document)) { 607 return fIsCanceled; 608 } 609 } 610 611 616 public void setCanceled(boolean isCanceled) { 617 IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null; 618 if (document == null) { 619 fIsCanceled= isCanceled; 620 return; 621 } 622 623 synchronized (getLockObject(document)) { 624 fIsCanceled= isCanceled; 625 } 626 } 627 628 632 private Object getLockObject(IDocument document) { 633 if (document instanceof ISynchronizable) { 634 Object lock= ((ISynchronizable)document).getLockObject(); 635 if (lock != null) 636 return lock; 637 } 638 return document; 639 } 640 641 650 public void install(JavaSourceViewer sourceViewer, JavaPresentationReconciler backgroundPresentationReconciler) { 651 fSourceViewer= sourceViewer; 652 fPresentationReconciler= backgroundPresentationReconciler; 653 654 fSourceViewer.prependTextPresentationListener(this); 655 fSourceViewer.addTextInputListener(this); 656 manageDocument(fSourceViewer.getDocument()); 657 } 658 659 662 public void uninstall() { 663 setCanceled(true); 664 665 if (fSourceViewer != null) { 666 fSourceViewer.removeTextPresentationListener(this); 667 releaseDocument(fSourceViewer.getDocument()); 668 invalidateTextPresentation(); 669 resetState(); 670 671 fSourceViewer.removeTextInputListener(this); 672 fSourceViewer= null; 673 } 674 } 675 676 681 public void highlightingStyleChanged(Highlighting highlighting) { 682 for (int i= 0, n= fPositions.size(); i < n; i++) { 683 HighlightedPosition position= (HighlightedPosition) fPositions.get(i); 684 if (position.getHighlighting() == highlighting) 685 fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength()); 686 } 687 } 688 689 692 private void invalidateTextPresentation() { 693 for (int i= 0, n= fPositions.size(); i < n; i++) { 694 Position position= (Position) fPositions.get(i); 695 fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength()); 696 } 697 } 698 699 707 private void addPositionFromUI(int offset, int length, Highlighting highlighting) { 708 Position position= createHighlightedPosition(offset, length, highlighting); 709 synchronized (fPositionLock) { 710 insertPosition(position); 711 } 712 713 IDocument document= fSourceViewer.getDocument(); 714 if (document == null) 715 return; 716 String positionCategory= getPositionCategory(); 717 try { 718 document.addPosition(positionCategory, position); 719 } catch (BadLocationException e) { 720 JavaPlugin.log(e); 722 } catch (BadPositionCategoryException e) { 723 JavaPlugin.log(e); 725 } 726 } 727 728 731 private void resetState() { 732 synchronized (fPositionLock) { 733 fPositions.clear(); 734 } 735 } 736 737 742 private void manageDocument(IDocument document) { 743 if (document != null) { 744 document.addPositionCategory(getPositionCategory()); 745 document.addPositionUpdater(fPositionUpdater); 746 document.addDocumentListener(this); 747 } 748 } 749 750 755 private void releaseDocument(IDocument document) { 756 if (document != null) { 757 document.removeDocumentListener(this); 758 document.removePositionUpdater(fPositionUpdater); 759 try { 760 document.removePositionCategory(getPositionCategory()); 761 } catch (BadPositionCategoryException e) { 762 JavaPlugin.log(e); 764 } 765 } 766 } 767 768 771 private String getPositionCategory() { 772 return toString(); 773 } 774 } 775 | Popular Tags |