/*******************************************************************************
* Copyright (c) 2008 Ralf Ebert
* 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:
* Ralf Ebert - initial API and implementation
*******************************************************************************/
package de.ralfebert.rcputils.databinding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
/**
* ModelDataBindingEditorPart is base class for editors that use data binding to
* edit a single model object.
*
* The actual editor implementation goes into the methods onLoad (loading the
* model object from the editor input), onCreatePartControl (creating the UI),
* onBind (binding the UI to the model), onSave (saving the model object).
*
* This resembles the typical structure for editors that edit a single model
* object.
*
* Please take care that the UI are the targets when creating your bindings as
* all changes in target observables (the UI) will cause the editor to get
* dirty.
*
* @author Ralf Ebert <info@ralfebert.de>
*/
public abstract class ModelDataBindingEditorPart<INPUT extends IEditorInput, MODEL> extends
DataBindingEditorPart<INPUT> {
/**
* Stores the model value. This is an observable itself so we can exchange
* the whole model, for example after save if a new object is retrieved by
* saving.
*/
private WritableValue modelValue;
private DataBindingContext dataBindingContext;
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
super.init(site, input);
modelValue = new WritableValue();
}
@Override
public final void doSave(IProgressMonitor monitor) {
dataBindingContext.updateModels();
modelValue.setValue(onSave(getModelObject(), monitor));
onReload(getModelObject());
dataBindingContext.updateTargets();
dirty.setDirty(false);
}
protected void onReload(MODEL modelObject) {
}
protected final void reload() {
if (isReady()) {
modelValue.setValue(onLoad(getEditorInput()));
onReload(getModelObject());
}
}
@SuppressWarnings("unchecked")
protected final MODEL getModelObject() {
return (MODEL) modelValue.getValue();
}
@Override
protected void onAfterUi(Composite parent) {
super.onAfterUi(parent);
// Load model
reload();
// Bind UI
dataBindingContext = new DataBindingContext();
onBind(dataBindingContext, modelValue);
// Changes in target observables (UI) => editor gets dirty
ChangeTracker changeTracker = new ChangeTracker();
changeTracker.trackTargetObservables(dataBindingContext);
changeTracker.addChangeListener(dirty);
}
/**
* Implement onLoad to retrieve the model object by the editor input object.
*/
protected abstract MODEL onLoad(INPUT input);
/**
* Implement onSave to persist the model object. You can return a new model
* object.
*/
protected abstract MODEL onSave(MODEL modelObject, IProgressMonitor monitor);
/**
* Implement onBind to bind the model to the UI. Use detail values like
* PojoObservables.observeDetailValue to refer to the model properties.
*/
protected abstract void onBind(DataBindingContext dataBindingContext, IObservableValue model);
protected boolean isReady() {
return true;
}
}