/* 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.processor; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.change.FeatureChange; import org.flowerplatform.codesync.remote.CodeSyncOperationsService; import org.flowerplatform.editor.model.change_processor.AbstractDiagramProcessor; import org.flowerplatform.emf_model.notation.Node; import org.flowerplatform.emf_model.notation.View; import com.crispico.flower.mp.model.codesync.CodeSyncElement; import com.crispico.flower.mp.model.codesync.CodeSyncPackage; /** * @author Mariana Gheorghe */ public abstract class AbstractChildrenUpdaterDiagramProcessor extends AbstractDiagramProcessor { @Override public void processFeatureChanges(EObject object, List<FeatureChange> featureChanges, View associatedViewOnOpenDiagram, Map<String, Object> viewDetails) { if (object == null) { return; } if (featureChanges == null) { // full content processFeatureChange(object, null, associatedViewOnOpenDiagram, viewDetails); } else { for (FeatureChange featureChange : featureChanges) { processFeatureChange(object, featureChange, associatedViewOnOpenDiagram, viewDetails); } } } protected void processFeatureChange(EObject object, FeatureChange featureChange, View associatedViewOnOpenDiagram, Map<String, Object> context) { if (featureChange == null) { processChildren(object, getChildrenForCodeSyncElement(object), associatedViewOnOpenDiagram, getChildrenForView(associatedViewOnOpenDiagram), context); } else { if (CodeSyncPackage.eINSTANCE.getCodeSyncElement_Children().equals(featureChange.getFeature())) { processChildren(object, getChildrenForCodeSyncElement(object), associatedViewOnOpenDiagram, getChildrenForView(associatedViewOnOpenDiagram), context); } } } protected void processChildren(EObject object, List<EObject> childModelElements, View associatedViewOnOpenDiagram, List<Node> childViews, Map<String, Object> viewDetails) { int newViewsIndex = getNewViewsIndex(object, childModelElements, associatedViewOnOpenDiagram); if (newViewsIndex >= 0) { // add a view for each child of the model element (cases: initial, or adding a new child model element) for (EObject child : childModelElements) { if (canAddChildView(associatedViewOnOpenDiagram, child)) { // Node newView = createChildView(associatedViewOnOpenDiagram, child); // newView.setDiagrammableElement(child); // associatedViewOnOpenDiagram.getPersistentChildren().add(newViewsIndex, newView); addChildView(associatedViewOnOpenDiagram, child, newViewsIndex, viewDetails); } newViewsIndex++; } } // add a model element for each view (cases: add a new view on client side) CopyOnWriteArrayList<Node> copyList = new CopyOnWriteArrayList<Node>(childViews); for (Iterator<Node> it = copyList.iterator(); it.hasNext();) { View child = it.next(); if (!containsModelElementForChildView(object, child)) { CodeSyncElement newChild = createModelElementChild(object, child); if (newChild != null) { getChildrenForCodeSyncElement(object).add(associatedViewOnOpenDiagram.getPersistentChildren().indexOf(child), newChild); } else { // associatedViewOnOpenDiagram.getPersistentChildren().remove(child); removeChildView(child, child.getDiagrammableElement(), viewDetails); associatedViewOnOpenDiagram.getPersistentChildren().remove(child); } } else { int currentViewIndex = associatedViewOnOpenDiagram.getPersistentChildren().indexOf(child); int moveToViewIndex = getNewViewsIndex(object, Arrays.asList(child.getDiagrammableElement()), associatedViewOnOpenDiagram); if (moveToViewIndex != -1 && currentViewIndex != moveToViewIndex) { associatedViewOnOpenDiagram.getPersistentChildren().move(moveToViewIndex, (Node) child); } } } if (newViewsIndex < 0) { // remove all views (cases: collapsed view/compartment) // associatedViewOnOpenDiagram.getPersistentChildren().removeAll(childViews); // remove all views (cases: collapsed view/compartment) CopyOnWriteArrayList<Node> persistentChildren = new CopyOnWriteArrayList<Node>(associatedViewOnOpenDiagram.getPersistentChildren()); for (Iterator<Node> it = persistentChildren.iterator(); it.hasNext();) { View child = it.next(); if (childViews.contains(child)) { removeChildView(child, child.getDiagrammableElement(), viewDetails); associatedViewOnOpenDiagram.getPersistentChildren().remove(child); } } } } protected CodeSyncElement getCodeSyncElement(EObject object) { return (CodeSyncElement) object; } protected List<EObject> getChildrenForCodeSyncElement(EObject object) { return (List<EObject>) CodeSyncOperationsService.getInstance() .getFeatureValue(getCodeSyncElement(object), CodeSyncPackage.eINSTANCE.getCodeSyncElement_Children()); } protected List<Node> getChildrenForView(View view) { return view.getPersistentChildren(); } ////////////////////////////////////// // Model elements to views methods ////////////////////////////////////// abstract protected int getNewViewsIndex(EObject object, List<EObject> childModelElements, View associatedViewOnOpenDiagram); // abstract protected Node createChildView(View associatedViewOnOpenDiagram, EObject child); abstract protected Node createChildView(View associatedViewOnOpenDiagram, EObject child, Map<String, Object> context); /** * @author Cristina Constatinescu */ protected Node addChildView(View associatedViewOnOpenDiagram, EObject child, int newViewsIndex, Map<String, Object> context) { Node newView = createChildView(associatedViewOnOpenDiagram, child, context); newView.setDiagrammableElement(child); newView.setViewType(associatedViewOnOpenDiagram.getViewType() + "." + getCodeSyncElement(child).getType()); associatedViewOnOpenDiagram.getPersistentChildren().add(newViewsIndex, newView); return newView; } /** * @author Cristina Constatinescu */ protected void removeChildView(View associatedViewOnOpenDiagram, EObject child, Map<String, Object> context) { associatedViewOnOpenDiagram.setDiagrammableElement(null); } protected boolean canAddChildView(View view, EObject candidate) { return !containsChildViewForModelElement(view, candidate); } protected boolean containsChildViewForModelElement(View view, EObject candidate) { if (candidate.eResource() == null) { return false; } String candidateFragment = candidate.eResource().getURIFragment(candidate); for (Node node : view.getPersistentChildren()) { EObject child = node.getDiagrammableElement(); if (child != null && child.eResource() != null && child.eResource().getURIFragment(child).equals(candidateFragment)) { return true; } } return false; } ////////////////////////////////////// // Views to model elements methods ////////////////////////////////////// abstract protected CodeSyncElement createModelElementChild(EObject object, View child); protected boolean containsModelElementForChildView(EObject object, View candidate) { EObject diagrammableElement = candidate.getDiagrammableElement(); if (diagrammableElement == null) { return false; } String candidateFragment = diagrammableElement.eResource() == null ? null : diagrammableElement.eResource().getURIFragment(diagrammableElement); if (candidateFragment == null) return false; if (candidateFragment.equals(object.eResource().getURIFragment(object))) { return true; } List<EObject> children = getChildrenForCodeSyncElement(object); for (EObject child : children) { if (candidateFragment.equals(child.eResource().getURIFragment(child))) { return true; } } return false; } }