/* 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.codesync.remote; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.flowerplatform.communication.service.ServiceInvocationContext; import org.flowerplatform.editor.model.remote.DiagramEditableResource; import org.flowerplatform.editor.model.remote.DiagramEditorStatefulService; import org.flowerplatform.emf_model.notation.Diagram; import org.flowerplatform.emf_model.notation.Edge; import org.flowerplatform.emf_model.notation.NotationFactory; import org.flowerplatform.emf_model.notation.NotationPackage; import org.flowerplatform.emf_model.notation.View; import com.crispico.flower.mp.model.codesync.CodeSyncElement; import com.crispico.flower.mp.model.codesync.CodeSyncPackage; import com.crispico.flower.mp.model.codesync.Relation; /** * @author Mariana Gheorghe */ public abstract class CodeSyncDiagramOperationsService { protected static CodeSyncDiagramOperationsService INSTANCE; public static CodeSyncDiagramOperationsService getInstance() { return INSTANCE; } public CodeSyncDiagramOperationsService() { INSTANCE = this; } public void displayMissingRelations(ServiceInvocationContext context, String viewId, boolean addMissingElements) { CodeSyncElement cse = (CodeSyncElement) getViewById(context, viewId).getDiagrammableElement(); List<View> views = getViewsForElement(cse); // add edges for relations where this element is the source for (View view : views) { addEdgesForRelations(cse, cse.getRelations(), view, addMissingElements, context.getAdditionalData()); } // add edges for relations where this element is the target addEdgesForRelationsWithTarget(cse, views, addMissingElements, context.getAdditionalData()); } /** * Adds new {@link Edge}s for each {@link Relation}. */ public void addEdgesForRelations(EObject object, List<Relation> relations, View associatedViewOnOpenDiagram, boolean addMissingElements, Map<String, Object> context) { Diagram diagram = getDiagram(context); for (Relation relation : relations) { List<View> views = getViewsForElement(relation.getTarget()); // if there are no views for the target and addMissingElements is true if (addMissingElements && views.size() == 0) { createViewForElement(relation.getTarget(), diagram); } else { for (View target : views) { if (getEdge(associatedViewOnOpenDiagram, target) == null) { createEdge(relation, associatedViewOnOpenDiagram, target, diagram); } } } } } public void addEdgesForRelationsWithTarget(EObject object, List<View> targetViews, boolean addMissingElements, Map<String, Object> context) { CodeSyncElement cse = (CodeSyncElement) object; Diagram diagram = getDiagram(context); for (EObject eObject : getInverseReferencesForElement(cse, CodeSyncPackage.eINSTANCE.getRelation_Target())) { Relation relation = (Relation) eObject; List<View> sourceViews = getViewsForElement(relation.getSource()); if (addMissingElements && sourceViews.size() == 0) { createViewForElement(relation.getSource(), diagram); } else { for (View sourceView : sourceViews) { for (View targetView : targetViews) { if (getEdge(sourceView, targetView) == null) { createEdge(relation, sourceView, targetView, diagram); } } } } } } protected abstract void createViewForElement(CodeSyncElement target, Diagram diagram); protected Edge createEdge(Relation relation, View source, View target, Diagram diagram) { Edge edge = NotationFactory.eINSTANCE.createEdge(); edge.setDiagrammableElement(relation); edge.setSource(source); edge.setTarget(target); edge.setViewType("edge"); diagram.getPersistentEdges().add(edge); return edge; } /** * Gets the {@link Edge} with the specified <code>source</code> and <code>target</code>, * if it exists. */ public Edge getEdge(View source, View target) { for (Edge edge : source.getSourceEdges()) { if (edge.getSource().equals(source) && edge.getTarget().equals(target)) { return edge; } } return null; } /** * Some views (e.g. class title) cannot have edges even though their diagrammable element can have relations. */ protected boolean acceptsEdges(View view) { // List<IDiagrammableElementFeatureChangesProcessor> processors = EditorModelPlugin.getInstance() // .getDiagramUpdaterChangeProcessor() // .getDiagrammableElementFeatureChangesProcessors(view.getViewType()); // for (IDiagrammableElementFeatureChangesProcessor processor : processors) { // if (processor instanceof CodeSyncElementRelationsChangesProcessor) { // return true; // } // } return false; } public Diagram getDiagram(Map<String, Object> context) { DiagramEditableResource der = (DiagramEditableResource) context.get(DiagramEditorStatefulService.ADDITIONAL_DATA_EDITABLE_RESOURCE); for (EObject eObject : der.getMainResource().getContents()) { if (eObject instanceof Diagram) { return (Diagram) eObject; } } throw new RuntimeException("No diagram for " + der.getEditableResourcePath()); } /** * Finds all the {@link View}s for <code>element</code> and filters out * elements that cannot accept edges. */ public List<View> getViewsForElement(CodeSyncElement element) { List<View> views = (List<View>) getInverseReferencesForElement(element, NotationPackage.eINSTANCE.getView_DiagrammableElement()); // filter out views that can't have edges for (Iterator<View> iterator = views.iterator(); iterator.hasNext();) { View view = (View) iterator.next(); if (!acceptsEdges(view)) { iterator.remove(); } } return views; } protected List<? extends EObject> getInverseReferencesForElement(CodeSyncElement element, EStructuralFeature feature) { List<EObject> result = new ArrayList<EObject>(); ECrossReferenceAdapter adapter = ECrossReferenceAdapter.getCrossReferenceAdapter(element); for (Setting setting : adapter.getNonNavigableInverseReferences(element)) { if (feature.equals(setting.getEStructuralFeature())) { result.add(setting.getEObject()); } } return result; } /////////////////////// // Utils /////////////////////// protected DiagramEditableResource getEditableResource(ServiceInvocationContext context) { return (DiagramEditableResource) context.getAdditionalData().get(DiagramEditorStatefulService.ADDITIONAL_DATA_EDITABLE_RESOURCE); } protected View getViewById(ServiceInvocationContext context, String viewId) { return (View) getEditableResource(context).getEObjectById(viewId); } }