/*
* generated by Xtext
*/
package org.eclipse.papyrus.uml.textedit.common.xtext.ui.contentassist;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.papyrus.infra.core.utils.DisplayUtils;
import org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.MultiplicityRule;
import org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.QualifiedName;
import org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.TypeRule;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
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.Type;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor;
/**
* see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#contentAssist on how to customize content assistant
*/
public class UmlCommonProposalProvider extends AbstractUmlCommonProposalProvider {
/** the label provider */
protected ILabelProvider labelProvider = DisplayUtils.getLabelProvider();
/** the edited model */
private Namespace model = null;
/** the edited element */
private Element contextElement = null;
/** the wanted type */
private Class<?> wantedType = Type.class;
/**
*
* Constructor.
*
*
*/
public UmlCommonProposalProvider() {
initModel();
}
/**
* 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;
}
/**
*
* 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$
}
/**
*
* @see org.eclipse.papyrus.parameter.editor.xtext.ui.contentassist.AbstractUmlParameterProposalProvider#complete_MultiplicityRule(org.eclipse.emf.ecore.EObject,
* org.eclipse.xtext.RuleCall, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext,
* org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*
* @param model
* @param ruleCall
* @param context
* @param acceptor
*/
@Override
public void complete_MultiplicityRule(EObject model, RuleCall ruleCall, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
String one = "[1]"; //$NON-NLS-1$
String one_star = "[1..*]"; //$NON-NLS-1$
String star = "[*]"; //$NON-NLS-1$
String completionString = ""; //$NON-NLS-1$
String displayString = ""; //$NON-NLS-1$
//String displayString = c.getName() ;
ICompletionProposal completionProposal = null;
completionString = "" + one.substring(context.getPrefix().length()); //$NON-NLS-1$
displayString = "" + one; //$NON-NLS-1$
completionProposal = createCompletionProposal(completionString, displayString, context);
acceptor.accept(completionProposal);
completionString = "" + one_star.substring(context.getPrefix().length()); //$NON-NLS-1$
displayString = "" + one_star + " "; //$NON-NLS-1$ //$NON-NLS-2$
completionProposal = createCompletionProposal(completionString, displayString, context);
acceptor.accept(completionProposal);
completionString = "" + star.substring(context.getPrefix().length()); //$NON-NLS-1$
displayString = "" + star; //$NON-NLS-1$
completionProposal = createCompletionProposal(completionString, displayString, context);
acceptor.accept(completionProposal);
}
/**
*
* @see org.eclipse.papyrus.uml.textedit.common.xtext.ui.contentassist.AbstractUmlCommonProposalProvider#completeMultiplicityRule_Bounds(org.eclipse.emf.ecore.EObject,
* org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext,
* org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*
* @param model
* @param assignment
* @param context
* @param acceptor
*/
@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("*")) { //$NON-NLS-1$ //$NON-NLS-2$
String completionString = "*"; //$NON-NLS-1$
String displayString = "*"; //$NON-NLS-1$
ICompletionProposal completionProposal = createCompletionProposal(completionString, displayString, context);
acceptor.accept(completionProposal);
}
}
}
}
/**
*
* @see org.eclipse.papyrus.collaborationuse.editor.xtext.ui.contentassist.AbstractUmlCollaborationUseProposalProvider#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)
*
* @param model
* @param assignment
* @param context
* @param acceptor
*/
@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.collaborationuse.editor.xtext.ui.contentassist.AbstractUmlCollaborationUseProposalProvider#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)
*
* @param model
* @param assignment
* @param context
* @param acceptor
*/
@Override
public void completeQualifiedName_Remaining(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
QualifiedName path = (QualifiedName)model;
for(NamedElement n : path.getPath().getOwnedMembers()) {
//we add the namespace only if he contains interesting element
if(n instanceof Namespace) {
if(n.getName().startsWith(context.getPrefix())) {
String completionString = n.getName().substring(context.getPrefix().length()) + "::"; //$NON-NLS-1$
String displayString = n.getName() + "::"; //$NON-NLS-1$
ICompletionProposal completionProposal = createCompletionProposal(n, completionString, displayString, context);
List<Type> accessibleType = getRecursivelyOwnedType((Namespace)n);
accessibleType.addAll(getRecursivelyImportedType((Namespace)n));
if(accessibleType.size() != 0) {
acceptor.accept(completionProposal);
}
}
//we add the namespace to the possible element, if the namespace has the correct type
if(n.getName().startsWith(context.getPrefix())) {
String completionString = n.getName().substring(context.getPrefix().length());
String displayString = n.getName();
ICompletionProposal completionProposal = createCompletionProposal(n, completionString, displayString, context);
if(isWantedType(n)) {
acceptor.accept(completionProposal);
}
}
}
}
for(Package p : path.getPath().getImportedPackages()) {
if(p.getName().startsWith(context.getPrefix())) {
String completionString = p.getName().substring(context.getPrefix().length()) + "::"; //$NON-NLS-1$
String displayString = p.getName() + "::"; //$NON-NLS-1$
ICompletionProposal completionProposal = createCompletionProposal(p, completionString, displayString, context);
List<Type> accessibleType = getRecursivelyOwnedType(p);
accessibleType.addAll(getRecursivelyImportedType(p));
if(accessibleType.size() != 0) {
acceptor.accept(completionProposal);
}
}
}
}
/**
*
* Provides custom completion for the root element in a qualified name
*
* @see org.eclipse.papyrus.uml.textedit.common.xtext.ui.contentassist.AbstractUmlCommonProposalProvider#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)
*
* @param model
* @param assignment
* @param context
* @param acceptor
*/
@Override
public void completeTypeRule_Path(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
Namespace root = getModel();
if(root == null) {
return;
}
// first accept the root Model
String completionString = root.getName() + "::"; //$NON-NLS-1$
String displayString = root.getName() + "::"; //$NON-NLS-1$
//String displayString = c.getName() ;
ICompletionProposal completionProposal = 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().startsWith(context.getPrefix())) {
completionString = p.getName().substring(context.getPrefix().length()) + "::"; //$NON-NLS-1$
displayString = p.getName() + "::"; //$NON-NLS-1$
completionProposal = createCompletionProposal(root, completionString, displayString, context);
List<Type> accessibleType = getRecursivelyOwnedType(p);
accessibleType.addAll(getRecursivelyImportedType(p));
if(accessibleType.size() != 0) {
acceptor.accept(completionProposal);
}
}
}
}
/**
* Provides custom completion for specifying the type of an {@link Element}, taking into account the path if the name is qualified
*
* @see org.eclipse.papyrus.property.editor.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 = getContextElement().getNearestPackage();
if(model instanceof TypeRule) {
TypeRule typeRule = (TypeRule)model;
QualifiedName path = typeRule.getPath();
while(path.getRemaining() != null) {
path = path.getRemaining();
}
namespace = path.getPath();
}
for(NamedElement n : namespace.getOwnedMembers()) {
if(isWantedType(n)) {
if(n.getName().startsWith(context.getPrefix())) {
String completionString = n.getName().substring(context.getPrefix().length());
String displayString = n.getName();
ICompletionProposal completionProposal = createCompletionProposal(n, completionString, displayString, context);
acceptor.accept(completionProposal);
}
}
if(n instanceof Namespace) {
for(Type t : getRecursivelyOwnedType((Namespace)n)) {
if(t.getName().startsWith(context.getPrefix())) {
String completionString = t.getName().substring(context.getPrefix().length());
String displayString = t.getName();;
ICompletionProposal completionProposal = createCompletionProposal(t, completionString, displayString, context);
acceptor.accept(completionProposal);
}
}
}
}
}
/**
* Private Utility method for creating a completion proposal
*
* @param namedElement
* The named element for which completion proposal must be created
* @param completionString
* The actual completion string
* @param displayString
* The way the completion is displayed in the completion list
* @param context
* Some information related to the context of the completion
* @return
*/
protected ICompletionProposal createCompletionProposal(NamedElement namedElement, String completionString, String displayString, ContentAssistContext context) {
String additionalProposalInfo = "" + namedElement.getQualifiedName() + "\n" + '(' + namedElement.eClass().getName() + ')'; //$NON-NLS-1$ //$NON-NLS-2$
ICompletionProposal completionProposal = new CompletionProposal(completionString, // String to be inserted
context.getOffset(), // Offset
context.getSelectedText().length(), // Replacement length
completionString.length(), // cursorPosition
labelProvider.getImage(namedElement), // image
" " + displayString, // displayString //$NON-NLS-1$
null, // contextInformation
additionalProposalInfo // additionalProposalInfo
);
return completionProposal;
}
/**
* Private Utility method for creating a completion proposal
*
* @param completionString
* The actual completion string
* @param displayString
* The way the completion is displayed in the completion list
* @param context
* Some information related to the context of the completion
* @return
*/
protected ICompletionProposal createCompletionProposal(String completionString, String displayString, ContentAssistContext context) {
ICompletionProposal completionProposal = new CompletionProposal(completionString, // String to be inserted
context.getOffset(), // Offset
context.getSelectedText().length(), // Replacement length
completionString.length(), // cursorPosition
null, // image
" " + displayString, // displayString //$NON-NLS-1$
null, // contextInformation
null // additionalProposalInfo
);
return completionProposal;
}
/**
*
* Private Utility method for creating a completion proposal with replacement of prefix
*
* @param namedElement
* The named element for which completion proposal must be created
* @param completionString
* The actual completion string
* @param displayString
* The way the completion is displayed in the completion list
* @param context
* Some information related to the context of the completion
* @return
*/
protected ICompletionProposal createCompletionProposalWithReplacementOfPrefix(NamedElement namedElement, String completionString, String displayString, ContentAssistContext context) {
String additionalProposalInfo = "" + namedElement.getQualifiedName() + "\n" + '(' + namedElement.eClass().getName() + ')'; //$NON-NLS-1$ //$NON-NLS-2$
ICompletionProposal completionProposal = new CompletionProposal(completionString, // String to be inserted
context.getOffset() - context.getPrefix().length(), // Offset
context.getPrefix().length(), // Replacement length
completionString.length(), // cursorPosition
labelProvider.getImage(namedElement), // image
" " + displayString, // displayString //$NON-NLS-1$
null, // contextInformation
additionalProposalInfo // additionalProposalInfo
);
return completionProposal;
}
/**
*
* This method shall be overridden in order to look for a more specific {@link Type} Utility methods which returns the list of {@link Type} 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
*/
protected List<Type> getRecursivelyImportedType(Namespace context) {
List<Type> recursivelyImportedTypes = new ArrayList<Type>();
EList<org.eclipse.uml2.uml.Package> importedPackages = context.getImportedPackages();
for(Package p : importedPackages) {
recursivelyImportedTypes.addAll(getRecursivelyOwnedType(p));
}
return recursivelyImportedTypes;
}
/**
* This method shall be overridden in order to look for a more specific {@link Type}
*
* Utility methods which returns the list of the type 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
*/
protected List<Type> getRecursivelyOwnedType(Namespace context) {
List<Type> recursivelyOwnedTypes = new ArrayList<Type>();
List<Element> allOwnedElements = context.getOwnedElements();
for(Element e : allOwnedElements) {
if(isWantedType(e)) {
recursivelyOwnedTypes.add((Type)e);
}
if(e instanceof Namespace) {
recursivelyOwnedTypes.addAll(this.getRecursivelyOwnedType((Namespace)e));
}
}
return recursivelyOwnedTypes;
}
/**
* 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 this.wantedType.isInstance(e);
}
/**
* This method allows to precise the wanted type of the element (to be more restrictive that {@link Port}
*
* Setter for {@link #wantedType}
*
* @param type
* the new type
*/
public void setWantedType(Class<?> type) {
this.wantedType = type;
}
}