/*****************************************************************************
* 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.ui.contentassist;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.papyrus.uml.textedit.property.xtext.scoping.UmlPropertyScopeProvider;
import org.eclipse.papyrus.uml.textedit.property.xtext.ui.contributions.UMLPropertyEditorPropertyUtil;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.ModifierSpecification;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.ModifiersRule;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.MultiplicityRule;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.PropertyRule;
import org.eclipse.papyrus.uml.textedit.property.xtext.umlProperty.QualifiedName;
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.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.gmf.glue.contentassist.CompletionProposalUtils;
import org.eclipse.xtext.gmf.glue.contentassist.CustomCompletionProposal;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor;
/**
* Customization of the default ProposalProvider of the textual property editor
*
* see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#contentAssist on how to customize content assistant
*/
public class UmlPropertyProposalProvider extends AbstractUmlPropertyProposalProvider {
/**
* Provides custom completion for the specifying the type of a property
*
* @see org.eclipse.papyrus.uml.textedit.property.xtext.ui.contentassist.AbstractUmlPropertyProposalProvider#completePropertyRule_Type(org.eclipse.emf.ecore.EObject, org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext, org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completePropertyRule_Type(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
List<Classifier> allClassifiers = new ArrayList<Classifier>() ;
allClassifiers.addAll(getRecursivelyOwnedClassifiers(UmlPropertyJavaValidator.getModel())) ;
allClassifiers.addAll(getRecursivelyImportedClassifiers(UmlPropertyJavaValidator.getModel())) ;
for (Classifier c : allClassifiers) {
if (c.getQualifiedName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
String displayString = c.getQualifiedName() ;
String completionString = CompletionProposalUtils.getQualifiedNameLabelWithSufficientDepth(c, UmlPropertyJavaValidator.getModel()) ;
ICompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(c, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
/**
* Provides custom completion for the root element in a qualified name
*
* @see org.eclipse.papyrus.uml.textedit.property.xtext.ui.contentassist.AbstractUmlPropertyProposalProvider#completeTypeRule_Path(org.eclipse.emf.ecore.EObject, org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext, org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completeTypeRule_Path(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
Namespace root = UmlPropertyJavaValidator.getModel() ;
if (root == null) {
return ;
}
// first accept the root Model
String completionString = root.getName() + "::";
String displayString = root.getName() + "::";
//String displayString = c.getName() ;
CustomCompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(root, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
// then accepts all packages imported by Model
List<Package> importedPackages = root.getImportedPackages() ;
for (Package p : importedPackages) {
if (p.getName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
completionString = p.getName() + "::";
displayString = p.getName() + "::";
//String displayString = c.getName() ;
completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(root, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
/**
* Provides custom completion for specifying the type of a property, taking into account the path if the name is qualified
*
* @see org.eclipse.papyrus.uml.textedit.property.xtext.ui.contentassist.AbstractUmlPropertyProposalProvider#completeTypeRule_Type(org.eclipse.emf.ecore.EObject, org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext, org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completeTypeRule_Type(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
Namespace namespace = ((Property)UmlPropertyJavaValidator.getContextElement()).getNamespace() ;
if (model instanceof TypeRule) {
TypeRule typeRule = (TypeRule)model ;
QualifiedName path = typeRule.getPath() ;
while (path.getRemaining() != null) {
path = path.getRemaining() ;
}
namespace = path.getPath() ;
}
else if (! (model instanceof PropertyRule)) {
return ;
}
for (NamedElement n : namespace.getOwnedMembers()) {
if (n instanceof Classifier) {
if (n.getName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
String completionString = n.getName() ;
String displayString = n.getName() ;
CustomCompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(n, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
}
/**
* Provides custom completion for a path in a qualified name
*
* @see org.eclipse.papyrus.uml.textedit.property.xtext.ui.contentassist.AbstractUmlPropertyProposalProvider#completeQualifiedName_Path(org.eclipse.emf.ecore.EObject, org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext, org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completeQualifiedName_Path(EObject model,
Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
//The customization consists in proposing nothing. Proposals are already handled by other methods
}
/**
* Provides custom completion for a path, taking into account the path which has already been specified
*
* @see org.eclipse.papyrus.uml.textedit.property.xtext.ui.contentassist.AbstractUmlPropertyProposalProvider#completeQualifiedName_Remaining(org.eclipse.emf.ecore.EObject, org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext, org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completeQualifiedName_Remaining(EObject model,
Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
QualifiedName path = (QualifiedName) model ;
for (NamedElement n : path.getPath().getOwnedMembers()) {
if (n instanceof Package) {
if (n.getName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
String completionString = n.getName() + "::";
String displayString = n.getName() + "::";
CustomCompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(n, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
for (Package p : path.getPath().getImportedPackages()) {
if (p.getName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
String completionString = p.getName() + "::";
String displayString = p.getName() + "::";
CustomCompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(p, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
@Override
public void completeRedefinesRule_Property(EObject model,
Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
for (Property inherited : UmlPropertyScopeProvider.retrieveInheritedProperties()) {
if (inherited.getName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
String completionString = inherited.getName() ;
String displayString = UMLPropertyEditorPropertyUtil.getLabel(inherited) ;
CustomCompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(inherited, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
@Override
public void completeSubsetsRule_Property(EObject model,
Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
for (Property inherited : UmlPropertyScopeProvider.retrieveInheritedProperties()) {
if (inherited.getName().toLowerCase().contains(context.getPrefix().toLowerCase())) {
String completionString = inherited.getName() ;
String displayString = UMLPropertyEditorPropertyUtil.getLabel(inherited) ;
CustomCompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposalWithReplacementOfPrefix(inherited, completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
/**
* Provides custom completion for keywords, in the context of "modifiers" specification
*
* @see org.eclipse.xtext.ui.editor.contentassist.AbstractJavaBasedContentProposalProvider#completeKeyword(org.eclipse.xtext.Keyword, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext, org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completeKeyword(Keyword keyword,
ContentAssistContext contentAssistContext,
ICompletionProposalAcceptor acceptor) {
EObject model = contentAssistContext.getCurrentModel() ;
if (! (model instanceof ModifiersRule)) {
super.completeKeyword(keyword, contentAssistContext, acceptor);
return ;
}
ModifiersRule modifiersRule = (ModifiersRule)model ;
boolean isOrdered = false ;
boolean isReadOnly = true ;
boolean isUnion = false ;
boolean isUnique = false ;
for (ModifierSpecification spec : modifiersRule.getValues()) {
if (spec.getValue() != null) {
switch (spec.getValue()) {
case ORDERED:
isOrdered = true ;
break;
case READ_ONLY:
isReadOnly = ! isReadOnly ;
break;
case UNION:
isUnion = true ;
break ;
case UNIQUE:
isUnique = true ;
break ;
default:
break;
}
}
}
String value = keyword.getValue() ;
if (value.equals("ordered")) {
if (!isOrdered) {
super.completeKeyword(keyword, contentAssistContext, acceptor);
}
}
else if (value.equals("readOnly")) {
if (!isReadOnly) {
super.completeKeyword(keyword, contentAssistContext, acceptor);
}
}
else if (value.equals("unique")) {
if (!isUnique) {
super.completeKeyword(keyword, contentAssistContext, acceptor);
}
}
else if (value.equals("union")) {
if (!isUnion) {
super.completeKeyword(keyword, contentAssistContext, acceptor);
}
} else {
super.completeKeyword(keyword, contentAssistContext, acceptor);
}
}
@Override
public void complete_MultiplicityRule(EObject model, RuleCall ruleCall,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
String zero_one = "[0..1]" ;
String one = "[1]" ;
String one_star = "[1..*]" ;
String star = "[*]" ;
String completionString = "" ;
String displayString = "";
ICompletionProposal completionProposal = null ;
completionString = "" + zero_one.substring(context.getPrefix().length()) ;
displayString = "" + zero_one ;
completionProposal = CompletionProposalUtils.createCompletionProposal(completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
completionString = "" + one.substring(context.getPrefix().length()) ;
displayString = "" + one ;
completionProposal = CompletionProposalUtils.createCompletionProposal(completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
completionString = "" + one_star.substring(context.getPrefix().length()) ;
displayString = "" + one_star + " ";
completionProposal = CompletionProposalUtils.createCompletionProposal(completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
completionString = "" + star.substring(context.getPrefix().length()) ;
displayString = "" + star ;
completionProposal = CompletionProposalUtils.createCompletionProposal(completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
@Override
public void completeMultiplicityRule_Bounds(EObject model,
Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
if (!(model instanceof MultiplicityRule)) {
return ;
}
MultiplicityRule multiplicityRule = (MultiplicityRule)model ;
if (multiplicityRule.getBounds().size() == 2) {
String value = multiplicityRule.getBounds().get(1).getValue() ;
try {
Integer.valueOf(value) ;
}
catch(Exception e) {
if (! multiplicityRule.getBounds().get(0).getValue().equals("*") && ! multiplicityRule.getBounds().get(1).getValue().equals("*")) {
String completionString = "*" ;
String displayString = "*";
ICompletionProposal completionProposal = CompletionProposalUtils.createCompletionProposal(completionString, displayString, context) ;
acceptor.accept(completionProposal) ;
}
}
}
}
/* ******************************************************************************
* Utility methods
********************************************************************************/
/**
* Utility methods wich returns the list of classifiers that are directly or indirectly owned by a context namespace
*
* @param context The context namespace
* @return the list of classifiers that are directly or indirectly owned by the context namespace
*/
private List<Classifier> getRecursivelyOwnedClassifiers(Namespace context) {
List<Classifier> recursivelyOwnedClassifiers = new ArrayList<Classifier>();
List<Element> allOwnedElements = context.getOwnedElements() ;
for (Element e : allOwnedElements) {
if (e instanceof Classifier) {
recursivelyOwnedClassifiers.add((Classifier)e) ;
}
if (e instanceof Namespace) {
recursivelyOwnedClassifiers.addAll(getRecursivelyOwnedClassifiers((Namespace)e)) ;
}
}
return recursivelyOwnedClassifiers ;
}
/**
* Utility methods which returns the list of classifiers that are directly or indirectly owned by the namespaces imported by a context namespace
*
* @param context The context namespace
* @return the list of classifiers that are directly or indirectly owned by the namespaces imported by the context namespace
*/
private List<Classifier> getRecursivelyImportedClassifiers(Namespace context) {
List<Classifier> recursivelyImportedClassifiers = new ArrayList<Classifier>() ;
List<Package> importedPackages = context.getImportedPackages() ;
for (Package p : importedPackages) {
recursivelyImportedClassifiers.addAll(getRecursivelyOwnedClassifiers(p)) ;
}
return recursivelyImportedClassifiers ;
}
}