package net.xoetrope.optional.data;
import java.util.Hashtable;
import java.util.Vector;
import net.xoetrope.xui.XListHolder;
import net.xoetrope.xui.data.XDataBinding;
import net.xoetrope.xui.data.XModel;
import net.xoetrope.optional.data.XTableModelAdapter;
import net.xoetrope.xui.data.table.XTableModel;
import net.xoetrope.xui.XProject;
/**
* A data binding for list components, including drop down lists. This binding
* allows a key field to be chosen so that records may be chosen using a key
* (or ID) value. A display field can also be specified so that the list need
* not display the first field from the table.
* <p>Copyright Xoetrope (c) 2001-2004</p>
* $Revision: 2.5 $
* License: see license.txt
*/
public class XListTableBinding extends XDataBinding
{
protected XTableModelAdapter modelAdapter;
protected XListHolder target;
protected boolean useUnique;
protected int displayColumnIdx;
protected int keyColumnIdx;
protected String keyColumnName;
private static final String[] attribNames = { "display", "key" };
/**
* Construct a new data binding
*/
public XListTableBinding()
{
}
/**
* Setup and configure the binding instance. The binding is configured via the
* XML setup registered for the particular binding type and then, subsequently
* by attibitional attributes of the binding instance specified in the page
* declaration, for the individual binding instance. The binding may also
* obtain configuration or reference information from the component and the
* project.
* @param project the owning project
* @param c the component being bound
* @param bindingConfig the XML element which contains the binding configuration
* @param instanceConfig the XML element which contains the setup attributes of the binding instance
*/
public void setup( XProject project,
Object c,
Hashtable bindingConfig,
Hashtable instanceConfig )
{
setupHelper( project, c, bindingConfig, instanceConfig );
target = (XListHolder)component;
XTableModel dataModel = (XTableModel)sourceModel;
modelAdapter = new XTableModelAdapter( dataModel );
keyColumnIdx = displayColumnIdx = 0;
String s = (String)instanceConfig.get( "display" );
if ( s != null )
setDisplayColumn( s );
else
setDisplayColumn( "0" );
s = (String)instanceConfig.get( "key" );
if ( s != null )
setKeyColumn( s );
}
/**
* Update the bound component with the value obtained from the data model.
*/
public void get()
{
Hashtable hashTable = null;
if ( useUnique )
hashTable= new Hashtable();
String lastItem = "";
Object selectedObj = null;
modelAdapter.sync();
if ( outputModel != null )
selectedObj = outputModel.get();
else
selectedObj = modelAdapter.getSelected( keyColumnIdx );
int items = target.getItemCount();
int numChildren = modelAdapter.getNumChildren();
if ( items != numChildren ) { // This should really check a 'dirty' flag
target.removeAll();
String selected = null;
if ( selectedObj != null )
selected = selectedObj.toString();
for ( int i = 0; i < numChildren; i++ ) {
String currentObj = (String)modelAdapter.get( i );
boolean addItem = false;
if ( useUnique ) {
if ( hashTable.get( currentObj ) == null ) {
hashTable.put( currentObj, currentObj );
addItem = true;
}
}
else if ( currentObj.compareTo( lastItem ) != 0 )
addItem = true;
if ( addItem ) {
target.addItem( currentObj );
if ( selected != null ) {
Object currentKey;
if ( displayColumnIdx != keyColumnIdx )
currentKey = ((XTableModel)modelAdapter.getModel()).getFieldValue( i , keyColumnIdx );
else
currentKey = currentObj;
if ( selected.equals( currentKey ) ) {
target.select( i );
lastItem = currentObj;
}
}
}
}
}
else if ( selectedObj != null ) {
int selRowIdx = modelAdapter.find( selectedObj.toString(), keyColumnIdx );
target.select( selRowIdx );
}
set();
}
/**
* Update the data model with the value retrieved from the bound component.
*/
public void set()
{
Object selObj = target.getSelectedObject();
String selString = "";
if ( selObj != null )
selString = selObj.toString();
int selRowIdx = modelAdapter.find( selString, displayColumnIdx );
if ( selRowIdx >= 0 ) {
Object result = ( ( XTableModel )modelAdapter.getModel() ).getFieldValue( selRowIdx, keyColumnIdx );
if ( result != null ) {
if ( outputModel == null )
setOutputPath( outputPath == null ? sourcePath : outputPath );
outputModel.set( result );
}
}
}
/**
* Set the model path for the source data
* @param newPath The path to which the source model is to be bound
*/
public void setSourcePath( String newPath )
{
if ( newPath != null ) {
modelAdapter = new XTableModelAdapter( (XModel)currentProject.getModel().get( newPath ));
sourcePath = newPath;
modelAdapter.setOutputField( displayColumnIdx );
}
}
/**
* Set the model path for the output/state data
* @param newPath The path to which the output model is to be bound
*/
public void setOutputPath( String newPath )
{
if ( newPath != null ) {
outputPath = XModel.prefixOutputPath( newPath );
outputModel = (XModel)currentProject.getModel().get( outputPath );
}
}
/**
* Update the model node used in the binding. Note that this method does not
* modify the path values stored by this node.
* @param newNode the new model for the data source
*/
public void setSource( XModel newNode )
{
modelAdapter = new XTableModelAdapter( newNode );
modelAdapter.setOutputField( displayColumnIdx );
}
/**
* Set the display column index, by default it is set to zero or the first column
* @param displayColumn the column index (zero based)
*/
public void setDisplayColumn( String displayColumn )
{
if ( displayColumn != null ) {
displayColumnIdx = new Integer( displayColumn ).intValue();
modelAdapter.setOutputField( displayColumnIdx );
}
}
/**
* Set the key column index, by default it is set to zero or the first column
* @param keyColumn the column index (zero based)
*/
public void setKeyColumn( String keyColumn )
{
if ( keyColumn != null ) {
try {
keyColumnIdx = new Integer( keyColumn ).intValue();
}
catch ( Exception e ) {
keyColumnName = keyColumn;
}
}
}
/**
* Get the names of the attributes used by this binding class
* @param required true to list only the require attribues, false for all attributes
*/
public Vector getAttributes( boolean required )
{
return super.getAttributes( required, attribNames );
}
/**
* Get the type of this binding
* @return the binding type name
*/
public String getType()
{
return "list_table";
}
}