/*****************************************************************************
* 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:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.common.listener;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.gmf.runtime.notation.NamedStyle;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
/**
* A Listener for GMF CustomStyle changes
*
* @author Camille Letavernier
*/
public class CustomStyleListener extends AdapterImpl {
private final Collection<String> styleNames;
//FIXME: Use a specific listener
private final IChangeListener listener;
private boolean disposed;
private final EStructuralFeature listenedFeature;
public CustomStyleListener(View source, EStructuralFeature listenedFeature, IChangeListener listener, String styleName) {
this(source, listenedFeature, listener, Collections.singleton(styleName));
}
public CustomStyleListener(View source, IChangeListener listener, Collection<String> styleNames) {
this(source, null, listener, styleNames);
}
public CustomStyleListener(View source, EStructuralFeature listenedFeature, IChangeListener listener, Collection<String> styleNames) {
this.styleNames = styleNames;
this.listener = listener;
this.listenedFeature = listenedFeature;
for(Object styleObject : source.getStyles()) {
if(styleObject instanceof NamedStyle) {
NamedStyle style = (NamedStyle)styleObject;
if(styleNames.contains(style.getName())) {
//FIXME: If a style's name is changed, we won't be notified. We should probably listen on all styles
//FIXME: If the style is an EObjectValueStyle or EObjectListValueStyle, we should also listen on values
style.eAdapters().add(this);
}
}
}
}
@Override
public void notifyChanged(Notification notification) {
//The listener has been disposed: remove it from the notifier
//and ignore the notification
if(disposed) {
((Notifier)notification.getNotifier()).eAdapters().remove(this);
return;
}
//A style object has been added or removed on the notifier: begin or
//stop listening the notifier, and notify our listener (if needed)
if(notification.getFeature() == NotationPackage.eINSTANCE.getView_Styles()) {
switch(notification.getEventType()) {
case Notification.ADD:
handleAdd((EObject)notification.getNewValue());
break;
case Notification.ADD_MANY:
for(Object object : (List<?>)notification.getNewValue()) {
handleAdd((EObject)object);
}
break;
case Notification.REMOVE:
handleRemove((EObject)notification.getOldValue());
break;
case Notification.REMOVE_MANY:
for(Object object : (List<?>)notification.getOldValue()) {
handleRemove((EObject)object);
}
break;
}
return;
}
//If the change occurred on one style instance, notify the listener (If needed)
if(notification.getFeature() == listenedFeature || listenedFeature == null) {
if(!notification.isTouch()) {
handleChange(notification.getNotifier());
}
}
}
private void handleRemove(EObject oldValue) {
oldValue.eAdapters().remove(this);
handleChange(oldValue);
}
private void handleAdd(EObject newValue) {
newValue.eAdapters().add(this);
handleChange(newValue);
}
private void handleChange(Object value) {
if(value instanceof NamedStyle) {
if(styleNames.contains(((NamedStyle)value).getName())) {
//FIXME: Build a usable event, so that listeners don't need to reset
//the whole CSS Engine/refresh the whole diagram each time.
listener.handleChange(null);
}
}
}
public void dispose() {
this.disposed = true;
}
}