001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.ui;
011:
012: import org.eclipse.core.resources.IResource;
013: import org.eclipse.core.resources.IResourceDelta;
014:
015: import org.eclipse.swt.widgets.Control;
016:
017: import org.eclipse.jface.viewers.IBasicPropertyConstants;
018: import org.eclipse.jface.viewers.ITreeContentProvider;
019: import org.eclipse.jface.viewers.TreeViewer;
020: import org.eclipse.jface.viewers.Viewer;
021:
022: import org.eclipse.jdt.core.*;
023:
024: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
025: import org.eclipse.jdt.internal.ui.JavaPlugin;
026:
027: /**
028: * A tree content provider for Java elements. It extends the
029: * StandardJavaElementContentProvider with support for listening to changes.
030: * <p>
031: * This class may be instantiated; it is not intended to be subclassed.
032: * </p>
033: * @deprecated use the StandardJavaElementContentProvider instead
034: * @see StandardJavaElementContentProvider
035: */
036: public class JavaElementContentProvider extends
037: StandardJavaElementContentProvider implements
038: ITreeContentProvider, IElementChangedListener {
039:
040: /** The tree viewer */
041: protected TreeViewer fViewer;
042: /** The input object */
043: protected Object fInput;
044:
045: /* (non-Javadoc)
046: * Method declared on IContentProvider.
047: */
048: public void dispose() {
049: super .dispose();
050: JavaCore.removeElementChangedListener(this );
051: }
052:
053: /* (non-Javadoc)
054: * Method declared on IContentProvider.
055: */
056: public void inputChanged(Viewer viewer, Object oldInput,
057: Object newInput) {
058: super .inputChanged(viewer, oldInput, newInput);
059: fViewer = (TreeViewer) viewer;
060: if (oldInput == null && newInput != null) {
061: JavaCore.addElementChangedListener(this );
062: } else if (oldInput != null && newInput == null) {
063: JavaCore.removeElementChangedListener(this );
064: }
065: fInput = newInput;
066: }
067:
068: /**
069: * Creates a new content provider for Java elements.
070: */
071: public JavaElementContentProvider() {
072: }
073:
074: /**
075: * Creates a new content provider for Java elements.
076: *
077: * @param provideMembers if <code>true</code> members below compilation units
078: * and class files are provided.
079: * @param provideWorkingCopy if <code>true</code> the element provider provides
080: * working copies for members of compilation units which have an associated working
081: * copy. Otherwise only original elements are provided.
082: *
083: * @since 2.0
084: */
085: public JavaElementContentProvider(boolean provideMembers,
086: boolean provideWorkingCopy) {
087: super (provideMembers, provideWorkingCopy);
088: }
089:
090: /* (non-Javadoc)
091: * Method declared on IElementChangedListener.
092: */
093: public void elementChanged(final ElementChangedEvent event) {
094: try {
095: processDelta(event.getDelta());
096: } catch (JavaModelException e) {
097: JavaPlugin.log(e);
098: }
099: }
100:
101: /**
102: * Processes a delta recursively. When more than two children are affected the
103: * tree is fully refreshed starting at this node. The delta is processed in the
104: * current thread but the viewer updates are posted to the UI thread.
105: *
106: * @param delta the delta to be processed
107: *
108: * @throws JavaModelException if an error occurs while processing the delta
109: */
110: protected void processDelta(IJavaElementDelta delta)
111: throws JavaModelException {
112: int kind = delta.getKind();
113: int flags = delta.getFlags();
114: IJavaElement element = delta.getElement();
115:
116: if (element instanceof ICompilationUnit) {
117: if (!getProvideWorkingCopy())
118: return;
119:
120: ICompilationUnit cu = (ICompilationUnit) element;
121: if (!JavaModelUtil.isPrimary(cu)
122: || !isOnClassPath((ICompilationUnit) element)) {
123: return;
124: }
125: }
126:
127: // handle open and closing of a solution or project
128: if (((flags & IJavaElementDelta.F_CLOSED) != 0)
129: || ((flags & IJavaElementDelta.F_OPENED) != 0)) {
130: postRefresh(element);
131: return;
132: }
133:
134: if (kind == IJavaElementDelta.REMOVED) {
135: Object parent = internalGetParent(element);
136: postRemove(element);
137: if (parent instanceof IPackageFragment)
138: updatePackageIcon((IPackageFragment) parent);
139: // we are filtering out empty subpackages, so we
140: // a package becomes empty we remove it from the viewer.
141: if (isPackageFragmentEmpty(element.getParent())) {
142: if (fViewer.testFindItem(parent) != null)
143: postRefresh(internalGetParent(parent));
144: }
145: return;
146: }
147:
148: if (kind == IJavaElementDelta.ADDED) {
149: Object parent = internalGetParent(element);
150: // we are filtering out empty subpackages, so we
151: // have to handle additions to them specially.
152: if (parent instanceof IPackageFragment) {
153: Object grandparent = internalGetParent(parent);
154: // 1GE8SI6: ITPJUI:WIN98 - Rename is not shown in Packages View
155: // avoid posting a refresh to an invisible parent
156: if (parent.equals(fInput)) {
157: postRefresh(parent);
158: } else {
159: // refresh from grandparent if parent isn't visible yet
160: if (fViewer.testFindItem(parent) == null)
161: postRefresh(grandparent);
162: else {
163: postRefresh(parent);
164: }
165: }
166: } else {
167: postAdd(parent, element);
168: }
169: }
170:
171: if (element instanceof ICompilationUnit) {
172: if (kind == IJavaElementDelta.CHANGED) {
173: postRefresh(element);
174: return;
175: }
176: }
177: // we don't show the contents of a compilation or IClassFile, so don't go any deeper
178: if ((element instanceof ICompilationUnit)
179: || (element instanceof IClassFile))
180: return;
181:
182: // the contents of an external JAR has changed
183: if (element instanceof IPackageFragmentRoot
184: && ((flags & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0))
185: postRefresh(element);
186:
187: if (isClassPathChange(delta)) {
188: // throw the towel and do a full refresh of the affected java project.
189: postRefresh(element.getJavaProject());
190: }
191:
192: if (delta.getResourceDeltas() != null) {
193: IResourceDelta[] rd = delta.getResourceDeltas();
194: for (int i = 0; i < rd.length; i++) {
195: processResourceDelta(rd[i], element);
196: }
197: }
198:
199: IJavaElementDelta[] affectedChildren = delta
200: .getAffectedChildren();
201: if (affectedChildren.length > 1) {
202: // a package fragment might become non empty refresh from the parent
203: if (element instanceof IPackageFragment) {
204: IJavaElement parent = (IJavaElement) internalGetParent(element);
205: // 1GE8SI6: ITPJUI:WIN98 - Rename is not shown in Packages View
206: // avoid posting a refresh to an invisible parent
207: if (element.equals(fInput)) {
208: postRefresh(element);
209: } else {
210: postRefresh(parent);
211: }
212: return;
213: }
214: // more than one child changed, refresh from here downwards
215: if (element instanceof IPackageFragmentRoot)
216: postRefresh(skipProjectPackageFragmentRoot((IPackageFragmentRoot) element));
217: else
218: postRefresh(element);
219: return;
220: }
221: for (int i = 0; i < affectedChildren.length; i++) {
222: processDelta(affectedChildren[i]);
223: }
224: }
225:
226: private boolean isOnClassPath(ICompilationUnit element) {
227: IJavaProject project = element.getJavaProject();
228: if (project == null || !project.exists())
229: return false;
230: return project.isOnClasspath(element);
231: }
232:
233: /*
234: * Updates the package icon
235: */
236: private void updatePackageIcon(final IJavaElement element) {
237: postRunnable(new Runnable() {
238: public void run() {
239: // 1GF87WR: ITPUI:ALL - SWTEx + NPE closing a workbench window.
240: Control ctrl = fViewer.getControl();
241: if (ctrl != null && !ctrl.isDisposed())
242: fViewer
243: .update(
244: element,
245: new String[] { IBasicPropertyConstants.P_IMAGE });
246: }
247: });
248: }
249:
250: /*
251: * Process resource deltas
252: */
253: private void processResourceDelta(IResourceDelta delta,
254: Object parent) {
255: int status = delta.getKind();
256: IResource resource = delta.getResource();
257: // filter out changes affecting the output folder
258: if (resource == null)
259: return;
260:
261: // this could be optimized by handling all the added children in the parent
262: if ((status & IResourceDelta.REMOVED) != 0) {
263: if (parent instanceof IPackageFragment)
264: // refresh one level above to deal with empty package filtering properly
265: postRefresh(internalGetParent(parent));
266: else
267: postRemove(resource);
268: }
269: if ((status & IResourceDelta.ADDED) != 0) {
270: if (parent instanceof IPackageFragment)
271: // refresh one level above to deal with empty package filtering properly
272: postRefresh(internalGetParent(parent));
273: else
274: postAdd(parent, resource);
275: }
276: IResourceDelta[] affectedChildren = delta.getAffectedChildren();
277:
278: if (affectedChildren.length > 1) {
279: // more than one child changed, refresh from here downwards
280: postRefresh(resource);
281: return;
282: }
283:
284: for (int i = 0; i < affectedChildren.length; i++)
285: processResourceDelta(affectedChildren[i], resource);
286: }
287:
288: private void postRefresh(final Object root) {
289: postRunnable(new Runnable() {
290: public void run() {
291: // 1GF87WR: ITPUI:ALL - SWTEx + NPE closing a workbench window.
292: Control ctrl = fViewer.getControl();
293: if (ctrl != null && !ctrl.isDisposed())
294: fViewer.refresh(root);
295: }
296: });
297: }
298:
299: private void postAdd(final Object parent, final Object element) {
300: postRunnable(new Runnable() {
301: public void run() {
302: // 1GF87WR: ITPUI:ALL - SWTEx + NPE closing a workbench window.
303: Control ctrl = fViewer.getControl();
304: if (ctrl != null && !ctrl.isDisposed())
305: fViewer.add(parent, element);
306: }
307: });
308: }
309:
310: private void postRemove(final Object element) {
311: postRunnable(new Runnable() {
312: public void run() {
313: // 1GF87WR: ITPUI:ALL - SWTEx + NPE closing a workbench window.
314: Control ctrl = fViewer.getControl();
315: if (ctrl != null && !ctrl.isDisposed())
316: fViewer.remove(element);
317: }
318: });
319: }
320:
321: private void postRunnable(final Runnable r) {
322: Control ctrl = fViewer.getControl();
323: if (ctrl != null && !ctrl.isDisposed()) {
324: ctrl.getDisplay().asyncExec(r);
325: }
326: }
327: }
|