/* license-start * * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details, at <http://www.gnu.org/licenses/>. * * Contributors: * Crispico - Initial API and implementation * * license-end */ package org.flowerplatform.editor.model.java.remote; import java.io.File; import java.util.Collection; import java.util.List; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; import org.flowerplatform.codesync.remote.CodeSyncDiagramOperationsService; import org.flowerplatform.codesync.remote.CodeSyncOperationsService; import org.flowerplatform.common.ied.InplaceEditorLabelParseResult; import org.flowerplatform.common.ied.InplaceEditorLabelParser; import org.flowerplatform.communication.service.ServiceInvocationContext; import org.flowerplatform.editor.model.EditorModelPlugin; import org.flowerplatform.editor.model.change_processor.IDiagrammableElementFeatureChangesProcessor; import org.flowerplatform.editor.model.java.JavaClassChildProcessor; import org.flowerplatform.editor.model.java.JavaInplaceEditorProvider; import org.flowerplatform.editor.model.remote.DiagramEditableResource; import org.flowerplatform.emf_model.notation.Bounds; import org.flowerplatform.emf_model.notation.Diagram; import org.flowerplatform.emf_model.notation.Node; import org.flowerplatform.emf_model.notation.NotationFactory; import org.flowerplatform.emf_model.notation.View; import com.crispico.flower.mp.codesync.base.CodeSyncPlugin; import com.crispico.flower.mp.codesync.code.java.adapter.JavaAttributeModelAdapter; import com.crispico.flower.mp.codesync.code.java.adapter.JavaOperationModelAdapter; import com.crispico.flower.mp.codesync.code.java.adapter.JavaTypeModelAdapter; import com.crispico.flower.mp.model.astcache.code.AstCacheCodeFactory; import com.crispico.flower.mp.model.astcache.code.AstCacheCodePackage; import com.crispico.flower.mp.model.astcache.code.Attribute; import com.crispico.flower.mp.model.astcache.code.ExtendedModifier; import com.crispico.flower.mp.model.astcache.code.ModifiableElement; import com.crispico.flower.mp.model.astcache.code.Modifier; import com.crispico.flower.mp.model.astcache.code.Operation; import com.crispico.flower.mp.model.astcache.code.Parameter; import com.crispico.flower.mp.model.astcache.code.TypedElement; import com.crispico.flower.mp.model.codesync.CodeSyncElement; import com.crispico.flower.mp.model.codesync.CodeSyncFactory; import com.crispico.flower.mp.model.codesync.CodeSyncPackage; import com.crispico.flower.mp.model.codesync.Relation; /** * @author Cristian Spiescu * @author Mariana Gheorghe */ public class JavaClassDiagramOperationsService extends CodeSyncDiagramOperationsService { public static final String SERVICE_ID = "classDiagramOperationsDispatcher"; public static final String ATTRIBUTE_SEPARATOR = "classAttributesCompartmentSeparator"; public static final String OPERATIONS_SEPARATOR = "classOperationsCompartmentSeparator"; private InplaceEditorLabelParser labelParser = new InplaceEditorLabelParser(new JavaInplaceEditorProvider()); public void setInplaceEditorText(ServiceInvocationContext context, String viewId, String text) { View view = getViewById(context, viewId); CodeSyncElement cse = (CodeSyncElement) view.getDiagrammableElement(); if (cse.getType().equals(JavaAttributeModelAdapter.ATTRIBUTE)) { processAttribute(cse, (Attribute) cse.getAstCacheElement(), text); } if (cse.getType().equals(JavaOperationModelAdapter.OPERATION)) { processOperation(cse, (Operation) cse.getAstCacheElement(), text); } if (cse.getType().equals(JavaTypeModelAdapter.CLASS)) { CodeSyncOperationsService.getInstance().setFeatureValue(cse, CodeSyncPackage.eINSTANCE.getCodeSyncElement_Name(), text); } } public String getInplaceEditorText(ServiceInvocationContext context, String viewId) { View view = getViewById(context, viewId); CodeSyncElement cse = (CodeSyncElement) view.getDiagrammableElement(); for (IDiagrammableElementFeatureChangesProcessor processor : EditorModelPlugin.getInstance().getDiagramUpdaterChangeProcessor() .getDiagrammableElementFeatureChangesProcessors(view.getViewType())) { if (processor instanceof JavaClassChildProcessor) { return ((JavaClassChildProcessor) processor).getLabel(cse, true); } } throw new RuntimeException("Cannot edit this element!"); } public void collapseCompartment(ServiceInvocationContext context, String viewId) { View view = getViewById(context, viewId); View cls = (View) view.eContainer(); cls.getPersistentChildren().remove(view); } public void expandCompartment_attributes(ServiceInvocationContext context, String viewId) { View cls = getViewById(context, viewId); // TODO test if there's already a separator? normally this shouldn't be available on client side in this case Node separator = NotationFactory.eINSTANCE.createNode(); separator.setViewType(ATTRIBUTE_SEPARATOR); // add it after the class title cls.getPersistentChildren().add(1, separator); } public void expandCompartment_operations(ServiceInvocationContext context, String viewId) { View cls = getViewById(context, viewId); Node separator = NotationFactory.eINSTANCE.createNode(); separator.setViewType(OPERATIONS_SEPARATOR); // add at the end of the list cls.getPersistentChildren().add(separator); } /** * Creates a new {@link CodeSyncElement} with an associated {@link Attribute}. * @author Sebastian Solomon */ public void addNew_attribute(ServiceInvocationContext context, String viewId, String label) { View view = getViewById(context, viewId); View cls = (View) view.eContainer(); CodeSyncElement clsCse = (CodeSyncElement) cls.getDiagrammableElement(); if (!clsCse.isDeleted()) { // if isDeleted(), don't add attribute CodeSyncElement attributeCse = CodeSyncFactory.eINSTANCE .createCodeSyncElement(); attributeCse.setType(JavaAttributeModelAdapter.ATTRIBUTE); // this is a new element => set added flag attributeCse.setAdded(true); Attribute attribute = AstCacheCodeFactory.eINSTANCE .createAttribute(); attribute.setCodeSyncElement(attributeCse); processAttribute(attributeCse, attribute, label); DiagramEditableResource der = getEditableResource(context); ResourceSet resourceSet = der.getResourceSet(); File project = CodeSyncPlugin.getInstance().getProjectsProvider() .getContainingProjectForFile((File) der.getFile()); Resource astCache = CodeSyncPlugin.getInstance().getAstCache( project, resourceSet); astCache.getContents().add(attribute); clsCse.getChildren().add(attributeCse); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().propagateParentSyncFalse(attributeCse); } } protected void processAttribute(CodeSyncElement attributeCse, Attribute attribute, String label) { InplaceEditorLabelParseResult result = labelParser.parseAttributeLabel(label); setName(attributeCse, result.getName()); setInitializer(attributeCse, attribute, result.getDefaultValue()); setType(attributeCse, attribute, result.getType()); setVisibility(attributeCse, attribute, result.getVisibilityCharacter()); } /** * Creates a new {@link CodeSyncElement} with an associated {@link Operation}. * @author Sebastian Solomon */ public void addNew_operation(ServiceInvocationContext context, String viewId, String label) { View view = getViewById(context, viewId); View cls = (View) view.eContainer(); CodeSyncElement clsCse = (CodeSyncElement) cls.getDiagrammableElement(); if (!clsCse.isDeleted()) { // if isDeleted(), don't add element CodeSyncElement operationCse = CodeSyncFactory.eINSTANCE .createCodeSyncElement(); operationCse.setType(JavaOperationModelAdapter.OPERATION); // this is a new element => set added flag operationCse.setAdded(true); Operation operation = AstCacheCodeFactory.eINSTANCE .createOperation(); operation.setCodeSyncElement(operationCse); processOperation(operationCse, operation, label); DiagramEditableResource der = getEditableResource(context); ResourceSet resourceSet = der.getResourceSet(); File project = CodeSyncPlugin.getInstance().getProjectsProvider() .getContainingProjectForFile((File) der.getFile()); Resource astCache = CodeSyncPlugin.getInstance().getAstCache( project, resourceSet); astCache.getContents().add(operation); clsCse.getChildren().add(operationCse); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().propagateParentSyncFalse(operationCse); } } protected void processOperation(CodeSyncElement operationCse, Operation operation, String label) { InplaceEditorLabelParseResult result = labelParser.parseOperationLabel(label); setName(operationCse, result.getName()); setType(operationCse, operation, result.getType()); setVisibility(operationCse, operation, result.getVisibilityCharacter()); setParameters(operationCse, operation, result.getParameters()); } public void addNewRelation(ServiceInvocationContext context, String sourceViewId, String targetViewId) { View sourceView = getViewById(context, sourceViewId); View targetView = getViewById(context, targetViewId); CodeSyncElement source = (CodeSyncElement) sourceView.getDiagrammableElement(); CodeSyncElement target = (CodeSyncElement) targetView.getDiagrammableElement(); Relation relation = CodeSyncFactory.eINSTANCE.createRelation(); relation.setSource(source); relation.setTarget(target); source.getRelations().add(relation); } /** * @author Sebastian Solomon */ public void deleteView(ServiceInvocationContext context, String viewId) { // View view = getViewById(context, viewId); // // CodeSyncElement cse = (CodeSyncElement) view.getDiagrammableElement(); // // if (cse.getType().equals(JavaAttributeModelAdapter.ATTRIBUTE) // || cse.getType().equals(JavaOperationModelAdapter.OPERATION) // || cse.getType().equals(JavaTypeModelAdapter.CLASS)) { // CodeSyncElement cls = (CodeSyncElement) cse.eContainer(); // if (cse.isAdded()) { // CodeSyncPlugin.getInstance().propagateParentSyncTrue(cse); // // delete it // if (cse.getType().equals(JavaTypeModelAdapter.CLASS)) { // View parent = (View) view.eContainer(); // parent.getPersistentChildren().remove(view); // } else { // // cls.getChildren().remove(cse); // } // } else { // mark as deleted // cse.setDeleted(true); // CodeSyncPlugin.getInstance().propagateParentSyncFalse(cse); // CodeSyncPlugin.getInstance().propageteOnChildDelete(cse); // } // TODO CS: below Sebastian's code, commented after merge with GH159 / relations View view = getViewById(context, viewId); EObject diagrammableElement = view.getDiagrammableElement(); if (diagrammableElement instanceof CodeSyncElement) { CodeSyncElement cse = (CodeSyncElement) view.getDiagrammableElement(); if (cse.getType().equals(JavaAttributeModelAdapter.ATTRIBUTE) || cse.getType().equals(JavaOperationModelAdapter.OPERATION)) { CodeSyncElement cls = (CodeSyncElement) cse.eContainer(); cls.getChildren().remove(cse); } // only remove the view, don't delete the class from the model if (cse.getType().equals(JavaTypeModelAdapter.CLASS)) { View parent = (View) view.eContainer(); parent.getPersistentChildren().remove(view); } } if (diagrammableElement instanceof Relation) { Relation relation = (Relation) diagrammableElement; relation.getSource().getRelations().remove(relation); } } /** * Creates a new {@link Node} for <code>element</code>. * * <p> * If the element is an attribute or operation, a view for the containing class * is also created. * @return */ @Override protected void createViewForElement(CodeSyncElement element, Diagram diagram) { CodeSyncElement cls = null; if (element.getType().equals(JavaTypeModelAdapter.CLASS)) { cls = element; } else { cls = (CodeSyncElement) element.eContainer(); } Node node = NotationFactory.eINSTANCE.createNode(); node.setViewType("class"); node.setDiagrammableElement(cls); Node classTitle = NotationFactory.eINSTANCE.createNode(); classTitle.setViewType("classTitle"); classTitle.setDiagrammableElement(cls); node.getPersistentChildren().add(classTitle); Node classAttrSeparator = NotationFactory.eINSTANCE.createNode(); classAttrSeparator.setViewType(JavaClassDiagramOperationsService.ATTRIBUTE_SEPARATOR); node.getPersistentChildren().add(classAttrSeparator); Node classOperationSeparator = NotationFactory.eINSTANCE.createNode(); classOperationSeparator.setViewType(JavaClassDiagramOperationsService.OPERATIONS_SEPARATOR); node.getPersistentChildren().add(classOperationSeparator); Bounds bounds = NotationFactory.eINSTANCE.createBounds(); bounds.setX(200); bounds.setHeight(100); bounds.setWidth(100); node.setLayoutConstraint(bounds); diagram.getPersistentChildren().add(node); } /////////////////////// // Model modifications /////////////////////// protected void setName(CodeSyncElement element, String newName) { EStructuralFeature feature = CodeSyncPackage.eINSTANCE.getCodeSyncElement_Name(); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().setFeatureValue(element, feature, newName); } protected void setType(CodeSyncElement element, TypedElement typedElement, String newType) { EStructuralFeature feature = AstCacheCodePackage.eINSTANCE.getTypedElement_Type(); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().setFeatureValue(element, feature, newType); } protected void setInitializer(CodeSyncElement element, Attribute attribute, String newInitializer) { EStructuralFeature feature = AstCacheCodePackage.eINSTANCE.getAttribute_Initializer(); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().setFeatureValue(element, feature, newInitializer); } protected void setVisibility(CodeSyncElement element, ModifiableElement modifiableElement, char newVisibility) { int type = 0; switch (newVisibility) { case '+': type = org.eclipse.jdt.core.dom.Modifier.PUBLIC; break; case '-': type = org.eclipse.jdt.core.dom.Modifier.PRIVATE; break; case '#': type = org.eclipse.jdt.core.dom.Modifier.PROTECTED; break; default: type = org.eclipse.jdt.core.dom.Modifier.NONE; break; } Collection<ExtendedModifier> modifiers = EcoreUtil.copyAll(getModifiers(element)); Modifier modifier = getVisibility(modifiers); Modifier newModifier = AstCacheCodeFactory.eINSTANCE.createModifier(); newModifier.setType(type); if (modifier == null || modifier.getType() != type) { if (modifier != null) { modifiers.remove(modifier); } modifiers.add(newModifier); } EStructuralFeature feature = AstCacheCodePackage.eINSTANCE.getModifiableElement_Modifiers(); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().setFeatureValue(element, feature, modifiers); } protected List<ExtendedModifier> getModifiers(CodeSyncElement codeSyncElement) { return (List<ExtendedModifier>) CodeSyncPlugin.getInstance().getCodeSyncOperationsService() .getFeatureValue(codeSyncElement, AstCacheCodePackage.eINSTANCE.getModifiableElement_Modifiers()); } protected Modifier getVisibility(Collection<ExtendedModifier> modifiers) { for (ExtendedModifier modifier : modifiers) { if (modifier instanceof Modifier) { switch (((Modifier) modifier).getType()) { case org.eclipse.jdt.core.dom.Modifier.PUBLIC: case org.eclipse.jdt.core.dom.Modifier.PRIVATE: case org.eclipse.jdt.core.dom.Modifier.PROTECTED: case org.eclipse.jdt.core.dom.Modifier.NONE: return (Modifier) modifier; } } } return null; } protected void setParameters(CodeSyncElement element, Operation operation, Collection<InplaceEditorLabelParseResult> newParameters) { // first create the list of parameters corresponding to newParameters List<Parameter> parameters = new BasicEList<>(); for (InplaceEditorLabelParseResult newParameter : newParameters) { Parameter parameter = AstCacheCodeFactory.eINSTANCE.createParameter(); parameter.setName(newParameter.getName()); parameter.setType(newParameter.getType()); parameters.add(parameter); } // compare the new parameters with the current list EStructuralFeature feature = AstCacheCodePackage.eINSTANCE.getOperation_Parameters(); CodeSyncPlugin.getInstance().getCodeSyncOperationsService().setFeatureValue(element, feature, parameters); } }