| /****************************************************************************** |
| * Copyright (c) 2002, 2007 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| ****************************************************************************/ |
| |
| package org.eclipse.gmf.runtime.diagram.core.listener; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.WeakHashMap; |
| |
| import org.eclipse.emf.common.command.Command; |
| import org.eclipse.emf.common.command.CompoundCommand; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.ecore.EAnnotation; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.transaction.NotificationFilter; |
| import org.eclipse.emf.transaction.ResourceSetChangeEvent; |
| import org.eclipse.emf.transaction.ResourceSetListenerImpl; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| import org.eclipse.emf.workspace.EMFOperationCommand; |
| import org.eclipse.gmf.runtime.diagram.core.internal.commands.PersistViewsCommand; |
| import org.eclipse.gmf.runtime.diagram.core.services.DiagramEventBrokerService; |
| import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.View; |
| |
| |
| |
| /** |
| * A model server listener that broadcast EObject events to all registered |
| * listeners. |
| * |
| * @author melaasar, mmostafa, cmahoney |
| */ |
| public class DiagramEventBroker |
| extends ResourceSetListenerImpl { |
| |
| private static String LISTEN_TO_ALL_FEATURES = "*"; //$NON-NLS-1$ |
| |
| /** listener map */ |
| private final NotifierToKeyToListenersSetMap preListeners = new NotifierToKeyToListenersSetMap(); |
| |
| private final NotifierToKeyToListenersSetMap postListeners = new NotifierToKeyToListenersSetMap(); |
| |
| private static final Map instanceMap = new WeakHashMap(); |
| |
| private WeakReference editingDomainRef; |
| |
| /** |
| * returns the pre commit listeners map |
| * @return pre commit listeners map |
| */ |
| protected NotifierToKeyToListenersSetMap getPreCommitListenersMap() { |
| return preListeners; |
| } |
| |
| /** |
| * returns the post commit listeners map |
| * @return post commit listeners map |
| */ |
| protected NotifierToKeyToListenersSetMap getPostCommitListenersMap() { |
| return postListeners; |
| } |
| |
| /** |
| * Utility class representing a Map of Notifier to a Map of Keys to a Set of |
| * listener |
| * |
| * @author mmostafa |
| */ |
| public final class NotifierToKeyToListenersSetMap { |
| |
| /** |
| * internal map to hold the listeners |
| */ |
| private final Map listenersMap = new WeakHashMap(); |
| |
| /** |
| * Adds a listener to the map |
| * |
| * @param notifier |
| * the notifier the listener will listen to |
| * @param key |
| * a key for the listener, this help in categorizing the |
| * listeners based on their interest |
| * @param listener |
| * the listener |
| */ |
| public void addListener(EObject notifier, Object key, Object listener) { |
| Map keys = (Map) listenersMap.get(notifier); |
| if (keys == null) { |
| keys = new HashMap(4); |
| listenersMap.put(notifier, keys); |
| } |
| Map listenersSet = (Map) keys.get(key); |
| if (listenersSet == null) { |
| listenersSet = new LinkedHashMap(4); |
| keys.put(key, listenersSet); |
| } |
| listenersSet.put(listener,null); |
| } |
| |
| /** |
| * Adds a listener to the notifier; this listener is added againest a |
| * generic key, <code>LISTEN_TO_ALL_FEATURES<code> |
| * so it can listen to all events on the notifier |
| * @param notifier the notifier the listener will listen to |
| * @param listener the listener |
| */ |
| public void addListener(EObject notifier, Object listener) { |
| addListener(notifier, LISTEN_TO_ALL_FEATURES, listener); |
| } |
| |
| /** |
| * removes a listener from the map |
| * |
| * @param notifier |
| * @param key |
| * @param listener |
| */ |
| public void removeListener(EObject notifier, Object key, Object listener) { |
| Map keys = (Map) listenersMap.get(notifier); |
| if (keys != null) { |
| Map listenersSet = (Map) keys.get(key); |
| if (listenersSet != null) { |
| listenersSet.remove(listener); |
| if (listenersSet.isEmpty()) { |
| keys.remove(key); |
| } |
| } |
| if (keys.isEmpty()) |
| listenersMap.remove(notifier); |
| } |
| } |
| |
| /** |
| * get listeners interested in the passed notifier and key |
| * |
| * @param notifier |
| * @param key |
| * @return <code>Set</code> of listeners |
| */ |
| public Set getListeners(Object notifier, Object key) { |
| Map keys = (Map) listenersMap.get(notifier); |
| if (keys != null) { |
| Map listenersSet = (Map) keys.get(key); |
| if (listenersSet != null) { |
| return listenersSet.keySet(); |
| } |
| } |
| return Collections.EMPTY_SET; |
| } |
| |
| /** |
| * return all listeners interested in the passed notifier |
| * |
| * @param notifier |
| * @return |
| */ |
| public Set getAllListeners(Object notifier) { |
| Map keys = (Map) listenersMap.get(notifier); |
| if (keys == null || keys.isEmpty()) { |
| return Collections.EMPTY_SET; |
| } |
| Set listenersCollection = new LinkedHashSet(); |
| Set enteries = keys.entrySet(); |
| for (Iterator iter = enteries.iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| Map listenersSet = (Map) entry.getValue(); |
| if (listenersSet != null && !listenersSet.isEmpty()) |
| listenersCollection.addAll(listenersSet.keySet()); |
| } |
| return listenersCollection; |
| } |
| |
| public boolean isEmpty() { |
| return listenersMap.isEmpty(); |
| } |
| } |
| |
| /** |
| * Creates a <code>DiagramEventBroker</code> that listens to all |
| * <code>EObject </code> notifications for the given editing domain. |
| */ |
| protected DiagramEventBroker() { |
| super(NotificationFilter.createNotifierTypeFilter(EObject.class)); |
| } |
| |
| |
| /** |
| * Gets the diagmam event broker instance for the editing domain passed in. |
| * There is one diagram event broker per editing domain. |
| * |
| * @param editingDomain |
| * @return Returns the diagram event broker. |
| */ |
| public static DiagramEventBroker getInstance( |
| TransactionalEditingDomain editingDomain) { |
| |
| return initializeDiagramEventBroker(editingDomain); |
| } |
| |
| /** |
| * Creates a new diagram event broker instance for the editing domain passed |
| * in only if the editing domain does not already have a diagram event |
| * broker. There is one diagram event broker per editing domain. Adds the |
| * diagram event broker instance as a listener to the editing domain. |
| * |
| * @param editingDomain |
| */ |
| public static void startListening(TransactionalEditingDomain editingDomain) { |
| initializeDiagramEventBroker(editingDomain); |
| } |
| |
| private static DiagramEventBroker initializeDiagramEventBroker(TransactionalEditingDomain editingDomain) { |
| WeakReference reference = (WeakReference) instanceMap.get(editingDomain); |
| if (reference == null) { |
| DiagramEventBroker diagramEventBroker = DiagramEventBrokerService.getInstance().createDiagramEventBroker(editingDomain); |
| if (null == diagramEventBroker) |
| diagramEventBroker = debFactory.createDiagramEventBroker(editingDomain); |
| if (diagramEventBroker.editingDomainRef == null) { |
| diagramEventBroker.editingDomainRef = new WeakReference( |
| editingDomain); |
| } |
| editingDomain.addResourceSetListener(diagramEventBroker); |
| reference = new WeakReference(diagramEventBroker); |
| instanceMap.put(editingDomain, reference); |
| } |
| return (DiagramEventBroker) reference.get(); |
| } |
| |
| /** |
| * Factory interface that can be used to create overrides of the DiagramEventBroker class |
| * @author sshaw |
| */ |
| public static interface DiagramEventBrokerFactory { |
| /** |
| * @param editingDomain the <code>TransactionalEditingDomain</code> that is associated |
| * with the <code>DiagramEventBroker</code> instance. |
| * @return the <code>DiagramEventBroker</code> instance. |
| */ |
| public DiagramEventBroker createDiagramEventBroker(TransactionalEditingDomain editingDomain); |
| } |
| |
| private static class DiagramEventBrokerFactoryImpl implements DiagramEventBrokerFactory { |
| public DiagramEventBroker createDiagramEventBroker(TransactionalEditingDomain editingDomain) { |
| DiagramEventBroker diagramEventBroker = new DiagramEventBroker(); |
| diagramEventBroker.editingDomainRef = new WeakReference( |
| editingDomain); |
| return diagramEventBroker; |
| } |
| } |
| |
| private static DiagramEventBrokerFactory debFactory = new DiagramEventBrokerFactoryImpl(); |
| |
| /** |
| * @param newDebFactory |
| */ |
| public static void registerDiagramEventBrokerFactory(DiagramEventBrokerFactory newDebFactory) { |
| debFactory = newDebFactory; |
| } |
| |
| /** |
| * @param editingDomain |
| */ |
| public static void stopListening(TransactionalEditingDomain editingDomain) { |
| DiagramEventBroker diagramEventBroker = getInstance(editingDomain); |
| if (diagramEventBroker != null) { |
| editingDomain.removeResourceSetListener(diagramEventBroker); |
| instanceMap.remove(editingDomain); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.transaction.ResourceSetListenerImpl#transactionAboutToCommit(org.eclipse.emf.transaction.ResourceSetChangeEvent) |
| */ |
| public Command transactionAboutToCommit(ResourceSetChangeEvent event) { |
| Set deletedObjects = NotificationUtil.getDeletedObjects(event); |
| Set addedObjects = NotificationUtil.getAddedObjects(event); |
| Set existingObjects = new HashSet(); |
| Set elementsInPersistQueue = new LinkedHashSet(); |
| CompoundCommand cc = new CompoundCommand(); |
| TransactionalEditingDomain editingDomain = (TransactionalEditingDomain) editingDomainRef |
| .get(); |
| boolean hasPreListeners = (preListeners.isEmpty() == false); |
| List viewsToPersistList = new ArrayList(); |
| boolean deleteElementCheckRequired = !deletedObjects.isEmpty(); |
| for (Iterator i = event.getNotifications().iterator(); i.hasNext();) { |
| final Notification notification = (Notification) i.next(); |
| if (shouldIgnoreNotification(notification)) |
| continue; |
| Object notifier = notification.getNotifier(); |
| if (notifier instanceof EObject) { |
| boolean deleted = false; |
| if (deleteElementCheckRequired){ |
| deleted = !existingObjects.contains(notifier); |
| if (deleted){ |
| deleted = isDeleted(deletedObjects, (EObject)notifier); |
| if (!deleted) |
| existingObjects.add(notifier); |
| } |
| } |
| // see bugzilla [186637] |
| if (deleted || |
| (addedObjects.contains(notifier) && NotationPackage.Literals.VIEW__ELEMENT.equals(notification.getFeature()))) { |
| continue; |
| } |
| if (editingDomain != null) { |
| View viewToPersist = getViewToPersist(notification, |
| elementsInPersistQueue); |
| if (viewToPersist != null) { |
| viewsToPersistList.add(viewToPersist); |
| } |
| } |
| if (hasPreListeners) { |
| Command cmd = fireTransactionAboutToCommit(notification); |
| if (cmd != null) { |
| cc.append(cmd); |
| } |
| } |
| } |
| } |
| |
| if (viewsToPersistList.isEmpty() == false) { |
| PersistViewsCommand persistCmd = new PersistViewsCommand( |
| editingDomain, viewsToPersistList); |
| cc.append(new EMFOperationCommand(editingDomain, persistCmd)); |
| } |
| |
| return cc.isEmpty() ? null |
| : cc; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.transaction.ResourceSetListenerImpl#resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent) |
| */ |
| public void resourceSetChanged(ResourceSetChangeEvent event) { |
| if (postListeners.isEmpty()) { |
| return; |
| } |
| Set deletedObjects = NotificationUtil.getDeletedObjects(event); |
| Set addedObjects = NotificationUtil.getAddedObjects(event); |
| Set existingObjects = new HashSet(); |
| boolean deleteElementCheckRequired = !deletedObjects.isEmpty(); |
| boolean handleNotificationOnAddedElement = false; |
| boolean handleNotificationOnDeletedElement = false; |
| for (Iterator i = event.getNotifications().iterator(); i.hasNext();) { |
| final Notification notification = (Notification) i.next(); |
| boolean customNotification = NotificationUtil.isCustomNotification(notification); |
| if (!customNotification && shouldIgnoreNotification(notification)) |
| continue; |
| Object notifier = notification.getNotifier(); |
| if (notifier instanceof EObject) { |
| boolean deleted = false; |
| if (deleteElementCheckRequired && !customNotification) { |
| deleted = !existingObjects.contains(notifier); |
| if (deleted) { |
| deleted = isDeleted(deletedObjects, (EObject) notifier); |
| if (!deleted) |
| existingObjects.add(notifier); |
| } |
| } |
| if (!customNotification) { |
| if (deleted) { |
| handleNotificationOnDeletedElement = true; |
| continue; |
| }// see bugzilla [186637] |
| else if (addedObjects.contains(notifier) && NotationPackage.Literals.VIEW__ELEMENT.equals(notification.getFeature())){ |
| handleNotificationOnAddedElement = true; |
| continue; |
| } |
| } |
| fireNotification(notification); |
| } |
| } |
| if (handleNotificationOnAddedElement) { |
| handleNotificationOnAddedElement(event); |
| } |
| if (handleNotificationOnDeletedElement) { |
| handleNotificationOnDeletedElement(event); |
| } |
| } |
| |
| /** |
| * This method allows clients to customize the Diagram event broker behavior when |
| * it comes to handling events on added objects. |
| * The default behavior will just ignore them |
| * @param event being handled |
| */ |
| protected void handleNotificationOnAddedElement(ResourceSetChangeEvent event) { |
| // default implementation does nothing |
| |
| } |
| |
| /** |
| * This method allows clients to customize the Diagram event broker behavior when |
| * it comes to handling events on deleted objects. |
| * The default behavior will just ignore them |
| * @param event event being handled |
| */ |
| protected void handleNotificationOnDeletedElement(ResourceSetChangeEvent event) { |
| // default implementation does nothing |
| |
| } |
| |
| |
| /** |
| * decide if the passed object is deleted or not; the decision is done by |
| * checking is the passed notifier or any of its ancestors exists in the passed |
| * deletedObjects Set, if it find the obnject to be deleted it will add it |
| * to the deleted objects set. |
| * @param deletedObjects |
| * @param notifier |
| * @return |
| */ |
| protected boolean isDeleted(Set deletedObjects, EObject notifier) { |
| EObject object = notifier; |
| while (object!=null){ |
| if (deletedObjects.contains(object)){ |
| if (object != notifier){ |
| //so we do not waste time on the second call |
| addDeletedBranch(deletedObjects,notifier); |
| } |
| return true; |
| } |
| object = object.eContainer(); |
| } |
| return false; |
| } |
| |
| private void addDeletedBranch(Set deletedObjects, EObject notifier) { |
| EObject object = notifier; |
| while (object != null){ |
| if (!deletedObjects.add(object)){ |
| break; |
| } |
| object = object.eContainer(); |
| } |
| |
| } |
| |
| |
| /** |
| * determine if the passed notification can be ignored or not the default |
| * implementation will ignore touch event if it is not a resolve event, also |
| * it will ignore the mutable feature events |
| * |
| * @param notification |
| * the notification to check |
| * @return true if the notification should be ignored, otherwise false |
| */ |
| protected boolean shouldIgnoreNotification(Notification notification) { |
| if ((notification.isTouch() && notification.getEventType() != Notification.RESOLVE) |
| || NotationPackage.eINSTANCE.getView_Mutable().equals( |
| notification.getFeature())) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Forward the supplied event to all listeners listening on the supplied |
| * target element. |
| * <P> |
| * <B> Note, for the MSL migration effort, each listener will be forwarded 2 |
| * events. First, a MSL complient Notification event followed by an |
| * ElementEvent (for backwards compatibility). The ElementEvent will be |
| * removed one the MSL migration is complete. |
| */ |
| protected void fireNotification(Notification event) { |
| Collection listenerList = getInterestedNotificationListeners(event, |
| postListeners); |
| if (!listenerList.isEmpty()) { |
| for (Iterator listenerIT = listenerList.iterator(); listenerIT |
| .hasNext();) { |
| NotificationListener listener = (NotificationListener) listenerIT |
| .next(); |
| listener.notifyChanged(event); |
| } |
| } |
| } |
| |
| /** |
| * Forwards the event to all interested listeners. |
| * |
| * @param event |
| * the event to handle |
| * @p |
| */ |
| private Command fireTransactionAboutToCommit(Notification event) { |
| Collection listenerList = getInterestedNotificationListeners(event, |
| preListeners); |
| if (!listenerList.isEmpty()) { |
| CompoundCommand cc = new CompoundCommand(); |
| for (Iterator listenerIT = listenerList.iterator(); listenerIT |
| .hasNext();) { |
| NotificationPreCommitListener listener = (NotificationPreCommitListener) listenerIT |
| .next(); |
| Command cmd = listener.transactionAboutToCommit(event); |
| if (cmd != null) { |
| cc.append(cmd); |
| } |
| } |
| return cc.isEmpty() ? null |
| : cc; |
| } |
| return null; |
| } |
| |
| private View getViewToPersist(Notification event, Set elementsInPersistQueue) { |
| if (!event.isTouch()) { |
| EObject elementToPersist = (EObject) event.getNotifier(); |
| while (elementToPersist != null |
| && !(elementToPersist instanceof View)) { |
| elementToPersist = elementToPersist.eContainer(); |
| } |
| if (elementToPersist != null |
| && !elementsInPersistQueue.contains(elementToPersist) |
| && ViewUtil.isTransient(elementToPersist)) { |
| if (!NotificationFilter.READ.matches(event)) { |
| elementsInPersistQueue.add(elementToPersist); |
| View view = (View) elementToPersist; |
| if (!view.isMutable()) { |
| // get Top view needs to get persisted |
| View viewToPersist = ViewUtil.getTopViewToPersist(view); |
| if (viewToPersist != null) { |
| elementsInPersistQueue.add(viewToPersist); |
| return viewToPersist; |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Add the supplied <tt>listener</tt> to the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param listener |
| * the listener |
| */ |
| public void addNotificationListener(EObject target, |
| NotificationPreCommitListener listener) { |
| if (target != null) { |
| preListeners.addListener(target, LISTEN_TO_ALL_FEATURES, listener); |
| } |
| } |
| |
| /** |
| * Add the supplied <tt>listener</tt> to the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param listener |
| * the listener |
| */ |
| public void addNotificationListener(EObject target, |
| NotificationListener listener) { |
| if (target != null) { |
| postListeners.addListener(target, LISTEN_TO_ALL_FEATURES, listener); |
| } |
| } |
| |
| /** |
| * Add the supplied <tt>listener</tt> to the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param key |
| * the key for the listener |
| * @param listener |
| * the listener |
| */ |
| public void addNotificationListener(EObject target, |
| EStructuralFeature key, NotificationPreCommitListener listener) { |
| if (target != null) { |
| preListeners.addListener(target, key, listener); |
| } |
| } |
| |
| /** |
| * Add the supplied <tt>listener</tt> to the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param key |
| * the key for the listener |
| * @param listener |
| * the listener |
| */ |
| public void addNotificationListener(EObject target, |
| EStructuralFeature key, NotificationListener listener) { |
| if (target != null) { |
| postListeners.addListener(target, key, listener); |
| } |
| } |
| |
| /** |
| * remove the supplied <tt>listener</tt> from the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param listener |
| * the listener |
| */ |
| public void removeNotificationListener(EObject target, |
| NotificationPreCommitListener listener) { |
| if (target != null) { |
| preListeners.removeListener(target, LISTEN_TO_ALL_FEATURES, |
| listener); |
| } |
| } |
| |
| /** |
| * remove the supplied <tt>listener</tt> from the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param listener |
| * the listener |
| */ |
| public void removeNotificationListener(EObject target, |
| NotificationListener listener) { |
| if (target != null) { |
| postListeners.removeListener(target, LISTEN_TO_ALL_FEATURES, |
| listener); |
| } |
| } |
| |
| /** |
| * remove the supplied <tt>listener</tt> from the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param key |
| * the key for the listener |
| * @param listener |
| * the listener |
| */ |
| public void removeNotificationListener(EObject target, Object key, |
| NotificationPreCommitListener listener) { |
| if (target != null) { |
| preListeners.removeListener(target, key, listener); |
| } |
| } |
| |
| /** |
| * remove the supplied <tt>listener</tt> from the listener list. |
| * |
| * @param target |
| * the traget to listen to |
| * @param key |
| * the key for the listener |
| * @param listener |
| * the listener |
| */ |
| public void removeNotificationListener(EObject target, Object key, |
| NotificationListener listener) { |
| if (target != null) { |
| postListeners.removeListener(target, key, listener); |
| } |
| } |
| |
| private Set getNotificationListeners(Object notifier, NotifierToKeyToListenersSetMap listeners) { |
| return listeners.getListeners(notifier, LISTEN_TO_ALL_FEATURES); |
| } |
| |
| /** |
| * @param notifier |
| * @param key |
| * @param preCommit |
| * @return |
| */ |
| private Set getNotificationListeners(Object notifier, Object key, |
| NotifierToKeyToListenersSetMap listeners) { |
| if (key != null) { |
| if (!key.equals(LISTEN_TO_ALL_FEATURES)) { |
| Set listenersSet = new LinkedHashSet(); |
| Collection c = listeners.getListeners(notifier, key); |
| if (c != null && !c.isEmpty()) |
| listenersSet.addAll(c); |
| c = listeners.getListeners(notifier, LISTEN_TO_ALL_FEATURES); |
| if (c != null && !c.isEmpty()) |
| listenersSet.addAll(c); |
| return listenersSet; |
| } else if (key.equals(LISTEN_TO_ALL_FEATURES)) { |
| return listeners.getAllListeners(notifier); |
| } |
| } |
| return listeners.getAllListeners(notifier); |
| } |
| |
| /** |
| * gets a subset of all the registered listeners who are interested in |
| * receiving the supplied event. |
| * |
| * @param event |
| * the event to use |
| * @return the interested listeners in the event |
| */ |
| protected Set getInterestedNotificationListeners(Notification event, |
| NotifierToKeyToListenersSetMap listeners) { |
| Set listenerSet = new LinkedHashSet(); |
| |
| Collection c = getNotificationListeners(event.getNotifier(), event |
| .getFeature(), listeners); |
| if (c != null) { |
| listenerSet.addAll(c); |
| } |
| |
| EObject notifier = (EObject) event.getNotifier(); |
| // the Visibility Event get fired to all interested listeners in the |
| // container |
| if (NotationPackage.eINSTANCE.getView_Visible().equals( |
| event.getFeature()) |
| && notifier.eContainer() != null) { |
| listenerSet.addAll(getNotificationListeners(notifier.eContainer(), |
| listeners)); |
| } else if (notifier instanceof EAnnotation) { |
| addListenersOfNotifier(listenerSet, notifier.eContainer(), event, |
| listeners); |
| } else if (!(notifier instanceof View)) { |
| while (notifier != null && !(notifier instanceof View)) { |
| notifier = notifier.eContainer(); |
| } |
| addListenersOfNotifier(listenerSet, notifier, event, listeners); |
| } |
| return listenerSet; |
| } |
| |
| public boolean isAggregatePrecommitListener() { |
| return true; |
| } |
| |
| /** |
| * Helper method to add all the listners of the given <code>notifier</code> |
| * to the list of listeners |
| * |
| * @param listenerSet |
| * @param notifier |
| */ |
| private void addListenersOfNotifier(Set listenerSet, EObject notifier, |
| Notification event, NotifierToKeyToListenersSetMap listeners) { |
| if (notifier != null) { |
| Collection c = getNotificationListeners(notifier, event |
| .getFeature(), listeners); |
| if (c != null) { |
| if (listenerSet.isEmpty()) |
| listenerSet.addAll(c); |
| else { |
| Iterator i = c.iterator(); |
| while (i.hasNext()) { |
| Object o = i.next(); |
| listenerSet.add(o); |
| } |
| } |
| } |
| } |
| } |
| |
| } |