/*****************************************************************************
* Copyright (c) 2010 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:
* Saadia Dhouib saadia.dhouib@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.communication.custom.helper;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.gmf.runtime.emf.core.util.CrossReferenceAdapter;
import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
import org.eclipse.gmf.runtime.notation.Connector;
import org.eclipse.gmf.runtime.notation.DecorationNode;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.communication.edit.parts.ModelEditPart;
import org.eclipse.uml2.uml.Message;
/**
* The Class InconsistentMessageViewsHelper is intended to give methods to help searching for inconsistent
* views of messages when they are deleted or re-oriented.
*
*/
public class InconsistentMessageViewsHelper {
/**
* Tests if the view is owned by the CommunicationDiagram.
*
* @param view
* a view
* @return true, if is owned by communication diagram <code>true</code> if the view is owned by the CompositeStructureDiagram, <code>false</code>
* if not
*/
public static boolean isOwnedByCommunicationDiagram(View view) {
EObject diagram = view.eContainer();
while(!(diagram instanceof Diagram)) {
diagram = diagram.eContainer();
}
String type = ((Diagram)diagram).getType();
return type == ModelEditPart.MODEL_ID;
}
/**
* Tests if the view is is the last label (ie. message) on the connection
*
* @param view
* a view
* @return true, if is last message on connection <code>true</code> if the view is is the last label (ie. message) on the connection,
* <code>false</code> if not
*/
public static boolean isLastMessageOnConnection(View view) {
//Verify if this view is the last label (ie. message) on the connection
//if true remove the parent view (ie. the connector view)
if(view instanceof DecorationNode) {
View parentView = (View)view.eContainer();
// ---------------------------------------------------------
// help to debug
//System.err.println("+-> parent View :" + parentView);
// ---------------------------------------------------------
//get children of the parent view
@SuppressWarnings("unchecked")
EList<View> children = parentView.getChildren();
for(View child : children) {
if((child instanceof DecorationNode) && (child.getElement() instanceof Message)) {
if(!child.getElement().equals(view.getElement())) {//ouups, there is another child which is different from this view!!!
return false;
}
}
}
//This is the last message on the connection, return true.
return true;
}
return false;
}
/**
* Returns the {@link CrossReferenceAdapter} corresponding to the element to destroy.
*
* @param request
* the request
* @param destructee
* the destroyed element
* @return the cross reference adapter
* the {@link CrossReferenceAdapter} corresponding to this element
*/
public static CrossReferenceAdapter getCrossReferenceAdapter(IEditCommandRequest request, EObject destructee) {
CrossReferenceAdapter crossReferenceAdapter = null;
@SuppressWarnings("rawtypes")
Map cacheMaps = (Map)request.getParameter("Cache_Maps");//$NON-NLS-1$ RequestCacheEntries.Cache_Maps
if(cacheMaps != null) {
crossReferenceAdapter = (CrossReferenceAdapter)cacheMaps.get("CrossRefAdapter");//$NON-NLS-1$ RequestCacheEntries.CrossRefAdapter
}
if(crossReferenceAdapter == null) {
crossReferenceAdapter = CrossReferenceAdapter.getExistingCrossReferenceAdapter(destructee);
if(crossReferenceAdapter == null) {
TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(destructee);
if(domain != null) {
crossReferenceAdapter = CrossReferenceAdapter.getCrossReferenceAdapter(domain.getResourceSet());
}
}
}
return crossReferenceAdapter;
}
/**
* This method looks for inconsistent views of connectors to delete in case the connector is
* re-oriented.
*
*
* @param viewsToDestroy
* the set of views of messages to destroy
*
* @return the list of {@link View} of the connectors to delete
*/
public static Set<View> addConnectorViewsToDestroy(Set<View> viewsToDestroy) {
//for all the views to destroy, we have to classify them by their own connector,
//then we have to verify for each connector that the set of messages (to destroy) on it are the only messages that he contains
//if yes, we have to add the view of the connector to list of views to destroy
//the set connectors that are concerned by the deleted to the messages views
Set<View> connectors = null;
Set<View> newViewsToDestroy = new HashSet<View>(viewsToDestroy);
//for all the messages to delete, search for their parent connector
Iterator<?> it = viewsToDestroy.iterator();
while(it.hasNext()) {
View msgView = (View)it.next();
if((msgView instanceof DecorationNode) && (msgView.getElement() instanceof Message)) {
if(msgView.eContainer() instanceof Connector) {
if(connectors == null) {
connectors = new HashSet<View>();
}
connectors.add((View)msgView.eContainer());
}
}
}
//Now the connectors set contains all the connectors that may have to be deleted
//we have to check which connector have to be deleted
if(connectors != null) {
//for each connector we have to search for the set of its labels views to be destroyed
Iterator<?> it1 = connectors.iterator();
while(it1.hasNext()) {
View conView = (View)it1.next();
//Construct the list of viewsOfLabelsToDestroy
Set<View> viewsOfLabelsToDestroy = null;
Iterator<?> it2 = viewsToDestroy.iterator();
while(it2.hasNext()) {
View msgView = (View)it2.next();
if((msgView instanceof DecorationNode) && (msgView.getElement() instanceof Message)) {
if((msgView.eContainer() instanceof Connector) && (msgView.eContainer().equals(conView))) {
if(viewsOfLabelsToDestroy == null) {
viewsOfLabelsToDestroy = new HashSet<View>();
}
viewsOfLabelsToDestroy.add((View)msgView);
}
}
}
//if the set of viewsOfLabelsToDestroy contains all the real children of the connector
//then add the connector to the views to destroy
@SuppressWarnings("unchecked")
EList<View> conChildren = conView.getChildren();
Set<View> comparisonResult = new HashSet<View>(conChildren.size());
for(Iterator<?> i = conChildren.iterator(); i.hasNext();) {
View element = (View)i.next();
if((element instanceof DecorationNode) && (element.getElement() instanceof Message)) {
if(!viewsOfLabelsToDestroy.contains(element))
comparisonResult.add(element);
}
}
if(comparisonResult.isEmpty()) {//the set of viewsOfLabelsToDestroy contains all the real children of the connector
newViewsToDestroy.add(conView);
}
}
}
return newViewsToDestroy;
}
/**
* This method looks for inconsistent views to delete in case the message is deleted or
* the connector of the message is re-oriented.
*
* @param destructee
* the modified message
* @param request
* the request to destroy a message or to re-orient a message
*
* @return the list of {@link View} to delete
*/
public static Set<View> getMemberViewsToDestroy(Message destructee, IEditCommandRequest request) {
Set<View> viewsToDestroy = new HashSet<View>();
CrossReferenceAdapter crossReferenceAdapter = InconsistentMessageViewsHelper.getCrossReferenceAdapter(request, destructee);
if(crossReferenceAdapter != null) {
Collection<Setting> revRefs = crossReferenceAdapter.getNonNavigableInverseReferences(destructee);
if(!revRefs.isEmpty()) {
for(Setting current : revRefs) {
//test if the view is linked with the removed message
if(current.getEObject() instanceof View) {
View view = (View)current.getEObject();
//we remove the view only if they are owned by the CompositeStructureDiagram
if(InconsistentMessageViewsHelper.isOwnedByCommunicationDiagram(view)) {
viewsToDestroy.add(view);
if(InconsistentMessageViewsHelper.isLastMessageOnConnection(view)) {
//remove the connector
//System.err.println("+-> the connector will be deleted : " + (View)view.eContainer());
//System.err.println("+-> the parent of the connector is : " + (View)view.eContainer().eContainer());
viewsToDestroy.add((View)view.eContainer());
}
}
}
}
}
}
return viewsToDestroy;
}
}