/***************************************************************************** * Copyright (c) 2012 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.stereotypeproperty.xtext.ui.contributions; import java.util.ArrayList; import java.util.Iterator; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.emf.common.util.Enumerator; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.papyrus.extensionpoints.editors.ui.IPopupEditorHelper; import org.eclipse.papyrus.uml.alf.alf.BOOLEAN_LITERAL; import org.eclipse.papyrus.uml.alf.alf.INTEGER_LITERAL; import org.eclipse.papyrus.uml.alf.alf.NameExpression; import org.eclipse.papyrus.uml.alf.alf.STRING_LITERAL; import org.eclipse.papyrus.uml.profile.structure.AppliedStereotypeProperty; import org.eclipse.papyrus.uml.textedit.stereotypeproperty.xtext.AppliedStereotypePropertyEditorUtil; import org.eclipse.papyrus.uml.textedit.stereotypeproperty.xtext.ui.internal.AppliedStereotypePropertyActivator; import org.eclipse.papyrus.uml.textedit.stereotypeproperty.xtext.validation.AppliedStereotypePropertyJavaValidator; import org.eclipse.papyrus.uml.textedit.stereotypeproperty.xtext.validation.SemanticValidator; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.xtext.gmf.glue.PopupEditorConfiguration; import org.eclipse.xtext.gmf.glue.edit.part.IXtextEMFReconciler; import com.google.inject.Injector; //import org.eclipse.papyrus.views.properties.runtime.modelhandler.emf.EMFUtils; //import org.eclipse.papyrus.views.properties.runtime.modelhandler.emf.TransactionUtil; /** * @author CEA LIST * * This class is used for contribution to the Papyrus extension point DirectEditor. It is used for the integration * of an xtext generated editor, for properties of UML classifiers. * */ public class StereotypePropertyPopupEditorConfigurationContribution extends PopupEditorConfiguration { protected IGraphicalEditPart graphicalEditPart; /** * Default implementation of the constructor for this class */ public StereotypePropertyPopupEditorConfigurationContribution() { super(); } /* * (non-Javadoc) * * @see * org.eclipse.xtext.gmf.glue.PopupEditorConfiguration#createPopupEditorHelper(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart) */ @Override public IPopupEditorHelper createPopupEditorHelper(Object editPart) { graphicalEditPart = null; if(!(editPart instanceof IGraphicalEditPart)) { return null; } graphicalEditPart = (IGraphicalEditPart)editPart; if(editPart instanceof IAdaptable) { final AppliedStereotypeProperty appliedStereotypeProperty = (AppliedStereotypeProperty)((IAdaptable)editPart).getAdapter(AppliedStereotypeProperty.class); AppliedStereotypePropertyJavaValidator.init(appliedStereotypeProperty); // retrieves the XText injector Injector injector = AppliedStereotypePropertyActivator.getInstance().getInjector("org.eclipse.papyrus.uml.textedit.stereotypeproperty.xtext.AppliedStereotypeProperty"); // builds the text content and extension for a temporary file, to be edited by the xtext editor String textToEdit = "" + this.getTextToEdit(appliedStereotypeProperty); String fileExtension = "" + ".stereotypeproperty"; // builds a new IXtextEMFReconciler. // Its purpose is to extract any relevant information from the textual specification, // and then merge it in the context UML model if necessary IXtextEMFReconciler reconciler = new IXtextEMFReconciler() { public void reconcile(EObject modelObject, EObject xtextObject) { Object[] result = AppliedStereotypePropertyEditorUtil.getPossibleElements(appliedStereotypeProperty); //ref element stereotype application if(appliedStereotypeProperty.getStereotypeProperty().getType().eClass().getName().equals("Stereotype")) { reconcileRefToStereotypeApp(appliedStereotypeProperty, xtextObject, result); return; } //int if(appliedStereotypeProperty.getStereotypeProperty().getType().getName().equals("Integer")) { reconcileInteger(appliedStereotypeProperty, xtextObject); return; } //boolean if(appliedStereotypeProperty.getStereotypeProperty().getType().getName().equals("Boolean")) { reconcileBoolean(appliedStereotypeProperty, xtextObject); return; } //string if(appliedStereotypeProperty.getStereotypeProperty().getType().getName().equals("String")) { reconcileString(appliedStereotypeProperty, xtextObject); return; } //dataType if(appliedStereotypeProperty.getStereotypeProperty().getType().eClass().getName().equals("DataType")) { reconcileString(appliedStereotypeProperty, xtextObject); return; } //primitiveType if(appliedStereotypeProperty.getStereotypeProperty().getType().eClass().getName().equals("PrimitiveType")) { reconcileString(appliedStereotypeProperty, xtextObject); return; } if(appliedStereotypeProperty.getStereotypeProperty().getType() instanceof Enumeration) { reconcileEnumerationLiteral(appliedStereotypeProperty, xtextObject, result); return; } //ref element if(appliedStereotypeProperty.getStereotypeProperty().getType() instanceof Element) { reconcileRefToElement(appliedStereotypeProperty, xtextObject, result); return; } } /** * this method is used to reconcile Enumeration literal with application of the stereotype * * @param appliedStereotypeProperty * the application of stereotype * @param xtextObject * the AST of the grammar * @param possibleElement * list of possible elements that can be used */ protected void reconcileEnumerationLiteral(final AppliedStereotypeProperty appliedStereotypeProperty, EObject xtextObject, Object[] possibleElement) { ArrayList<NameExpression> eObjects = getAllElementRef(xtextObject); //cardinality 1 if(appliedStereotypeProperty.getStereotypeProperty().getUpper() == 1) { if(eObjects.size() == 0) { updateProperties(appliedStereotypeProperty, null); return; } else { NameExpression nameExpression = eObjects.get(0); String id = nameExpression.getId(); //EObject foundStereotypeApplication=AppliedStereotypePropertyEditorUtil.getNamedElementFor(nameExpression, result); EObject foundStereotypeApplication = null; //look for object for(int i = 0; i < possibleElement.length; i++) { if(possibleElement[i] instanceof EEnumLiteral && ((EEnumLiteral)possibleElement[i]).getName().equals(id)) { foundStereotypeApplication = (EEnumLiteral)possibleElement[i]; } if(possibleElement[i] instanceof Enumerator && ((Enumerator)possibleElement[i]).getName().equals(id)) { updateProperties(appliedStereotypeProperty, possibleElement[i]); } } if(foundStereotypeApplication != null) { updateProperties(appliedStereotypeProperty, foundStereotypeApplication); } } } } /** * this method is used to reconcile references to Stereotype Application with the current application of the stereotype * * @param appliedStereotypeProperty * the application of stereotype * @param xtextObject * the AST of the grammar * @param possibleElement * list of possible elements that can be used */ @SuppressWarnings("rawtypes") protected void reconcileRefToStereotypeApp(final AppliedStereotypeProperty appliedStereotypeProperty, EObject xtextObject, Object[] result) { ArrayList<NameExpression> eObjects = getAllElementRef(xtextObject); //cardinality 1 if(appliedStereotypeProperty.getStereotypeProperty().getUpper() == 1) { if(eObjects.size() == 0) { updateProperties(appliedStereotypeProperty, null); return; } else { NameExpression nameExpression = eObjects.get(0); EObject foundStereotypeApplication = AppliedStereotypePropertyEditorUtil.getApplicationStereotypeFor(nameExpression, result); updateProperties(appliedStereotypeProperty, foundStereotypeApplication); return; } } //cardinality * else { if(eObjects.size() == 0) { updateProperties(appliedStereotypeProperty, new ArrayList()); return; } else { //iterate on NameExpression ArrayList<EObject> stereotypeApplicationList = new ArrayList<EObject>(); Iterator<NameExpression> iterator = eObjects.iterator(); while(iterator.hasNext()) { NameExpression nameExpression = iterator.next(); EObject foundStereotypeApplication = AppliedStereotypePropertyEditorUtil.getApplicationStereotypeFor(nameExpression, result); if(foundStereotypeApplication != null) { stereotypeApplicationList.add(foundStereotypeApplication); } } updateProperties(appliedStereotypeProperty, stereotypeApplicationList); return; } } } /** * this method is used to reconcile integer with the current application of the stereotype * * @param appliedStereotypeProperty * the application of stereotype * @param xtextObject * the AST of the grammar */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected void reconcileInteger(final AppliedStereotypeProperty appliedStereotypeProperty, EObject xtextObject) { ArrayList<INTEGER_LITERAL> intList = AppliedStereotypePropertyEditorUtil.get_INTEGER(xtextObject); if(appliedStereotypeProperty.getStereotypeProperty().getUpper() == 1) { if(intList.size() == 0) { updateProperties(appliedStereotypeProperty, null); return; } else { INTEGER_LITERAL theint = intList.get(0); Integer value = new Integer(theint.getValue()); updateProperties(appliedStereotypeProperty, value.intValue()); return; } } else { if(intList.size() == 0) { updateProperties(appliedStereotypeProperty, new ArrayList()); return; } else { //iterate on NameExpression ArrayList resultList = new ArrayList(); Iterator<INTEGER_LITERAL> iterator = resultList.iterator(); while(iterator.hasNext()) { INTEGER_LITERAL theint = iterator.next(); Integer value = new Integer(theint.getValue()); resultList.add(value.intValue()); } updateProperties(appliedStereotypeProperty, resultList); return; } } } /** * this method is used to reconcile boolean with the current application of the stereotype * * @param appliedStereotypeProperty * the application of stereotype * @param xtextObject * the AST of the grammar */ @SuppressWarnings("rawtypes") protected void reconcileBoolean(final AppliedStereotypeProperty appliedStereotypeProperty, EObject xtextObject) { ArrayList<BOOLEAN_LITERAL> booleanList = AppliedStereotypePropertyEditorUtil.get_BOOLEAN(xtextObject); if(appliedStereotypeProperty.getStereotypeProperty().getUpper() == 1) { if(booleanList.size() == 0) { updateProperties(appliedStereotypeProperty, null); return; } else { BOOLEAN_LITERAL theboolean = booleanList.get(0); Boolean value = new Boolean(theboolean.getValue().toString()); updateProperties(appliedStereotypeProperty, value.booleanValue()); return; } } else { if(booleanList.size() == 0) { updateProperties(appliedStereotypeProperty, new ArrayList()); return; } else { //iterate on NameExpression ArrayList<Boolean> resultList = new ArrayList<Boolean>(); Iterator<BOOLEAN_LITERAL> iterator = booleanList.iterator(); while(iterator.hasNext()) { BOOLEAN_LITERAL theboolean = iterator.next(); Boolean value = new Boolean(theboolean.getValue().toString()); resultList.add(value.booleanValue()); } updateProperties(appliedStereotypeProperty, resultList); return; } } } /** * this method is used to reconcile references element with the current application of the stereotype * * @param appliedStereotypeProperty * the application of stereotype * @param xtextObject * the AST of the grammar * @param possibleElement * list of possible elements that can be used */ @SuppressWarnings("rawtypes") protected void reconcileRefToElement(final AppliedStereotypeProperty appliedStereotypeProperty, EObject xtextObject, Object[] result) { ArrayList<NameExpression> eObjects = getAllElementRef(xtextObject); //cardinality 1 if(appliedStereotypeProperty.getStereotypeProperty().getUpper() == 1) { if(eObjects.size() == 0) { updateProperties(appliedStereotypeProperty, null); return; } else { NameExpression nameExpression = eObjects.get(0); EObject foundStereotypeApplication = AppliedStereotypePropertyEditorUtil.getNamedElementFor(nameExpression, result); updateProperties(appliedStereotypeProperty, foundStereotypeApplication); return; } } //cardinality * else { if(eObjects.size() == 0) { updateProperties(appliedStereotypeProperty, new ArrayList()); return; } else { //iterate on NameExpression ArrayList<EObject> stereotypeApplicationList = new ArrayList<EObject>(); Iterator<NameExpression> iterator = eObjects.iterator(); while(iterator.hasNext()) { NameExpression nameExpression = iterator.next(); EObject foundStereotypeApplication = AppliedStereotypePropertyEditorUtil.getNamedElementFor(nameExpression, result); if(foundStereotypeApplication != null) { stereotypeApplicationList.add(foundStereotypeApplication); } } updateProperties(appliedStereotypeProperty, stereotypeApplicationList); return; } } } /** * this method is used to reconcile Strings with the current application of the stereotype * * @param appliedStereotypeProperty * the application of stereotype * @param xtextObject * the AST of the grammar */ @SuppressWarnings("rawtypes") protected void reconcileString(final AppliedStereotypeProperty appliedStereotypeProperty, EObject xtextObject) { ArrayList<STRING_LITERAL> theStringList = AppliedStereotypePropertyEditorUtil.get_STRING(xtextObject); if(appliedStereotypeProperty.getStereotypeProperty().getUpper() == 1) { if(theStringList.size() == 0) { updateProperties(appliedStereotypeProperty, null); return; } else { STRING_LITERAL theString = theStringList.get(0); updateProperties(appliedStereotypeProperty, theString.getValue()); return; } } else { if(theStringList.size() == 0) { updateProperties(appliedStereotypeProperty, new ArrayList()); return; } else { //iterate on NameExpression ArrayList<String> resultList = new ArrayList<String>(); Iterator<STRING_LITERAL> iterator = theStringList.iterator(); while(iterator.hasNext()) { STRING_LITERAL theString = iterator.next(); resultList.add(theString.getValue()); } updateProperties(appliedStereotypeProperty, resultList); return; } } } }; return super.createPopupEditorHelper(graphicalEditPart, injector, reconciler, textToEdit, fileExtension, new SemanticValidator()); } else { return null; } } /** * this method create and execute a command to update the value of the property for the stereotype property * * @param appliedStereotypeProperty * @param value * the value that will be set */ protected void updateProperties(final AppliedStereotypeProperty appliedStereotypeProperty, final Object value) { TransactionalEditingDomain domain = graphicalEditPart.getEditingDomain(); RecordingCommand command = new RecordingCommand(domain, "UpdateAppliedStereotypeProperty") { @Override protected void doExecute() { appliedStereotypeProperty.getBaseElement().setValue(appliedStereotypeProperty.getStereotype(), appliedStereotypeProperty.getStereotypeProperty().getName(), value); } }; domain.getCommandStack().execute(command); } private ArrayList<NameExpression> getAllElementRef(EObject xtextObject) { ArrayList<NameExpression> result = new ArrayList<NameExpression>(); TreeIterator<EObject> iterator = xtextObject.eAllContents(); while(iterator.hasNext()) { EObject eObject = iterator.next(); if(eObject instanceof NameExpression) { result.add((NameExpression)eObject); } } return result; } /* * (non-Javadoc) * * @see org.eclipse.xtext.gmf.glue.PopupEditorConfiguration#getTextToEdit(java.lang.Object) */ @Override public String getTextToEdit(Object editedObject) { if(editedObject instanceof AppliedStereotypeProperty) { return AppliedStereotypePropertyEditorUtil.getLabel((AppliedStereotypeProperty)editedObject).trim(); // TODO: default values not supported by the grammar // TODO: either complete the grammar, or use another label provider } return "<UNDEFINED>"; } }