diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileDocumentProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileDocumentProvider.java index e626f3be29a..d1e2dedf928 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileDocumentProvider.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileDocumentProvider.java @@ -209,7 +209,7 @@ public ClassFileDocumentProvider() { protected boolean setDocumentContent(IDocument document, IEditorInput editorInput, String encoding) throws CoreException { if (editorInput instanceof IClassFileEditorInput) { IClassFile classFile= ((IClassFileEditorInput) editorInput).getClassFile(); - String source= classFile.getSource(); + String source= getSourceIfPresent(classFile); if (source == null) source= ""; //$NON-NLS-1$ document.set(source); @@ -218,6 +218,15 @@ protected boolean setDocumentContent(IDocument document, IEditorInput editorInpu return super.setDocumentContent(document, editorInput, encoding); } + private String getSourceIfPresent(IClassFile classFile) { + try { + return classFile.getSource(); + } catch (JavaModelException e) { + //Assume no source... + return null; + } + } + /** * Creates an annotation model derived from the given class file editor input. * diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileEditor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileEditor.java index 6c54d42df4d..5be307c34c2 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileEditor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileEditor.java @@ -73,15 +73,18 @@ import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.jdt.core.ClasspathContainerInitializer; +import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IElementChangedListener; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModelStatusConstants; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IOrdinaryClassFile; import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.ISourceReference; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; @@ -111,6 +114,75 @@ * Java specific text editor. */ public class ClassFileEditor extends JavaEditor implements ClassFileDocumentProvider.InputChangeListener { + + private final class LoadJob extends Job implements IElementChangedListener { + private final IJavaElement fElement; + private volatile boolean continueListening; + + private LoadJob(IJavaElement element) { + super("Restoring editor input for " + element.getElementName()); //$NON-NLS-1$ + fElement= element; + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + if(monitor.isCanceled() || disposed) { + continueListening = false; + return Status.CANCEL_STATUS; + } + if (!(fElement instanceof IOrdinaryClassFile) || fElement.exists()) { + return Status.OK_STATUS; + } + /* + * Let's try to find the class file, + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=83221 + */ + IOrdinaryClassFile cf= (IOrdinaryClassFile)fElement; + IType type= cf.getType(); + IJavaProject project= fElement.getJavaProject(); + if (project != null) { + type= project.findType(type.getFullyQualifiedName()); + if (type != null) { + continueListening = false; + IJavaElement javaElement= type.getParent(); + IEditorInput editorInput= EditorUtility.getEditorInput(javaElement); + PlatformUI.getWorkbench().getDisplay().asyncExec(() -> { + if (!disposed) { + setInput(editorInput); + if(javaElement instanceof ISourceReference ref) { + setBreadcrumbInput(ref); + } + } + }); + } else { + if (!continueListening) { + continueListening= true; + JavaCore.addElementChangedListener(this); + } + } + } + } catch (CoreException e) { + return e.getStatus(); + } finally { + if (!continueListening) { + JavaCore.removeElementChangedListener(this); + } + } + return Status.OK_STATUS; + } + + @Override + public boolean belongsTo(Object family) { + return family == ClassFileEditor.class; + } + + @Override + public void elementChanged(ElementChangedEvent event) { + schedule(100); + } + } + /** * A form to attach source to a class file. */ @@ -409,7 +481,9 @@ private void updateCodeView(StyledText styledText, IClassFile classFile) { try { content= disassembler.disassemble(classFile.getBytes(), "\n", ClassFileBytesDisassembler.DETAILED); //$NON-NLS-1$ } catch (JavaModelException ex) { - JavaPlugin.log(ex.getStatus()); + if (!ex.isDoesNotExist()) { + JavaPlugin.log(ex.getStatus()); + } } catch (ClassFormatException ex) { JavaPlugin.log(ex); } @@ -511,6 +585,7 @@ private boolean isEqualInput(IEditorInput input1, IEditorInput input2) { * @since 3.3 */ private StyledText fNoSourceTextWidget; + private volatile boolean disposed; /** * Default constructor. @@ -644,21 +719,8 @@ public boolean isEditorInputReadOnly() { protected IEditorInput transformEditorInput(IEditorInput input) throws CoreException{ if (input instanceof HandleEditorInput handle) { IJavaElement element= handle.getElement(); - if (!element.exists() && element instanceof IOrdinaryClassFile) { - /* - * Let's try to find the class file, - * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=83221 - */ - IOrdinaryClassFile cf= (IOrdinaryClassFile)element; - IType type= cf.getType(); - IJavaProject project= element.getJavaProject(); - if (project != null) { - type= project.findType(type.getFullyQualifiedName()); - if (type == null) - return null; - element= type.getParent(); - } - } + LoadJob job= new LoadJob(element); + job.schedule(); input= EditorUtility.getEditorInput(element); } if (input instanceof IFileEditorInput) { @@ -694,21 +756,6 @@ private void doSetInputCached(IEditorInput input) throws CoreException { message, null)); } - - JavaModelException e= probeInputForSource(input); - if (e != null) { - IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input; - IClassFile file= classFileEditorInput.getClassFile(); - IJavaProject javaProject= file.getJavaProject(); - if (!javaProject.exists() || !javaProject.isOnClasspath(file)) { - throw new CoreException(JavaUIStatus.createError( - IJavaModelStatusConstants.INVALID_RESOURCE, - JavaEditorMessages.ClassFileEditor_error_classfile_not_on_classpath, - null)); - } - throw e; - } - IDocumentProvider documentProvider= getDocumentProvider(); if (documentProvider instanceof ClassFileDocumentProvider) { ((ClassFileDocumentProvider) documentProvider).removeInputChangeListener(this); @@ -799,23 +846,6 @@ private void createPartControlCached(Composite parent) { } } - private JavaModelException probeInputForSource(IEditorInput input) { - if (input == null) { - return null; - } - - IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input; - IClassFile file= classFileEditorInput.getClassFile(); - - try { - file.getSourceRange(); - } catch (JavaModelException e) { - return e; - } - - return null; - } - /** * Checks if the class file input has no source attached. If so, a source attachment form is shown. * @@ -836,7 +866,7 @@ private void verifyInput(IEditorInput input) throws JavaModelException { boolean wasUsingSourceCopyAction= fSourceCopyAction == getAction(ITextEditorActionConstants.COPY); // show source attachment form if no source found - if (file.getSourceRange() == null) { + if (!hasSource(file)) { // dispose old source attachment form if (fSourceAttachmentForm != null) { fSourceAttachmentForm.dispose(); @@ -925,6 +955,15 @@ public void run() { } } + private static boolean hasSource(IClassFile file) { + try { + return file.getSourceRange() != null; + } catch (JavaModelException e) { + //assume no source then... + return false; + } + } + /* * @see ClassFileDocumentProvider.InputChangeListener#inputChanged(IClassFileEditorInput) */ @@ -973,6 +1012,7 @@ public void doOperation(int operation) { */ @Override public void dispose() { + disposed = true; // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18510 IDocumentProvider documentProvider= getDocumentProvider(); if (documentProvider instanceof ClassFileDocumentProvider) { diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/InternalClassFileEditorInput.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/InternalClassFileEditorInput.java index 0cb974c8d71..c92f2420d07 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/InternalClassFileEditorInput.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/InternalClassFileEditorInput.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.nio.file.Files; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; @@ -45,7 +44,7 @@ public class InternalClassFileEditorInput implements IClassFileEditorInput, IPer private IClassFile fClassFile; - private IPath fPath; + private volatile IPath fPath; public InternalClassFileEditorInput(IClassFile classFile) { fClassFile= classFile; @@ -182,10 +181,12 @@ private static IPath writeToTempFile(IClassFile classFile) { return new Path(file.toString()); } catch (IOException e) { JavaPlugin.log(e); - } catch (CoreException e) { - JavaPlugin.log(e.getStatus()); + } catch (JavaModelException ex) { + if (!ex.isDoesNotExist()) { + JavaPlugin.log(ex.getStatus()); + } } - throw new IllegalArgumentException("Could not create temporary file."); //$NON-NLS-1$ + return IPath.EMPTY; } } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java index 937dd308d9e..ede85da4205 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java @@ -1999,9 +1999,8 @@ private void hideBreadcrumb() { /** * Sets the breadcrumb input to the given element. * @param element the element to use as input for the breadcrumb - * @since 3.4 */ - private void setBreadcrumbInput(ISourceReference element) { + protected void setBreadcrumbInput(ISourceReference element) { if (fBreadcrumb == null) return;