/*
* generated by Xtext
*/
package org.eclipse.papyrus.uml.textedit.common.xtext.scoping;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.QualifiedName;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.PackageImport;
import org.eclipse.uml2.uml.Type;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.Scopes;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
import org.eclipse.xtext.scoping.impl.SimpleScope;
/**
* This class contains custom scoping description.
*
* see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping
* on how and when to use it
*
*/
public class UmlCommonScopeProvider extends AbstractDeclarativeScopeProvider {
/** the edited model */
private Namespace model = null;
/** the edited element */
private Element contextElement = null;
/**
*
* Constructor.
*
*/
public UmlCommonScopeProvider() {
initModel();
}
/**
*
* This method initializes the fields {@link #model} {@link #contextElement} thanks to the current selection
*
*/
protected void initModel() {
IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
ISelection mySelection = activePage.getSelection();
if(mySelection instanceof IStructuredSelection) {
Object first = ((IStructuredSelection)mySelection).getFirstElement();
if(first != null) {
if(first instanceof IAdaptable) {
Element el = (Element)((IAdaptable)first).getAdapter(Element.class);
this.contextElement = el;
if(el != null) {
List<Namespace> namespaces = el.getNearestPackage().allNamespaces();
if(namespaces.size() == 0) {
this.model = el.getNearestPackage();
} else {
this.model = namespaces.get(namespaces.size() - 1);
}
}
}
}
}
Assert.isNotNull(contextElement, "I can't find the edited element"); //$NON-NLS-1$
Assert.isNotNull(this.model, "I can't find the model owning the edited element"); //$NON-NLS-1$
}
/**
* Getter for {@link #model}
*
* @return
* {@link #model}
*/
protected Namespace getModel() {
return this.model;
}
/**
* Getter for {@link #contextElement}
*
* @return
* {@link #contextElement}
*/
protected Element getContextElement() {
return this.contextElement;
}
/**
* Rule for computing the scope of PropertyRule
*
* @param ctx
*
* @param ref
* @return
*/
public IScope scope_TypeRule_type(org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.TypeRule ctx, EReference ref) {
return create___TypeRule_type___Scope(ctx);
}
/**
* Shall overridden to restrict the possible {@link Type}
*
* This method provides the scope for the {@link Type}
*
* @param ctx
* @return
*/
protected IScope create___TypeRule_type___Scope(org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.TypeRule ctx) {
if(ctx.getPath() == null) {
Iterator<EObject> i = org.eclipse.xtext.gmf.glue.edit.part.PopupXtextEditorHelper.context.eResource().getAllContents();
List<EObject> allContent = new ArrayList<EObject>();
while(i.hasNext()) {
EObject object = i.next();
if(object instanceof Element) {
if(isWantedType((Element)object)) {
allContent.add(object);
}
}
}
Iterable<IEObjectDescription> visibleParameterBoxes = Scopes.scopedElementsFor(allContent);
return new SimpleScope(visibleParameterBoxes);
} else {
// In the case where a path (qualified name prefix) has been specified,
// retrieves visible elements from this name space
List<Element> tmpVisibleElementsFromPath = new ArrayList<Element>();
if(ctx.getPath() != null) {
QualifiedName qualifiedName = ctx.getPath();
while(qualifiedName.getRemaining() != null) {
qualifiedName = qualifiedName.getRemaining();
}
Namespace nearestNamespace = qualifiedName.getPath();
if(nearestNamespace != null) {
List<Element> tmpVisiblePropertiesFromPath = new ArrayList<Element>();
tmpVisiblePropertiesFromPath.addAll(getOwnedAndImportedType(nearestNamespace));
for(Element e : tmpVisiblePropertiesFromPath) {
tmpVisibleElementsFromPath.add(e);
}
}
}
// builds the nested scope base on hierarchy and then inheritance
SimpleScope resultScope = null;
Iterable<IEObjectDescription> iterableIEobjectDescriptions;
if(!tmpVisibleElementsFromPath.isEmpty()) {
iterableIEobjectDescriptions = Scopes.scopedElementsFor(tmpVisibleElementsFromPath);
resultScope = resultScope != null ? new SimpleScope(resultScope, iterableIEobjectDescriptions) : new SimpleScope(iterableIEobjectDescriptions);
}
return resultScope != null ? resultScope : new SimpleScope(Scopes.scopedElementsFor(new ArrayList<Element>()));
}
}
/**
*
* shall be overridden to restrict the possible {@link Type}
*
*
* Returns the owned and imported {@link Type} imported namespace
*
* @param visited
* the visited namespace
* @return
* the owned and imported {@link Type} imported namespace
*/
protected List<Element> getOwnedAndImportedType(Namespace visited) {
List<Element> visibleElements = new ArrayList<Element>();
// first retrieves imported properties
for(ElementImport eImport : visited.getElementImports()) {
if(isWantedType(eImport.getImportedElement())) {
visibleElements.add(eImport.getImportedElement());
}
}
// then retrieves owned properties
for(NamedElement n : visited.getOwnedMembers()) {
if(isWantedType(n)) {
visibleElements.add(n);
}
if(n instanceof Namespace) {
visibleElements.addAll(getOwnedAndImportedType((Namespace)n));
}
}
return visibleElements;
}
/**
* Returns the imported {@link Namespace}
*
* @param visited
* the visited namespace
* @return
* the imported {@link Namespace}
*/
protected List<Namespace> getImportedNamespaces(Namespace visited) {
List<Namespace> namespaces = new ArrayList<Namespace>();
// retrieves imported namespaces
for(PackageImport pImport : visited.getPackageImports()) {
namespaces.add(pImport.getImportedPackage());
}
for(ElementImport eImport : visited.getElementImports()) {
if(eImport.getImportedElement() instanceof Namespace)
namespaces.add((Namespace)eImport.getImportedElement());
}
return namespaces;
}
/**
* Returns the owned and imported {@link Namespace}
*
* @param visited
* the visited namespace
* @return
* the owned and imported {@link Namespace}
*/
protected List<Namespace> getOwnedAndImportedNamespaces(Namespace visited) {
List<Namespace> namespaces = new ArrayList<Namespace>();
// first retrieves imported namespaces
namespaces.addAll(getImportedNamespaces(visited));
// then retrieves owned namespaces
for(NamedElement n : visited.getOwnedMembers()) {
if(n instanceof Namespace)
namespaces.add((Namespace)n);
}
return namespaces;
}
/**
* @param ctx
* @param ref
* @return
*/
public IScope scope_QualifiedName_path(QualifiedName ctx, EReference ref) {
List<Namespace> visibleNamespaces = new ArrayList<Namespace>();
if(ctx != null && ctx.eContainer() != null && ctx.eContainer() instanceof QualifiedName) {
Namespace parentNameSpace = ((QualifiedName)ctx.eContainer()).getPath();
visibleNamespaces.addAll(getOwnedAndImportedNamespaces(parentNameSpace));
} else {
visibleNamespaces.add(getModel());
visibleNamespaces.addAll(getImportedNamespaces(getModel()));
}
Iterable<IEObjectDescription> iterableIEobjectDescription = Scopes.scopedElementsFor(visibleNamespaces);
return new SimpleScope(iterableIEobjectDescription);
}
/**
* Inherited class should overridden this method in order to have a mode specific type
*
* Tests if the element is an instance of the wanted type
*
* @param e
* the element to test
* @return
* <code>true</code> is the element is an instance of the wanted type
*/
protected boolean isWantedType(Element e) {
return e instanceof Type;
}
}