001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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 java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.core.runtime.CoreException;
016:
017: import org.eclipse.core.resources.IFile;
018: import org.eclipse.core.resources.IFolder;
019: import org.eclipse.core.resources.IResource;
020:
021: import org.eclipse.jface.viewers.ITreeContentProvider;
022: import org.eclipse.jface.viewers.Viewer;
023:
024: import org.eclipse.jdt.core.IClassFile;
025: import org.eclipse.jdt.core.ICompilationUnit;
026: import org.eclipse.jdt.core.IJarEntryResource;
027: import org.eclipse.jdt.core.IJavaElement;
028: import org.eclipse.jdt.core.IJavaElementDelta;
029: import org.eclipse.jdt.core.IJavaModel;
030: import org.eclipse.jdt.core.IJavaProject;
031: import org.eclipse.jdt.core.IPackageFragment;
032: import org.eclipse.jdt.core.IPackageFragmentRoot;
033: import org.eclipse.jdt.core.IParent;
034: import org.eclipse.jdt.core.ISourceReference;
035: import org.eclipse.jdt.core.JavaCore;
036: import org.eclipse.jdt.core.JavaModelException;
037:
038: /**
039: * A base content provider for Java elements. It provides access to the
040: * Java element hierarchy without listening to changes in the Java model.
041: * If updating the presentation on Java model change is required than
042: * clients have to subclass, listen to Java model changes and have to update
043: * the UI using corresponding methods provided by the JFace viewers or their
044: * own UI presentation.
045: * <p>
046: * The following Java element hierarchy is surfaced by this content provider:
047: * <p>
048: * <pre>
049: Java model (<code>IJavaModel</code>)
050: Java project (<code>IJavaProject</code>)
051: package fragment root (<code>IPackageFragmentRoot</code>)
052: package fragment (<code>IPackageFragment</code>)
053: compilation unit (<code>ICompilationUnit</code>)
054: binary class file (<code>IClassFile</code>)
055: * </pre>
056: * </p>
057: * <p>
058: * Note that when the entire Java project is declared to be package fragment root,
059: * the corresponding package fragment root element that normally appears between the
060: * Java project and the package fragments is automatically filtered out.
061: * </p>
062: *
063: * @since 2.0
064: */
065: public class StandardJavaElementContentProvider implements
066: ITreeContentProvider, IWorkingCopyProvider {
067:
068: protected static final Object[] NO_CHILDREN = new Object[0];
069: protected boolean fProvideMembers;
070: protected boolean fProvideWorkingCopy;
071:
072: /**
073: * Creates a new content provider. The content provider does not
074: * provide members of compilation units or class files.
075: */
076: public StandardJavaElementContentProvider() {
077: this (false);
078: }
079:
080: /**
081: *@deprecated Use {@link #StandardJavaElementContentProvider(boolean)} instead.
082: * Since 3.0 compilation unit children are always provided as working copies. The Java Model
083: * does not support the 'original' mode anymore.
084: */
085: public StandardJavaElementContentProvider(boolean provideMembers,
086: boolean provideWorkingCopy) {
087: this (provideMembers);
088: }
089:
090: /**
091: * Creates a new <code>StandardJavaElementContentProvider</code>.
092: *
093: * @param provideMembers if <code>true</code> members below compilation units
094: * and class files are provided.
095: */
096: public StandardJavaElementContentProvider(boolean provideMembers) {
097: fProvideMembers = provideMembers;
098: fProvideWorkingCopy = provideMembers;
099: }
100:
101: /**
102: * Returns whether members are provided when asking
103: * for a compilation units or class file for its children.
104: *
105: * @return <code>true</code> if the content provider provides members;
106: * otherwise <code>false</code> is returned
107: */
108: public boolean getProvideMembers() {
109: return fProvideMembers;
110: }
111:
112: /**
113: * Sets whether the content provider is supposed to return members
114: * when asking a compilation unit or class file for its children.
115: *
116: * @param b if <code>true</code> then members are provided.
117: * If <code>false</code> compilation units and class files are the
118: * leaves provided by this content provider.
119: */
120: public void setProvideMembers(boolean b) {
121: //hello
122: fProvideMembers = b;
123: }
124:
125: /**
126: * @deprecated Since 3.0 compilation unit children are always provided as working copies. The Java model
127: * does not support the 'original' mode anymore.
128: */
129: public boolean getProvideWorkingCopy() {
130: return fProvideWorkingCopy;
131: }
132:
133: /**
134: * @deprecated Since 3.0 compilation unit children are always provided from the working copy. The Java model
135: * offers a unified world and does not support the 'original' mode anymore.
136: */
137: public void setProvideWorkingCopy(boolean b) {
138: fProvideWorkingCopy = b;
139: }
140:
141: /* (non-Javadoc)
142: * @see IWorkingCopyProvider#providesWorkingCopies()
143: */
144: public boolean providesWorkingCopies() {
145: return getProvideWorkingCopy();
146: }
147:
148: /* (non-Javadoc)
149: * Method declared on IStructuredContentProvider.
150: */
151: public Object[] getElements(Object parent) {
152: return getChildren(parent);
153: }
154:
155: /* (non-Javadoc)
156: * Method declared on IContentProvider.
157: */
158: public void inputChanged(Viewer viewer, Object oldInput,
159: Object newInput) {
160: }
161:
162: /* (non-Javadoc)
163: * Method declared on IContentProvider.
164: */
165: public void dispose() {
166: }
167:
168: /* (non-Javadoc)
169: * Method declared on ITreeContentProvider.
170: */
171: public Object[] getChildren(Object element) {
172: if (!exists(element))
173: return NO_CHILDREN;
174:
175: try {
176: if (element instanceof IJavaModel)
177: return getJavaProjects((IJavaModel) element);
178:
179: if (element instanceof IJavaProject)
180: return getPackageFragmentRoots((IJavaProject) element);
181:
182: if (element instanceof IPackageFragmentRoot)
183: return getPackageFragmentRootContent((IPackageFragmentRoot) element);
184:
185: if (element instanceof IPackageFragment)
186: return getPackageContent((IPackageFragment) element);
187:
188: if (element instanceof IFolder)
189: return getFolderContent((IFolder) element);
190:
191: if (element instanceof IJarEntryResource) {
192: return ((IJarEntryResource) element).getChildren();
193: }
194:
195: if (getProvideMembers()
196: && element instanceof ISourceReference
197: && element instanceof IParent) {
198: return ((IParent) element).getChildren();
199: }
200: } catch (CoreException e) {
201: return NO_CHILDREN;
202: }
203: return NO_CHILDREN;
204: }
205:
206: /* (non-Javadoc)
207: * @see ITreeContentProvider
208: */
209: public boolean hasChildren(Object element) {
210: if (getProvideMembers()) {
211: // assume CUs and class files are never empty
212: if (element instanceof ICompilationUnit
213: || element instanceof IClassFile) {
214: return true;
215: }
216: } else {
217: // don't allow to drill down into a compilation unit or class file
218: if (element instanceof ICompilationUnit
219: || element instanceof IClassFile
220: || element instanceof IFile)
221: return false;
222: }
223:
224: if (element instanceof IJavaProject) {
225: IJavaProject jp = (IJavaProject) element;
226: if (!jp.getProject().isOpen()) {
227: return false;
228: }
229: }
230:
231: if (element instanceof IParent) {
232: try {
233: // when we have Java children return true, else we fetch all the children
234: if (((IParent) element).hasChildren())
235: return true;
236: } catch (JavaModelException e) {
237: return true;
238: }
239: }
240: Object[] children = getChildren(element);
241: return (children != null) && children.length > 0;
242: }
243:
244: /* (non-Javadoc)
245: * Method declared on ITreeContentProvider.
246: */
247: public Object getParent(Object element) {
248: if (!exists(element))
249: return null;
250: return internalGetParent(element);
251: }
252:
253: /**
254: * Evaluates all children of a given {@link IPackageFragmentRoot}. Clients can override this method.
255: * @param root The root to evaluate the children for.
256: * @return The children of the root
257: * @exception JavaModelException if the package fragment root does not exist or if an
258: * exception occurs while accessing its corresponding resource
259: *
260: * @since 3.3
261: */
262: protected Object[] getPackageFragmentRootContent(
263: IPackageFragmentRoot root) throws JavaModelException {
264: IJavaElement[] fragments = root.getChildren();
265: if (isProjectPackageFragmentRoot(root)) {
266: return fragments;
267: }
268: Object[] nonJavaResources = root.getNonJavaResources();
269: if (nonJavaResources == null)
270: return fragments;
271: return concatenate(fragments, nonJavaResources);
272: }
273:
274: /**
275: * Evaluates all children of a given {@link IJavaProject}. Clients can override this method.
276: * @param project The Java project to evaluate the children for.
277: * @return The children of the project. Typically these are package fragment roots but can also be other elements.
278: * @exception JavaModelException if the Java project does not exist or if an
279: * exception occurs while accessing its corresponding resource
280: */
281: protected Object[] getPackageFragmentRoots(IJavaProject project)
282: throws JavaModelException {
283: if (!project.getProject().isOpen())
284: return NO_CHILDREN;
285:
286: IPackageFragmentRoot[] roots = project
287: .getPackageFragmentRoots();
288: List list = new ArrayList(roots.length);
289: // filter out package fragments that correspond to projects and
290: // replace them with the package fragments directly
291: for (int i = 0; i < roots.length; i++) {
292: IPackageFragmentRoot root = roots[i];
293: if (isProjectPackageFragmentRoot(root)) {
294: Object[] fragments = getPackageFragmentRootContent(root);
295: for (int j = 0; j < fragments.length; j++) {
296: list.add(fragments[j]);
297: }
298: } else {
299: list.add(root);
300: }
301: }
302: Object[] resources = project.getNonJavaResources();
303: for (int i = 0; i < resources.length; i++) {
304: list.add(resources[i]);
305: }
306: return list.toArray();
307: }
308:
309: /**
310: * Note: This method is for internal use only. Clients should not call this method.
311: */
312: protected Object[] getJavaProjects(IJavaModel jm)
313: throws JavaModelException {
314: return jm.getJavaProjects();
315: }
316:
317: /**
318: * Evaluates all children of a given {@link IPackageFragment}. Clients can override this method.
319: * @param fragment The fragment to evaluate the children for.
320: * @return The children of the given package fragment.
321: * @exception JavaModelException if the package fragment does not exist or if an
322: * exception occurs while accessing its corresponding resource
323: *
324: * @since 3.3
325: */
326: protected Object[] getPackageContent(IPackageFragment fragment)
327: throws JavaModelException {
328: if (fragment.getKind() == IPackageFragmentRoot.K_SOURCE) {
329: return concatenate(fragment.getCompilationUnits(), fragment
330: .getNonJavaResources());
331: }
332: return concatenate(fragment.getClassFiles(), fragment
333: .getNonJavaResources());
334: }
335:
336: /**
337: * Evaluates all children of a given {@link IFolder}. Clients can override this method.
338: * @param folder The folder to evaluate the children for.
339: * @return The children of the given package fragment.
340: * @exception CoreException if the folder does not exist.
341: *
342: * @since 3.3
343: */
344: protected Object[] getFolderContent(IFolder folder)
345: throws CoreException {
346: IResource[] members = folder.members();
347: IJavaProject javaProject = JavaCore.create(folder.getProject());
348: if (javaProject == null || !javaProject.exists())
349: return members;
350: boolean isFolderOnClasspath = javaProject.isOnClasspath(folder);
351: List nonJavaResources = new ArrayList();
352: // Can be on classpath but as a member of non-java resource folder
353: for (int i = 0; i < members.length; i++) {
354: IResource member = members[i];
355: // A resource can also be a java element
356: // in the case of exclusion and inclusion filters.
357: // We therefore exclude Java elements from the list
358: // of non-Java resources.
359: if (isFolderOnClasspath) {
360: if (javaProject.findPackageFragmentRoot(member
361: .getFullPath()) == null) {
362: nonJavaResources.add(member);
363: }
364: } else if (!javaProject.isOnClasspath(member)) {
365: nonJavaResources.add(member);
366: }
367: }
368: return nonJavaResources.toArray();
369: }
370:
371: /**
372: * Note: This method is for internal use only. Clients should not call this method.
373: */
374: protected boolean isClassPathChange(IJavaElementDelta delta) {
375:
376: // need to test the flags only for package fragment roots
377: if (delta.getElement().getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT)
378: return false;
379:
380: int flags = delta.getFlags();
381: return (delta.getKind() == IJavaElementDelta.CHANGED
382: && ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0)
383: || ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) || ((flags & IJavaElementDelta.F_REORDER) != 0));
384: }
385:
386: /**
387: * Note: This method is for internal use only. Clients should not call this method.
388: */
389: protected Object skipProjectPackageFragmentRoot(
390: IPackageFragmentRoot root) {
391: if (isProjectPackageFragmentRoot(root))
392: return root.getParent();
393: return root;
394: }
395:
396: /**
397: * Note: This method is for internal use only. Clients should not call this method.
398: */
399: protected boolean isPackageFragmentEmpty(IJavaElement element)
400: throws JavaModelException {
401: if (element instanceof IPackageFragment) {
402: IPackageFragment fragment = (IPackageFragment) element;
403: if (fragment.exists()
404: && !(fragment.hasChildren() || fragment
405: .getNonJavaResources().length > 0)
406: && fragment.hasSubpackages())
407: return true;
408: }
409: return false;
410: }
411:
412: /**
413: * Note: This method is for internal use only. Clients should not call this method.
414: */
415: protected boolean isProjectPackageFragmentRoot(
416: IPackageFragmentRoot root) {
417: IJavaProject javaProject = root.getJavaProject();
418: return javaProject != null
419: && javaProject.getPath().equals(root.getPath());
420: }
421:
422: /**
423: * Note: This method is for internal use only. Clients should not call this method.
424: */
425: protected boolean exists(Object element) {
426: if (element == null) {
427: return false;
428: }
429: if (element instanceof IResource) {
430: return ((IResource) element).exists();
431: }
432: if (element instanceof IJavaElement) {
433: return ((IJavaElement) element).exists();
434: }
435: return true;
436: }
437:
438: /**
439: * Note: This method is for internal use only. Clients should not call this method.
440: */
441: protected Object internalGetParent(Object element) {
442:
443: // try to map resources to the containing package fragment
444: if (element instanceof IResource) {
445: IResource parent = ((IResource) element).getParent();
446: IJavaElement jParent = JavaCore.create(parent);
447: // http://bugs.eclipse.org/bugs/show_bug.cgi?id=31374
448: if (jParent != null && jParent.exists())
449: return jParent;
450: return parent;
451: } else if (element instanceof IJavaElement) {
452: IJavaElement parent = ((IJavaElement) element).getParent();
453: // for package fragments that are contained in a project package fragment
454: // we have to skip the package fragment root as the parent.
455: if (element instanceof IPackageFragment) {
456: return skipProjectPackageFragmentRoot((IPackageFragmentRoot) parent);
457: }
458: return parent;
459: } else if (element instanceof IJarEntryResource) {
460: return ((IJarEntryResource) element).getParent();
461: }
462: return null;
463: }
464:
465: /**
466: * Note: This method is for internal use only. Clients should not call this method.
467: */
468: protected static Object[] concatenate(Object[] a1, Object[] a2) {
469: int a1Len = a1.length;
470: int a2Len = a2.length;
471: if (a1Len == 0)
472: return a2;
473: if (a2Len == 0)
474: return a1;
475: Object[] res = new Object[a1Len + a2Len];
476: System.arraycopy(a1, 0, res, 0, a1Len);
477: System.arraycopy(a2, 0, res, a1Len, a2Len);
478: return res;
479: }
480:
481: }
|