/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.viewsupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.metamodels.diagram.Diagram;
import org.teiid.designer.metamodels.diagram.PresentationEntity;
import org.teiid.designer.metamodels.relational.Procedure;
import org.teiid.designer.ui.UiConstants;
/**
* <p>ModelObjectContentProvider is the global ContentProvider for all access to ModelResources
* and all objects inside ModelResources.</p>
* <p>ModelObjectContentProvider implements ITreeContentProvider because this interface has the right
* methods for the functionality this class provides.</p>
* <p>ModelObjectContentProvider is a singleton to ensure that any operations it performs on a given
* ModelResource is safe and synchronous.</p>
*
* @since 8.0
*/
final public class ModelObjectContentProvider
implements ITreeContentProvider, UiConstants.ExtensionPoints.DiagramContentProvider {
// ===========================================
// Static
private static final Object[] NO_CHILDREN = new Object[0];
private static ModelObjectContentProvider theInstance;
/** list of ITreeContentProviders from the diagramProvider extension point */
private static final ArrayList diagramProviders = new ArrayList();
/** key=diagram type ID, value=ITreeContentProvider to use for getParent */
private static final HashMap diagramProviderIdMap = new HashMap();
private static ExtendedModelObjectContentProvider extendedContentProvider = new ExtendedModelObjectContentProvider();
/** DEBUG flag to remove any diagram lookup & creation logic. Should be false */
private static boolean IGNORE_DIAGRAMS = false;
/**
* Obtain the singleton instance of ModelObjectContentProvider.
*/
public static ModelObjectContentProvider getInstance() {
if ( theInstance == null ) {
theInstance = new ModelObjectContentProvider();
theInstance.loadProviderList();
}
return theInstance;
}
// ===========================================
// Constructors
/**
* Construct an instance of ModelObjectContentProvider.
*/
private ModelObjectContentProvider() {
}
private void loadProviderList() {
// -------------------------------------------------------------------------------------------------------
// build a list of all DiagramProvider contributions of type ILabelProvider
// -------------------------------------------------------------------------------------------------------
// get the DiagramProvider extension point from the plugin class
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(UiConstants.PLUGIN_ID, DIAGRAM_ID);
// get the all extensions to the DiagramProvider extension point
IExtension[] extensions = extensionPoint.getExtensions();
// walk through the extensions and find all ITreeContentProviders
for ( int i=0 ; i<extensions.length ; ++i ) {
IConfigurationElement[] elements = extensions[i].getConfigurationElements();
try {
// first, find the content provider instance and add it to the instance list
ITreeContentProvider contentProvider = null;
for ( int j=0 ; j<elements.length ; ++j ) {
if ( elements[j].getName().equals(DIAGRAM_CLASS)) {
Object provider = elements[j].createExecutableExtension(DIAGRAM_CLASSNAME);
if ( provider instanceof ITreeContentProvider ) {
contentProvider = (ITreeContentProvider) provider;
diagramProviders.add(provider);
break;
}
}
}
// second, build a map referencing all the diagram types that this provider supports
for ( int j=0 ; j<elements.length ; ++j ) {
if ( elements[j].getName().equals(DIAGRAM_TYPE)) {
String type = elements[j].getAttribute(DIAGRAM_TYPE_NAME);
diagramProviderIdMap.put(type, contentProvider);
}
}
} catch (Exception e) {
// catch any Exception that occurred obtaining the configuration and log it
String message = UiConstants.Util.getString("ModelObjectContentProvider.configurationErrorMessage", //$NON-NLS-1$
extensions[i].getUniqueIdentifier());
UiConstants.Util.log(IStatus.ERROR, e, message);
}
}
}
/**
* Walks through all DiagramContentProvider contributions and asks them for children
* of the parentElement. They may obtain previously created and saved diagrams, or they
* may create new diagrams. Any children they return are integrated into the child array
* returned from the getChildren method.
* @param parentElement
* @return
*/
private static ArrayList getDiagramChildren(Object parentElement) {
ArrayList result = new ArrayList();
if(isXsdObject(parentElement) ){
return result;
}
if(isViewProcedureFunction(parentElement)) {
return result;
}
final boolean startedTxn = ModelerCore.startTxn(false, true, null, theInstance);
boolean succeeded = false;
try{
for ( Iterator iter = diagramProviders.iterator() ; iter.hasNext() ; ) {
ITreeContentProvider provider = (ITreeContentProvider) iter.next();
try {
Object[] diagrams = provider.getChildren(parentElement);
if ( diagrams != null && diagrams.length > 0 ) {
result.addAll(Arrays.asList(diagrams));
}
} catch (Exception e) {
// catch any Exception that occurred in the diagram provider and log it
String message = UiConstants.Util.getString("ModelObjectContentProvider.diagramProviderErrorMessage"); //$NON-NLS-1$
UiConstants.Util.log(IStatus.ERROR, e, message);
}
}
// not really sure if I should roll back if any exceptions get caught.
succeeded = true;
} finally {
if( startedTxn ){
if ( succeeded ) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
return result;
}
private static boolean isXsdObject(final Object obj){
if(obj == null){
return false;
}
if(obj instanceof ModelResource){
return ((ModelResource)obj).isXsd();
}
if(obj instanceof EObject){
final Resource rsrc = ((EObject)obj).eResource();
return ModelUtil.isXsdFile(rsrc);
}
if(obj instanceof Resource){
return ModelUtil.isXsdFile( (Resource)obj );
}
return false;
}
private static boolean isViewProcedureFunction(final Object obj) {
boolean isViewProcFunction = false;
if(obj == null || !(obj instanceof Procedure) ) {
return isViewProcFunction;
}
if(ModelUtil.isVirtual(obj) && ((Procedure)obj).isFunction()) {
isViewProcFunction = true;
}
return isViewProcFunction;
}
// ===========================================
// ITreeContentProvider Methods
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
@Override
public synchronized Object[] getChildren(Object parentElement) {
Object[] children = NO_CHILDREN;
try {
//BusyCursor.showBusy();
if ( parentElement instanceof PresentationEntity ) {
// then NO_CHILDREN is the right answer
} else if ( (parentElement instanceof EObject)
|| (parentElement instanceof ModelResource) ) {
Object[] emfChildren = null;
if ( parentElement instanceof EObject ) {
emfChildren = ModelUtilities.getModelContentProvider().getChildren(parentElement);
} else {
try {
emfChildren = ((ModelResource) parentElement).getEObjects().toArray();
} catch ( ModelWorkspaceException exception ) {
if ( ((ModelResource)parentElement).hasErrors() ) {
// There are errors, so simply return an empty list ...
return children;
}
throw exception;
}
}
// Find any additional extended children for object
Object[] extendedChildren = extendedContentProvider.getChildren(parentElement);
int totalChildren = emfChildren.length;
if( extendedChildren != null && extendedChildren.length > 0 ) {
totalChildren += extendedChildren.length;
}
Object[] tmpChildren = new Object[totalChildren];
for ( int i=0 ; i<emfChildren.length ; ++i ) {
tmpChildren[i] = emfChildren[i];
}
if( extendedChildren != null && extendedChildren.length > 0) {
int theIndex = emfChildren.length;
for( int i = 0 ; i < extendedChildren.length ; ++i) {
tmpChildren[theIndex++] = extendedChildren[i];
}
}
if ( IGNORE_DIAGRAMS ) {
return (tmpChildren);
}
ArrayList diagramList = getDiagramChildren(parentElement);
if ( diagramList.isEmpty() ) {
children = tmpChildren;
} else {
ArrayList allChildren = new ArrayList(diagramList);
for ( int i=0 ; i<tmpChildren.length ; ++i ) {
allChildren.add(tmpChildren[i]);
}
children = allChildren.toArray();
}
}
} catch (CoreException ex) {
children = NO_CHILDREN;
} finally {
//BusyCursor.endBusy();
}
return children;
}
/*
* Get children, with model contents sorted in alphabetical order
*/
public synchronized Object[] getSortedChildren(Object parentElement) {
Object[] children = NO_CHILDREN;
try {
//BusyCursor.showBusy();
if ( parentElement instanceof PresentationEntity ) {
// then NO_CHILDREN is the right answer
} else if ( (parentElement instanceof EObject)
|| (parentElement instanceof ModelResource) ) {
// Get the children (raw order)
Object[] emfChildren = null;
if ( parentElement instanceof EObject ) {
emfChildren = ModelUtilities.getModelContentProvider().getChildren(parentElement);
} else {
try {
emfChildren = ((ModelResource) parentElement).getEObjects().toArray();
} catch ( ModelWorkspaceException exception ) {
if ( ((ModelResource)parentElement).hasErrors() ) {
// There are errors, so simply return an empty list ...
return children;
}
throw exception;
}
}
List eClasses = new ArrayList();
// Put the children into List of Name-Value pair objects
List nameValueList = new ArrayList(emfChildren.length);
for(int i=0; i<emfChildren.length; i++) {
Object child = emfChildren[i];
if(child instanceof EObject) {
EObject eObj = (EObject)child;
String name = ModelerCore.getModelEditor().getName(eObj);
String eClassName = eObj.eClass().getName();
nameValueList.add(new NameValuePair(name,eObj,eClassName));
if(!eClasses.contains(eClassName)) {
eClasses.add(eClassName);
}
}
}
// Sort the NameValueList, alpha sort each Class separately in the order provided
List sortedNameValueList = sortNameValueList(nameValueList,eClasses);
// Sorted Object array
Object[] sortedChildren = new Object[sortedNameValueList.size()];
for(int i=0; i<sortedNameValueList.size(); i++) {
NameValuePair nvPair = (NameValuePair)sortedNameValueList.get(i);
sortedChildren[i] = nvPair.getValue();
}
// Find any additional extended children for object
Object[] extendedChildren = extendedContentProvider.getChildren(parentElement);
int totalChildren = emfChildren.length;
if( extendedChildren != null && extendedChildren.length > 0 ) {
totalChildren += extendedChildren.length;
}
Object[] tmpChildren = new Object[totalChildren];
for ( int i=0 ; i<sortedChildren.length ; ++i ) {
tmpChildren[i] = sortedChildren[i];
}
if( extendedChildren != null && extendedChildren.length > 0) {
int theIndex = sortedChildren.length;
for( int i = 0 ; i < extendedChildren.length ; ++i) {
tmpChildren[theIndex++] = extendedChildren[i];
}
}
if ( IGNORE_DIAGRAMS ) {
return (sortedChildren);
}
ArrayList diagramList = getDiagramChildren(parentElement);
if ( diagramList.isEmpty() ) {
children = tmpChildren;
} else {
ArrayList allChildren = new ArrayList(diagramList);
for ( int i=0 ; i<tmpChildren.length ; ++i ) {
allChildren.add(tmpChildren[i]);
}
children = allChildren.toArray();
}
}
} catch (CoreException ex) {
children = NO_CHILDREN;
} finally {
//BusyCursor.endBusy();
}
return children;
}
private List sortNameValueList(List nameValueList, List eClassList) {
List resultList = new ArrayList(nameValueList.size());
// Iterate the eClass name list, group the like elements
Iterator eClassIter = eClassList.iterator();
while(eClassIter.hasNext()) {
String currentEClass = (String)eClassIter.next();
if(currentEClass!=null) {
// Iterate the entire name value list, create a subList of only the current eClass
List nameValueSubList = new ArrayList(nameValueList.size());
Iterator nvIter = nameValueList.iterator();
while(nvIter.hasNext()) {
NameValuePair nvPair = (NameValuePair)nvIter.next();
if( currentEClass.equals(nvPair.getEClassName()) ) {
nameValueSubList.add(nvPair);
}
}
// Sort the subList for the current eClass
Collections.sort(nameValueSubList);
// Add the sorted List to the result List
resultList.addAll(nameValueSubList);
}
}
return resultList;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
@Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
@Override
public void dispose() {
// don't dispose anything - this is a static instance.
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
@Override
public Object getParent(Object element) {
Object result = null;
if ( element instanceof Diagram ) {
String type = ((Diagram) element).getType();
if ( type != null ) {
ITreeContentProvider provider = (ITreeContentProvider) diagramProviderIdMap.get(type);
if ( provider != null ) {
try {
result = provider.getParent(element);
} catch (Exception e) {
// catch any Exception that occurred in the diagram provider and log it
String message = UiConstants.Util.getString("ModelObjectContentProvider.diagramProviderErrorMessage"); //$NON-NLS-1$
UiConstants.Util.log(IStatus.ERROR, e, message);
}
}
}
} else if (element instanceof EObject) {
result = ModelUtilities.getModelContentProvider().getParent(element);
if ( result instanceof ModelResource ) {
result = ((ModelResource) result).getResource();
} else if ( result instanceof Resource ) {
result = ModelerCore.getModelEditor().findModelResource((Resource) result);
if ( result != null ) {
result = ((ModelResource) result).getResource();
}
}
} else if( extendedContentProvider.getParent(element) != null ) {
result = extendedContentProvider.getParent(element);
}
return result;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
@Override
public boolean hasChildren(Object element) {
return hasChildren(element, false);
// Object[] children= getChildren(element);
// return (children != null) && children.length > 0;
}
private boolean hasChildren(Object parentElement, boolean dummyBoolean) {
if ( parentElement instanceof PresentationEntity ) {
return false;
} else if ( (parentElement instanceof EObject)
|| (parentElement instanceof ModelResource) ) {
try {
if ( parentElement instanceof EObject ) {
if( ModelUtilities.getModelContentProvider().hasChildren(parentElement) )
return true;
} else {
if( ((ModelResource) parentElement).getEObjects().size() > 0 )
return true;
}
if( hasDiagramChildren(parentElement) )
return true;
if( getDiagramChildren(parentElement).size() > 0 )
return true;
}catch (CoreException e) {
e.printStackTrace();
} finally {
}
} else if( parentElement instanceof IExtendedModelObject ){
return extendedContentProvider.hasChildren(parentElement);
}
return false;
}
private boolean hasDiagramChildren(Object parentElement) {
if(isXsdObject(parentElement) ){
return false;
}
for ( Iterator iter = diagramProviders.iterator() ; iter.hasNext() ; ) {
ITreeContentProvider provider = (ITreeContentProvider) iter.next();
if( provider.hasChildren(parentElement) )
return true;
}
return false;
}
class NameValuePair implements Comparable {
private String name;
private String eClassName;
private Object value;
public NameValuePair(String name, Object value, String eClassName) {
this.name = name;
this.value = value;
this.eClassName = eClassName;
}
public String getName() {
return this.name;
}
public Object getValue() {
return this.value;
}
public String getEClassName() {
return this.eClassName;
}
@Override
public int compareTo(Object o) {
int result = -1;
if (o instanceof NameValuePair) {
NameValuePair col2 = (NameValuePair) o;
if ( this.name == null ) {
result = ( col2.getName() == null ? 0 : -1 );
}
else if ( col2.getName() == null ) {
result = 1;
}
else {
result = this.getName().compareToIgnoreCase(col2.getName());
}
}
return result;
}
}
}