/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui;
import com.google.dart.engine.element.ClassElement;
import com.google.dart.engine.element.CompilationUnitElement;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.FunctionElement;
import com.google.dart.engine.element.visitor.GeneralizingElementVisitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import java.util.ArrayList;
import java.util.Collections;
/**
* "New" base content provider for Dart elements. It provides access to the Dart element hierarchy
* without listening to changes in the Dart model. If updating the presentation on Dart model change
* is required than clients have to subclass, listen to Dart model changes and have to update the UI
* using corresponding methods provided by the JFace viewers or their own UI presentation.
* <p>
* The following Dart element hierarchy is surfaced by this content provider:
* <p>
* TODO(pquitslund): update this hierarchy to reflect the new element model
*
* <pre>
* Dart model (<code>DartModel</code>)
* Dart project (<code>DartProject</code>)
* library (<code>DartLibrary</code>)
* compilation unit (<code>CompilationUnit</code>)
* library file (<code>LibraryConfigurationFile</code>)
* Imported Libraries
* </pre>
* </p>
*/
public class StandardDartElementContentProvider implements ITreeContentProvider,
IWorkingCopyProvider {
protected static final Object[] NO_CHILDREN = new Object[0];
// Whether to return members when asking a compilation unit for its children.
private final boolean provideMembers;
/**
* Creates a new content provider. The content provider does not provide members of compilation
* units or class files.
*/
public StandardDartElementContentProvider() {
this(true);
}
/**
* Creates a new <code>NewStandardDartElementContentProvider</code>.
*
* @param provideMembers if <code>true</code>, members below compilation units are provided
*/
public StandardDartElementContentProvider(boolean provideMembers) {
this.provideMembers = provideMembers;
}
@Override
public void dispose() {
}
@Override
public Object[] getChildren(Object element) {
//TODO (pquitslund): complete cases
if (!exists(element)) {
return NO_CHILDREN;
}
if (element instanceof IProject) {
IProject project = (IProject) element;
if (!(project.isOpen())) {
return NO_CHILDREN;
}
//TODO (pquitslund): support dart projects
return NO_CHILDREN;
// if (project.hasNature(DartCore.DART_PROJECT_NATURE)) {
// DartProject dartProject = DartCore.create(project);
// return dartProject.getDartLibraries();
// }
}
try {
if (element instanceof IFile) {
return NO_CHILDREN;
}
if (element instanceof IFolder) {
return getFolderContent((IFolder) element);
}
if (element instanceof CompilationUnitElement) {
return getCompilationUnitMembers((CompilationUnitElement) element);
}
if (element instanceof ClassElement) {
return getClassMembers((ClassElement) element);
}
if (element instanceof FunctionElement) {
return NO_CHILDREN;
}
} catch (CoreException e) {
// Fall through
}
return NO_CHILDREN;
}
@Override
public Object[] getElements(Object parent) {
return getChildren(parent);
}
@Override
public Object getParent(Object element) {
if (!exists(element)) {
return null;
}
return internalGetParent(element);
}
@Override
public boolean hasChildren(Object element) {
//TODO (pquitslund): support all cases
if (element instanceof CompilationUnitElement) {
if (!provideMembers()) {
return false;
}
return getChildren(element).length > 0;
}
if (element instanceof FunctionElement) {
return false;
}
return getChildren(element).length > 0;
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public boolean providesWorkingCopies() {
return true;
}
/**
* Note: This method is for internal use only. Clients should not call this method.
*/
protected boolean exists(Object element) {
if (element == null) {
return false;
}
if (element instanceof IResource) {
return ((IResource) element).exists();
}
return true;
}
protected Object[] getFolderContent(IFolder folder) throws CoreException {
//TODO (pquitslund): implement
return NO_CHILDREN;
}
/**
* Note: This method is for internal use only. Clients should not call this method.
*/
protected Object internalGetParent(Object element) {
//TODO (pquitslund): handle all cases
if (element instanceof Element) {
return ((Element) element).getEnclosingElement();
}
return null;
}
/**
* Returns whether members are provided when asking for a compilation units or class file for its
* children.
*
* @return <code>true</code> if the content provider provides members; otherwise
* <code>false</code> is returned
*/
protected boolean provideMembers() {
return provideMembers;
}
private Object[] getClassMembers(ClassElement ce) {
return getSortedMembers(ce);
}
private Object[] getCompilationUnitMembers(CompilationUnitElement cu) {
return getSortedMembers(cu);
}
/**
* Get members sorted by offset.
*/
private Object[] getSortedMembers(Element element) {
final ArrayList<Element> members = new ArrayList<Element>();
element.visitChildren(new GeneralizingElementVisitor<Void>() {
@Override
public Void visitElement(Element element) {
if (!element.isSynthetic()) {
members.add(element);
}
return null;
}
});
Collections.sort(members, Element.SORT_BY_OFFSET);
return members.toArray(new Element[members.size()]);
}
}