blob: 1cd04849bad59722d2ee7c76c79d4139893ed8ef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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.jface.internal.databinding;
import java.util.Collection;
import org.eclipse.jface.databinding.BindingException;
import org.eclipse.jface.databinding.ChangeEvent;
import org.eclipse.jface.databinding.IChangeListener;
import org.eclipse.jface.databinding.IUpdatableTree;
/**
* TreeBinding facts:
* o No Conversion, Validation on various tree elements
* o On a bind, only root elements will be pushed from the model to the target
* o <code>ChangeEvent.VIRTUAL</code> event will request children as needed
*
*/
public class TreeBinding extends Binding {
private final IUpdatableTree target;
private final IUpdatableTree model;
private int updating = 0; // Virtual requests are allowed while an update is in progress
/**
* @param context
* @param target
* @param model
*/
public TreeBinding(DataBindingContext context,
IUpdatableTree target, IUpdatableTree model) {
super(context);
this.target = target;
this.model = model;
// some sanity check, target should support all declared model elements
Class[] targetTypes=target.getTypes();
Class[] modelTypes=model.getTypes();
if (targetTypes==null || modelTypes==null)
throw new BindingException("Tree type is not set"); //$NON-NLS-1$
for (int i = 0; i < modelTypes.length; i++) {
boolean canHandle=false;
for (int j = 0; j < targetTypes.length; j++)
if (targetTypes[j].isAssignableFrom(modelTypes[i])) {
canHandle=true;
break;
}
if (!canHandle)
throw new BindingException("Target does not supports type: " + modelTypes[i]); //$NON-NLS-1$
}
target.addChangeListener(targetChangeListener);
model.addChangeListener(modelChangeListener);
}
private IChangeListener targetChangeListener = new IChangeListener() {
public void handleChange(ChangeEvent changeEvent) {
if (updating != 0 && changeEvent.getChangeType()!=ChangeEvent.VIRTUAL)
return;
if (changeEvent.getChangeType() == ChangeEvent.VERIFY) {
// No Conversion on the object itself
} else {
update(model, target, changeEvent);
}
}
};
private IChangeListener modelChangeListener = new IChangeListener() {
public void handleChange(ChangeEvent changeEvent) {
if (updating != 0 && changeEvent.getChangeType()!=ChangeEvent.VIRTUAL)
return;
update(target, model, changeEvent);
}
};
/**
* Update the collection from the event.
*
* @param needsUpdate
* IUpdatable to be updated
* @param event
*/
private void update(IUpdatableTree needsUpdate, IUpdatableTree source, ChangeEvent event) {
int index = event.getPosition();
Object parent = event.getParent();
try {
updating ++;
switch (event.getChangeType()) {
case ChangeEvent.VIRTUAL:
source.setElements(parent, needsUpdate.getElements(parent));
break;
case ChangeEvent.CHANGE:
needsUpdate.setElement(parent, index, event.getNewValue());
break;
case ChangeEvent.ADD:
needsUpdate.addElement(parent, index, event.getNewValue());
break;
case ChangeEvent.REMOVE:
needsUpdate.removeElement(parent, index);
break;
case ChangeEvent.REPLACE:
Object val = event.getNewValue();
if (val.getClass().isArray())
needsUpdate.setElements(parent, (Object[]) val);
else if (val instanceof Collection)
needsUpdate.setElements(parent, ((Collection)val).toArray());
else
throw new BindingException ("Invalid REPLACE event"); //$NON-NLS-1$
break;
}
} finally {
updating --;
}
}
/**
* Copy model's root elements into the target
* It is up to the target to fire a Virtual request event to get
* the rest of the children
*/
public void updateTargetFromModel() {
copyRootContents(target, model);
}
private void copyRootContents(IUpdatableTree destination,
IUpdatableTree source) {
try {
updating ++;
destination.setElements(null, source.getElements(null));
} finally {
updating --;
}
}
}