blob: e5894a396393d79d35b7c560d24d3912b2251337 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2019 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Xavier Le Pallec (for CEA LIST) xlepallec@lilo.org - Bug 558456
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.mapping.js2java;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
import org.eclipse.papyrus.infra.gmfdiag.common.editpart.ResizeableListCompartmentEditPart;
import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassAttributeCompartmentEditPart;
import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassAttributeCompartmentEditPartCN;
import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassOperationCompartmentEditPart;
import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassOperationCompartmentEditPartCN;
import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.OperationForClassEditPart;
import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.PropertyForClassEditPart;
import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.Activator;
import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.mapping.jsonstructures.JsonUmlClass;
import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.mapping.jsonstructures.JsonUmlOperation;
import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.mapping.jsonstructures.JsonUmlProperty;
import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.messages.Messages;
//import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassEditPart;
import org.eclipse.papyrus.uml.diagram.common.editparts.ClassEditPart;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Property;
/**
* This class aims at fulfilling the class edit part according to a textual
* definition of a class (UmlClass) with cascading actions for properties and
* operations.<BR>
* It has to add new properties/operations and removing previous existing ones
* that do not appear in the textual definition anymore. That's the reason there
* are a lot of java attributes: to memorize previous existing elements.
*
*/
public class JsonUmlClassToEditPart {
private static final Activator LOGGER = Activator.getDefault();
private JsonUmlClass theClass;
private ClassEditPart editPart;
private org.eclipse.uml2.uml.Class papyrusUmlClass;
private TransactionalEditingDomain editingDomain;
private ResizeableListCompartmentEditPart attributeCompartment;
private ResizeableListCompartmentEditPart operationCompartment;
private Map<String, org.eclipse.uml2.uml.Property> properties;
private Map<String, PropertyForClassEditPart> propertyEditParts;
private Map<String, OperationForClassEditPart> operationEditParts;
private Map<String, org.eclipse.uml2.uml.Operation> operations;
/**
* This constructor takes a textual definition (UmlClass) and a Papyrus Class
* (referenced by the class edit part).<BR>
* The constructor creates all the structures to remember the state of the class
* before the edition.<BR>
* Finally the constructor launches all the process: fetch previous existing
* element and the mapping (replacing/adding/removing).
*
* @param theClass
* textual definition.
* @param editPart
* a Papyrus Class (GEF-level)
*/
public JsonUmlClassToEditPart(JsonUmlClass theClass, ClassEditPart editPart) {
super();
try {
this.editPart = editPart;
this.theClass = theClass;
this.properties = new HashMap<>();
this.propertyEditParts = new HashMap<>();
this.operations = new HashMap<>();
this.operationEditParts = new HashMap<>();
fetchPapyrusUmlElements();
updatePapyrusUmlClassAccordingTextualVersion();
} catch (Exception ex) {
LOGGER.logError(ex.toString(), ex);
}
}
/**
* Load all the elements of the Papyrus class (the update is not done yet). This
* method calls the other fetch methods.
*/
private void fetchPapyrusUmlElements() {
if (this.editPart.getModel() instanceof View) {
View model = View.class.cast(this.editPart.getModel());
if (model.getElement() instanceof org.eclipse.uml2.uml.Class) {
this.papyrusUmlClass = org.eclipse.uml2.uml.Class.class.cast(model.getElement());
List<?> children = editPart.getChildren();
for (Object child : children) {
if (child instanceof ClassAttributeCompartmentEditPart || child instanceof ClassAttributeCompartmentEditPartCN) {
this.attributeCompartment = ResizeableListCompartmentEditPart.class.cast(child);
fetchAllAttributes();
} else if (child instanceof ClassOperationCompartmentEditPart || child instanceof ClassOperationCompartmentEditPartCN) {
this.operationCompartment = ResizeableListCompartmentEditPart.class.cast(child);
fetchAllOperations();
}
}
try {
this.editingDomain = ServiceUtilsForEObject.getInstance()
.getTransactionalEditingDomain(papyrusUmlClass);
} catch (ServiceException ex) {
LOGGER.logError(ex.toString(), ex);
}
} else {
LOGGER.logCastProblem("model.getElement()", org.eclipse.uml2.uml.Class.class); //$NON-NLS-1$
}
} else {
LOGGER.logCastProblem("editPart.getModel()", View.class); //$NON-NLS-1$
}
}
/**
* This methods create a global command encapsulating the commands for updating
* the name, the properties and the operations. It calls the process* methods.
*/
private void updatePapyrusUmlClassAccordingTextualVersion() {
Command globalCommand = createGlobalCommand();
if (!theClass.getName().equals(papyrusUmlClass.getName())) {
globalCommand = globalCommand.chain(commandForSettingName());
}
globalCommand = processProperties(globalCommand);
globalCommand = processOperations(globalCommand);
editingDomain.getCommandStack().execute(globalCommand);
}
/**
* This method creates an empty command that will be used to give a name to the
* global command.
*
* @return the empty/naming command.
*/
private RecordingCommand createGlobalCommand() {
return new RecordingCommand(editingDomain, Messages.JsonUmlClassToEditPart_TextualEditionOf_TitleCommand + this.papyrusUmlClass.getName()) {
@Override
protected void doExecute() {
// no actions to perform
// it's just a command to give a name to the global command.
}
};
}
/**
* This method creates a command to updating/setting the name of the class.
*
* @return the naming command.
*/
private Command commandForSettingName() {
return new RecordingCommand(editingDomain, Messages.JsonUmlClassToEditPart_SetNameCommand_TitleCommand) {
@Override
protected void doExecute() {
papyrusUmlClass.setName(theClass.getName());
}
};
}
/**
* This method call {@link JsonUmlClassToEditPart#fetchAttribute(Object)} for each
* attribute in the properties compartment.
*/
private void fetchAllAttributes() {
for (Object child : attributeCompartment.getChildren()) {
if (child instanceof PropertyForClassEditPart) {
fetchAttribute(PropertyForClassEditPart.class.cast(child));
}
}
}
/**
* This method call {@link JsonUmlClassToEditPart#fetchOperation(Object)} for each
* operation in the operations compartment.
*/
private void fetchAllOperations() {
for (Object child : operationCompartment.getChildren()) {
if (child instanceof OperationForClassEditPart) {
fetchOperation(OperationForClassEditPart.class.cast(child));
}
}
}
/**
* This method gets real property and its associated element (edit part and the
* notation element) and stores them in the corresponding maps.
*
* @param child
* the property edit part
*/
private void fetchAttribute(PropertyForClassEditPart propertyEditPart) {
if (propertyEditPart.getModel() instanceof View) {
View visualStuff = View.class.cast(propertyEditPart.getModel());
if (visualStuff.getElement() instanceof Property) {
Property property = Property.class.cast(visualStuff.getElement());
this.propertyEditParts.put(property.getName(), propertyEditPart);
this.properties.put(property.getName(), property);
} else {
LOGGER.logCastProblem("visualStuff.getElement()", Property.class); //$NON-NLS-1$
}
} else {
LOGGER.logCastProblem("propertyEditPart.getModel()", View.class); //$NON-NLS-1$
}
}
/**
* This method gets real operation and its associated element (edit part and the
* notation element) and stores them in the corresponding maps.
*
* @param child
* the operation edit part
*/
private void fetchOperation(OperationForClassEditPart operationEditPart) {
if (operationEditPart.getModel() instanceof View) {
View visualStuff = View.class.cast(operationEditPart.getModel());
if (visualStuff.getElement() instanceof Operation) {
Operation operation = (Operation) visualStuff.getElement();
this.operationEditParts.put(operation.getName(), operationEditPart);
this.operations.put(operation.getName(), operation);
} else {
LOGGER.logCastProblem("visualStuff.getElement()", Operation.class); //$NON-NLS-1$
}
} else {
LOGGER.logCastProblem("operationEditPart.getModel()", View.class); //$NON-NLS-1$
}
}
/**
* Get the list of the real properties found in the class edit part.
*
* @return list of the real properties
*/
private Property[] getAllAttributes() {
return this.properties.values().toArray(new Property[0]);
}
/**
* Get the list of the real operations found in the class edit part.
*
* @return list of the real operations
*/
private Operation[] getAllOperations() {
return this.operations.values().toArray(new Operation[0]);
}
/**
* This method updates the properties.<BR>
* First, for each property in the textual definition of the class, it looks if
* a property in the papyrus class exists with the same name. If it is, it
* updates it and removes it from the list of properties to actually remove. If
* not, it creates a new property.<BR>
* Second, all the existing properties that have not been "met" are removed.
*
* @param globalCommand
* the global command on which all the properties edition
* commands will be chained with.
* @return the new global command.
*/
private Command processProperties(Command globalCommand) {
try {
for (JsonUmlProperty property : theClass.getProperties()) {
Property papyrusProperty = properties.get(property.getName());
if (papyrusProperty != null) {
globalCommand = globalCommand
.chain(ToEditPartFactory.getInstance().createJsonUmlPropertyToEditPart(editingDomain, editPart, attributeCompartment)
.commandForUpdatingProperty(property, papyrusProperty));
properties.remove(property.getName(), papyrusProperty);
} else {
globalCommand = globalCommand
.chain(ToEditPartFactory.getInstance().createJsonUmlPropertyToEditPart(editingDomain, editPart, attributeCompartment)
.commandForAddingProperty(property));
}
}
for (Property papyrusProperty : getAllAttributes()) {
globalCommand = globalCommand
.chain(ToEditPartFactory.getInstance().createJsonUmlPropertyToEditPart(editingDomain, editPart, attributeCompartment)
.commandForRemovingProperty(propertyEditParts, papyrusProperty));
}
} catch (Exception ex) {
LOGGER.logError(ex.toString(), ex);
}
return globalCommand;
}
/**
* This method updates the operations.<BR>
* First, for each operation in the textual definition of the class, it looks if
* an operation in the papyrus class exists with the same name. If it is, it
* updates it and removes it from the list of properties to actually remove. If
* not, it creates a new operation.<BR>
* Second, all the existing operations that have not been "met" are removed.
*
* @param globalCommand
* the global command on which all the operations edition
* commands will be chained with.
* @return the new global command.
*/
private Command processOperations(Command globalCommand) {
try {
for (JsonUmlOperation operation : theClass.getOperations()) {
Operation papyrusOperation = operations.get(operation.getName());
if (papyrusOperation != null) {
globalCommand = globalCommand
.chain(ToEditPartFactory.getInstance().createJsonUmlOperationToEditPart(editingDomain, editPart, operationCompartment)
.commandForUpdatingOperation(operation, papyrusOperation));
operations.remove(operation.getName(), papyrusOperation);
} else {
globalCommand = globalCommand
.chain(ToEditPartFactory.getInstance().createJsonUmlOperationToEditPart(editingDomain, editPart, operationCompartment)
.commandForAddingOperation(operation));
}
}
for (Operation papyrusOperation : getAllOperations()) {
globalCommand = globalCommand
.chain(ToEditPartFactory.getInstance().createJsonUmlOperationToEditPart(editingDomain, editPart, operationCompartment)
.commandForRemovingOperation(operationEditParts, papyrusOperation));
}
} catch (Exception ex) {
LOGGER.logError(ex.toString(), ex);
}
return globalCommand;
}
}