package net.xoetrope.xui;
import java.util.Vector;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xui.XProjectManager;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.data.XBaseModel;
import net.xoetrope.xui.data.XDataBinding;
import net.xoetrope.xui.data.XModel;
/**
* <p>A class used by XPage to manage the data binding coordination
* </p>
* <p>Copyright (c) Xoetrope Ltd., 2002-2005</p>
* <p>License: see license.txt</p>
* $Revision: 1.1 $
*/
public class XDataBindingContext
{
/**
* Vector of XDataBinding Objects currently in use by the XPage
*/
public Vector modelBindings;
protected XPathEvaluator evaluator;
/**
* Creates a new instance of XDataBindingContext
*/
public XDataBindingContext( XPathEvaluator pathEvaluator )
{
modelBindings = new Vector();
evaluator = pathEvaluator;
}
//--Start of Data Binding-----------------------------------------------------
/**
* Retrieve the Vector of XDataBinding for the XPage
* @return Vector of XDataBinding
*/
public Vector getBindings()
{
return modelBindings;
}
/**
* Add a binding of a component to the data model. If the page has already
* been activated this method will update the binding automatically.
* @param b the binding
* "param doGet do a get on the binding once it has been added
*/
public void addBinding( XDataBinding b, boolean doGet )
{
if ( b != null ) {
modelBindings.addElement( b );
if ( doGet )
b.get();
}
}
/**
* Remove a binding of a component to the data model.
* @param b the binding
*/
public void removeBinding( XDataBinding b )
{
modelBindings.removeElement( b );
}
/**
* Iterate all of the bindings in the page to reflect the model state.
*/
public void updateBindings()
{
// iterate over components and update their bindings
int numBindings = modelBindings.size();
for ( int i = 0; i < numBindings; i++ ) {
XDataBinding binding = ( ( XDataBinding )modelBindings.elementAt( i ) );
updateBinding( binding );
}
}
/**
* Update the bound model node for the binding. First the output path is
* reevaluated and then updated by setting the output node. Then the source
* path is reevaluated and set. Evaluation of the paths allows derived classes
* to dynamically modify the bindings. Some bindings may save the selection or
* state information to the output node and subsequently use it to restore the
* component state. This method does not alter the data held by the bound model
* nodes. To actually save the data use saveBoundComponentValues and to update
* the UI use updateBoundComponentValues.
* @param binding The databinding to be updated
*/
public void updateBinding( XDataBinding binding )
{
if ( binding.getReevaluate()) {
String rawOutputPath = binding.getOutputPath();
String rawSourcePath = binding.getSourcePath();
if ( rawOutputPath == null )
rawOutputPath = rawSourcePath;
XModel rootNode = XProjectManager.getCurrentProject().getModel();
if ( rawOutputPath != null ) {
String outputPath = evaluator.evaluatePath( rawOutputPath );
if (( outputPath != null ) && ( outputPath.length() > 0 )) {
if (( rawOutputPath.indexOf( "${" ) < 0 ) || !rawOutputPath.equals( outputPath )) {
// Strip any attribute values as the output node should not be
// distinguished by the selected values
String evaluatedPath = evaluator.stripAttributeValues( outputPath );
boolean appendByDefault = XBaseModel.getAppendByDefault();
XBaseModel.setAppendByDefault( true );
XModel outputNode = ( XModel )rootNode.get( XModel.prefixOutputPath( evaluatedPath ));
XBaseModel.setAppendByDefault( appendByDefault );
// If an attribute had been specified then the newNode might not
// have the selected value and we would need to set it or else the
// bound component won't show the correct initial value
if ( !evaluatedPath.equals( outputPath ) ) {
XModel valueNode = ( XModel )rootNode.get( XModel.prefixOutputPath( outputPath ));
if ( valueNode != null ) {
Object outputValue = valueNode.get();
if ( outputValue != null )
outputNode.set( outputValue );
}
}
binding.setOutput( outputNode, outputPath );
}
}
}
if ( rawSourcePath != null ) {
String sourcePath = evaluator.evaluatePath( rawSourcePath );
if (( sourcePath != null ) && ( sourcePath.length() > 0 )) {
if (( rawSourcePath.indexOf( "${" ) < 0 ) || !rawSourcePath.equals( sourcePath )) {
XModel sourceNode = ( XModel )rootNode.get( sourcePath );
binding.setSource( sourceNode );
binding.get();
}
}
}
}
}
/**
* Update the UI with values from the model
*/
public void updateBoundComponentValues()
{
// iterate over components and update their values
int numBindings = modelBindings.size();
for ( int i = 0; i < numBindings; i++ ) {
try {
XDataBinding binding = ( ( XDataBinding )modelBindings.elementAt( i ) );
binding.get();
}
catch ( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "Unable to update the bindings: " + ex.getMessage() );
}
}
}
/**
* Save the component values to the model
*/
public void saveBoundComponentValues()
{
// iterate over components and save their values
int numBindings = modelBindings.size();
for ( int i = 0; i < numBindings; i++ ) {
try {
XDataBinding binding = ( ( XDataBinding )modelBindings.elementAt( i ) );
binding.set();
}
catch( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "Unable to save the binding values: " + ex.getMessage() );
ex.printStackTrace();
}
}
}
/**
* Find the data binding associated with a component
* @param targetComp the component whose binding is required
* @return the binding or null if no binding is found
*/
public XDataBinding getBinding( Object targetComp )
{
// iterate over components
int numBindings = modelBindings.size();
for ( int i = 0; i < numBindings; i++ ) {
XDataBinding binding = ((XDataBinding)modelBindings.elementAt( i ));
if ( binding.getComponent() == targetComp )
return binding;
}
return null;
}
/**
* Find the data binding associated with a data source path
* @param targetPath the path to the bound model
* @return the binding or null if no binding is found
*/
public XDataBinding getBinding( String targetPath )
{
// iterate over components
int numBindings = modelBindings.size();
for ( int i = 0; i < numBindings; i++ ) {
XDataBinding binding = ((XDataBinding)modelBindings.elementAt( i ));
if ( binding.getSourcePath().compareTo( targetPath ) == 0 )
return binding;
}
return null;
}
}