/*******************************************************************************
* Copyright (c) 2006, 2010 Soyatec (http://www.soyatec.com) 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:
* Soyatec - initial API and implementation
*******************************************************************************/
package org.eclipse.papyrus.xwt.internal.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.papyrus.xwt.internal.utils.UserData;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Widget;
public class ScopeKeeper implements DisposeListener {
protected HashMap<String, Object> nameMap = new HashMap<String, Object>();
protected HashMap<Widget, HashMap<Object, HashMap<String, IObservable>>> bindingData = new HashMap<Widget, HashMap<Object, HashMap<String, IObservable>>>();
protected Widget host;
private final ScopeKeeper parent;
private ChangeListenerSupport changeListenerSupport = new ChangeListenerSupport();
class ChangeListenerSupport implements IChangeListener {
private List<IChangeListener> changeListeners = Collections.emptyList();
public void handleChange(ChangeEvent event) {
for(IChangeListener changeListener : changeListeners) {
changeListener.handleChange(event);
}
// notify to parent as well.
Widget parent = UserData.getTreeParent(host);
ScopeKeeper scopeKeeper = UserData.findScopeKeeper(parent);
if(scopeKeeper != null) {
scopeKeeper.fireChangeListener(event);
}
}
public boolean addChangeListener(IChangeListener listener) {
if(changeListeners.contains(listener)) {
return false;
}
if(changeListeners == Collections.EMPTY_LIST) {
changeListeners = new ArrayList<IChangeListener>();
}
changeListeners.add(listener);
return true;
}
public void removeChangeListener(IChangeListener listener) {
changeListeners.remove(listener);
}
public void dispose() {
changeListeners = null;
}
}
public ScopeKeeper(ScopeKeeper parent, Widget host) {
super();
this.parent = parent;
host.addDisposeListener(this);
this.host = host;
}
public void widgetDisposed(DisposeEvent e) {
Widget source = e.widget;
if(source == host) {
for(HashMap<Object, HashMap<String, IObservable>> hashMap : bindingData.values()) {
for(HashMap<String, IObservable> map : hashMap.values()) {
for(IObservable observable : map.values()) {
observable.removeChangeListener(changeListenerSupport);
}
}
}
changeListenerSupport.dispose();
}
HashMap<Object, HashMap<String, IObservable>> hashMap = bindingData.get(source);
if(hashMap != null) {
for(HashMap<String, IObservable> map : hashMap.values()) {
for(IObservable observable : map.values()) {
observable.removeChangeListener(changeListenerSupport);
}
}
bindingData.remove(source);
}
}
public void addNamedObject(String name, Object object) {
nameMap.put(name, object);
}
public Widget getHost() {
return host;
}
public Object getNamedObject(String name) {
Object object = nameMap.get(name);
if(object != null) {
return object;
}
return parent == null ? null : parent.getNamedObject(name);
}
public Collection<String> names() {
return nameMap.keySet();
}
public boolean containsName(String name) {
if(nameMap.containsKey(name)) {
return true;
}
return parent == null ? false : parent.containsName(name);
}
/**
* Register a change listener. The second call to register a same listener
* has no effect.
*
* @param listener
*/
public boolean addChangeListener(IChangeListener listener) {
return changeListenerSupport.addChangeListener(listener);
}
/**
* Remove the registered change listener
*
* @param listener
*/
public void removeChangeListener(IChangeListener listener) {
changeListenerSupport.removeChangeListener(listener);
}
public void fireChangeListener(ChangeEvent event) {
changeListenerSupport.handleChange(event);
}
void addObservableValue(Widget widget, Object data, String property, IObservable value) {
if(widget == null) {
widget = host;
} else {
widget.addDisposeListener(this);
}
HashMap<Object, HashMap<String, IObservable>> widgetData = bindingData.get(widget);
if(widgetData == null) {
widgetData = new HashMap<Object, HashMap<String, IObservable>>();
bindingData.put(widget, widgetData);
}
HashMap<String, IObservable> objectData = widgetData.get(data);
if(objectData == null) {
objectData = new HashMap<String, IObservable>();
widgetData.put(data, objectData);
}
if(objectData.containsKey(property)) {
throw new IllegalStateException();
}
objectData.put(property, value);
value.addChangeListener(changeListenerSupport);
}
IObservableValue getObservableValue(Widget control, Object data, String property) {
IObservable observable = getObservable(control, data, property);
if(observable instanceof IObservableValue) {
return (IObservableValue)observable;
}
return null;
}
IObservableList getObservableList(Widget control, Object data, String property) {
IObservable observable = getObservable(control, data, property);
if(observable instanceof IObservableList) {
return (IObservableList)observable;
}
return null;
}
IObservableSet getObservableSet(Widget control, Object data, String property) {
IObservable observable = getObservable(control, data, property);
if(observable instanceof IObservableSet) {
return (IObservableSet)observable;
}
return null;
}
IObservable localGetObservable(Widget control, Object data, String property) {
// find locally
for(HashMap<Object, HashMap<String, IObservable>> widgetData : bindingData.values()) {
if(widgetData != null) {
HashMap<String, IObservable> objectData = widgetData.get(data);
if(objectData != null) {
IObservable observable = objectData.get(property);
if(observable != null) {
return observable;
}
}
}
}
return null;
}
IObservable getObservable(Widget control, Object data, String property) {
// find locally
IObservable observable = localGetObservable(control, data, property);
if(observable != null) {
return observable;
}
// find in other ScopeKeeper and then keep it in this ScopeKeeper.
Widget rootWidget = UserData.findRootWidget(control);
observable = deepFindObservable(rootWidget, data, property);
if(observable != null) {
addObservableValue(control, data, property, observable);
}
return observable;
}
static IObservable deepFindObservable(Widget control, Object data, String property) {
ScopeKeeper scopeKeeper = UserData.getLocalScopeKeeper(control);
if(scopeKeeper != null) {
IObservable observable = scopeKeeper.localGetObservable(control, data, property);
if(observable != null) {
return observable;
}
}
if(control instanceof Composite) {
Composite composite = (Composite)control;
for(Control child : composite.getChildren()) {
IObservable observable = deepFindObservable(child, data, property);
if(observable != null) {
return observable;
}
}
}
return null;
}
}