/***************************************************************************** * Copyright (c) 2012 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: * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.common.editpolicies; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.StringTokenizer; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; import org.eclipse.gmf.runtime.diagram.core.commands.DeleteCommand; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.notation.Node; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.infra.gmfdiag.common.editpart.IPapyrusEditPart; import org.eclipse.papyrus.uml.appearance.helper.AppliedStereotypeHelper; import org.eclipse.papyrus.uml.appearance.helper.UMLVisualInformationPapyrusConstant; import org.eclipse.papyrus.uml.diagram.common.Activator; import org.eclipse.papyrus.uml.diagram.common.commands.CreateAppliedStereotypeViewCommand; import org.eclipse.papyrus.uml.diagram.common.commands.SetNodeVisibilityCommand; import org.eclipse.papyrus.uml.diagram.common.editparts.AppliedStereotypeConpartmentEditPart; import org.eclipse.papyrus.uml.diagram.common.figure.node.IPapyrusNodeUMLElementFigure; import org.eclipse.papyrus.uml.tools.listeners.PapyrusStereotypeListener; import org.eclipse.swt.widgets.Display; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Stereotype; import org.eclipse.uml2.uml.util.UMLUtil; /** * this edit policy can be apply only on {@link IPapyrusEditPart} in order to * access to primary figure. the primary figure has to be a {@link IPapyrusNodeUMLElementFigure} */ public class AppliedStereotypeCompartmentEditPolicy extends AppliedStereotypeNodeLabelDisplayEditPolicy { /** * Creates a new AppliedStereotype display edit policy */ public AppliedStereotypeCompartmentEditPolicy() { super(); } @Override public void activate() { super.activate(); // if stereotype has been applied, compartment has to be created final GraphicalEditPart editPart = (GraphicalEditPart)getHost(); Element umlElement = (Element)editPart.resolveSemanticElement(); //umlElement may be null if the semantic element has been deleted and the view hasn't been cleaned if(umlElement != null) { Iterator<EObject> iterator = umlElement.getStereotypeApplications().iterator(); while(iterator.hasNext()) { final EObject appliedstereotype = iterator.next(); createAppliedStereotypeCompartment(appliedstereotype); } } } protected boolean hasToDisplayCompartment(EObject applicationOfStereotype) { String stereotypesPropertiesToDisplay = AppliedStereotypeHelper.getAppliedStereotypesPropertiesToDisplay((View)getHost().getModel()); HashSet<org.eclipse.uml2.uml.Stereotype> stereoSet = new HashSet<org.eclipse.uml2.uml.Stereotype>(); ArrayList<String> stPropList = new ArrayList<String>(); // fill our data structure in order to generate the string StringTokenizer propStringTokenizer = new StringTokenizer(stereotypesPropertiesToDisplay, ","); while(propStringTokenizer.hasMoreElements()) { // extract property to display String propertyQN = propStringTokenizer.nextToken(); // stereotype String stereotypeQN = propertyQN.substring(0, propertyQN.indexOf(".")); Stereotype stereotype = hostSemanticElement.getAppliedStereotype(stereotypeQN); if(stereotype != null) { stereoSet.add(stereotype); } stPropList.add(propertyQN); } // Display each stereotype Iterator<org.eclipse.uml2.uml.Stereotype> stereoIter = stereoSet.iterator(); while(stereoIter.hasNext()) { Stereotype stereotype = stereoIter.next(); if(stereotype != null) { if(applicationOfStereotype.equals(hostSemanticElement.getStereotypeApplication(stereotype))) { return true; } } } return false; } /** * the goal of this method is to execute the a command to create a notation node for a compartment of stereotype * * @param editPart * the editpart owner of the new compartment * @param appliedstereotype * the stereotype application */ protected void executeAppliedStereotypeCompatmentCreation(final GraphicalEditPart editPart, final EObject appliedstereotype) { try { editPart.getEditingDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { CreateAppliedStereotypeViewCommand command = new CreateAppliedStereotypeViewCommand(editPart.getEditingDomain(), editPart.getNotationView(), appliedstereotype, hasToDisplayCompartment(appliedstereotype)); editPart.getEditingDomain().getCommandStack().execute(command); } }); } }); } catch (Exception e) { Activator.log.error(e); } } /** * * {@inheritedDoc} */ @Override public void notifyChanged(Notification notification) { // change the label of the figure managed by the host edit part (managed // by the parent edit // part in general...) // it must be changed only if: // - the annotation corresponding to the display of the stereotype // changes // - the stereotype application list has changed final int eventType = notification.getEventType(); if(eventType == PapyrusStereotypeListener.APPLIED_STEREOTYPE) { // a stereotype was applied to the notifier // then a new listener should be added to the stereotype application getDiagramEventBroker().addNotificationListener((EObject)notification.getNewValue(), this); createAppliedStereotypeCompartment((EObject)notification.getNewValue()); } else if(eventType == PapyrusStereotypeListener.UNAPPLIED_STEREOTYPE) { getDiagramEventBroker().removeNotificationListener((EObject)notification.getOldValue(), this); cleanStereotypeDisplayInEAnnotation(); removeAppliedStereotypeCompartment((EObject)notification.getNewValue()); } // if element that has changed is a stereotype => refresh the label. if(notification.getNotifier() instanceof Node && (notification.getEventType() == Notification.ADD) && (notification.getNewValue() instanceof EAnnotation)) { if(UMLVisualInformationPapyrusConstant.STEREOTYPE_ANNOTATION == ((EAnnotation)notification.getNewValue()).getSource()) { // stereotype annotation has changed => refresh label display refreshDisplay(); } } } /** * this method creates a node for the compartment of stereotype if it does not exist. * * @param stereotypeApplication * the stereotype application */ public void createAppliedStereotypeCompartment(final EObject stereotypeApplication) { final GraphicalEditPart editPart = (GraphicalEditPart)getHost(); final View node = editPart.getNotationView(); // llok for the coressponded node for the stereotype application View correspondedAppliedStereotype = getCoresspondedStereotypeApplication(stereotypeApplication, node); //it does not exist if(correspondedAppliedStereotype == null) { executeAppliedStereotypeCompatmentCreation(editPart, stereotypeApplication); } } /** * the goal of this method is to execute the a command to create a notation node for a compartment of stereotype * * @param editPart * the editpart owner of the new compartment * @param appliedstereotype * the stereotype application */ protected void setVisivility(final View view, final boolean isVisible) { try { final GraphicalEditPart editPart = (GraphicalEditPart)getHost(); editPart.getEditingDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { SetNodeVisibilityCommand setCommand = new SetNodeVisibilityCommand(editPart.getEditingDomain(), view, isVisible); editPart.getEditingDomain().getCommandStack().execute(setCommand); } }); } }); } catch (Exception e) { System.err.println(e); } } /** * the goal of this method is to return the node that references the stereotype application * * @param stereotypeApplication * the application of the sterotype * @param node * the notation node where we look for all subnodes * @return the corresponded node or null */ protected View getCoresspondedStereotypeApplication(final EObject stereotypeApplication, final View node) { View correspondedAppliedStereotype = null; int i = 0; // wee look for through all sub nodes while(correspondedAppliedStereotype == null && i < node.getChildren().size()) { if((node.getChildren().get(i)) instanceof Node) { if(stereotypeApplication.equals(((Node)(node.getChildren().get(i))).getElement())) { correspondedAppliedStereotype = ((Node)(node.getChildren().get(i))); } } i++; } return correspondedAppliedStereotype; } /** * this method suppress the sub-nodes that references the stereotype application * it cleans also all sub-nodes with the type ApplicationStereotype that not references an application of stereotypes * (this is the case when a stereotype has been unapplied without suppress the compartment. * * @param stereotypeApplication */ public void removeAppliedStereotypeCompartment(final EObject stereotypeApplication) { if(stereotypeApplication == null) { return; } final GraphicalEditPart editPart = (GraphicalEditPart)getHost(); final View node = editPart.getNotationView(); try { int i = 0; //we go through all sub nodes while(i < node.getChildren().size()) { if((node.getChildren().get(i)) instanceof Node) { final Node currentNode = (Node)(node.getChildren().get(i)); //it references the stereotype application? if(stereotypeApplication.equals(currentNode.getElement())) { //yes, Execution of the Deletion command editPart.getEditingDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { DeleteCommand command = new DeleteCommand(currentNode); editPart.getEditingDomain().getCommandStack().execute(new GMFtoEMFCommandWrapper(command)); } }); } }); } // the sub nodes has the type appliedStereotypeCompartment but does not references a application of stereotype if((currentNode.getType().equals(AppliedStereotypeConpartmentEditPart.ID)) && (!(currentNode.getElement() instanceof DynamicEObjectImpl))) { //yes, Execution of the Deletion command editPart.getEditingDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { DeleteCommand command = new DeleteCommand(currentNode); editPart.getEditingDomain().getCommandStack().execute(new GMFtoEMFCommandWrapper(command)); } }); } }); } } i++; } } catch (Exception e) { System.err.println(e); } } /** * Refreshes the stereotype display */ @Override protected void refreshAppliedStereotypesPropertiesInCompartment(String stereotypesPropertiesToDisplay, IPapyrusNodeUMLElementFigure figure) { final boolean displayInCompartment = AppliedStereotypeHelper.hasAppliedStereotypesPropertiesToDisplay((View)getHost().getModel(), UMLVisualInformationPapyrusConstant.STEREOTYPE_COMPARTMENT_LOCATION); // if the string is not empty, then, the figure has to display it. Else, // it displays nothing final GraphicalEditPart editPart = (GraphicalEditPart)getHost(); final View node = editPart.getNotationView(); int i = 0; //we go through all sub nodes while(i < node.getChildren().size()) { if((node.getChildren().get(i)) instanceof Node) { final Node currentNode = (Node)(node.getChildren().get(i)); if(currentNode.getType().equals(AppliedStereotypeConpartmentEditPart.ID)) { EObject stereotypeApplication = currentNode.getElement(); Stereotype stereotype = UMLUtil.getStereotype(stereotypeApplication); if(stereotype != null && stereotypesPropertiesToDisplay.contains(stereotype.getQualifiedName())) { setVisivility(currentNode, displayInCompartment); } else { setVisivility(currentNode, false); } } } i++; } } }