1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.javaeditor;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
17 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.resources.IResource;
21 import org.eclipse.core.filebuffers.FileBuffers;
22 import org.eclipse.core.filebuffers.LocationKind;
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.ISynchronizable;
26 import org.eclipse.jface.text.source.IAnnotationModel;
28 import org.eclipse.ui.IEditorInput;
29 import org.eclipse.ui.IFileEditorInput;
31 import org.eclipse.ui.editors.text.FileDocumentProvider;
33 import org.eclipse.jdt.core.ElementChangedEvent;
34 import org.eclipse.jdt.core.IClassFile;
35 import org.eclipse.jdt.core.IElementChangedListener;
36 import org.eclipse.jdt.core.IJavaElement;
37 import org.eclipse.jdt.core.IJavaElementDelta;
38 import org.eclipse.jdt.core.IJavaProject;
39 import org.eclipse.jdt.core.IPackageFragmentRoot;
40 import org.eclipse.jdt.core.IType;
41 import org.eclipse.jdt.core.JavaCore;
42 import org.eclipse.jdt.core.JavaModelException;
44 import org.eclipse.jdt.ui.text.IJavaPartitions;
45 import org.eclipse.jdt.ui.text.JavaTextTools;
47 import org.eclipse.jdt.internal.ui.IResourceLocator;
48 import org.eclipse.jdt.internal.ui.JavaPlugin;
52 * A document provider for class files. Class files can be either inside
54 public class ClassFileDocumentProvider extends FileDocumentProvider {
57 * An input change listener to request the editor to reread the input.
59 public interface InputChangeListener {
60 void inputChanged(IClassFileEditorInput input);
64 * Synchronizes the document with external resource changes.
66 protected class ClassFileSynchronizer implements IElementChangedListener {
68 protected IClassFileEditorInput fInput;
69 protected IPackageFragmentRoot fPackageFragmentRoot;
72 * Default constructor.
74 * @param input the class file editor input
76 public ClassFileSynchronizer(IClassFileEditorInput input) {
80 IJavaElement parent= fInput.getClassFile().getParent();
81 while (parent != null && !(parent instanceof IPackageFragmentRoot)) {
82 parent= parent.getParent();
84 fPackageFragmentRoot= (IPackageFragmentRoot) parent;
88 * Installs the synchronizer.
90 public void install() {
91 JavaCore.addElementChangedListener(this);
95 * Uninstalls the synchronizer.
97 public void uninstall() {
98 JavaCore.removeElementChangedListener(this);
102 * @see IElementChangedListener#elementChanged
104 public void elementChanged(ElementChangedEvent e) {
105 check(fPackageFragmentRoot, e.getDelta());
109 * Recursively check whether the class file has been deleted.
111 * @param input the package fragment root
112 * @param delta the Java element delta
113 * @return <code>true</code> if delta processing can be stopped
115 protected boolean check(IPackageFragmentRoot input, IJavaElementDelta delta) {
116 IJavaElement element= delta.getElement();
118 if ((delta.getKind() & IJavaElementDelta.REMOVED) != 0 || (delta.getFlags() & IJavaElementDelta.F_CLOSED) != 0) {
119 // http://dev.eclipse.org/bugs/show_bug.cgi?id=19023
120 if (element.equals(input.getJavaProject()) || element.equals(input)) {
121 handleDeleted(fInput);
126 if (((delta.getFlags() & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) && input.equals(element)) {
127 handleDeleted(fInput);
131 if (((delta.getFlags() & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) && input.equals(element)) {
132 handleDeleted(fInput);
136 IJavaElementDelta[] subdeltas= delta.getAffectedChildren();
137 for (int i= 0; i < subdeltas.length; i++) {
138 if (check(input, subdeltas[i]))
142 if ((delta.getFlags() & IJavaElementDelta.F_SOURCEDETACHED) != 0 ||
143 (delta.getFlags() & IJavaElementDelta.F_SOURCEATTACHED) != 0)
145 IClassFile file= fInput != null ? fInput.getClassFile() : null;
146 IJavaProject project= input != null ? input.getJavaProject() : null;
148 boolean isOnClasspath= false;
149 if (file != null && project != null)
150 isOnClasspath= project.isOnClasspath(file);
153 fireInputChanged(fInput);
156 handleDeleted(fInput);
166 * Correcting the visibility of <code>FileSynchronizer</code>.
168 protected class _FileSynchronizer extends FileSynchronizer {
169 public _FileSynchronizer(IFileEditorInput fileEditorInput) {
170 super(fileEditorInput);
175 * Bundle of all required informations.
177 protected class ClassFileInfo extends FileInfo {
179 ClassFileSynchronizer fClassFileSynchronizer= null;
181 ClassFileInfo(IDocument document, IAnnotationModel model, _FileSynchronizer fileSynchronizer) {
182 super(document, model, fileSynchronizer);
185 ClassFileInfo(IDocument document, IAnnotationModel model, ClassFileSynchronizer classFileSynchronizer) {
186 super(document, model, null);
187 fClassFileSynchronizer= classFileSynchronizer;
191 /** Input change listeners. */
192 private List<InputChangeListener> fInputListeners= new ArrayList<InputChangeListener>();
195 * Creates a new document provider.
197 public ClassFileDocumentProvider() {
202 * @see StorageDocumentProvider#setDocumentContent(IDocument, IEditorInput)
205 protected boolean setDocumentContent(IDocument document, IEditorInput editorInput, String encoding) throws CoreException {
206 if (editorInput instanceof IClassFileEditorInput) {
207 IClassFile classFile= ((IClassFileEditorInput) editorInput).getClassFile();
208 String source= classFile.getSource();
210 source= ""; //$NON-NLS-1$
211 document.set(source);
214 return super.setDocumentContent(document, editorInput, encoding);
218 * Creates an annotation model derived from the given class file editor input.
220 * @param classFileEditorInput the editor input from which to query the annotations
221 * @return the created annotation model
222 * @exception CoreException if the editor input could not be accessed
224 protected IAnnotationModel createClassFileAnnotationModel(IClassFileEditorInput classFileEditorInput) throws CoreException {
225 IResource resource= null;
226 IClassFile classFile= classFileEditorInput.getClassFile();
228 IResourceLocator locator= (IResourceLocator) classFile.getAdapter(IResourceLocator.class);
230 resource= locator.getContainingResource(classFile);
232 if (resource != null) {
233 ClassFileMarkerAnnotationModel model= new ClassFileMarkerAnnotationModel(resource);
234 model.setClassFile(classFile);
242 * @see org.eclipse.ui.editors.text.StorageDocumentProvider#createEmptyDocument()
246 protected IDocument createEmptyDocument() {
247 IDocument document= FileBuffers.getTextFileBufferManager().createEmptyDocument(null, LocationKind.IFILE);
248 if (document instanceof ISynchronizable)
249 ((ISynchronizable)document).setLockObject(new Object());
254 * @see AbstractDocumentProvider#createDocument(Object)
257 protected IDocument createDocument(Object element) throws CoreException {
258 IDocument document= super.createDocument(element);
259 if (document != null) {
260 JavaTextTools tools= JavaPlugin.getDefault().getJavaTextTools();
261 tools.setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING);
267 * @see AbstractDocumentProvider#createElementInfo(Object)
270 protected ElementInfo createElementInfo(Object element) throws CoreException {
272 if (element instanceof IClassFileEditorInput) {
274 IClassFileEditorInput input = (IClassFileEditorInput) element;
275 ExternalClassFileEditorInput external= null;
276 if (input instanceof ExternalClassFileEditorInput)
277 external= (ExternalClassFileEditorInput) input;
279 if (external != null) {
281 refreshFile(external.getFile());
282 } catch (CoreException x) {
283 handleCoreException(x, JavaEditorMessages.ClassFileDocumentProvider_error_createElementInfo);
287 IDocument d= createDocument(input);
288 IAnnotationModel m= createClassFileAnnotationModel(input);
290 if (external != null) {
291 ClassFileInfo info= new ClassFileInfo(d, m, (_FileSynchronizer) null);
292 info.fModificationStamp= computeModificationStamp(external.getFile());
293 info.fEncoding= getPersistedEncoding(element);
295 } else if (input instanceof InternalClassFileEditorInput) {
296 ClassFileSynchronizer s= new ClassFileSynchronizer(input);
298 ClassFileInfo info= new ClassFileInfo(d, m, s);
299 info.fEncoding= getPersistedEncoding(element);
308 * @see FileDocumentProvider#disposeElementInfo(Object, ElementInfo)
311 protected void disposeElementInfo(Object element, ElementInfo info) {
312 ClassFileInfo classFileInfo= (ClassFileInfo) info;
313 if (classFileInfo.fClassFileSynchronizer != null) {
314 classFileInfo.fClassFileSynchronizer.uninstall();
315 classFileInfo.fClassFileSynchronizer= null;
318 super.disposeElementInfo(element, info);
322 * @see org.eclipse.ui.texteditor.IDocumentProviderExtension3#isSynchronized(java.lang.Object)
326 public boolean isSynchronized(Object element) {
327 Object elementInfo= getElementInfo(element);
328 if (elementInfo instanceof ClassFileInfo) {
329 IClassFileEditorInput input= (IClassFileEditorInput)element;
332 resource= input.getClassFile().getUnderlyingResource();
333 } catch (JavaModelException e) {
336 return resource == null || resource.isSynchronized(IResource.DEPTH_ZERO);
342 * Handles the deletion of the element underlying the given class file editor input.
343 * @param input the editor input
345 protected void handleDeleted(IClassFileEditorInput input) {
347 fireElementDeleted(input);
354 IClassFile cf= input.getClassFile();
357 * Let's try to find the class file - maybe the JAR changed
359 IType type= cf.getType();
360 IJavaProject project= cf.getJavaProject();
361 if (project != null) {
362 type= project.findType(type.getFullyQualifiedName());
364 IEditorInput editorInput= EditorUtility.getEditorInput(type.getParent());
365 if (editorInput instanceof IClassFileEditorInput) {
366 fireInputChanged((IClassFileEditorInput)editorInput);
371 } catch (JavaModelException x) {
372 // Don't log and fall through: element deleted
375 fireElementDeleted(input);
380 * Fires input changes to input change listeners.
382 * @param input the class file editor input
384 protected void fireInputChanged(IClassFileEditorInput input) {
385 List<InputChangeListener> list= new ArrayList<InputChangeListener>(fInputListeners);
386 for (Iterator<InputChangeListener> i = list.iterator(); i.hasNext();)
387 i.next().inputChanged(input);
391 * Adds an input change listener.
393 * @param listener the input change listener
395 public void addInputChangeListener(InputChangeListener listener) {
396 fInputListeners.add(listener);
400 * Removes an input change listener.
402 * @param listener the input change listener
404 public void removeInputChangeListener(InputChangeListener listener) {
405 fInputListeners.remove(listener);