| /******************************************************************************* |
| * Copyright (c) 2013 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: |
| * Cedric Dumoulin - cedric.dumoulin@lifl.fr |
| ******************************************************************************/ |
| package org.eclipse.papyrus.layers.stackmodel.exprmatcher; |
| |
| import static org.eclipse.papyrus.layers.stackmodel.Activator.log; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.util.EContentAdapter; |
| import org.eclipse.gmf.runtime.notation.Diagram; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.papyrus.layers.stackmodel.layers.LayersStack; |
| import org.eclipse.papyrus.layers.stackmodel.layers.LayersStackApplication; |
| import org.eclipse.papyrus.layers.stackmodel.notifier.LayersTreeEventNotifier; |
| import org.eclipse.uml2.uml.NamedElement; |
| import org.eclipse.uml2.uml.UMLPackage; |
| |
| |
| /** |
| * An EMF {@link Adapter} listening on uml::NamedElement properties changes. |
| * |
| * This class listen to a {@link NamedElement} and send following events to listeners: |
| * <ul> |
| * <li>valueChanged</li> |
| * </ul> |
| * |
| * @author cedric dumoulin |
| * |
| */ |
| public class ValueChangedEventNotifier extends EContentAdapter { |
| |
| boolean isDisposed = false; |
| |
| /** |
| * List of listener to notify. |
| */ |
| protected List<IValueChangedEventListener> listeners = new ArrayList<IValueChangedEventListener>(); |
| |
| /** |
| * Something happen on the tree of object |
| * |
| * @see org.eclipse.emf.ecore.util.EContentAdapter#notifyChanged(org.eclipse.emf.common.notify.Notification) |
| * |
| * @param msg |
| */ |
| @Override |
| public void notifyChanged(Notification notification) { |
| |
| // Self atttach |
| super.notifyChanged(notification); |
| |
| // Take into account the domain hierarchy found from the notation. |
| |
| // Now, filter |
| if (isDiagramRootView(notification)) { |
| fireValueChangedEvent(notification); |
| } |
| else if (isUmlDomainElementChanged(notification)) { |
| fireValueChangedEvent(notification); |
| } |
| |
| |
| // // We are only interested in NamedElement (from newValue if set, or oldValue if removed) |
| // Object newValue = notification.getNewValue(); |
| // if( ! (newValue instanceof NamedElement || notification.getOldValue() instanceof NamedElement ) ) { |
| // return; |
| // } |
| // // Check diagram modification |
| // // There is 4 sources: View::persistedChildren and View::transientChildren |
| // // Diagram::persistedChildren and Diagram::transientChildren |
| // Object feature = notification.getFeature(); |
| // if( feature == UMLPackage.eINSTANCE.getNamedElement() |
| // || feature == NotationPackage.eINSTANCE.getView_TransientChildren() |
| // || feature == NotationPackage.eINSTANCE.getDiagram_PersistedEdges() |
| // || feature == NotationPackage.eINSTANCE.getDiagram_TransientEdges() ) { |
| // // LayerOperator::layers || LayersStack::layers |
| // // check the event type. |
| // switch(notification.getEventType()) { |
| // case Notification.SET: |
| // |
| // break; |
| // case Notification.ADD: |
| // // A view is added |
| // fireValueChangedEvent(notification); |
| // break; |
| // case Notification.REMOVE: |
| // // A layer is removed |
| // fireDiagramViewRemovedEvent(notification); |
| // break; |
| // } |
| // } |
| |
| }; |
| |
| /** |
| * Return true if the notification indicates a change in a uml element. |
| * |
| * @param notification |
| * @return |
| */ |
| private boolean isUmlDomainElementChanged(Notification notification) { |
| // Notifier should be the diagram |
| if (!(notification.getNotifier() instanceof NamedElement)) { |
| return false; |
| } |
| |
| Object feature = notification.getFeature(); |
| |
| if (feature == UMLPackage.eINSTANCE.getNamedElement_Name()) { |
| // check the event type. |
| switch (notification.getEventType()) { |
| case Notification.SET: |
| case Notification.ADD: |
| case Notification.REMOVE: |
| |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return true if the notification indicates that a Diagram root view is modifified. |
| * |
| * @param notification |
| * @return |
| */ |
| private boolean isDiagramRootView(Notification notification) { |
| |
| // Notifier should be the diagram |
| if (!(notification.getNotifier() instanceof Diagram)) { |
| return false; |
| } |
| |
| Object feature = notification.getFeature(); |
| |
| if (feature == NotationPackage.eINSTANCE.getView_PersistedChildren() |
| || feature == NotationPackage.eINSTANCE.getView_TransientChildren() |
| || feature == NotationPackage.eINSTANCE.getDiagram_PersistedEdges() |
| || feature == NotationPackage.eINSTANCE.getDiagram_TransientEdges()) { |
| // LayerOperator::layers || LayersStack::layers |
| // check the event type. |
| switch (notification.getEventType()) { |
| case Notification.SET: |
| case Notification.ADD: |
| case Notification.REMOVE: |
| |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * This Adapter is for {@link LayersTreeEventNotifier}. |
| * |
| * @see org.eclipse.emf.common.notify.impl.AdapterImpl#isAdapterForType(java.lang.Object) |
| * |
| * @param type |
| * @return |
| */ |
| @Override |
| public boolean isAdapterForType(Object type) { |
| return type == ValueChangedEventNotifier.class; |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param layersModel |
| */ |
| public ValueChangedEventNotifier() { |
| } |
| |
| /** |
| * Dispose the synchronizer |
| */ |
| public void dispose() { |
| |
| if (isDisposed()) { |
| return; |
| } |
| |
| isDisposed = true; |
| listeners.clear(); |
| } |
| |
| /** |
| * Return true if the object is disposed. |
| * |
| * @return |
| */ |
| public boolean isDisposed() { |
| return isDisposed == true; |
| } |
| |
| /** |
| * Add the specified listener to the list of listener. |
| * Do not add it if the listener is already in the list. |
| * |
| * @param listener |
| */ |
| public void addEventListener(IValueChangedEventListener listener) { |
| |
| if (listener == null) { |
| return; |
| } |
| |
| // Check if exist |
| if (listeners.contains(listener)) { |
| return; |
| } |
| |
| listeners.add(listener); |
| } |
| |
| /** |
| * Remove the specified listener from the list of listeners. |
| * |
| * @param listener |
| */ |
| public void removeEventListener(IValueChangedEventListener listener) { |
| |
| listeners.remove(listener); |
| } |
| |
| /** |
| * Called by events when a {@link LayersStack} is added to the {@link LayersStackApplication} |
| * |
| * @param msg |
| */ |
| protected void fireValueChangedEvent(Notification msg) { |
| for (IValueChangedEventListener listener : listeners) { |
| listener.valueChanged(msg); |
| } |
| } |
| |
| /** |
| * Handle View::element hierarchy in the self adapt mechanism. |
| * Handles a notification by calling {@link #handleContainment handleContainment} for any containment-based notification. |
| */ |
| @Override |
| protected void selfAdapt(Notification notification) |
| { |
| if (log.isDebugEnabled()) { |
| log.debug(this.getClass().getSimpleName() + ".selfAdapt(" + notification + ")"); |
| } |
| |
| if (notification.getFeature() == NotationPackage.eINSTANCE.getView_Element()) |
| { |
| handleContainment(notification); |
| } |
| else { |
| super.selfAdapt(notification); |
| } |
| } |
| |
| /** |
| * Handle View::element hierarchy in the self adapt mechanism. |
| * |
| * @see org.eclipse.emf.ecore.util.EContentAdapter#setTarget(org.eclipse.emf.ecore.EObject) |
| * |
| * @param target |
| */ |
| @Override |
| protected void setTarget(EObject target) { |
| if (log.isDebugEnabled()) { |
| log.debug(this.getClass().getSimpleName() + ".setTarget(" + target + ")"); |
| } |
| |
| // Handle the View::element tree |
| if (target instanceof View) { |
| EObject extraTarget = ((View) target).getElement(); |
| if (extraTarget != null) { |
| log.info(this.getClass().getSimpleName() + ".setExtraTarget(" + extraTarget + ")"); |
| // copied from org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EObject) |
| // basicSetTarget(target); |
| // Add the extra object |
| addAdapter(extraTarget); |
| // Add the content of the extra object |
| // for (Iterator<? extends Notifier> i = resolve() ? |
| // extraTarget.eContents().iterator() : |
| // ((InternalEList<? extends Notifier>)extraTarget.eContents()).basicIterator(); |
| // i.hasNext(); ) |
| // { |
| // Notifier notifier = i.next(); |
| // addAdapter(notifier); |
| // } |
| |
| } |
| } |
| } |
| |
| /** |
| * Handle View::element hierarchy in the self adapt mechanism. |
| * |
| * @see org.eclipse.emf.ecore.util.EContentAdapter#unsetTarget(org.eclipse.emf.ecore.EObject) |
| * |
| * @param target |
| */ |
| @Override |
| protected void unsetTarget(EObject target) { |
| // TODO Auto-generated method stub |
| super.unsetTarget(target); |
| // Handle the View::element tree |
| if (target instanceof View) { |
| EObject extraTarget = ((View) target).getElement(); |
| if (extraTarget != null) { |
| // copied from org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EObject) |
| // basicSetTarget(target); |
| // Remove the extra object |
| removeAdapter(extraTarget); |
| // Remove contents of the extra object |
| // for (Iterator<? extends Notifier> i = resolve() ? |
| // extraTarget.eContents().iterator() : |
| // ((InternalEList<? extends Notifier>)extraTarget.eContents()).basicIterator(); |
| // i.hasNext(); ) |
| // { |
| // Notifier notifier = i.next(); |
| // removeAdapter(notifier); |
| // } |
| |
| } |
| } |
| } |
| |
| } |