/***************************************************************************** * Copyright (c) 2011 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: * E.D.Willink - Initial API and implementation * CEA LIST - Architecture refactoring * *****************************************************************************/ package org.eclipse.papyrus.uml.textedit.constraintwithessentialocl.xtext; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.ocl.examples.pivot.Operation; import org.eclipse.ocl.examples.pivot.Property; import org.eclipse.ocl.examples.pivot.context.ClassContext; import org.eclipse.ocl.examples.pivot.context.EClassContext; import org.eclipse.ocl.examples.pivot.context.OperationContext; import org.eclipse.ocl.examples.pivot.context.ParserContext; import org.eclipse.ocl.examples.pivot.context.PropertyContext; import org.eclipse.ocl.examples.pivot.manager.MetaModelManager; import org.eclipse.ocl.examples.pivot.uml.UML2Ecore2Pivot; import org.eclipse.ocl.examples.pivot.utilities.BaseResource; import org.eclipse.ocl.examples.xtext.essentialocl.utilities.EssentialOCLPlugin; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.extensionpoints.editors.ui.IPopupEditorHelper; import org.eclipse.papyrus.infra.core.Activator; import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.LiteralString; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.UMLFactory; import org.eclipse.xtext.gmf.glue.edit.part.DefaultXtextSemanticValidator; import org.eclipse.xtext.gmf.glue.edit.part.IXTextSemanticValidator; import org.eclipse.xtext.gmf.glue.edit.part.IXtextEMFReconciler; import org.eclipse.xtext.gmf.glue.edit.part.PopupXtextEditorHelper; import org.eclipse.xtext.gmf.glue.partialEditing.SourceViewerHandle; import org.eclipse.xtext.resource.XtextResource; import com.google.inject.Injector; /** * this plugin is the configuration of the essential editor * */ public class EssentialOCLPopupEditorConfiguration extends org.eclipse.xtext.gmf.glue.PopupEditorConfiguration { /** * this is a specific reconcilers to manipulate OCL constraint * */ public class Reconciler implements IXtextEMFReconcilerWithContext { public void configureResource(XtextResource resource, EObject umlObject) { //to launch the editor, it is important to set the context. if not there is no completion and the constraint can not be validated //thanks to E.D.Willink if(resource instanceof BaseResource){ BaseResource baseResource = (BaseResource) resource; ResourceSet resourceSet = baseResource.getResourceSet(); MetaModelManager metaModelManager = MetaModelManager.getAdapter(resourceSet); if( umlObject instanceof Element){ baseResource.setParserContext(getParserContext((Element)umlObject, metaModelManager)); } } } /** * this method returns the parser context for an element * in the case of a model, the context of parser must be set on the level M +1 * in the case of the profile the context must be on the level M * @param modelelement * @param metaModelManager * @return parser context, if the context is unknown, it can return null */ public ParserContext getParserContext(Element modelelement, MetaModelManager metaModelManager){ //to launch the editor, it is important to set the context. if not there is no completion and the constraint can not be validated //thanks to E.D.Willink ParserContext parserContext=null; if(isInProfileContext(modelelement)){ org.eclipse.ocl.examples.pivot.Element pivotElement = getPivotModel(modelelement, metaModelManager); URI uri = metaModelManager.getResourceIdentifier(modelelement, null); if (pivotElement instanceof Property) { parserContext = new PropertyContext(metaModelManager, uri, (Property) pivotElement); } else if (pivotElement instanceof Operation) { parserContext = new OperationContext(metaModelManager, uri, (Operation) pivotElement, null); } else if (pivotElement instanceof org.eclipse.ocl.examples.pivot.Class) { parserContext = new ClassContext(metaModelManager, uri, (org.eclipse.ocl.examples.pivot.Class) pivotElement); } else { Activator.log.error("Unknown context type", new ExecutionException("Unknown context type for "+modelelement)); } } else{ parserContext =new EClassContext(metaModelManager, null, modelelement.eClass()); } return parserContext; } /** * test if the current element has a profile has direct or indirect owner * @param element the current element * @return true if the direct or indirect owner is a profile */ protected boolean isInProfileContext(Element element){ if( element instanceof Profile){ return true; } else{ // the element is not a profile //but it has got a owner if( element.getOwner()!=null){ return isInProfileContext(element.getOwner()); } else{ //it has not parent, so we can deduce that we have not meet a profile. //this element is not in the context of a profile return false;} } } /** * * @see org.eclipse.xtext.gmf.glue.edit.part.IXtextEMFReconciler#reconcile(org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject) * * @param modelObject the uml element to modify * @param xtextObject the xtext structure */ public void reconcile(EObject modelObject, EObject xtextObject) { if (!(modelObject instanceof org.eclipse.uml2.uml.Constraint)) { return; } String newTextualRepresentation = editorHelper.getSourceViewerHandle().getDocument().get() ; // // Creates and executes the update command // TransactionalEditingDomain editingDomain =org.eclipse.emf.transaction.util.TransactionUtil.getEditingDomain((org.eclipse.uml2.uml.Constraint)modelObject); UpdateConstraintCommand updateCommand = new UpdateConstraintCommand(editingDomain,(org.eclipse.uml2.uml.Constraint)modelObject, newTextualRepresentation); editingDomain.getCommandStack().execute(new GMFtoEMFCommandWrapper(updateCommand)); } } /** * the command to save the content of the OCL constraint into the body of the UML constraint element * */ protected class UpdateConstraintCommand extends AbstractTransactionalCommand { protected final org.eclipse.uml2.uml.Constraint constraint; protected final String newTextualRepresentation; public UpdateConstraintCommand(TransactionalEditingDomain editingDomain,org.eclipse.uml2.uml.Constraint constraint, String newTextualRepresentation) { super(editingDomain, "Constraint Update", getWorkspaceFiles(constraint)); this.constraint = constraint; this.newTextualRepresentation = newTextualRepresentation; } @Override protected CommandResult doExecuteWithResult(IProgressMonitor arg0, IAdaptable arg1) throws ExecutionException { org.eclipse.uml2.uml.OpaqueExpression opaqueExpression = null ; int indexOfOCLBody = -1 ; if (constraint.getSpecification() == null || !(constraint.getSpecification() instanceof org.eclipse.uml2.uml.OpaqueExpression)) { opaqueExpression = UMLFactory.eINSTANCE.createOpaqueExpression() ; } else { opaqueExpression = (org.eclipse.uml2.uml.OpaqueExpression)constraint.getSpecification() ; for (int i = 0 ; i < opaqueExpression.getLanguages().size() && indexOfOCLBody == -1 ; i++) { if (opaqueExpression.getLanguages().get(i).equals("OCL")) { indexOfOCLBody = i ; } } } if (indexOfOCLBody == -1) { opaqueExpression.getLanguages().add("OCL") ; opaqueExpression.getBodies().add(newTextualRepresentation) ; } else { opaqueExpression.getBodies().remove(indexOfOCLBody) ; opaqueExpression.getBodies().add(indexOfOCLBody, newTextualRepresentation) ; } constraint.setSpecification(opaqueExpression) ; return CommandResult.newOKCommandResult(constraint); } } protected PopupXtextEditorHelper editorHelper = null ; /** * * Constructor. * */ public EssentialOCLPopupEditorConfiguration() { } @Override public IPopupEditorHelper createPopupEditorHelper(Object editPart) { editorHelper=null; if (!(editPart instanceof IGraphicalEditPart)) { return null; } IGraphicalEditPart graphicalEditPart = (IGraphicalEditPart)editPart; Object model = graphicalEditPart.getModel(); if (model == null) { return null; } if (!(model instanceof View)) { return null; } View view = (View) model; EObject element = view.getElement(); if (element == null) { return null; } if (!(element instanceof org.eclipse.uml2.uml.Constraint)) { return null; } org.eclipse.uml2.uml.Constraint constraint = (org.eclipse.uml2.uml.Constraint) element; org.eclipse.uml2.uml.ValueSpecification specification = constraint.getSpecification(); if (specification == null) { return null; } if (!(specification instanceof org.eclipse.uml2.uml.LiteralString || specification instanceof org.eclipse.uml2.uml.OpaqueExpression)) { return null; } Injector xtextInjector = EssentialOCLPopupPlugin.getInstance().getInjector(EssentialOCLPlugin.LANGUAGE_ID); IXtextEMFReconciler modelReconciler = new Reconciler(); String textToEdit = getTextToEdit(element); String fileExtension = "essentialocl"; IXTextSemanticValidator semanticValidator = new DefaultXtextSemanticValidator(); SourceViewerHandle.bindPartialModelEditorClass(EssentialOCLPartialModelEditor.class) ; editorHelper = (PopupXtextEditorHelper)super.createPopupEditorHelper(graphicalEditPart, xtextInjector, modelReconciler, textToEdit, fileExtension, semanticValidator); return editorHelper ; } protected org.eclipse.ocl.examples.pivot.Element getPivotModel(EObject umlObject,MetaModelManager metaModelManager) { Resource umlResource = umlObject.eResource(); if (umlResource == null) { return null; } UML2Ecore2Pivot adapter = UML2Ecore2Pivot.getAdapter(umlResource, metaModelManager); //this line is very important, its allows to reload the context and ensure a good completion if the model is modified adapter.dispose(); adapter = UML2Ecore2Pivot.getAdapter(umlResource, metaModelManager); adapter.getPivotRoot(); return adapter.getCreated(org.eclipse.ocl.examples.pivot.Element.class, umlObject); } @Override public String getTextToEdit(Object editedObject) { Constraint umlConstraint = (Constraint)editedObject ; String value = "" ; if (umlConstraint.getSpecification() != null) { if (umlConstraint.getSpecification() instanceof LiteralString) { if (((LiteralString)umlConstraint.getSpecification()).getValue() != null) { value += ((LiteralString)umlConstraint.getSpecification()).getValue() ; } } else if (umlConstraint.getSpecification() instanceof org.eclipse.uml2.uml.OpaqueExpression) { int indexOfOCLBody = -1 ; org.eclipse.uml2.uml.OpaqueExpression opaqueExpression = (org.eclipse.uml2.uml.OpaqueExpression)umlConstraint.getSpecification() ; for (int i = 0 ; i < opaqueExpression.getLanguages().size() && indexOfOCLBody == -1 ; i ++) { if (opaqueExpression.getLanguages().get(i).equals("OCL")) { value += opaqueExpression.getBodies().get(i) ; indexOfOCLBody = i ; } } } } return value; } }