1 11 package org.eclipse.jdt.internal.ui.text.folding; 12 13 import java.util.ArrayList ; 14 import java.util.Collection ; 15 import java.util.Collections ; 16 import java.util.Comparator ; 17 import java.util.HashMap ; 18 import java.util.Iterator ; 19 import java.util.LinkedHashMap ; 20 import java.util.LinkedList ; 21 import java.util.List ; 22 import java.util.Map ; 23 24 import org.eclipse.jface.preference.IPreferenceStore; 25 26 import org.eclipse.jface.text.Assert; 27 import org.eclipse.jface.text.BadLocationException; 28 import org.eclipse.jface.text.IDocument; 29 import org.eclipse.jface.text.IRegion; 30 import org.eclipse.jface.text.Position; 31 import org.eclipse.jface.text.Region; 32 import org.eclipse.jface.text.source.Annotation; 33 import org.eclipse.jface.text.source.IAnnotationModel; 34 import org.eclipse.jface.text.source.projection.IProjectionListener; 35 import org.eclipse.jface.text.source.projection.IProjectionPosition; 36 import org.eclipse.jface.text.source.projection.ProjectionAnnotation; 37 import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; 38 import org.eclipse.jface.text.source.projection.ProjectionViewer; 39 40 import org.eclipse.ui.texteditor.IDocumentProvider; 41 import org.eclipse.ui.texteditor.ITextEditor; 42 43 import org.eclipse.jdt.core.ElementChangedEvent; 44 import org.eclipse.jdt.core.ICompilationUnit; 45 import org.eclipse.jdt.core.IElementChangedListener; 46 import org.eclipse.jdt.core.IJavaElement; 47 import org.eclipse.jdt.core.IJavaElementDelta; 48 import org.eclipse.jdt.core.IMember; 49 import org.eclipse.jdt.core.IParent; 50 import org.eclipse.jdt.core.ISourceRange; 51 import org.eclipse.jdt.core.ISourceReference; 52 import org.eclipse.jdt.core.IType; 53 import org.eclipse.jdt.core.JavaCore; 54 import org.eclipse.jdt.core.JavaModelException; 55 import org.eclipse.jdt.core.ToolFactory; 56 import org.eclipse.jdt.core.compiler.IScanner; 57 import org.eclipse.jdt.core.compiler.ITerminalSymbols; 58 import org.eclipse.jdt.core.compiler.InvalidInputException; 59 60 import org.eclipse.jdt.ui.IWorkingCopyManager; 61 import org.eclipse.jdt.ui.PreferenceConstants; 62 import org.eclipse.jdt.ui.text.folding.IJavaFoldingStructureProvider; 63 64 import org.eclipse.jdt.internal.ui.JavaPlugin; 65 import org.eclipse.jdt.internal.ui.javaeditor.ClassFileEditor; 66 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor; 67 import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput; 68 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; 69 import org.eclipse.jdt.internal.ui.text.DocumentCharacterIterator; 70 71 72 77 public class DefaultJavaFoldingStructureProvider implements IProjectionListener, IJavaFoldingStructureProvider { 78 79 private static final class JavaProjectionAnnotation extends ProjectionAnnotation { 80 81 private IJavaElement fJavaElement; 82 private boolean fIsComment; 83 84 public JavaProjectionAnnotation(IJavaElement element, boolean isCollapsed, boolean isComment) { 85 super(isCollapsed); 86 fJavaElement= element; 87 fIsComment= isComment; 88 } 89 90 public IJavaElement getElement() { 91 return fJavaElement; 92 } 93 94 public void setElement(IJavaElement element) { 95 fJavaElement= element; 96 } 97 98 public boolean isComment() { 99 return fIsComment; 100 } 101 102 public void setIsComment(boolean isComment) { 103 fIsComment= isComment; 104 } 105 106 109 public String toString() { 110 return "JavaProjectionAnnotation:\n" + "\telement: \t"+fJavaElement.toString()+"\n" + "\tcollapsed: \t" + isCollapsed() + "\n" + "\tcomment: \t" + fIsComment + "\n"; } 115 } 116 117 private static final class Tuple { 118 JavaProjectionAnnotation annotation; 119 Position position; 120 Tuple(JavaProjectionAnnotation annotation, Position position) { 121 this.annotation= annotation; 122 this.position= position; 123 } 124 } 125 126 private class ElementChangedListener implements IElementChangedListener { 127 128 131 public void elementChanged(ElementChangedEvent e) { 132 IJavaElementDelta delta= findElement(fInput, e.getDelta()); 133 if (delta != null) 134 processDelta(delta); 135 } 136 137 private IJavaElementDelta findElement(IJavaElement target, IJavaElementDelta delta) { 138 139 if (delta == null || target == null) 140 return null; 141 142 IJavaElement element= delta.getElement(); 143 144 if (element.getElementType() > IJavaElement.CLASS_FILE) 145 return null; 146 147 if (target.equals(element)) 148 return delta; 149 150 IJavaElementDelta[] children= delta.getAffectedChildren(); 151 152 for (int i= 0; i < children.length; i++) { 153 IJavaElementDelta d= findElement(target, children[i]); 154 if (d != null) 155 return d; 156 } 157 158 return null; 159 } 160 } 161 162 169 private static final class CommentPosition extends Position implements IProjectionPosition { 170 CommentPosition(int offset, int length) { 171 super(offset, length); 172 } 173 174 177 public IRegion[] computeProjectionRegions(IDocument document) throws BadLocationException { 178 DocumentCharacterIterator sequence= new DocumentCharacterIterator(document, offset, offset + length); 179 int prefixEnd= 0; 180 int contentStart= findFirstContent(sequence, prefixEnd); 181 182 int firstLine= document.getLineOfOffset(offset + prefixEnd); 183 int captionLine= document.getLineOfOffset(offset + contentStart); 184 int lastLine= document.getLineOfOffset(offset + length); 185 186 Assert.isTrue(firstLine <= captionLine, "first folded line is greater than the caption line"); Assert.isTrue(captionLine <= lastLine, "caption line is greater than the last folded line"); 189 IRegion preRegion; 190 if (firstLine < captionLine) { 191 int preOffset= document.getLineOffset(firstLine); 193 IRegion preEndLineInfo= document.getLineInformation(captionLine); 194 int preEnd= preEndLineInfo.getOffset(); 195 preRegion= new Region(preOffset, preEnd - preOffset); 196 } else { 197 preRegion= null; 198 } 199 200 if (captionLine < lastLine) { 201 int postOffset= document.getLineOffset(captionLine + 1); 202 IRegion postRegion= new Region(postOffset, offset + length - postOffset); 203 204 if (preRegion == null) 205 return new IRegion[] { postRegion }; 206 207 return new IRegion[] { preRegion, postRegion }; 208 } 209 210 if (preRegion != null) 211 return new IRegion[] { preRegion }; 212 213 return null; 214 } 215 216 224 private int findFirstContent(final CharSequence content, int prefixEnd) { 225 int lenght= content.length(); 226 for (int i= prefixEnd; i < lenght; i++) { 227 if (Character.isUnicodeIdentifierPart(content.charAt(i))) 228 return i; 229 } 230 return 0; 231 } 232 233 260 263 public int computeCaptionOffset(IDocument document) { 264 DocumentCharacterIterator sequence= new DocumentCharacterIterator(document, offset, offset + length); 266 return findFirstContent(sequence, 0); 267 } 268 } 269 270 277 private static final class JavaElementPosition extends Position implements IProjectionPosition { 278 279 private IMember fMember; 280 281 public JavaElementPosition(int offset, int length, IMember member) { 282 super(offset, length); 283 Assert.isNotNull(member); 284 fMember= member; 285 } 286 287 public void setMember(IMember member) { 288 Assert.isNotNull(member); 289 fMember= member; 290 } 291 292 295 public IRegion[] computeProjectionRegions(IDocument document) throws BadLocationException { 296 int nameStart= offset; 297 try { 298 303 ISourceRange nameRange= fMember.getNameRange(); 304 if (nameRange != null) 305 nameStart= nameRange.getOffset(); 306 307 } catch (JavaModelException e) { 308 } 310 311 int firstLine= document.getLineOfOffset(offset); 312 int captionLine= document.getLineOfOffset(nameStart); 313 int lastLine= document.getLineOfOffset(offset + length); 314 315 318 if (captionLine < firstLine) 319 captionLine= firstLine; 320 if (captionLine > lastLine) 321 captionLine= lastLine; 322 323 IRegion preRegion; 324 if (firstLine < captionLine) { 325 int preOffset= document.getLineOffset(firstLine); 326 IRegion preEndLineInfo= document.getLineInformation(captionLine); 327 int preEnd= preEndLineInfo.getOffset(); 328 preRegion= new Region(preOffset, preEnd - preOffset); 329 } else { 330 preRegion= null; 331 } 332 333 if (captionLine < lastLine) { 334 int postOffset= document.getLineOffset(captionLine + 1); 335 IRegion postRegion= new Region(postOffset, offset + length - postOffset); 336 337 if (preRegion == null) 338 return new IRegion[] { postRegion }; 339 340 return new IRegion[] { preRegion, postRegion }; 341 } 342 343 if (preRegion != null) 344 return new IRegion[] { preRegion }; 345 346 return null; 347 } 348 349 352 public int computeCaptionOffset(IDocument document) throws BadLocationException { 353 int nameStart= offset; 354 try { 355 ISourceRange nameRange= fMember.getNameRange(); 357 if (nameRange != null) 358 nameStart= nameRange.getOffset(); 359 } catch (JavaModelException e) { 360 } 362 363 return nameStart - offset; 364 } 365 366 } 367 368 private IDocument fCachedDocument; 369 private ProjectionAnnotationModel fCachedModel; 370 371 private ITextEditor fEditor; 372 private ProjectionViewer fViewer; 373 private IJavaElement fInput; 374 private IElementChangedListener fElementListener; 375 376 private boolean fAllowCollapsing= false; 377 private boolean fCollapseJavadoc= false; 378 private boolean fCollapseImportContainer= true; 379 private boolean fCollapseInnerTypes= true; 380 private boolean fCollapseMethods= false; 381 private boolean fCollapseHeaderComments= true; 382 383 384 private IType fFirstType; 385 private boolean fHasHeaderComment; 386 387 388 public DefaultJavaFoldingStructureProvider() { 389 } 390 391 public void install(ITextEditor editor, ProjectionViewer viewer) { 392 if (editor instanceof JavaEditor) { 393 fEditor= editor; 394 fViewer= viewer; 395 fViewer.addProjectionListener(this); 396 } 397 } 398 399 public void uninstall() { 400 if (isInstalled()) { 401 projectionDisabled(); 402 fViewer.removeProjectionListener(this); 403 fViewer= null; 404 fEditor= null; 405 } 406 } 407 408 protected boolean isInstalled() { 409 return fEditor != null; 410 } 411 412 415 public void projectionEnabled() { 416 projectionDisabled(); 422 423 if (fEditor instanceof JavaEditor) { 424 initialize(); 425 fElementListener= new ElementChangedListener(); 426 JavaCore.addElementChangedListener(fElementListener); 427 } 428 } 429 430 433 public void projectionDisabled() { 434 fCachedDocument= null; 435 if (fElementListener != null) { 436 JavaCore.removeElementChangedListener(fElementListener); 437 fElementListener= null; 438 } 439 } 440 441 public void initialize() { 442 443 if (!isInstalled()) 444 return; 445 446 initializePreferences(); 447 448 try { 449 450 IDocumentProvider provider= fEditor.getDocumentProvider(); 451 fCachedDocument= provider.getDocument(fEditor.getEditorInput()); 452 fAllowCollapsing= true; 453 454 fFirstType= null; 455 fHasHeaderComment= false; 456 457 if (fEditor instanceof CompilationUnitEditor) { 458 IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager(); 459 fInput= manager.getWorkingCopy(fEditor.getEditorInput()); 460 } else if (fEditor instanceof ClassFileEditor) { 461 IClassFileEditorInput editorInput= (IClassFileEditorInput) fEditor.getEditorInput(); 462 fInput= editorInput.getClassFile(); 463 } 464 465 if (fInput != null) { 466 ProjectionAnnotationModel model= (ProjectionAnnotationModel) fEditor.getAdapter(ProjectionAnnotationModel.class); 467 if (model != null) { 468 fCachedModel= model; 469 if (fInput instanceof ICompilationUnit) { 470 ICompilationUnit unit= (ICompilationUnit) fInput; 471 synchronized (unit) { 472 try { 473 unit.reconcile(ICompilationUnit.NO_AST, false, null, null); 474 } catch (JavaModelException x) { 475 } 476 } 477 } 478 479 Map additions= computeAdditions((IParent) fInput); 480 484 List removals= new LinkedList (); 485 Iterator existing= model.getAnnotationIterator(); 486 while (existing.hasNext()) 487 removals.add(existing.next()); 488 model.replaceAnnotations((Annotation[]) removals.toArray(new Annotation[removals.size()]), additions); 489 } 490 } 491 492 } finally { 493 fCachedDocument= null; 494 fCachedModel= null; 495 fAllowCollapsing= false; 496 497 fFirstType= null; 498 fHasHeaderComment= false; 499 } 500 } 501 502 private void initializePreferences() { 503 IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); 504 fCollapseInnerTypes= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_INNERTYPES); 505 fCollapseImportContainer= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_IMPORTS); 506 fCollapseJavadoc= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_JAVADOC); 507 fCollapseMethods= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_METHODS); 508 fCollapseHeaderComments= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_HEADERS); 509 } 510 511 private Map computeAdditions(IParent parent) { 512 Map map= new LinkedHashMap (); try { 514 computeAdditions(parent.getChildren(), map); 515 } catch (JavaModelException x) { 516 } 517 return map; 518 } 519 520 private void computeAdditions(IJavaElement[] elements, Map map) throws JavaModelException { 521 for (int i= 0; i < elements.length; i++) { 522 IJavaElement element= elements[i]; 523 524 computeAdditions(element, map); 525 526 if (element instanceof IParent) { 527 IParent parent= (IParent) element; 528 computeAdditions(parent.getChildren(), map); 529 } 530 } 531 } 532 533 private void computeAdditions(IJavaElement element, Map map) { 534 535 boolean createProjection= false; 536 537 boolean collapse= false; 538 switch (element.getElementType()) { 539 540 case IJavaElement.IMPORT_CONTAINER: 541 collapse= fAllowCollapsing && fCollapseImportContainer; 542 createProjection= true; 543 break; 544 case IJavaElement.TYPE: 545 collapse= fAllowCollapsing && fCollapseInnerTypes && isInnerType((IType) element); 546 createProjection= true; 547 break; 548 case IJavaElement.METHOD: 549 collapse= fAllowCollapsing && fCollapseMethods; 550 createProjection= true; 551 break; 552 } 553 554 if (createProjection) { 555 IRegion[] regions= computeProjectionRanges(element); 556 if (regions != null) { 557 for (int i= 0; i < regions.length - 1; i++) { 559 Position position= createProjectionPosition(regions[i], null); 560 boolean commentCollapse; 561 if (position != null) { 562 if (i == 0 && (regions.length > 2 || fHasHeaderComment) && element == fFirstType) { 563 commentCollapse= fAllowCollapsing && fCollapseHeaderComments; 564 } else { 565 commentCollapse= fAllowCollapsing && fCollapseJavadoc; 566 } 567 map.put(new JavaProjectionAnnotation(element, commentCollapse, true), position); 568 } 569 } 570 Position position= createProjectionPosition(regions[regions.length - 1], element); 572 if (position != null) 573 map.put(new JavaProjectionAnnotation(element, collapse, false), position); 574 } 575 } 576 } 577 578 private boolean isInnerType(IType type) { 579 580 try { 581 return type.isMember(); 582 } catch (JavaModelException x) { 583 IJavaElement parent= type.getParent(); 584 if (parent != null) { 585 int parentType= parent.getElementType(); 586 return (parentType != IJavaElement.COMPILATION_UNIT && parentType != IJavaElement.CLASS_FILE); 587 } 588 } 589 590 return false; 591 } 592 593 603 private IRegion[] computeProjectionRanges(IJavaElement element) { 604 605 try { 606 if (element instanceof ISourceReference) { 607 ISourceReference reference= (ISourceReference) element; 608 ISourceRange range= reference.getSourceRange(); 609 610 String contents= reference.getSource(); 611 if (contents == null) 612 return null; 613 614 List regions= new ArrayList (); 615 if (fFirstType == null && element instanceof IType) { 616 fFirstType= (IType) element; 617 IRegion headerComment= computeHeaderComment(fFirstType); 618 if (headerComment != null) { 619 regions.add(headerComment); 620 fHasHeaderComment= true; 621 } 622 } 623 624 IScanner scanner= ToolFactory.createScanner(true, false, false, false); 625 scanner.setSource(contents.toCharArray()); 626 final int shift= range.getOffset(); 627 int start= shift; 628 while (true) { 629 630 int token= scanner.getNextToken(); 631 start= shift + scanner.getCurrentTokenStartPosition(); 632 633 switch (token) { 634 case ITerminalSymbols.TokenNameCOMMENT_JAVADOC: 635 case ITerminalSymbols.TokenNameCOMMENT_BLOCK: { 636 int end= shift + scanner.getCurrentTokenEndPosition() + 1; 637 regions.add(new Region(start, end - start)); 638 } 639 case ITerminalSymbols.TokenNameCOMMENT_LINE: 640 continue; 641 } 642 643 break; 644 } 645 646 regions.add(new Region(start, shift + range.getLength() - start)); 647 648 if (regions.size() > 0) { 649 IRegion[] result= new IRegion[regions.size()]; 650 regions.toArray(result); 651 return result; 652 } 653 } 654 } catch (JavaModelException e) { 655 } catch (InvalidInputException e) { 656 } 657 658 return null; 659 } 660 661 private IRegion computeHeaderComment(IType type) throws JavaModelException { 662 if (fCachedDocument == null) 663 return null; 664 665 ISourceRange range= type.getSourceRange(); 667 if (range == null) 668 return null; 669 int start= 0; 670 int end= range.getOffset(); 671 672 if (fInput instanceof ISourceReference) { 673 String content; 674 try { 675 content= fCachedDocument.get(start, end - start); 676 } catch (BadLocationException e) { 677 return null; } 679 680 686 IScanner scanner= ToolFactory.createScanner(true, false, false, false); 687 scanner.setSource(content.toCharArray()); 688 689 int headerStart= -1; 690 int headerEnd= -1; 691 try { 692 boolean foundComment= false; 693 int terminal= scanner.getNextToken(); 694 while (terminal != ITerminalSymbols.TokenNameEOF && !(terminal == ITerminalSymbols.TokenNameclass || terminal == ITerminalSymbols.TokenNameinterface || terminal == ITerminalSymbols.TokenNameenum || (foundComment && (terminal == ITerminalSymbols.TokenNameimport || terminal == ITerminalSymbols.TokenNamepackage)))) { 695 696 if (terminal == ITerminalSymbols.TokenNameCOMMENT_JAVADOC || terminal == ITerminalSymbols.TokenNameCOMMENT_BLOCK || terminal == ITerminalSymbols.TokenNameCOMMENT_LINE) { 697 if (!foundComment) 698 headerStart= scanner.getCurrentTokenStartPosition(); 699 headerEnd= scanner.getCurrentTokenEndPosition(); 700 foundComment= true; 701 } 702 terminal= scanner.getNextToken(); 703 } 704 705 706 } catch (InvalidInputException ex) { 707 return null; 708 } 709 710 if (headerEnd != -1) { 711 return new Region(headerStart, headerEnd - headerStart); 712 } 713 } 714 return null; 715 } 716 717 private Position createProjectionPosition(IRegion region, IJavaElement element) { 718 719 if (fCachedDocument == null) 720 return null; 721 722 try { 723 724 int start= fCachedDocument.getLineOfOffset(region.getOffset()); 725 int end= fCachedDocument.getLineOfOffset(region.getOffset() + region.getLength()); 726 if (start != end) { 727 int offset= fCachedDocument.getLineOffset(start); 728 int endOffset; 729 if (fCachedDocument.getNumberOfLines() > end + 1) 730 endOffset= fCachedDocument.getLineOffset(end + 1); 731 else if (end > start) 732 endOffset= fCachedDocument.getLineOffset(end) + fCachedDocument.getLineLength(end); 733 else 734 return null; 735 if (element instanceof IMember) 736 return new JavaElementPosition(offset, endOffset - offset, (IMember) element); 737 else 738 return new CommentPosition(offset, endOffset - offset); 739 } 740 741 } catch (BadLocationException x) { 742 } 743 744 return null; 745 } 746 747 protected void processDelta(IJavaElementDelta delta) { 748 749 if (!isInstalled()) 750 return; 751 752 if ((delta.getFlags() & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_CHILDREN)) == 0) 753 return; 754 755 ProjectionAnnotationModel model= (ProjectionAnnotationModel) fEditor.getAdapter(ProjectionAnnotationModel.class); 756 if (model == null) 757 return; 758 759 try { 760 761 IDocumentProvider provider= fEditor.getDocumentProvider(); 762 fCachedDocument= provider.getDocument(fEditor.getEditorInput()); 763 fCachedModel= model; 764 fAllowCollapsing= false; 765 766 fFirstType= null; 767 fHasHeaderComment= false; 768 769 Map additions= new HashMap (); 770 List deletions= new ArrayList (); 771 List updates= new ArrayList (); 772 773 Map updated= computeAdditions((IParent) fInput); 774 Map previous= createAnnotationMap(model); 775 776 777 Iterator e= updated.keySet().iterator(); 778 while (e.hasNext()) { 779 JavaProjectionAnnotation newAnnotation= (JavaProjectionAnnotation) e.next(); 780 IJavaElement element= newAnnotation.getElement(); 781 Position newPosition= (Position) updated.get(newAnnotation); 782 783 List annotations= (List ) previous.get(element); 784 if (annotations == null) { 785 786 additions.put(newAnnotation, newPosition); 787 788 } else { 789 Iterator x= annotations.iterator(); 790 boolean matched= false; 791 while (x.hasNext()) { 792 Tuple tuple= (Tuple) x.next(); 793 JavaProjectionAnnotation existingAnnotation= tuple.annotation; 794 Position existingPosition= tuple.position; 795 if (newAnnotation.isComment() == existingAnnotation.isComment()) { 796 if (existingPosition != null && (!newPosition.equals(existingPosition))) { 797 existingPosition.setOffset(newPosition.getOffset()); 798 existingPosition.setLength(newPosition.getLength()); 799 updates.add(existingAnnotation); 800 } 801 matched= true; 802 x.remove(); 803 break; 804 } 805 } 806 if (!matched) 807 additions.put(newAnnotation, newPosition); 808 809 if (annotations.isEmpty()) 810 previous.remove(element); 811 } 812 } 813 814 e= previous.values().iterator(); 815 while (e.hasNext()) { 816 List list= (List ) e.next(); 817 int size= list.size(); 818 for (int i= 0; i < size; i++) 819 deletions.add(((Tuple) list.get(i)).annotation); 820 } 821 822 match(deletions, additions, updates); 823 824 Annotation[] removals= new Annotation[deletions.size()]; 825 deletions.toArray(removals); 826 Annotation[] changes= new Annotation[updates.size()]; 827 updates.toArray(changes); 828 model.modifyAnnotations(removals, additions, changes); 829 830 } finally { 831 fCachedDocument= null; 832 fAllowCollapsing= true; 833 fCachedModel= null; 834 835 fFirstType= null; 836 fHasHeaderComment= false; 837 } 838 } 839 840 848 private void match(List deletions, Map additions, List changes) { 849 if (deletions.isEmpty() || (additions.isEmpty() && changes.isEmpty())) 850 return; 851 852 List newDeletions= new ArrayList (); 853 List newChanges= new ArrayList (); 854 855 Iterator deletionIterator= deletions.iterator(); 856 while (deletionIterator.hasNext()) { 857 JavaProjectionAnnotation deleted= (JavaProjectionAnnotation) deletionIterator.next(); 858 Position deletedPosition= fCachedModel.getPosition(deleted); 859 if (deletedPosition == null) 860 continue; 861 862 Tuple deletedTuple= new Tuple(deleted, deletedPosition); 863 864 Tuple match= findMatch(deletedTuple, changes, null); 865 boolean addToDeletions= true; 866 if (match == null) { 867 match= findMatch(deletedTuple, additions.keySet(), additions); 868 addToDeletions= false; 869 } 870 871 if (match != null) { 872 IJavaElement element= match.annotation.getElement(); 873 deleted.setElement(element); 874 deletedPosition.setLength(match.position.getLength()); 875 if (deletedPosition instanceof JavaElementPosition && element instanceof IMember) { 876 JavaElementPosition jep= (JavaElementPosition) deletedPosition; 877 jep.setMember((IMember) element); 878 } 879 880 deletionIterator.remove(); 881 newChanges.add(deleted); 882 883 if (addToDeletions) 884 newDeletions.add(match.annotation); 885 } 886 } 887 888 deletions.addAll(newDeletions); 889 changes.addAll(newChanges); 890 } 891 892 915 private Tuple findMatch(Tuple tuple, Collection annotations, Map positionMap) { 916 Iterator it= annotations.iterator(); 917 while (it.hasNext()) { 918 JavaProjectionAnnotation annotation= (JavaProjectionAnnotation) it.next(); 919 if (tuple.annotation.isComment() == annotation.isComment()) { 920 Position position= positionMap == null ? fCachedModel.getPosition(annotation) : (Position) positionMap.get(annotation); 921 if (position == null) 922 continue; 923 924 if (tuple.position.getOffset() == position.getOffset()) { 925 it.remove(); 926 return new Tuple(annotation, position); 927 } 928 } 929 } 930 931 return null; 932 } 933 934 private Map createAnnotationMap(IAnnotationModel model) { 935 Map map= new HashMap (); 936 Iterator e= model.getAnnotationIterator(); 937 while (e.hasNext()) { 938 Object annotation= e.next(); 939 if (annotation instanceof JavaProjectionAnnotation) { 940 JavaProjectionAnnotation java= (JavaProjectionAnnotation) annotation; 941 Position position= model.getPosition(java); 942 Assert.isNotNull(position); 943 List list= (List ) map.get(java.getElement()); 944 if (list == null) { 945 list= new ArrayList (2); 946 map.put(java.getElement(), list); 947 } 948 list.add(new Tuple(java, position)); 949 } 950 } 951 952 Comparator comparator= new Comparator () { 953 public int compare(Object o1, Object o2) { 954 return ((Tuple) o1).position.getOffset() - ((Tuple) o2).position.getOffset(); 955 } 956 }; 957 for (Iterator it= map.values().iterator(); it.hasNext();) { 958 List list= (List ) it.next(); 959 Collections.sort(list, comparator); 960 } 961 return map; 962 } 963 } 964 | Popular Tags |