1 11 12 package org.eclipse.jdt.internal.ui.javaeditor; 13 14 15 import java.io.BufferedReader ; 16 import java.io.IOException ; 17 import java.io.InputStream ; 18 import java.io.InputStreamReader ; 19 import java.io.Reader ; 20 import java.net.URI ; 21 import java.util.ArrayList ; 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 import java.util.Map ; 26 27 import org.eclipse.core.filesystem.EFS; 28 import org.eclipse.core.filesystem.IFileStore; 29 import org.eclipse.core.filesystem.URIUtil; 30 31 import org.eclipse.core.runtime.Assert; 32 import org.eclipse.core.runtime.CoreException; 33 import org.eclipse.core.runtime.IPath; 34 import org.eclipse.core.runtime.IProgressMonitor; 35 import org.eclipse.core.runtime.ISafeRunnable; 36 import org.eclipse.core.runtime.IStatus; 37 import org.eclipse.core.runtime.ListenerList; 38 import org.eclipse.core.runtime.MultiStatus; 39 import org.eclipse.core.runtime.NullProgressMonitor; 40 import org.eclipse.core.runtime.OperationCanceledException; 41 import org.eclipse.core.runtime.SafeRunner; 42 import org.eclipse.core.runtime.Status; 43 import org.eclipse.core.runtime.SubProgressMonitor; 44 import org.eclipse.core.runtime.jobs.ISchedulingRule; 45 46 import org.eclipse.core.resources.IEncodedStorage; 47 import org.eclipse.core.resources.IFile; 48 import org.eclipse.core.resources.IFileState; 49 import org.eclipse.core.resources.IMarker; 50 import org.eclipse.core.resources.IResource; 51 import org.eclipse.core.resources.IStorage; 52 53 import org.eclipse.swt.SWT; 54 import org.eclipse.swt.graphics.GC; 55 import org.eclipse.swt.graphics.Image; 56 import org.eclipse.swt.graphics.Rectangle; 57 import org.eclipse.swt.widgets.Canvas; 58 import org.eclipse.swt.widgets.Display; 59 60 import org.eclipse.jface.preference.IPreferenceStore; 61 import org.eclipse.jface.util.IPropertyChangeListener; 62 import org.eclipse.jface.util.PropertyChangeEvent; 63 64 import org.eclipse.jface.text.BadLocationException; 65 import org.eclipse.jface.text.DefaultLineTracker; 66 import org.eclipse.jface.text.IDocument; 67 import org.eclipse.jface.text.ILineTracker; 68 import org.eclipse.jface.text.Position; 69 import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation; 70 import org.eclipse.jface.text.source.Annotation; 71 import org.eclipse.jface.text.source.AnnotationModel; 72 import org.eclipse.jface.text.source.AnnotationModelEvent; 73 import org.eclipse.jface.text.source.IAnnotationAccessExtension; 74 import org.eclipse.jface.text.source.IAnnotationModel; 75 import org.eclipse.jface.text.source.IAnnotationModelListener; 76 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; 77 import org.eclipse.jface.text.source.IAnnotationPresentation; 78 import org.eclipse.jface.text.source.ImageUtilities; 79 80 import org.eclipse.ui.IFileEditorInput; 81 import org.eclipse.ui.IStorageEditorInput; 82 import org.eclipse.ui.IURIEditorInput; 83 import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel; 84 import org.eclipse.ui.texteditor.AnnotationPreference; 85 import org.eclipse.ui.texteditor.AnnotationPreferenceLookup; 86 import org.eclipse.ui.texteditor.IDocumentProvider; 87 import org.eclipse.ui.texteditor.MarkerAnnotation; 88 import org.eclipse.ui.texteditor.MarkerUtilities; 89 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel; 90 91 import org.eclipse.ui.editors.text.EditorsUI; 92 import org.eclipse.ui.editors.text.ForwardingDocumentProvider; 93 import org.eclipse.ui.editors.text.TextFileDocumentProvider; 94 95 import org.eclipse.jdt.core.IBuffer; 96 import org.eclipse.jdt.core.IClasspathEntry; 97 import org.eclipse.jdt.core.ICompilationUnit; 98 import org.eclipse.jdt.core.IJavaModel; 99 import org.eclipse.jdt.core.IJavaProject; 100 import org.eclipse.jdt.core.IProblemRequestor; 101 import org.eclipse.jdt.core.JavaCore; 102 import org.eclipse.jdt.core.JavaModelException; 103 import org.eclipse.jdt.core.WorkingCopyOwner; 104 import org.eclipse.jdt.core.compiler.CategorizedProblem; 105 import org.eclipse.jdt.core.compiler.IProblem; 106 107 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 108 import org.eclipse.jdt.internal.corext.util.Messages; 109 110 import org.eclipse.jdt.launching.JavaRuntime; 111 112 import org.eclipse.jdt.ui.JavaUI; 113 import org.eclipse.jdt.ui.PreferenceConstants; 114 import org.eclipse.jdt.ui.text.IJavaPartitions; 115 116 import org.eclipse.jdt.internal.ui.IJavaStatusConstants; 117 import org.eclipse.jdt.internal.ui.JavaPlugin; 118 import org.eclipse.jdt.internal.ui.JavaPluginImages; 119 import org.eclipse.jdt.internal.ui.javaeditor.saveparticipant.IPostSaveListener; 120 import org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor; 121 import org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension; 122 import org.eclipse.jdt.internal.ui.text.spelling.JavaSpellingReconcileStrategy; 123 124 125 public class CompilationUnitDocumentProvider extends TextFileDocumentProvider implements ICompilationUnitDocumentProvider { 126 127 130 static protected class CompilationUnitInfo extends FileInfo { 131 public ICompilationUnit fCopy; 132 } 133 134 137 static public class ProblemAnnotation extends Annotation implements IJavaAnnotation, IAnnotationPresentation, IQuickFixableAnnotation { 138 139 public static final String SPELLING_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.spelling"; 141 145 private static final int TASK_LAYER; 146 149 private static final int INFO_LAYER; 150 153 private static final int WARNING_LAYER; 154 157 private static final int ERROR_LAYER; 158 159 static { 160 AnnotationPreferenceLookup lookup= EditorsUI.getAnnotationPreferenceLookup(); 161 TASK_LAYER= computeLayer("org.eclipse.ui.workbench.texteditor.task", lookup); INFO_LAYER= computeLayer("org.eclipse.jdt.ui.info", lookup); WARNING_LAYER= computeLayer("org.eclipse.jdt.ui.warning", lookup); ERROR_LAYER= computeLayer("org.eclipse.jdt.ui.error", lookup); } 166 167 private static int computeLayer(String annotationType, AnnotationPreferenceLookup lookup) { 168 Annotation annotation= new Annotation(annotationType, false, null); 169 AnnotationPreference preference= lookup.getAnnotationPreference(annotation); 170 if (preference != null) 171 return preference.getPresentationLayer() + 1; 172 else 173 return IAnnotationAccessExtension.DEFAULT_LAYER + 1; 174 } 175 176 private static Image fgQuickFixImage; 177 private static Image fgQuickFixErrorImage; 178 private static boolean fgQuickFixImagesInitialized= false; 179 180 private ICompilationUnit fCompilationUnit; 181 private List fOverlaids; 182 private IProblem fProblem; 183 private Image fImage; 184 private boolean fQuickFixImagesInitialized= false; 185 private int fLayer= IAnnotationAccessExtension.DEFAULT_LAYER; 186 private boolean fIsQuickFixable; 187 private boolean fIsQuickFixableStateSet= false; 188 189 190 public ProblemAnnotation(IProblem problem, ICompilationUnit cu) { 191 192 fProblem= problem; 193 fCompilationUnit= cu; 194 195 if (JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID == fProblem.getID()) { 196 setType(SPELLING_ANNOTATION_TYPE); 197 fLayer= WARNING_LAYER; 198 } else if (IProblem.Task == fProblem.getID()) { 199 setType(JavaMarkerAnnotation.TASK_ANNOTATION_TYPE); 200 fLayer= TASK_LAYER; 201 } else if (fProblem.isWarning()) { 202 setType(JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE); 203 fLayer= WARNING_LAYER; 204 } else if (fProblem.isError()) { 205 setType(JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE); 206 fLayer= ERROR_LAYER; 207 } else { 208 setType(JavaMarkerAnnotation.INFO_ANNOTATION_TYPE); 209 fLayer= INFO_LAYER; 210 } 211 } 212 213 216 public int getLayer() { 217 return fLayer; 218 } 219 220 private void initializeImages() { 221 if (!fQuickFixImagesInitialized) { 223 if (!isQuickFixableStateSet()) 224 setQuickFixable(isProblem() && indicateQuixFixableProblems() && JavaCorrectionProcessor.hasCorrections(this)); if (isQuickFixable()) { 226 if (!fgQuickFixImagesInitialized) { 227 fgQuickFixImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_PROBLEM); 228 fgQuickFixErrorImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_ERROR); 229 fgQuickFixImagesInitialized= true; 230 } 231 if (JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(getType())) 232 fImage= fgQuickFixErrorImage; 233 else 234 fImage= fgQuickFixImage; 235 } 236 fQuickFixImagesInitialized= true; 237 } 238 } 239 240 private boolean indicateQuixFixableProblems() { 241 return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION); 242 } 243 244 247 public void paint(GC gc, Canvas canvas, Rectangle r) { 248 initializeImages(); 249 if (fImage != null) 250 ImageUtilities.drawImage(fImage, gc, canvas, r, SWT.CENTER, SWT.TOP); 251 } 252 253 256 public Image getImage(Display display) { 257 initializeImages(); 258 return fImage; 259 } 260 261 264 public String getText() { 265 return fProblem.getMessage(); 266 } 267 268 271 public String [] getArguments() { 272 return isProblem() ? fProblem.getArguments() : null; 273 } 274 275 278 public int getId() { 279 return fProblem.getID(); 280 } 281 282 285 public boolean isProblem() { 286 String type= getType(); 287 return JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE.equals(type) || 288 JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(type) || 289 SPELLING_ANNOTATION_TYPE.equals(type); 290 } 291 292 295 public boolean hasOverlay() { 296 return false; 297 } 298 299 302 public IJavaAnnotation getOverlay() { 303 return null; 304 } 305 306 309 public void addOverlaid(IJavaAnnotation annotation) { 310 if (fOverlaids == null) 311 fOverlaids= new ArrayList (1); 312 fOverlaids.add(annotation); 313 } 314 315 318 public void removeOverlaid(IJavaAnnotation annotation) { 319 if (fOverlaids != null) { 320 fOverlaids.remove(annotation); 321 if (fOverlaids.size() == 0) 322 fOverlaids= null; 323 } 324 } 325 326 329 public Iterator getOverlaidIterator() { 330 if (fOverlaids != null) 331 return fOverlaids.iterator(); 332 return null; 333 } 334 335 338 public ICompilationUnit getCompilationUnit() { 339 return fCompilationUnit; 340 } 341 342 345 public String getMarkerType() { 346 if (fProblem instanceof CategorizedProblem) 347 return ((CategorizedProblem) fProblem).getMarkerType(); 348 return null; 349 } 350 351 355 public void setQuickFixable(boolean state) { 356 fIsQuickFixable= state; 357 fIsQuickFixableStateSet= true; 358 } 359 360 364 public boolean isQuickFixableStateSet() { 365 return fIsQuickFixableStateSet; 366 } 367 368 372 public boolean isQuickFixable() { 373 Assert.isTrue(isQuickFixableStateSet()); 374 return fIsQuickFixable; 375 } 376 } 377 378 384 protected static class ReverseMap { 385 386 static class Entry { 387 Position fPosition; 388 Object fValue; 389 } 390 391 private List fList= new ArrayList (2); 392 private int fAnchor= 0; 393 394 public ReverseMap() { 395 } 396 397 public Object get(Position position) { 398 399 Entry entry; 400 401 int length= fList.size(); 403 for (int i= fAnchor; i < length; i++) { 404 entry= (Entry) fList.get(i); 405 if (entry.fPosition.equals(position)) { 406 fAnchor= i; 407 return entry.fValue; 408 } 409 } 410 411 for (int i= 0; i < fAnchor; i++) { 413 entry= (Entry) fList.get(i); 414 if (entry.fPosition.equals(position)) { 415 fAnchor= i; 416 return entry.fValue; 417 } 418 } 419 420 return null; 421 } 422 423 private int getIndex(Position position) { 424 Entry entry; 425 int length= fList.size(); 426 for (int i= 0; i < length; i++) { 427 entry= (Entry) fList.get(i); 428 if (entry.fPosition.equals(position)) 429 return i; 430 } 431 return -1; 432 } 433 434 public void put(Position position, Object value) { 435 int index= getIndex(position); 436 if (index == -1) { 437 Entry entry= new Entry(); 438 entry.fPosition= position; 439 entry.fValue= value; 440 fList.add(entry); 441 } else { 442 Entry entry= (Entry) fList.get(index); 443 entry.fValue= value; 444 } 445 } 446 447 public void remove(Position position) { 448 int index= getIndex(position); 449 if (index > -1) 450 fList.remove(index); 451 } 452 453 public void clear() { 454 fList.clear(); 455 } 456 } 457 458 463 protected static class CompilationUnitAnnotationModel extends ResourceMarkerAnnotationModel implements IProblemRequestor, IProblemRequestorExtension { 464 465 private static class ProblemRequestorState { 466 boolean fInsideReportingSequence= false; 467 List fReportedProblems; 468 } 469 470 private ThreadLocal fProblemRequestorState= new ThreadLocal (); 471 private int fStateCount= 0; 472 473 private ICompilationUnit fCompilationUnit; 474 private List fGeneratedAnnotations= new ArrayList (); 475 private IProgressMonitor fProgressMonitor; 476 private boolean fIsActive= false; 477 private boolean fIsHandlingTemporaryProblems; 478 479 private ReverseMap fReverseMap= new ReverseMap(); 480 private List fPreviouslyOverlaid= null; 481 private List fCurrentlyOverlaid= new ArrayList (); 482 private Thread fActiveThread; 483 484 485 public CompilationUnitAnnotationModel(IResource resource) { 486 super(resource); 487 } 488 489 public void setCompilationUnit(ICompilationUnit unit) { 490 fCompilationUnit= unit; 491 } 492 493 protected MarkerAnnotation createMarkerAnnotation(IMarker marker) { 494 String markerType= MarkerUtilities.getMarkerType(marker); 495 if (markerType != null && markerType.startsWith(JavaMarkerAnnotation.JAVA_MARKER_TYPE_PREFIX)) 496 return new JavaMarkerAnnotation(marker); 497 return super.createMarkerAnnotation(marker); 498 } 499 500 503 protected AnnotationModelEvent createAnnotationModelEvent() { 504 return new CompilationUnitAnnotationModelEvent(this, getResource()); 505 } 506 507 protected Position createPositionFromProblem(IProblem problem) { 508 int start= problem.getSourceStart(); 509 if (start < 0) 510 return null; 511 512 int length= problem.getSourceEnd() - problem.getSourceStart() + 1; 513 if (length < 0) 514 return null; 515 516 return new Position(start, length); 517 } 518 519 522 public void beginReporting() { 523 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get(); 524 if (state == null) 525 internalBeginReporting(false); 526 } 527 528 531 public void beginReportingSequence() { 532 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get(); 533 if (state == null) 534 internalBeginReporting(true); 535 } 536 537 543 private void internalBeginReporting(boolean insideReportingSequence) { 544 if (fCompilationUnit != null && fCompilationUnit.getJavaProject().isOnClasspath(fCompilationUnit)) { 545 ProblemRequestorState state= new ProblemRequestorState(); 546 state.fInsideReportingSequence= insideReportingSequence; 547 state.fReportedProblems= new ArrayList (); 548 synchronized (getLockObject()) { 549 fProblemRequestorState.set(state); 550 ++fStateCount; 551 } 552 } 553 } 554 555 558 public void acceptProblem(IProblem problem) { 559 if (fIsHandlingTemporaryProblems || problem.getID() == JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID) { 560 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get(); 561 if (state != null) 562 state.fReportedProblems.add(problem); 563 } 564 } 565 566 569 public void endReporting() { 570 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get(); 571 if (state != null && !state.fInsideReportingSequence) 572 internalEndReporting(state); 573 } 574 575 578 public void endReportingSequence() { 579 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get(); 580 if (state != null && state.fInsideReportingSequence) 581 internalEndReporting(state); 582 } 583 584 private void internalEndReporting(ProblemRequestorState state) { 585 int stateCount= 0; 586 synchronized(getLockObject()) { 587 -- fStateCount; 588 stateCount= fStateCount; 589 fProblemRequestorState.set(null); 590 } 591 592 if (stateCount == 0) 593 reportProblems(state.fReportedProblems); 594 } 595 596 601 private void reportProblems(List reportedProblems) { 602 if (fProgressMonitor != null && fProgressMonitor.isCanceled()) 603 return; 604 605 boolean temporaryProblemsChanged= false; 606 607 synchronized (getLockObject()) { 608 609 boolean isCanceled= false; 610 611 fPreviouslyOverlaid= fCurrentlyOverlaid; 612 fCurrentlyOverlaid= new ArrayList (); 613 614 if (fGeneratedAnnotations.size() > 0) { 615 temporaryProblemsChanged= true; 616 removeAnnotations(fGeneratedAnnotations, false, true); 617 fGeneratedAnnotations.clear(); 618 } 619 620 if (reportedProblems != null && reportedProblems.size() > 0) { 621 622 Iterator e= reportedProblems.iterator(); 623 while (e.hasNext()) { 624 625 if (fProgressMonitor != null && fProgressMonitor.isCanceled()) { 626 isCanceled= true; 627 break; 628 } 629 630 IProblem problem= (IProblem) e.next(); 631 Position position= createPositionFromProblem(problem); 632 if (position != null) { 633 634 try { 635 ProblemAnnotation annotation= new ProblemAnnotation(problem, fCompilationUnit); 636 overlayMarkers(position, annotation); 637 addAnnotation(annotation, position, false); 638 fGeneratedAnnotations.add(annotation); 639 640 temporaryProblemsChanged= true; 641 } catch (BadLocationException x) { 642 } 644 } 645 } 646 } 647 648 removeMarkerOverlays(isCanceled); 649 fPreviouslyOverlaid= null; 650 } 651 652 if (temporaryProblemsChanged) 653 fireModelChanged(); 654 } 655 656 private void removeMarkerOverlays(boolean isCanceled) { 657 if (isCanceled) { 658 fCurrentlyOverlaid.addAll(fPreviouslyOverlaid); 659 } else if (fPreviouslyOverlaid != null) { 660 Iterator e= fPreviouslyOverlaid.iterator(); 661 while (e.hasNext()) { 662 JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) e.next(); 663 annotation.setOverlay(null); 664 } 665 } 666 } 667 668 674 private void setOverlay(Object value, ProblemAnnotation problemAnnotation) { 675 if (value instanceof JavaMarkerAnnotation) { 676 JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) value; 677 if (annotation.isProblem()) { 678 annotation.setOverlay(problemAnnotation); 679 fPreviouslyOverlaid.remove(annotation); 680 fCurrentlyOverlaid.add(annotation); 681 } 682 } else { 683 } 684 } 685 686 private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) { 687 Object value= getAnnotations(position); 688 if (value instanceof List ) { 689 List list= (List ) value; 690 for (Iterator e = list.iterator(); e.hasNext();) 691 setOverlay(e.next(), problemAnnotation); 692 } else { 693 setOverlay(value, problemAnnotation); 694 } 695 } 696 697 700 private void startCollectingProblems() { 701 fGeneratedAnnotations.clear(); 702 } 703 704 707 private void stopCollectingProblems() { 708 if (fGeneratedAnnotations != null) 709 removeAnnotations(fGeneratedAnnotations, true, true); 710 fGeneratedAnnotations.clear(); 711 } 712 713 716 public synchronized boolean isActive() { 717 return fIsActive && fActiveThread == Thread.currentThread(); 718 } 719 720 723 public void setProgressMonitor(IProgressMonitor monitor) { 724 fProgressMonitor= monitor; 725 } 726 727 730 public synchronized void setIsActive(boolean isActive) { 731 Assert.isLegal(!isActive || Display.getCurrent() == null); fIsActive= isActive; 733 if (fIsActive) 734 fActiveThread= Thread.currentThread(); 735 else 736 fActiveThread= null; 737 } 738 739 743 public void setIsHandlingTemporaryProblems(boolean enable) { 744 if (fIsHandlingTemporaryProblems != enable) { 745 fIsHandlingTemporaryProblems= enable; 746 if (fIsHandlingTemporaryProblems) 747 startCollectingProblems(); 748 else 749 stopCollectingProblems(); 750 } 751 752 } 753 754 private Object getAnnotations(Position position) { 755 synchronized (getLockObject()) { 756 return fReverseMap.get(position); 757 } 758 } 759 760 763 protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) throws BadLocationException { 764 super.addAnnotation(annotation, position, fireModelChanged); 765 766 synchronized (getLockObject()) { 767 Object cached= fReverseMap.get(position); 768 if (cached == null) 769 fReverseMap.put(position, annotation); 770 else if (cached instanceof List ) { 771 List list= (List ) cached; 772 list.add(annotation); 773 } else if (cached instanceof Annotation) { 774 List list= new ArrayList (2); 775 list.add(cached); 776 list.add(annotation); 777 fReverseMap.put(position, list); 778 } 779 } 780 } 781 782 785 protected void removeAllAnnotations(boolean fireModelChanged) { 786 super.removeAllAnnotations(fireModelChanged); 787 synchronized (getLockObject()) { 788 fReverseMap.clear(); 789 } 790 } 791 792 795 protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) { 796 Position position= getPosition(annotation); 797 synchronized (getLockObject()) { 798 Object cached= fReverseMap.get(position); 799 if (cached instanceof List ) { 800 List list= (List ) cached; 801 list.remove(annotation); 802 if (list.size() == 1) { 803 fReverseMap.put(position, list.get(0)); 804 list.clear(); 805 } 806 } else if (cached instanceof Annotation) { 807 fReverseMap.remove(position); 808 } 809 } 810 super.removeAnnotation(annotation, fireModelChanged); 811 } 812 } 813 814 815 protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension { 816 817 private ListenerList fListenerList; 818 819 public GlobalAnnotationModelListener() { 820 fListenerList= new ListenerList(ListenerList.IDENTITY); 821 } 822 823 826 public void modelChanged(IAnnotationModel model) { 827 Object [] listeners= fListenerList.getListeners(); 828 for (int i= 0; i < listeners.length; i++) { 829 ((IAnnotationModelListener) listeners[i]).modelChanged(model); 830 } 831 } 832 833 836 public void modelChanged(AnnotationModelEvent event) { 837 Object [] listeners= fListenerList.getListeners(); 838 for (int i= 0; i < listeners.length; i++) { 839 Object curr= listeners[i]; 840 if (curr instanceof IAnnotationModelListenerExtension) { 841 ((IAnnotationModelListenerExtension) curr).modelChanged(event); 842 } 843 } 844 } 845 846 public void addListener(IAnnotationModelListener listener) { 847 fListenerList.add(listener); 848 } 849 850 public void removeListener(IAnnotationModelListener listener) { 851 fListenerList.remove(listener); 852 } 853 } 854 855 856 private final static String HANDLE_TEMPORARY_PROBLEMS= PreferenceConstants.EDITOR_EVALUTE_TEMPORARY_PROBLEMS; 857 858 859 860 private boolean fIsAboutToSave= false; 861 862 private ISavePolicy fSavePolicy; 863 864 private IPropertyChangeListener fPropertyListener; 865 866 private GlobalAnnotationModelListener fGlobalAnnotationModelListener; 867 871 private final Map fFakeCUMapForMissingInfo= new HashMap (); 872 873 874 877 public CompilationUnitDocumentProvider() { 878 879 IDocumentProvider provider= new TextFileDocumentProvider(); 880 provider= new ForwardingDocumentProvider(IJavaPartitions.JAVA_PARTITIONING, new JavaDocumentSetupParticipant(), provider); 881 setParentDocumentProvider(provider); 882 883 fGlobalAnnotationModelListener= new GlobalAnnotationModelListener(); 884 fPropertyListener= new IPropertyChangeListener() { 885 public void propertyChange(PropertyChangeEvent event) { 886 if (HANDLE_TEMPORARY_PROBLEMS.equals(event.getProperty())) 887 enableHandlingTemporaryProblems(); 888 } 889 }; 890 JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyListener); 891 } 892 893 899 protected ICompilationUnit createCompilationUnit(IFile file) { 900 Object element= JavaCore.create(file); 901 if (element instanceof ICompilationUnit) 902 return (ICompilationUnit) element; 903 return null; 904 } 905 906 909 protected FileInfo createEmptyFileInfo() { 910 return new CompilationUnitInfo(); 911 } 912 913 916 protected IAnnotationModel createAnnotationModel(IFile file) { 917 return new CompilationUnitAnnotationModel(file); 918 } 919 920 923 protected FileInfo createFileInfo(Object element) throws CoreException { 924 ICompilationUnit original= null; 925 if (element instanceof IFileEditorInput) { 926 IFileEditorInput input= (IFileEditorInput) element; 927 original= createCompilationUnit(input.getFile()); 928 if (original == null) 929 return null; 930 } 931 932 FileInfo info= super.createFileInfo(element); 933 if (!(info instanceof CompilationUnitInfo)) 934 return null; 935 936 if (original == null) 937 original= createFakeCompiltationUnit(element, false); 938 if (original == null) 939 return null; 940 941 CompilationUnitInfo cuInfo= (CompilationUnitInfo) info; 942 setUpSynchronization(cuInfo); 943 944 IProblemRequestor requestor= cuInfo.fModel instanceof IProblemRequestor ? (IProblemRequestor) cuInfo.fModel : null; 945 if (requestor instanceof IProblemRequestorExtension) { 946 IProblemRequestorExtension extension= (IProblemRequestorExtension) requestor; 947 extension.setIsActive(false); 948 extension.setIsHandlingTemporaryProblems(isHandlingTemporaryProblems()); 949 } 950 951 if (JavaModelUtil.isPrimary(original)) 952 original.becomeWorkingCopy(requestor, getProgressMonitor()); 953 cuInfo.fCopy= original; 954 955 if (cuInfo.fModel instanceof CompilationUnitAnnotationModel) { 956 CompilationUnitAnnotationModel model= (CompilationUnitAnnotationModel) cuInfo.fModel; 957 model.setCompilationUnit(cuInfo.fCopy); 958 } 959 960 if (cuInfo.fModel != null) 961 cuInfo.fModel.addAnnotationModelListener(fGlobalAnnotationModelListener); 962 963 return cuInfo; 964 } 965 966 974 private ICompilationUnit createFakeCompiltationUnit(Object element, boolean setContents) { 975 if (element instanceof IStorageEditorInput) 976 return createFakeCompiltationUnit((IStorageEditorInput)element, setContents); 977 else if (element instanceof IURIEditorInput) 978 return createFakeCompiltationUnit((IURIEditorInput)element); 979 return null; 980 } 981 982 990 private ICompilationUnit createFakeCompiltationUnit(IStorageEditorInput editorInput, boolean setContents) { 991 try { 992 final IStorage storage= editorInput.getStorage(); 993 final IPath storagePath= storage.getFullPath(); 994 if (storage.getName() == null || storagePath == null) 995 return null; 996 997 final IPath documentPath; 998 if (storage instanceof IFileState) 999 documentPath= storagePath.append(Long.toString(((IFileState)storage).getModificationTime())); 1000 else 1001 documentPath= storagePath; 1002 1003 WorkingCopyOwner woc= new WorkingCopyOwner() { 1004 1008 public IBuffer createBuffer(ICompilationUnit workingCopy) { 1009 return new DocumentAdapter(workingCopy, documentPath); 1010 } 1011 }; 1012 1013 IClasspathEntry[] cpEntries= null; 1014 IJavaProject jp= findJavaProject(storagePath); 1015 if (jp != null) 1016 cpEntries= jp.getResolvedClasspath(true); 1017 1018 if (cpEntries == null || cpEntries.length == 0) 1019 cpEntries= new IClasspathEntry[] { JavaRuntime.getDefaultJREContainerEntry() }; 1020 1021 final ICompilationUnit cu= woc.newWorkingCopy(storage.getName(), cpEntries, getProgressMonitor()); 1022 if (setContents) { 1023 int READER_CHUNK_SIZE= 2048; 1024 int BUFFER_SIZE= 8 * READER_CHUNK_SIZE; 1025 1026 String charsetName= null; 1027 if (storage instanceof IEncodedStorage) 1028 charsetName= ((IEncodedStorage)storage).getCharset(); 1029 if (charsetName == null) 1030 charsetName= getDefaultEncoding(); 1031 1032 Reader in= null; 1033 InputStream contents= storage.getContents(); 1034 try { 1035 in= new BufferedReader (new InputStreamReader (contents, charsetName)); 1036 StringBuffer buffer= new StringBuffer (BUFFER_SIZE); 1037 char[] readBuffer= new char[READER_CHUNK_SIZE]; 1038 int n; 1039 n= in.read(readBuffer); 1040 while (n > 0) { 1041 buffer.append(readBuffer, 0, n); 1042 n= in.read(readBuffer); 1043 } 1044 cu.getBuffer().setContents(buffer.toString()); 1045 } catch (IOException e) { 1046 JavaPlugin.log(e); 1047 return null; 1048 } finally { 1049 try { 1050 if (in != null) 1051 in.close(); 1052 else 1053 contents.close(); 1054 } catch (IOException x) { 1055 } 1056 } 1057 } 1058 1059 if (!isModifiable(editorInput)) 1060 JavaModelUtil.reconcile(cu); 1061 1062 return cu; 1063 } catch (CoreException ex) { 1064 JavaPlugin.log(ex.getStatus()); 1065 return null; 1066 } 1067 } 1068 1069 1076 private ICompilationUnit createFakeCompiltationUnit(IURIEditorInput editorInput) { 1077 try { 1078 final URI uri= editorInput.getURI(); 1079 final IFileStore fileStore= EFS.getStore(uri); 1080 final IPath path= URIUtil.toPath(uri); 1081 if (fileStore.getName() == null || path == null) 1082 return null; 1083 1084 WorkingCopyOwner woc= new WorkingCopyOwner() { 1085 1089 public IBuffer createBuffer(ICompilationUnit workingCopy) { 1090 return new DocumentAdapter(workingCopy, path); 1091 } 1092 }; 1093 1094 IClasspathEntry[] cpEntries= null; 1095 IJavaProject jp= findJavaProject(path); 1096 if (jp != null) 1097 cpEntries= jp.getResolvedClasspath(true); 1098 1099 if (cpEntries == null || cpEntries.length == 0) 1100 cpEntries= new IClasspathEntry[] { JavaRuntime.getDefaultJREContainerEntry() }; 1101 1102 final ICompilationUnit cu= woc.newWorkingCopy(fileStore.getName(), cpEntries, getProgressMonitor()); 1103 1104 if (!isModifiable(editorInput)) 1105 JavaModelUtil.reconcile(cu); 1106 1107 return cu; 1108 } catch (CoreException ex) { 1109 return null; 1110 } 1111 } 1112 1113 1121 private IJavaProject findJavaProject(IPath path) { 1122 if (path == null) 1123 return null; 1124 1125 String [] pathSegments= path.segments(); 1126 IJavaModel model= JavaCore.create(JavaPlugin.getWorkspace().getRoot()); 1127 IJavaProject[] projects; 1128 try { 1129 projects= model.getJavaProjects(); 1130 } catch (JavaModelException e) { 1131 return null; } 1133 for (int i= 0; i < projects.length; i++) { 1134 IPath projectPath= projects[i].getProject().getFullPath(); 1135 String projectSegment= projectPath.segments()[0]; 1136 for (int j= 0; j < pathSegments.length; j++) 1137 if (projectSegment.equals(pathSegments[j])) 1138 return projects[i]; 1139 } 1140 return null; 1141 } 1142 1143 1146 protected void disposeFileInfo(Object element, FileInfo info) { 1147 if (info instanceof CompilationUnitInfo) { 1148 CompilationUnitInfo cuInfo= (CompilationUnitInfo) info; 1149 1150 try { 1151 cuInfo.fCopy.discardWorkingCopy(); 1152 } catch (JavaModelException x) { 1153 handleCoreException(x, x.getMessage()); 1154 } 1155 1156 if (cuInfo.fModel != null) 1157 cuInfo.fModel.removeAnnotationModelListener(fGlobalAnnotationModelListener); 1158 } 1159 super.disposeFileInfo(element, info); 1160 } 1161 1162 1166 public void connect(Object element) throws CoreException { 1167 super.connect(element); 1168 if (getFileInfo(element) != null) 1169 return; 1170 1171 CompilationUnitInfo info= (CompilationUnitInfo)fFakeCUMapForMissingInfo.get(element); 1172 if (info == null) { 1173 ICompilationUnit cu= createFakeCompiltationUnit(element, true); 1174 if (cu == null) 1175 return; 1176 info= new CompilationUnitInfo(); 1177 info.fCopy= cu; 1178 info.fElement= element; 1179 info.fModel= new AnnotationModel(); 1180 fFakeCUMapForMissingInfo.put(element, info); 1181 } 1182 info.fCount++; 1183 } 1184 1185 1189 public IAnnotationModel getAnnotationModel(Object element) { 1190 IAnnotationModel model= super.getAnnotationModel(element); 1191 if (model != null) 1192 return model; 1193 1194 FileInfo info= (FileInfo)fFakeCUMapForMissingInfo.get(element); 1195 if (info != null) { 1196 if (info.fModel != null) 1197 return info.fModel; 1198 if (info.fTextFileBuffer != null) 1199 return info.fTextFileBuffer.getAnnotationModel(); 1200 } 1201 1202 return null; 1203 } 1204 1205 1209 public void disconnect(Object element) { 1210 CompilationUnitInfo info= (CompilationUnitInfo)fFakeCUMapForMissingInfo.get(element); 1211 if (info != null) { 1212 if (info.fCount == 1) { 1213 fFakeCUMapForMissingInfo.remove(element); 1214 info.fModel= null; 1215 try { 1217 info.fCopy.discardWorkingCopy(); 1218 } catch (JavaModelException ex) { 1219 handleCoreException(ex, ex.getMessage()); 1220 } 1221 } else 1222 info.fCount--; 1223 } 1224 super.disconnect(element); 1225 } 1226 1227 1228 1236 private IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) { 1237 if (monitor != null) 1238 return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); 1239 1240 return new NullProgressMonitor(); 1241 } 1242 1243 protected void commitWorkingCopy(IProgressMonitor monitor, Object element, final CompilationUnitInfo info, boolean overwrite) throws CoreException { 1244 1245 if (monitor == null) 1246 monitor= new NullProgressMonitor(); 1247 1248 monitor.beginTask("", 120); 1250 try { 1251 final IProgressMonitor subMonitor1= getSubProgressMonitor(monitor, 50); 1252 1253 try { 1254 SafeRunner.run(new ISafeRunnable() { 1255 public void run() { 1256 try { 1257 info.fCopy.reconcile(ICompilationUnit.NO_AST, false, null, subMonitor1); 1258 } catch (JavaModelException ex) { 1259 handleException(ex); 1260 } catch (OperationCanceledException ex) { 1261 } 1263 } 1264 public void handleException(Throwable ex) { 1265 IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, "Error in JDT Core during reconcile while saving", ex); JavaPlugin.getDefault().getLog().log(status); 1267 } 1268 }); 1269 } finally { 1270 subMonitor1.done(); 1271 } 1272 1273 IDocument document= info.fTextFileBuffer.getDocument(); 1274 IResource resource= info.fCopy.getResource(); 1275 1276 Assert.isTrue(resource instanceof IFile); 1277 1278 boolean isSynchronized= resource.isSynchronized(IResource.DEPTH_ZERO); 1279 1280 1282 if (!isSynchronized && isDeleted(element)) 1283 info.fTextFileBuffer.setDirty(true); 1284 1285 if (!resource.exists()) { 1286 IProgressMonitor subMonitor2= getSubProgressMonitor(monitor, 70); 1288 try { 1289 createFileFromDocument(subMonitor2, (IFile) resource, document); 1290 } finally { 1291 subMonitor2.done(); 1292 } 1293 return; 1294 } 1295 1296 if (fSavePolicy != null) 1297 fSavePolicy.preSave(info.fCopy); 1298 1299 IProgressMonitor subMonitor3= getSubProgressMonitor(monitor, 50); 1300 try { 1301 fIsAboutToSave= true; 1302 info.fCopy.commitWorkingCopy(isSynchronized || overwrite, subMonitor3); 1303 notifyPostSaveListeners(info.fCopy, info, getSubProgressMonitor(monitor, 20)); 1304 } catch (CoreException x) { 1305 fireElementStateChangeFailed(element); 1307 throw x; 1308 } catch (RuntimeException x) { 1309 fireElementStateChangeFailed(element); 1311 throw x; 1312 } finally { 1313 fIsAboutToSave= false; 1314 subMonitor3.done(); 1315 } 1316 1317 if (info.fModel instanceof AbstractMarkerAnnotationModel) { 1320 AbstractMarkerAnnotationModel model= (AbstractMarkerAnnotationModel) info.fModel; 1321 model.updateMarkers(document); 1322 } 1323 1324 if (fSavePolicy != null) { 1325 ICompilationUnit unit= fSavePolicy.postSave(info.fCopy); 1326 if (unit != null && info.fModel instanceof AbstractMarkerAnnotationModel) { 1327 IResource r= unit.getResource(); 1328 IMarker[] markers= r.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO); 1329 if (markers != null && markers.length > 0) { 1330 AbstractMarkerAnnotationModel model= (AbstractMarkerAnnotationModel) info.fModel; 1331 for (int i= 0; i < markers.length; i++) 1332 model.updateMarker(document, markers[i], null); 1333 } 1334 } 1335 } 1336 } finally { 1337 monitor.done(); 1338 } 1339 } 1340 1341 1344 protected DocumentProviderOperation createSaveOperation(final Object element, final IDocument document, final boolean overwrite) throws CoreException { 1345 final FileInfo info= getFileInfo(element); 1346 if (info instanceof CompilationUnitInfo) { 1347 1348 ICompilationUnit cu= ((CompilationUnitInfo)info).fCopy; 1350 if (cu != null && !JavaModelUtil.isPrimary(cu)) 1351 return super.createSaveOperation(element, document, overwrite); 1352 1353 if (info.fTextFileBuffer.getDocument() != document) { 1354 Status status= new Status(IStatus.WARNING, EditorsUI.PLUGIN_ID, IStatus.ERROR, JavaEditorMessages.CompilationUnitDocumentProvider_saveAsTargetOpenInEditor, null); 1359 throw new CoreException(status); 1360 } 1361 1362 return new DocumentProviderOperation() { 1363 1366 protected void execute(IProgressMonitor monitor) throws CoreException { 1367 commitWorkingCopy(monitor, element, (CompilationUnitInfo) info, overwrite); 1368 } 1369 1372 public ISchedulingRule getSchedulingRule() { 1373 if (info.fElement instanceof IFileEditorInput) { 1374 IFile file= ((IFileEditorInput) info.fElement).getFile(); 1375 return computeSchedulingRule(file); 1376 } else 1377 return null; 1378 } 1379 }; 1380 } 1381 1382 return null; 1383 } 1384 1385 1390 protected boolean isHandlingTemporaryProblems() { 1391 IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); 1392 return store.getBoolean(HANDLE_TEMPORARY_PROBLEMS); 1393 } 1394 1395 1398 protected void enableHandlingTemporaryProblems() { 1399 boolean enable= isHandlingTemporaryProblems(); 1400 for (Iterator iter= getFileInfosIterator(); iter.hasNext();) { 1401 FileInfo info= (FileInfo) iter.next(); 1402 if (info.fModel instanceof IProblemRequestorExtension) { 1403 IProblemRequestorExtension extension= (IProblemRequestorExtension) info.fModel; 1404 extension.setIsHandlingTemporaryProblems(enable); 1405 } 1406 } 1407 } 1408 1409 1412 public void setSavePolicy(ISavePolicy savePolicy) { 1413 fSavePolicy= savePolicy; 1414 } 1415 1416 1419 public void addGlobalAnnotationModelListener(IAnnotationModelListener listener) { 1420 fGlobalAnnotationModelListener.addListener(listener); 1421 } 1422 1423 1426 public void removeGlobalAnnotationModelListener(IAnnotationModelListener listener) { 1427 fGlobalAnnotationModelListener.removeListener(listener); 1428 } 1429 1430 1433 public ICompilationUnit getWorkingCopy(Object element) { 1434 FileInfo fileInfo= getFileInfo(element); 1435 if (fileInfo instanceof CompilationUnitInfo) { 1436 CompilationUnitInfo info= (CompilationUnitInfo)fileInfo; 1437 return info.fCopy; 1438 } 1439 CompilationUnitInfo cuInfo= (CompilationUnitInfo)fFakeCUMapForMissingInfo.get(element); 1440 if (cuInfo != null) 1441 return cuInfo.fCopy; 1442 1443 return null; 1444 } 1445 1446 1449 public void shutdown() { 1450 JavaPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyListener); 1451 Iterator e= getConnectedElementsIterator(); 1452 while (e.hasNext()) 1453 disconnect(e.next()); 1454 fFakeCUMapForMissingInfo.clear(); 1455 } 1456 1457 1460 public void saveDocumentContent(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException { 1461 if (!fIsAboutToSave) 1462 return; 1463 super.saveDocument(monitor, element, document, overwrite); 1464 } 1465 1466 1469 public ILineTracker createLineTracker(Object element) { 1470 return new DefaultLineTracker(); 1471 } 1472 1473 1489 protected void notifyPostSaveListeners(final ICompilationUnit unit, final CompilationUnitInfo info, final IProgressMonitor monitor) throws CoreException { 1490 final IBuffer buffer= unit.getBuffer(); 1491 IPostSaveListener[] listeners= JavaPlugin.getDefault().getSaveParticipantRegistry().getEnabledPostSaveListeners(unit.getJavaProject().getProject()); 1492 1493 String message= JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantProblem; 1494 final MultiStatus errorStatus= new MultiStatus(JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, message, null); 1495 1496 monitor.beginTask(JavaEditorMessages.CompilationUnitDocumentProvider_progressNotifyingSaveParticipants, listeners.length * 5); 1497 try { 1498 for (int i= 0; i < listeners.length; i++) { 1499 final IPostSaveListener listener= listeners[i]; 1500 final String participantName= listener.getName(); 1501 SafeRunner.run(new ISafeRunnable() { 1502 public void run() { 1503 try { 1504 long stamp= unit.getResource().getModificationStamp(); 1505 1506 listener.saved(unit, getSubProgressMonitor(monitor, 4)); 1507 1508 if (stamp != unit.getResource().getModificationStamp()) { 1509 String msg= Messages.format(JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantSavedFile, participantName); 1510 errorStatus.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null)); 1511 } 1512 1513 if (buffer.hasUnsavedChanges()) 1514 buffer.save(getSubProgressMonitor(monitor, 1), true); 1515 1516 } catch (CoreException ex) { 1517 handleException(ex); 1518 } finally { 1519 monitor.worked(1); 1520 } 1521 } 1522 1523 public void handleException(Throwable ex) { 1524 String msg= Messages.format("The save participant ''{0}'' caused an exception: {1}", new String [] { listener.getId(), ex.toString()}); JavaPlugin.log(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null)); 1526 1527 msg= Messages.format(JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantFailed, new String [] { participantName, ex.toString()}); 1528 errorStatus.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null)); 1529 1530 if (info != null && buffer.hasUnsavedChanges()) { 1532 try { 1533 info.fTextFileBuffer.revert(getSubProgressMonitor(monitor, 1)); 1534 } catch (CoreException e) { 1535 msg= Messages.format("Error on revert after failure of save participant ''{0}''.", participantName); IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, ex); 1537 JavaPlugin.getDefault().getLog().log(status); 1538 } 1539 1540 if (info.fModel instanceof AbstractMarkerAnnotationModel) { 1541 AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel)info.fModel; 1542 markerModel.resetMarkers(); 1543 } 1544 } 1545 1546 } 1557 }); 1558 } 1559 } finally { 1560 monitor.done(); 1561 if (!errorStatus.isOK()) 1562 throw new CoreException(errorStatus); 1563 } 1564 } 1565 1566} 1567 | Popular Tags |