/***************************************************************************** * 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.state.xtext.ui.contentassist; import java.util.ArrayList; import java.util.List; 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.papyrus.infra.core.utils.DisplayUtils; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.QualifiedName; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.StateRule; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.SubmachineRule; import org.eclipse.papyrus.uml.textedit.state.xtext.validation.UmlStateJavaValidator; 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.StateMachine; import org.eclipse.xtext.Assignment; 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 UmlStateProposalProvider extends AbstractUmlStateProposalProvider { private ILabelProvider labelProvider = DisplayUtils.getLabelProvider() ; /** * Provides custom completion for the specifying the submachine of submachine state * * @see org.eclipse.papyrus.property.editor.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 completeStateRule_Submachine(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { // the customization consists in proposing nothing. Proposals are handled by other methods. List<StateMachine> allStateMachines = new ArrayList<StateMachine>() ; allStateMachines.addAll(getRecursivelyOwnedStatemachines(UmlStateJavaValidator.getModel())) ; allStateMachines.addAll(getRecursivelyImportedStatemachines(UmlStateJavaValidator.getModel())) ; for (StateMachine s : allStateMachines) { if (s.getName().contains(context.getPrefix())) { String displayString = s.getQualifiedName() ; String completionString = getSubmachineLabel(s) ; ICompletionProposal completionProposal = createCompletionProposalWithReplacementOfPrefix(s, completionString, displayString, context) ; acceptor.accept(completionProposal) ; } } } /** * Provides custom completion for the root element in a qualified name * * @see org.eclipse.papyrus.property.editor.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 completeSubmachineRule_Path(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { // TODO Auto-generated method stub Namespace root = UmlStateJavaValidator.getModel() ; if (root == null) { return ; } // first accept the root Model String completionString = root.getName() + "::"; String displayString = root.getName() + "::"; //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()) + "::"; displayString = p.getName() + "::"; //String displayString = c.getName() ; completionProposal = createCompletionProposal(root, completionString, displayString, context) ; acceptor.accept(completionProposal) ; } } } /** * Provides custom completion for specifying the submachine of a submachine state, 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 completeSubmachineRule_Submachine(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { // TODO Auto-generated method stub Namespace namespace = UmlStateJavaValidator.getContextElement().getNearestPackage() ; if (model instanceof SubmachineRule) { SubmachineRule typeRule = (SubmachineRule)model ; QualifiedName path = typeRule.getPath() ; while (path.getRemaining() != null) { path = path.getRemaining() ; } namespace = path.getPath() ; } else if (! (model instanceof StateRule)) { return ; } for (NamedElement n : namespace.getOwnedMembers()) { if (n instanceof StateMachine) { if (n.getName().startsWith(context.getPrefix())) { String completionString = n.getName().substring(context.getPrefix().length()) ; String displayString = n.getName() ; //String displayString = c.getName() ; ICompletionProposal completionProposal = createCompletionProposal(n, completionString, displayString, context) ; acceptor.accept(completionProposal) ; } } } //super.completeTypeRule_Type(model, assignment, context, acceptor) ; } /** * Provides custom completion for a path in a qualified name * * @see org.eclipse.papyrus.property.editor.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.property.editor.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) { // TODO Auto-generated method stub QualifiedName path = (QualifiedName) model ; for (NamedElement n : path.getPath().getOwnedMembers()) { if (n instanceof Namespace && !(n instanceof StateMachine)) { if (n.getName().startsWith(context.getPrefix())) { String completionString = n.getName().substring(context.getPrefix().length()) + "::"; String displayString = n.getName() + "::"; //String displayString = c.getName() ; ICompletionProposal completionProposal = createCompletionProposal(n, completionString, displayString, context) ; acceptor.accept(completionProposal) ; } } } for (Package p : path.getPath().getImportedPackages()) { if (p.getName().startsWith(context.getPrefix())) { String completionString = p.getName().substring(context.getPrefix().length()) + "::"; String displayString = p.getName() + "::"; //String displayString = c.getName() ; ICompletionProposal completionProposal = createCompletionProposal(p, completionString, displayString, context) ; acceptor.accept(completionProposal) ; } } } /* ****************************************************************************** * Utility methods ********************************************************************************/ public static String getSubmachineLabel(StateMachine statemachine) { String label = "" ; Namespace model = UmlStateJavaValidator.getModel() ; List<Package> importedPackages = new ArrayList<Package>(model.getImportedPackages()) ; List<Namespace> visitedNamespaces = new ArrayList<Namespace>() ; Namespace currentNamespace = statemachine.getNamespace() ; boolean rootFound = false ; while (currentNamespace != null && !rootFound) { visitedNamespaces.add(currentNamespace) ; if (importedPackages.contains(currentNamespace) || currentNamespace == model) { rootFound = true ; } Element owner = currentNamespace.getOwner() ; currentNamespace = owner != null ? (Namespace)owner : null ; } for (int i = visitedNamespaces.size() - 1 ; i >= 0 ; i--) { label += visitedNamespaces.get(i).getName() + "::" ; } return label + statemachine.getName() ; } /** * 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() + ')' ; 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 null , // contextInformation additionalProposalInfo // 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() + ')' ; 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 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 null , // contextInformation null // additionalProposalInfo ); return completionProposal ; } /** * Utility methods wich returns the list of statemachines that are directly or indirectly owned by a context statemachine * * @param context The context namespace * @return the list of statemachines that are directly or indirectly owned by the context namespace */ private List<StateMachine> getRecursivelyOwnedStatemachines(Namespace context) { List<StateMachine> recursivelyOwnedStatemachines = new ArrayList<StateMachine>(); List<Element> allOwnedElements = context.getOwnedElements() ; for (Element e : allOwnedElements) { if (e instanceof StateMachine) { recursivelyOwnedStatemachines.add((StateMachine)e) ; } else if (e instanceof Namespace) { recursivelyOwnedStatemachines.addAll(getRecursivelyOwnedStatemachines((Namespace)e)) ; } } return recursivelyOwnedStatemachines ; } /** * Utility methods which returns the list of statemachines that are directly or indirectly owned by the namespaces imported by a context namespace * * @param context The context namespace * @return the list of statemachines that are directly or indirectly owned by the namespaces imported by the context namespace */ private List<StateMachine> getRecursivelyImportedStatemachines (Namespace context) { List<StateMachine> recursivelyImportedStateMachines = new ArrayList<StateMachine>() ; List<Package> importedPackages = context.getImportedPackages() ; for (Package p : importedPackages) { recursivelyImportedStateMachines.addAll(getRecursivelyOwnedStatemachines(p)) ; } return recursivelyImportedStateMachines ; } }