/*****************************************************************************
* Copyright (c) 2010 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* CEA LIST - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.textedit.property.xtext.scoping;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.QualifiedName;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.RedefinesRule;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.SubsetsRule;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.TypeRule;
import org.eclipse.papyrus.uml.textedit.property.xtext.validation.UmlPropertyJavaValidator;
import org.eclipse.uml2.uml.Classifier;
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.Property;
import org.eclipse.xtext.gmf.glue.edit.part.PopupXtextEditorHelper;
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 UmlPropertyScopeProvider extends AbstractDeclarativeScopeProvider {
/**
* Rule for computing the scope of PropertyRule
* @param ctx
* @param ref
* @return
*/
public IScope scope_TypeRule_type(TypeRule ctx, EReference ref) {
return create___TypeRule_type___Scope(ctx) ;
}
private IScope create___TypeRule_type___Scope(TypeRule ctx) {
if (ctx.getPath() == null) {
Iterator<EObject> i = PopupXtextEditorHelper.context.eResource().getAllContents() ;
List<EObject> allContent = new ArrayList<EObject>() ;
while (i.hasNext()) {
EObject object = i.next() ;
if (object instanceof Classifier)
allContent.add(object) ;
}
Iterable<IEObjectDescription> visibleClassifiers = Scopes.scopedElementsFor(allContent) ;
return new SimpleScope(visibleClassifiers) ;
}
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(new Visitor_GetOwnedAndImportedClassifiers().visit(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>())) ;
}
}
/**
* @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(new Visitor_GetOwnedNamespacesAndImportedNamespaces().visit(parentNameSpace)) ;
}
else {
visibleNamespaces.add(UmlPropertyJavaValidator.getModel()) ;
//visibleNamespaces.addAll(new Visitor_GetImportedNamespaces().visit(UmlPropertyJavaValidator.getModel())) ;
visibleNamespaces.addAll(new Visitor_GetOwnedNamespacesAndImportedNamespaces().visit(UmlPropertyJavaValidator.getModel())) ;
}
Iterable<IEObjectDescription> iterableIEobjectDescription = Scopes.scopedElementsFor(visibleNamespaces) ;
return new SimpleScope(iterableIEobjectDescription) ;
}
private class Visitor_GetImportedNamespaces {
public List<Namespace> visit(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;
}
}
private class Visitor_GetOwnedNamespacesAndImportedNamespaces extends Visitor_GetImportedNamespaces {
@Override
public List<Namespace> visit(Namespace visited) {
List<Namespace> namespaces = new ArrayList<Namespace>() ;
// first retrieves imported namespaces
namespaces.addAll(super.visit(visited)) ;
// then retrieves owned namespaces
for (NamedElement n : visited.getOwnedMembers()) {
if (n instanceof Namespace)
namespaces.add((Namespace)n) ;
}
return namespaces;
}
}
private class Visitor_GetOwnedAndImportedClassifiers {
public List<Element> visit(Namespace visited) {
List<Element> visibleElements = new ArrayList<Element>() ;
// first retrieves imported properties
for (ElementImport eImport : visited.getElementImports()) {
if (eImport.getImportedElement() instanceof Classifier)
visibleElements.add(eImport.getImportedElement()) ;
}
// then retrieves owned properties
for (NamedElement n : visited.getOwnedMembers()) {
if (n instanceof Classifier)
visibleElements.add(n) ;
}
return visibleElements;
}
}
/**
* Rule for computing the scope of PropertyRule
* @param ctx
* @param ref
* @return
*/
public IScope scope_RedefinesRule_property(RedefinesRule ctx, EReference ref) {
Iterable<IEObjectDescription> iterableIEobjectDescription = Scopes.scopedElementsFor(retrieveInheritedProperties()) ;
return new SimpleScope(iterableIEobjectDescription) ;
}
/**
* Rule for computing the scope of PropertyRule
* @param ctx
* @param ref
* @return
*/
public IScope scope_SubsetsRule_property(SubsetsRule ctx, EReference ref) {
Iterable<IEObjectDescription> iterableIEobjectDescription = Scopes.scopedElementsFor(retrieveInheritedProperties()) ;
return new SimpleScope(iterableIEobjectDescription) ;
}
public static List<Property> retrieveInheritedProperties() {
Property editedProperty = (Property)PopupXtextEditorHelper.context ;
if (editedProperty == null)
return null ;
Classifier owner = (Classifier) editedProperty.getNamespace() ;
List<Property> inheritedProperties = new ArrayList<Property>() ;
for (Classifier parent : owner.getGenerals()) {
for (Property p : parent.getAllAttributes()) {
if (! inheritedProperties.contains(p)) ;
inheritedProperties.add(p) ;
}
}
return inheritedProperties ;
}
}