/***************************************************************************** * Copyright (c) 2009 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: * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.common.editpolicies; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; 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.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.editpolicies.GraphicalEditPolicy; import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker; import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.infra.core.listenerservice.IPapyrusListener; 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.tools.listeners.PapyrusStereotypeListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Stereotype; /** * Specific edit policy for label displaying stereotypes and their properties * for representing UML elements. */ public abstract class AbstractAppliedStereotypeDisplayEditPolicy extends GraphicalEditPolicy implements NotificationListener, IPapyrusListener { /** constant for this edit policy role */ public final static String STEREOTYPE_LABEL_POLICY = "AppliedStereotypeDisplayEditPolicy"; /** host semantic element */ protected Element hostSemanticElement; /** * Creates a new AppliedStereotype display edit policy */ public AbstractAppliedStereotypeDisplayEditPolicy() { super(); } /** * clean stereotype to display in Eannotation this method can be called directly * at the activation of this class */ protected void cleanStereotypeDisplayInEAnnotation(){ String stereotypesToDisplay = AppliedStereotypeHelper.getStereotypesToDisplay((View)getHost().getModel()); StringTokenizer strQualifiedName = new StringTokenizer(stereotypesToDisplay, ","); while(strQualifiedName.hasMoreElements()) { String currentStereotype = strQualifiedName.nextToken(); // check if current stereotype is applied final Element umlElement = getUMLElement(); Stereotype stereotype = umlElement.getAppliedStereotype(currentStereotype); if(stereotype == null) { removeEAnnotationAboutStereotype(currentStereotype); } } } /** * * {@inheritDoc} */ public void activate() { // retrieve the view and the element managed by the edit part View view = getView(); if(view == null) { return; } hostSemanticElement = getUMLElement(); // adds a listener on the view and the element controlled by the // editpart getDiagramEventBroker().addNotificationListener(view, this); if(hostSemanticElement == null) { return; } getDiagramEventBroker().addNotificationListener(hostSemanticElement, this); // adds the listener for stereotype application and applied stereotypes // add listener to react to the application and remove of a stereotype // add a lister to each already applied stereotyped for(EObject stereotypeApplication : hostSemanticElement.getStereotypeApplications()) { getDiagramEventBroker().addNotificationListener(stereotypeApplication, this); } refreshDisplay(); // try to display stereotype properties cleanStereotypeDisplayInEAnnotation(); } /** * * {@inheritDoc} */ public void deactivate() { // retrieve the view and the element managed by the edit part View view = getView(); if(view == null) { return; } getDiagramEventBroker().removeNotificationListener(view, this); if(hostSemanticElement == null) { return; } // remove listeners to applied stereotyped for(EObject stereotypeApplication : hostSemanticElement.getStereotypeApplications()) { getDiagramEventBroker().removeNotificationListener(stereotypeApplication, this); } // remove notification on element getDiagramEventBroker().removeNotificationListener(hostSemanticElement, this); // removes the reference to the semantic element hostSemanticElement = null; } /** * Gets the diagram event broker from the editing domain. * * @return the diagram event broker */ protected DiagramEventBroker getDiagramEventBroker() { TransactionalEditingDomain theEditingDomain = ((IGraphicalEditPart)getHost()).getEditingDomain(); if(theEditingDomain != null) { return DiagramEventBroker.getInstance(theEditingDomain); } return null; } /** * Returns the uml element controlled by the host edit part * * @return the uml element controlled by the host edit part */ protected Element getUMLElement() { return (Element)getView().getElement(); } /** * Returns the view controlled by the host edit part * * @return the view controlled by the host edit part */ protected View getView() { return (View)getHost().getModel(); } protected void removeEAnnotationAboutStereotype(final String stereotypeQN){ try { ((GraphicalEditPart)getHost()).getEditingDomain().runExclusive(new Runnable() { public void run() { Display.getCurrent().asyncExec(new Runnable() { public void run() { String presentationKind = AppliedStereotypeHelper.getAppliedStereotypePresentationKind(getView()); RecordingCommand command = AppliedStereotypeHelper.getRemoveAppliedStereotypeCommand(((GraphicalEditPart)getHost()).getEditingDomain(), getView(),stereotypeQN, presentationKind); ((GraphicalEditPart)getHost()).getEditingDomain().getCommandStack().execute(command); } }); } }); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * * {@inheritedDoc} */ 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); } else if(eventType == PapyrusStereotypeListener.UNAPPLIED_STEREOTYPE) { getDiagramEventBroker().removeNotificationListener((EObject)notification.getOldValue(), this); cleanStereotypeDisplayInEAnnotation(); } // if element that has changed is a stereotype => refresh the label. if(notification.getNotifier() instanceof EAnnotation) { if(UMLVisualInformationPapyrusConstant.STEREOTYPE_ANNOTATION == ((EAnnotation)notification.getNotifier()).getSource()) { // stereotype annotation has changed => refresh label display refreshDisplay(); } } // if element that has changed is a stereotype => refresh the label. if((eventType == PapyrusStereotypeListener.MODIFIED_STEREOTYPE)) { // stereotype annotation has changed => refresh label display refreshDisplay(); } // The value of a property of stereotype (dynamic profile) has changed // To avoid refresh to be called during stereotype removal (stereotype#base_xxx set to null in particular) a complementary test is // added here to ensure the stereotype is still applied (the notifier is a stereotype application of the semantic element). if((notification.getNotifier() instanceof DynamicEObjectImpl) && (hostSemanticElement != null) && (hostSemanticElement.getStereotypeApplications().contains(notification.getNotifier()))) { refreshDisplay(); } } /** * Refreshes the display for the element controlled by the edit part with * this edit policies */ public abstract void refreshDisplay(); /** * Parses the string containing the complete definition of properties to be * displayed, and generates a map. * * @param stereotypesToDisplay * the list of stereotypes to display * @param stereotypesPropertiesToDisplay * the properties of stereotypes to display * @return a map. The keys are the name of displayed stereotypes, the * corresponding data is a collection of its properties to be * displayed */ protected Map<String, List<String>> parseStereotypeProperties(String stereotypesToDisplay, String stereotypesPropertiesToDisplay) { Map<String, List<String>> propertiesMap = new HashMap<String, List<String>>(); StringTokenizer stringTokenizer = new StringTokenizer(stereotypesPropertiesToDisplay, UMLVisualInformationPapyrusConstant.STEREOTYPE_PROPERTIES_LIST_SEPARATOR); while(stringTokenizer.hasMoreTokens()) { String propertyName = stringTokenizer.nextToken(); // retrieve the name of the stereotype for this property String stereotypeName = propertyName.substring(0, propertyName.lastIndexOf(".")); // stereotypequalifiedName.propertyname if(!propertiesMap.containsKey(stereotypeName)) { List<String> propertiesForStereotype = new ArrayList<String>(); propertiesMap.put(stereotypeName, propertiesForStereotype); } propertiesMap.get(stereotypeName).add(propertyName.substring(propertyName.lastIndexOf(".") + 1, propertyName.length())); } return propertiesMap; } /** * Returns the image to be displayed for the applied stereotypes. * * @return the image that represents the first applied stereotype or <code>null</code> if no image has to be displayed */ public Image stereotypeIconToDisplay() { String stereotypespresentationKind = AppliedStereotypeHelper.getAppliedStereotypePresentationKind((View)getHost().getModel()); if(stereotypespresentationKind == null) { return null; } if(stereotypespresentationKind.equals(UMLVisualInformationPapyrusConstant.ICON_STEREOTYPE_PRESENTATION) || stereotypespresentationKind.equals(UMLVisualInformationPapyrusConstant.TEXT_ICON_STEREOTYPE_PRESENTATION)) { // retrieve the first stereotype in the list of displayed stereotype String stereotypesToDisplay = AppliedStereotypeHelper.getStereotypesToDisplay((View)getHost().getModel()); StringTokenizer tokenizer = new StringTokenizer(stereotypesToDisplay, ","); if(tokenizer.hasMoreTokens()) { String firstStereotypeName = tokenizer.nextToken(); Stereotype stereotype = getUMLElement().getAppliedStereotype(firstStereotypeName); return Activator.getIconElement(getUMLElement(), stereotype, false); } } return null; } }