package net.xoetrope.builder;
import java.io.Reader;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xui.WidgetAdapter;
import net.xoetrope.xui.XAppender;
import net.xoetrope.xui.XAttributedComponent;
import net.xoetrope.xui.XContentPane;
import net.xoetrope.xui.XPage;
import net.xoetrope.xui.PageSupport;
import net.xoetrope.xui.XPageDisplay;
import net.xoetrope.xui.XPageLoader;
import net.xoetrope.xui.XProjectManager;
import net.xoetrope.xui.XRadioButtonGroup;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.XTextHolder;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.data.XDataBinding;
import net.xoetrope.xui.data.XDataBindingFactory;
import net.xoetrope.xui.evaluator.XAttributeEvaluator;
import net.xoetrope.xui.style.XStyleFactory;
import net.xoetrope.xui.validation.XValidationFactory;
import net.xoetrope.xui.XContentHolder;
import net.xoetrope.registry.ComponentAdapter;
import net.xoetrope.registry.ComponentCustomizer;
import net.xoetrope.xui.XAttributedComponentEx;
import net.xoetrope.xui.XMultiAttributedComponent;
import net.xoetrope.xui.data.XBasicDataBindingFactory;
import net.xoetrope.xui.data.XRegisteredDataBindingFactory;
import net.xoetrope.xui.evaluator.XDefaultAttributeEvaluator;
import net.xoetrope.xui.events.XuiEventHandler;
import net.xoetrope.xui.helper.ReflectionHelper;
import net.xoetrope.xui.helper.XLayoutHelper;
import net.xoetrope.xui.helper.XAttributedComponentHelper;
import net.xoetrope.xui.style.XStyle;
/**
* A builder of XUI pages from an XML source. An instance of the class is setup
* by XApplet as a secondary page loader so that if a class file for the
* page is not found then an attempt is made to load the page from an XML file
* with the same base name.
* <br>
* Components, Menus, Events, Validations and Data Binding can be configured via the
* XML declarations.
* <br>
* The loading process itself relies heavily on the component factories to do
* the bulk of the work involved in constructing and adding components. The XPage
* class also performs much of the work involved in adding events and binding data.
* <p>Copyright (c) Xoetrope Ltd., 2002-2007</p>
* <p>License: see license.txt</p>
* $Revision: 2.59 $
*/
public class XuiBuilder implements XPageLoader
{
protected String packageName;
protected XStyleFactory componentFactory;
protected Object checkBoxGroup;
protected PageSupport page;
protected PageSupport rootPage;
protected XAppender menuBar;
protected Hashtable validationFactories;
protected Hashtable attributeSets;
protected static Hashtable currentAttributes;
protected XLayoutHelper layoutHelper;
private static int nextChildId;
protected XProject currentProject;
protected WidgetAdapter adapter;
protected ComponentCustomizer customizer;
/** The default attribute evaluator. The evaluator can be replaced to support
* various ways of evaluating and interpreting dynamic attributes */
protected XAttributeEvaluator evaluator;
protected XuiEventHandler eventHandler;
/**
* A secondary classloader for attempts to load classes referenced by a page
*/
protected ClassLoader secondaryClassloader;
protected String includeFileName;
/**
* The default class used to instantiate a page. As of XUI 2.0 the implementation
* of the page can be customized to suit different widget libraries.
*/
public static final String DEFAULT_PAGE_CLASS = "net.xoetrope.xui.XPage";
/**
* Construct an instance of the builder with the default package set to net.xoetrope.awt
* @param project the current project
*/
public XuiBuilder( XProject project )
{
currentProject = project;
init( XPage.XUI_AWT_PACKAGE );
}
/**
* Construct a new builder and set the default package
* @param project the current project
* @param packageName the name of the default package e.g. net.xoetrope.awt
*/
public XuiBuilder( XProject project, String packageName )
{
currentProject = project;
init( packageName );
}
/**
* Initialize the builder
* @param packageName the default componnet package or use AWT if none is specified
*/
protected void init( String packageName )
{
Object ref = currentProject.getObject( "Builder" );
if ( ref == null )
currentProject.setObject( "Builder", this );
adapter = WidgetAdapter.getInstance();
if ( packageName == null )
packageName = XPage.XUI_AWT_PACKAGE;
validationFactories = new Hashtable( 2 );
componentFactory = new XStyleFactory( currentProject, packageName );
layoutHelper = (XLayoutHelper)currentProject.getObject( "LayoutHelper" );
XBasicDataBindingFactory.register( currentProject );
XRegisteredDataBindingFactory.register( currentProject );
evaluator = (XDefaultAttributeEvaluator)currentProject.getObject( "DefaultAttributeEvaluator" );
if ( evaluator == null ) {
evaluator = new XDefaultAttributeEvaluator( currentProject );
evaluator.setCurrentProject( currentProject );
currentProject.setObject( "DefaultAttributeEvaluator", evaluator );
}
customizer = (ComponentCustomizer)currentProject.getObject( "ComponentCustomizer" );
if ( customizer == null ) {
customizer = new ComponentCustomizer( currentProject );
currentProject.setObject( "ComponentCustomizer", customizer );
try {
Reader r = currentProject.getBufferedReader( "customizations.xml" );
if ( r != null )
customizer.read( r );
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
}
/**
* Set a secondary classloader for loading the classes referenced by pages
* @param cl the class loader
*/
public void setClassLoader( ClassLoader cl )
{
secondaryClassloader = cl;
}
/**
* Set the default package name. The default package name is used when
* creating widgets such that a button class like XButton is instatiated as
* <defPackageName>.XButton.class. By default this expands to
* net.xoetrope.awt.XButton.clas
* @param defPackageName the default package name
*/
public void setPackageName( String defPackageName )
{
if ( defPackageName == null )
packageName = XPage.XUI_AWT_PACKAGE;
else
packageName = defPackageName;
componentFactory = new XStyleFactory( currentProject, packageName );
}
/**
* Set the current page
* @param p the page object
* @since 3.0
*/
public void setPage( PageSupport p )
{
page = p;
}
/**
* Loads an XPage via a reader obtained from the XProject (searches
* the classpath). The pageName is assumed to be the name of an XML file. For
* example if the pageName is 'welcome' then the 'welcome.xml' file is read as
* a UTF8 encoded XML file (by default).
* @param defPackageName the package or path to the page
* @param pageName the page name or the name of the class implementing the page
* @param include true if the page to be loaded is being included in another
* page in which case any class attribute of the included page is ignored
* @return the page
*/
public PageSupport loadPage( String defPackageName, String pageName, boolean include )
{
packageName = defPackageName;
Reader r = null;
try {
r = currentProject.getBufferedReader( pageName + ".xml", null );
}
catch ( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "BUILDER", "File NOT found: " + pageName + ". Error: " + ex.getMessage() );
}
try {
if (( r == null ) || !r.ready())
return null;
return readPage( r, pageName, ".xml", include );
}
catch ( Exception e ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "BUILDER", "File NOT found: " + pageName + ". Error: " + e.getMessage() );
}
finally {
if ( !include )
rootPage = null;
}
return null;
}
/**
* Loads a frameset. If a frameset is used then the calls to the XPageDisplay
* interface should use the form that specifies the target areas. By default
* frames are specified in a file (if found) called frames.xml. The frames
* are added to a container laid out with a BorderLayout.
* <br>
* Frames can be used to control how parts of the screen are updated. The
* default page updated by the page transition/swapping methods is the 'content'
* frame. Other areas can be used as non swapping areas for toolbars,
* navigation controls, sidebars or status areas. Frames may also be hidden
* and shown as needed.
* @param defPackageName the package or path to the page
* @param frameSetName the page name or the name of the class implementing the page
* @param pageDisplay the object that will display the pages and frameset
* @param useFrames true to setup the frameset or false to add just a single target area
* @return true if a frameset is loaded
*/
public boolean loadFrames( String defPackageName, String frameSetName, XPageDisplay pageDisplay, boolean useFrames )
{
if ( !useFrames ) {
loadSingleTarget( pageDisplay );
return true;
}
// Only add frames once
/** @todo check this beahvior for multi-project applications, secondary projects may be allowed to add targets? */
boolean addFrames = ( pageDisplay.getNumTargets() == 0 );
packageName = defPackageName;
Reader r = null;
try {
r = currentProject.getBufferedReader( frameSetName + ".xml", null );
}
catch ( Exception ex ) {
}
if ( r == null ) {
loadSingleTarget( pageDisplay );
return true;
}
XmlElement model = XmlSource.read( r );
Vector componentNodes = model.getChildren();
int numChildren = componentNodes.size();
if ( numChildren == 0 ) {
if ( !"NONE".equals( currentProject.getStartupParam( "DefaultTarget" )))
loadSingleTarget( pageDisplay );
return true;
}
Hashtable framesetParams = new Hashtable();
Enumeration framesetAttribNames = model.enumerateAttributeNames();
while ( framesetAttribNames.hasMoreElements()) {
String attribName = (String)framesetAttribNames.nextElement();
framesetParams.put( attribName, (String)model.getAttribute( attribName ));
}
pageDisplay.setupFrameset( framesetParams );
for ( int i = 0; i < numChildren; i++ ) {
XmlElement childNode = ( XmlElement )componentNodes.elementAt( i );
String typeStr = childNode.getName();
String targetName = childNode.getAttribute( "name" );
String pageName = childNode.getAttribute( "content" );
Hashtable params = new Hashtable();
Enumeration attribNames = childNode.enumerateAttributeNames();
while ( attribNames.hasMoreElements()) {
String attribName = (String)attribNames.nextElement();
params.put( attribName, (String)childNode.getAttribute( attribName ));
}
if ( typeStr.equals( "Frame" )) {
try {
Object constraint = layoutHelper.getConstraint( childNode.getAttribute( "constraint" ));
int preferredWidth = new Integer( childNode.getAttribute( "width" ) ).intValue();
int preferredHeight = new Integer( childNode.getAttribute( "height" ) ).intValue();
XContentHolder target;
if ( addFrames )
target = pageDisplay.addTarget( targetName, constraint,
preferredWidth,
preferredHeight,
params );
else {/** @todo set the target parameters for this new frame */
target = (XContentHolder)pageDisplay.findTarget( targetName );
target.setup( targetName, preferredWidth, preferredHeight, params );
}
if ( pageName != null ) {
target.setContent( pageName );
PageSupport targetPage = currentProject.getPageManager().loadPage( pageName );
pageDisplay.displayPage( targetPage, targetName );
}
}
catch ( NumberFormatException ex1 ) {
ex1.printStackTrace();
}
}
else if ( typeStr.equals( "Toolbar" )) {
String constraint = childNode.getAttribute( "constraint" );
PageSupport toolbar = currentProject.getPageManager().loadPage( pageName );
pageDisplay.displayDecoration( toolbar, constraint );
}
}
pageDisplay.doLayout();
return true;
}
/**
* Load a single target, used in case a frameset is not loaded
* @param pageDisplay the object that will display the pages and frameset
*/
protected void loadSingleTarget( XPageDisplay pageDisplay )
{
int clientWidth = 640;
int clientHeight = 480;
String temp = currentProject.getStartupParam( "ClientWidth" );
if ( temp != null )
clientWidth = Integer.parseInt( temp );
temp = currentProject.getStartupParam( "ClientHeight" );
if ( temp != null )
clientHeight = Integer.parseInt( temp );
pageDisplay.addTarget( BuildProperties.CONTENT_TARGET, BorderLayout.CENTER, clientWidth, clientHeight, null );
}
/**
* Read an XML description of the page and construct a new XPage. An instance
* of the class specified by the class attribute is constructed or else an
* instance of XPage if no class attribute is specified. The new page is
* populated but is not yet added to its parent.
* <br>
* The startup file parameter 'DefaultClass' is used to obtain a default for
* each page's class if a class parameter is not specified in the page's XML
* <br>
* The startup file parameter 'Validations' is used to obtain a default for
* each page's set of validation rules
*
* @param reader a input stream from which to read the page
* @param pageName the name of the page
* @param ext the file extension
* @param include the page to be loaded is being included in another page
* @return the page
*/
public PageSupport readPage( Reader reader, String pageName, String ext, boolean include )
{
XmlElement model = XmlSource.read( reader );
if ( BuildProperties.DEBUG && ( model == null ))
DebugLogger.logError( "BUILDER", "The file - " + pageName + " - could not be parsed!" );
setupPage( model, pageName, ext, include );
eventHandler = page.getEventHandler();
XmlElement componentsNode = null;
XmlElement eventsNode = null;
XmlElement dataNode = null;
XmlElement menuNode = null;
XmlElement validationsNode = null;
XmlElement scriptsNode = null;
Vector componentNodes = model.getChildren();
int numChildren = componentNodes.size();
for ( int i = 0; i < numChildren; i++ ) {
XmlElement childNode = ( XmlElement )componentNodes.elementAt( i );
String typeStr = childNode.getName().toLowerCase();
if ( typeStr.equals( "components" ))
componentsNode = childNode;
else if ( typeStr.equals( "events" ))
eventsNode = childNode;
else if ( typeStr.equals( "data" ))
dataNode = childNode;
else if ( typeStr.equals( "validations" ))
validationsNode = childNode;
else if ( typeStr.equals( "menubar" ))
menuNode = childNode;
else if ( typeStr.equals( "attributes" ))
loadAttributeSet( childNode );
else if ( typeStr.equals( "include" )) {
loadPage( packageName, childNode.getAttribute( "file" ), true );
componentFactory.setParentComponent( page );
}
else if ( typeStr.equals( "scripts" ))
scriptsNode = childNode;
else
loadOtherElement( page, childNode );
}
if ( componentsNode != null )
addComponents( ( include ? componentFactory.getParentComponent() : page ), componentsNode );
if ( menuNode != null )
addMenu( page, menuNode );
if ( dataNode != null )
addBindings( page, dataNode );
if ( eventsNode != null )
addEvents( page, eventsNode );
if ( validationsNode != null )
addValidations( page, validationsNode );
if ( scriptsNode != null )
addScripts( page, scriptsNode );
// String styleValue = ( String )model.getAttribute( "style" );
// if ( styleValue != null )
// currentResource.setStyleName( page, styleValue );
page.validate();
return page;
}
/**
* Loads a class as the basis for a page
* @param className the full class name
* @return an instance of the XPage class or a derivative
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
protected PageSupport loadClass( String className ) throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
XProjectManager.setCurrentProject( currentProject );
if ( secondaryClassloader != null ) {
try {
return (PageSupport)ReflectionHelper.constructViaReflection( secondaryClassloader, className );
}
catch ( Exception e ) {}
}
return (PageSupport)ReflectionHelper.constructViaReflection( null, className );
}
/**
* Load any element other than the predefined node types e.g. Component, Bindings etc...
* Allows an editor to insert extra data in the page, e.g. guides
* @param page the page currently being loaded
* @param childNode the xml element to process
*/
protected void loadOtherElement( PageSupport page, XmlElement childNode )
{
if ( childNode.getName().toLowerCase().equals( "guides" )) {
try {
Object gs = ReflectionHelper.constructViaReflection( "net.xoetrope.optional.layout.GuideSupport", XProject.class, currentProject );
BuilderSupport bs = (BuilderSupport)gs;
String guideFile = childNode.getAttribute( "include" );
if (( guideFile != null ) && ( guideFile.length() > 0 ))
bs.read( guideFile );
else
bs.read( childNode );
page.setAttribute( "guides", "guidesupport", gs );
}
catch ( Exception e )
{
if ( BuildProperties.DEBUG )
DebugLogger.logWarning( "BUILDER", "Unable to read the guides" );
}
}
}
/**
* Loads the page based on the contents of the page tag or by using default
* values.
*
* @param pageName the name of the page
* @param ext the file extension
* @param include the page to be loaded is being included in another page
*/
protected void setupPage( XmlElement model, String pageName, String ext, boolean include )
{
XProjectManager.setCurrentProject( currentProject );
String className = model.getAttribute( "class" );
if (( className == null ) || ( className.length() == 0 )) {
// Try to get a default startup class name if none has been specified in the XML
try {
className = currentProject.getStartupParam( "DefaultClass" );
}
catch ( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.trace( "BUILDER", "No class specified and cannot find the DefaultClass startup property" );
}
if ( className == null )
className = DEFAULT_PAGE_CLASS;
}
if ( !include ) {
if ( ( className.indexOf( '.' ) <= 0 ) && ( packageName.length() > 1 ) )
className = packageName + ( packageName.endsWith( "." ) ? "" : "." ) + className;
try {
page = loadClass( className );
}
catch ( Exception e ) {
if ( BuildProperties.DEBUG ) {
// The class may not have been created yet
if ( e instanceof ClassNotFoundException )
DebugLogger.trace( "BUILDER", "Unable to load the named class: " + className );
else {
// There is a problem in the constructor
DebugLogger.logError( "BUILDER", "Unable to load the named class: " + className );
e.printStackTrace();
}
}
try {
page = (PageSupport)ReflectionHelper.constructViaReflection( null, DEFAULT_PAGE_CLASS );
}
catch ( Exception e2 ) {
e.printStackTrace();
}
}
// Perhaps use classname by default
// or check for existance of the file within XPage ... might add delay in constructing non validated pages
try {
String validationName = model.getAttribute( "Validations" );
if ( validationName == null || validationName.length() == 0 )
validationName = currentProject.getStartupParam( "Validations" );
if ( validationName != null ) {
if ( BuildProperties.DEBUG )
DebugLogger.trace( "BUILDER", "Reading validations: " + validationName );
page.setValidationFactory( getValidationFactory( validationName ) );
}
}
catch ( Exception ex ) {
ex.printStackTrace();
}
if ( page instanceof XContentPane )
componentFactory.setParentComponent( (( XContentPane )page).getContentPane() );
else
componentFactory.setParentComponent( page );
String styleName = model.getAttribute( "style" );
if ( styleName != null )
componentFactory.applyStyle( page, styleName );
}
if ( !include ) {
setPageName( pageName );
setPageExtension( ext );
}
// int width = 0;//, height = 0;
String layoutMgr = null;
Hashtable layoutAttributes = null;
Enumeration attribNamesEnum = model.enumerateAttributeNames();
while ( attribNamesEnum.hasMoreElements()) {
String attribName = (String)attribNamesEnum.nextElement();
String attribValue = (String)model.getAttribute( attribName );
String attribNameLwr = attribName.toLowerCase();
if ( attribNameLwr.equals( "class" ))
;
else if ( attribNameLwr.equals( "resource" ))
;//setResourceBundle( page, attribValue );
else if ( attribNameLwr.equals( "layout" )) {
if ( attribValue != null )
layoutMgr = attribValue;
XmlElement layoutElement = model.getFirstChildNamed( "Layout" );
if ( layoutElement != null ) {
layoutAttributes = new Hashtable();
Enumeration layoutAttribNamesEnum = layoutElement.enumerateAttributeNames();
while ( layoutAttribNamesEnum.hasMoreElements()) {
String layoutAttribName = (String)layoutAttribNamesEnum.nextElement();
String layoutAttribValue = (String)layoutElement.getAttribute( layoutAttribName );
layoutAttributes.put( layoutAttribName, layoutAttribValue );
}
}
else
layoutAttributes = currentAttributes;
}
else
page.setAttribute( attribName, null, evaluateAttribute( page, attribValue ));
setPageAttribute( page, attribName, attribValue );
}
setResourceBundle( page, model.getAttribute( "resource" ));
/** @todo this method attempts to set all the attributes of the layout and it's parent as the
* attributes are embedded in the parent element. Need to separate the two and provide a separate
* element for the layout.
*/
if ( layoutMgr != null )
componentFactory.addLayout( include ? componentFactory.getParentComponent() : page, layoutHelper.getLayoutType( layoutMgr ), layoutAttributes );
rootPage = (PageSupport)page;
}
/**
* Set the name of the page's resource bundle
* @param page the page that owns the resource
* @param the resource bundle name, minus any extension
*/
protected void setResourceBundle( PageSupport page, String attribValue )
{
String resName;
if (( attribValue != null ) && ( attribValue.length() > 0 ))
resName = page.evaluatePath( attribValue );
else
resName = currentProject.getStartupParam( "Language" );
componentFactory.setResourceBundle( resName );
page.getComponentFactory().setResourceBundle( resName );
}
/**
* Get a page attribute (this version does nothing)
* @param c the component associated with an attribute
* @param name the attribute name
* @param value the attribute value
*/
public void setPageAttribute( Object c, String name, String value )
{
}
/**
* Process an attribute element
* @param attrElement the attribute element
*/
public void loadAttributeSet( XmlElement childNode )
{
if ( attributeSets == null )
attributeSets = new Hashtable();
String attribSetName = childNode.getAttribute( "name" );
Vector attribs = new Vector();
Enumeration attribNames = childNode.enumerateAttributeNames();
while ( attribNames.hasMoreElements()) {
String attribName = (String)attribNames.nextElement();
if ( attribName.equals( "name" ))
attribSetName = childNode.getAttribute( "name" );
else {
Object[] attribPair = new Object[ 2 ];
attribPair[ 0 ] = attribName;
attribPair[ 1 ] = childNode.getAttribute( attribName );
attribs.add( attribPair );
}
}
if (( attribSetName != null ) && ( attribSetName.length() > 0 ))
attributeSets.put( attribSetName, attribs );
}
/**
* Insert the attributes of a named attribute set into the node
* @param node the node to be modified if it has an atttributes attribute
*/
public void insertAttributes( XmlElement node )
{
String attribSetName = node.getAttribute( "attributes" );
if (( attribSetName != null ) && ( attribSetName.length() > 0 )) {
Vector attribs = (Vector)attributeSets.get( attribSetName );
int numAttribPairs = attribs.size();
for ( int i = 0; i < numAttribPairs; i ++ ) {
Object[] attribPair = (Object[])attribs.elementAt( i );
node.setAttribute( (String)attribPair[ 0 ], (String)attribPair[ 1 ] );
}
}
}
/**
* Set the attribute evaluator object.
* @param e the new evaluator
*/
public void setAttributeEvaluator( XAttributeEvaluator e )
{
evaluator = e;
}
/**
* Get the value of an attribute.
* @param page the page being loaded
* @param attributeValue the raw value of the attribute
* @return the evaluated value of the attribute
*/
public Object evaluateAttribute( PageSupport page, String attributeValue )
{
if ( attributeValue == null )
return null;
if ( evaluator != null )
return evaluator.evaluateAttribute( page, attributeValue );
return page.evaluateAttribute( attributeValue );
}
/**
* Get the value of an attribute.
* @param page the page being loaded
* @param attributeValue the raw value of the attribute
* @return the evaluated value of the attribute
*/
public String evaluateAttributeAsString( PageSupport page, String attributeValue )
{
Object rc = evaluateAttribute( page, attributeValue );
if ( rc != null )
return rc.toString();
return null;
}
/**
* Adds the elements specified by the Components element and its children
* @param page the new page object
* @param model the Components XML element (and implicitly its children)
*/
protected void addComponents( Object page, XmlElement model )
{
// componentFactory.setParentComponent( (Container)page );
Vector componentNodes = model.getChildren();
int numChildren = componentNodes.size();
for ( int i = 0; i < numChildren; i++ ) {
XmlElement childNode = ( XmlElement )componentNodes.elementAt( i );
String childName = childNode.getName();
if ( childName == null )
continue;
else if ( !"Repeat".equalsIgnoreCase( childName ))
addComponent( childNode );
else {
String repeatReference = childNode.getAttribute( "while" );
pushRepeatReference( repeatReference );
// Repeat the child addition.
boolean whileClauseResult = ((Boolean)rootPage.evaluateAttribute( repeatReference )).booleanValue();
if ( whileClauseResult ) {
i--;
addComponents( page, childNode );
}
popRepeatReference( repeatReference );
}
}
}
/**
* Adds the event handlers. Events are specified in the XML as having 'type'
* (e.g. MouseHandler, ActionHandler etc...), 'name' (the method name to be
* invoked) and 'target' (the name of the component to which the handler is
* attached) attributes
* @param page The page that contains the response methods
* @param model the 'events' XML element
*/
protected void addEvents( PageSupport page, XmlElement model )
{
// String typeStr, methodStr, targetStr, cursorStr;
// cursorStr = "";
Vector eventNodes = model.getChildren();
int numChildren = eventNodes.size();
for ( int i = 0; i < numChildren; i++ ) {
XmlElement childNode = ( XmlElement )eventNodes.elementAt( i );
if ( childNode.getName().compareTo( "Repeat" ) != 0 )
addEvent( childNode );
else {
String repeatReference = childNode.getAttribute( "while" );
pushRepeatReference( repeatReference );
// Repeat the child addition.
boolean whileClauseResult = ((Boolean)rootPage.evaluateAttribute( repeatReference )).booleanValue();
if ( whileClauseResult ) {
i--;
addEvents( page, childNode );
}
popRepeatReference( repeatReference );
}
}
}
/**
* Adds the event handlers. Events are specified in the XML as having 'type'
* (e.g. MouseHandler, ActionHandler etc...), 'name' (the method name to be
* invoked) and 'target' (the name of the component to which the handler is
* attached) attributes
* @param childNode the 'events' XML element
*/
protected void addEvent( XmlElement childNode )
{
String typeStr, methodStr, targetStr, cursorStr;
cursorStr = "";
typeStr = methodStr = targetStr = null;
try {
Enumeration attribNamesEnum = childNode.enumerateAttributeNames();
while ( attribNamesEnum.hasMoreElements()) {
String attribName = (String)attribNamesEnum.nextElement();
String attribValue = childNode.getAttribute( attribName );
if ( "type".equals( attribName ))
typeStr = evaluateAttributeAsString( rootPage, attribValue );
else if ( "method".equals( attribName )) {
// Do not evaluate this method... the actual event handler
// is only meant to be invoked in response to an event.
methodStr = attribValue;
}
else if ( "target".equals( attribName ))
targetStr = evaluateAttributeAsString( rootPage, attribValue );
else if ( "cursor".equals( attribName ))
cursorStr = evaluateAttributeAsString( rootPage, attribValue );
else
page.setAttribute( attribName, targetStr, evaluateAttribute( page, attribValue ));
}
if ( "MenuHandler".equals( typeStr ))
addHandler( page, getMenuItem( targetStr ), "MenuHandler", methodStr );
else {
Object targetComp = page.findComponent( targetStr );
if ( BuildProperties.DEBUG ) {
if ( targetComp == null )
DebugLogger.logError( "BUILDER", "Unable to find the component '" + targetStr + "' named in the event element " + methodStr );
}
addHandler( page, targetComp, typeStr, methodStr );
if ( cursorStr.equals( "true" ))
adapter.setCursor( targetComp, Cursor.getPredefinedCursor( Cursor.HAND_CURSOR ) );
}
}
catch ( Exception e )
{
if ( BuildProperties.DEBUG )
DebugLogger.logError( "BUILDER", "While adding the event element: " + methodStr );
e.printStackTrace();
}
}
/**
* Adds an event handler.
* @param xpage The page that contains the response methods
* @param targetComp the component to which the event handler is added
* @param typeStr the type of handler
* @param methodName the name of the response method
*/
public void addHandler( PageSupport xpage, Object targetComp, String typeStr, String methodName )
{
eventHandler.addHandler( xpage, targetComp, typeStr, methodName );
}
/**
* Adds data bindings to the page.
* @param page the page to which the component/data bindings are added
* @param model the data model
*/
protected void addBindings( PageSupport page, XmlElement model )
{
if ( model == null )
return;
Vector eventNodes = model.getChildren();
int numChildren = eventNodes.size();
for ( int i = 0; i < numChildren; i++ ) {
XmlElement childNode = ( XmlElement )eventNodes.elementAt( i );
if ( childNode.getName().compareTo( "Repeat" ) != 0 )
addBinding( childNode );
else {
// Repeat the child addition.
String repeatReference = childNode.getAttribute( "while" );
pushRepeatReference( repeatReference );
boolean whileClauseResult = ((Boolean)rootPage.evaluateAttribute( repeatReference )).booleanValue();
if ( whileClauseResult ) {
i--;
addBindings( page, childNode );
}
popRepeatReference( repeatReference );
}
}
}
/**
* Adds data bindings to the page.
* @param model the data model
*/
protected void addBinding( XmlElement childNode )
{
String nameStr = null;
try {
Hashtable instanceConfig = new Hashtable();
Enumeration attribNames = childNode.enumerateAttributeNames();
while ( attribNames.hasMoreElements()) {
String attribName = (String)attribNames.nextElement();
String attribValue = childNode.getAttribute( attribName );
instanceConfig.put( attribName, evaluateAttribute( page, attribValue ));
}
instanceConfig.put( "sourcePath", childNode.getAttribute( "source" ));
String s = childNode.getAttribute( "output" );
if ( s != null )
instanceConfig.put( "outputPath", s );
nameStr = (String)instanceConfig.get( "target" );
if ( nameStr == null ) {
nameStr = childNode.getAttribute( "target" );
nameStr = evaluateAttributeAsString( rootPage, nameStr );
}
Object targetComp = page.findComponent( nameStr );
if ( BuildProperties.DEBUG ) {
if ( targetComp == null )
DebugLogger.logError( "BUILDER", "While adding the data binding element for the target component: " + nameStr + " Please check that the component name is specified correctly and that the case matches." );
}
String typeStr = (String)instanceConfig.get( "type" );
if (( typeStr!= null ) && typeStr.equals( "custom" )) {
if ( BuildProperties.DEBUG )
DebugLogger.logWarning( "BUILDER", "Deprecated binding configuration, please use the bindings registry (bindings.xml) instead of \'custom\' attributes" );
String customClass = (String)instanceConfig.get( "class" );
try {
XDataBinding customBinding = (XDataBinding)Class.forName( customClass.trim() ).newInstance();
customBinding.setup( currentProject, targetComp, null, instanceConfig );
page.addBinding( customBinding );
return;
}
catch ( Exception ex ) {
System.out.println( "could not load binding class - " + customClass );
}
}
XDataBinding factoryBinding = getFactoryBinding( page, targetComp, instanceConfig );
if ( factoryBinding != null )
page.addBinding( factoryBinding );
else if ( BuildProperties.DEBUG ) {
DebugLogger.logError( "BUILDER", "Failed to create the binding for the target: " + nameStr + " and the data source:" + (String)instanceConfig.get( "source" ));
}
}
catch ( Exception e )
{
if ( BuildProperties.DEBUG ) {
DebugLogger.logError( "BUILDER", "Undetermined error while adding the data binding element for the target component: " + nameStr + ". Please check the binding specification and following stack trace." );
e.printStackTrace();
}
}
}
/**
* Try to get a binding factory to construct the binding
* @param currentProject the current project
* @param page the page that will own the binding
* @param compType the component type
* @param bindingNode the XML element defining the binding
* @return the new binding if one could be constructed
*/
public XDataBinding getFactoryBinding( PageSupport page, Object compType, Hashtable instanceConfig )
{
XDataBinding binding = null;
Vector bindingFactories = page.getProject().getBindingsFactories();
for ( int i = 0; i < bindingFactories.size(); i++ ) {
/**
* @todo These factories need to be extended to determine the binding type
* from both the component type and model node type. This probably
* requires some sort of configuration or perhaps a voting mechanism
* to allow a binding be composed of mulitple bindings and adapters so
* that it is possible to go from any given node type to any (possibly
* unknown to XUI) component type. - LO'C 2 May 2005
*/
binding = ((XDataBindingFactory)bindingFactories.elementAt( i )).getBinding( page, compType, instanceConfig );
if ( binding != null )
return binding;
}
return null;
}
/**
* Set the name of the page
* @param pageName the new page name.
*/
protected void setPageName( String pageName )
{
page.setName( pageName );
}
/**
* Set the file extension of the page
* @param ext the new file extension.
*/
protected void setPageExtension( String ext )
{
page.setExtension( ext );
}
/**
* Adds an individual component element to the page (this method may be called
* recursively for nested elements). Several methods will be attempted until a
* component is successfully created. Firstly the built-in component types are
* checked, then any additional registered component constructors. The types
* can be specified by type ID, type name or class name.
* @param childNode the XML element containing the component specification.
* @return the new component
*/
protected Object addComponent( XmlElement childNode )
{
String nameStr = null, xStr, yStr, wStr, hStr, contentStr, styleStr,
layoutMgr, constraintStr, eagerStr;
Object comp = null;
String childName = childNode.getName();
if ( childName.equals( "Layout" ))
return null;
try {
int x = 0, y = 0, w = 30, h = 20;
nameStr = wStr = hStr = contentStr = styleStr = layoutMgr =
constraintStr = eagerStr = null;
xStr = yStr = "0";
wStr = hStr = "-1";
Hashtable layoutAttributes = null;
Hashtable componentAttributes = new Hashtable(); // Local copy of the component attributes
currentAttributes = componentAttributes;
insertAttributes( childNode );
Enumeration attribNamesEnum = childNode.enumerateAttributeNames();
while ( attribNamesEnum.hasMoreElements() ) {
String attribName = (String)attribNamesEnum.nextElement();
String attribValue = (String)childNode.getAttribute( attribName );
attribValue = evaluateAttributeAsString( rootPage, attribValue );
if ( attribName.equals( "x" ))
xStr = attribValue;
else if ( attribName.equals( "y" ))
yStr = attribValue;
else if ( attribName.equals( "w" ))
wStr = attribValue;
else if ( attribName.equals( "h" ))
hStr = attribValue;
else if ( attribName.equals( "eager" ))
eagerStr = attribValue;
else if ( attribName.equals( "attributes" ))
continue; // already processed
else {
if ( attribName.equals( "name" ))
nameStr = attribValue;
else if ( attribName.equals( "layout" )) {
layoutMgr = attribValue;
XmlElement layoutElement = childNode.getFirstChildNamed( "Layout" );
if ( layoutElement != null ) {
layoutAttributes = new Hashtable();
Enumeration layoutAttribNamesEnum = layoutElement.enumerateAttributeNames();
while ( layoutAttribNamesEnum.hasMoreElements()) {
String layoutAttribName = (String)layoutAttribNamesEnum.nextElement();
String layoutAttribValue = (String)layoutElement.getAttribute( layoutAttribName );
layoutAttributes.put( layoutAttribName, layoutAttribValue );
}
}
else
layoutAttributes = componentAttributes;
}
else if ( attribName.equals( "constraint" ))
constraintStr = attribValue;
else {
if ( attribName.equals( "content" ))
contentStr = attribValue;
else if ( attribName.equals( "key" ))
contentStr = attribValue;
else if ( attribName.equals( "style" )) {
styleStr = attribValue;
if ( componentFactory instanceof XStyleFactory )
continue;
}
else {
if ( nameStr == null ) {
nameStr = childNode.getAttribute( "name" );
// Synthesise a name to distinguish this component
if ( nameStr == null )
nameStr = "child" + new Integer( ++nextChildId ).toString();
}
// Save a copy of the attributes in the page for post creation usage
rootPage.setAttribute( attribName, nameStr, evaluateAttribute( rootPage, attribValue ));
}
// Save a local copy for use during the construction process
componentAttributes.put( attribName, attribValue );
}
}
}
x = y = w = h = -1;
x = getInt( xStr, x );
y = getInt( yStr, y );
w = getInt( wStr, w );
h = getInt( hStr, h );
if ( includeFileName != null ) {
if (( nameStr == null ) || ( nameStr.length() == 0 ))
nameStr = includeFileName;
page.setAttribute( "Include", nameStr, evaluateAttribute( page, includeFileName ));
includeFileName = null;
}
if ( childName.equalsIgnoreCase( "include" )) {
Object parentObject = componentFactory.getParentComponent();
includeFileName = evaluateAttributeAsString( page, childNode.getAttribute( "file" ));
pushIncludeReference( includeFileName );
loadPage( packageName, includeFileName, true );
popIncludeReference( includeFileName );
componentFactory.setParentComponent( parentObject );
return null;
}
else if ( childName.equalsIgnoreCase( "attributes" )) {
loadAttributeSet( childNode );
return null;
}
// Load with a name like 'Button'
try {
if ( constraintStr == null )
comp = componentFactory.addComponent( childName,
x, y, w, h,
contentStr,
styleStr
);
else {
comp = componentFactory.addComponent( childName,
layoutHelper.getConstraint( constraintStr ),
contentStr,
styleStr
);
if (( x >= 0 ) || ( y >= 0 ))
adapter.setLocation( comp, x, y );
if (( w > 0 ) || ( h > 0 ))
adapter.setSize( comp, Math.max( 2, w ), Math.max( 2, h ));
}
}
catch ( Exception e ) {
if ( BuildProperties.DEBUG )
e.printStackTrace();
comp = null;
}
finally {
if ( comp == null ) {
componentAttributes.put( "x", xStr );
componentAttributes.put( "y", yStr );
componentAttributes.put( "w", wStr );
componentAttributes.put( "h", hStr );
Object obj = componentFactory.addElement( childName, nameStr, contentStr, componentAttributes );
if ( obj == null ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "BUILDER", "Unable to add component: " + nameStr );
// Try to find the class.
String clazz = (String)componentAttributes.get( "class" );
if ( clazz != null )
comp = componentFactory.addComponent( clazz, x, y, w, h, contentStr, styleStr );
// Construct a dummy component
if ( comp == null )
comp = componentFactory.addComponent( XPage.UNKNOWN, x, y, w, h, contentStr, styleStr );
componentAttributes.put( "type", childName );
}
}
}
if ( comp == null )
return null;
// Add the layout manager if one has been specified
/** @todo this method attempts to set all the attributes of the layout and it's parent as the
* attributes are embedded in the parent element. Need to separate the two and provide a separate
* element for the layout.
*/
if (( adapter.isContainer( comp )) && ( layoutMgr != null ))
componentFactory.addLayout( comp, layoutHelper.getLayoutType( layoutMgr ), layoutAttributes );
// Set the component name
adapter.setName( comp, nameStr );
// If a panel is found set it to the parent and recursively add its children
if ( adapter.isContainer( comp )) {
Object parentObject = componentFactory.getParentComponent();
componentFactory.setParentComponent( comp );
if ( "true".equals( eagerStr ))
setComponentAttributes( childName, comp, componentAttributes );
addComponents( comp, childNode );
currentAttributes = componentAttributes;
componentFactory.setParentComponent( parentObject );
adapter.doLayout( comp );
}
// Special handling for radio buttons
// For the first rb create a group
// For subsequent rbs add them to the group
// If another type of component is found reset the groups
if ( comp instanceof XRadioButtonGroup ) {
XRadioButtonGroup rb = ((XRadioButtonGroup)comp);
if ( checkBoxGroup == null ) {
// The radio button may already have a group
if ( rb.getRadioButtonGroup() == null )
checkBoxGroup = rb.createGroup();
else
checkBoxGroup = rb.getRadioButtonGroup();
}
else
rb.setRadioButtonGroup( checkBoxGroup );
}
else
checkBoxGroup = null;
// Now customize the component
String customization = (String)childNode.getAttribute( "customizer" );
if (( customization != null ) && ( customization.length() > 0 ))
customizer.customize( comp, customization, ComponentCustomizer.POST_CREATE_TIME );
// Setup any extra attributes specified in the XML
if ( !"true".equals( eagerStr ))
setComponentAttributes( childName, comp, componentAttributes );
}
catch ( Exception e ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "BUILDER", "While adding the component element: " + nameStr );
e.printStackTrace();
}
return comp;
}
/**
* Adds a menu to the application. Although specified in the XML as part of the
* page the menu is actually added to the application frame.
* @param page the page
* @param model the Menu XML element
*/
protected void addMenu( PageSupport page, XmlElement model )
{
Object parent = componentFactory.getParentComponent();
componentFactory.setParentComponent( page );
String basePackageName = currentProject.getWidgetPackageName() + ".X";
String attribStr;
WidgetAdapter adapter = WidgetAdapter.getInstance();
try {
// if ( adapter.requiresParent()) {
// Object[] args = new Object[ 1 ];
// args[ 0 ] = parent;
// menuBar = (XAppender)ReflectionHelper.constructViaReflection( basePackageName + XPage.MENUBAR, args );
// }
// else
menuBar = (XAppender)Class.forName( basePackageName + XPage.MENUBAR ).newInstance();
menuBar.setName( page.getName());
XStyle menuStyle = null;
String menuStyleName = model.getAttribute( "style" );
Color menuBkColor = null;
Color menuTextColor = null;
Font menuFont = null;
if (( menuStyleName != null ) && ( menuStyleName.length() > 0 )) {
menuStyle = currentProject.getStyleManager().getStyle( menuStyleName );
menuBkColor = menuStyle.getStyleAsColor( XStyle.COLOR_BACK );
menuTextColor = menuStyle.getStyleAsColor( XStyle.COLOR_FORE );
menuFont = currentProject.getStyleManager().getFont( menuStyleName );
adapter.setBackground( menuBar, menuBkColor );
adapter.setForeground( menuBar, menuTextColor );
adapter.setFont( menuBar, menuFont );
}
Vector menuNodes = model.getChildren();
int numMenus = menuNodes.size();
for ( int i = 0; i < numMenus; i++ ) {
XmlElement childNode = ( XmlElement )menuNodes.elementAt( i );
addMenu( menuBar, childNode, basePackageName,
menuStyle, menuBkColor, menuTextColor, menuFont );
}
menuBar.setup();
}
catch ( Exception ex ) {
ex.printStackTrace();
}
componentFactory.setParentComponent( parent );
}
private void addMenu( XAppender menuBar, XmlElement childNode,
String basePackageName, XStyle menuStyle,
Color menuBkColor, Color menuTextColor,
Font menuFont ) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
XAppender menu = null;
if ( adapter.requiresParent()) {
Object[] args = new Object[ 1 ];
args[ 0 ] = menuBar;
menu = (XAppender)ReflectionHelper.constructViaReflection( basePackageName + XPage.MENU, args );
}
else {
menu = ( XAppender )Class.forName( basePackageName + XPage.MENU ).newInstance();
}
((XTextHolder)menu).setText( componentFactory.translate( childNode.getAttribute( "content" ) ));
if ( menuStyle != null ) {
adapter.setBackground( menu, menuBkColor );
adapter.setForeground( menu, menuTextColor );
adapter.setFont( menu, menuFont );
}
addMenuItems( menu, childNode, basePackageName,
menuStyle, menuBkColor, menuTextColor, menuFont );
String attribStr = childNode.getAttribute( "enabled" );
if (( attribStr != null ) && attribStr.equals( "false" ))
adapter.setEnabled( menu, false );
attribStr = childNode.getAttribute( "visible" );
if (( attribStr != null ) && attribStr.equals( "false" ))
adapter.setVisible( menu, false );
menuBar.append( menu, childNode.getAttribute( "name" ) );
}
private void addMenuItems( XAppender menu, XmlElement childNode,
String basePackageName, XStyle menuStyle,
Color menuBkColor, Color menuTextColor,
Font menuFont ) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
int numMenuItems = childNode.getChildren().size();
for ( int j = 0; j < numMenuItems; j++ ) {
XmlElement itemNode = ( XmlElement )childNode.elementAt( j );
if ( itemNode.getName().equalsIgnoreCase( "Menu" )) {
addMenu( menu, itemNode,
basePackageName, menuStyle,
menuBkColor, menuTextColor,
menuFont );
}
else {
String menuText = itemNode.getAttribute( "content" );
if ( menuText != null ) {
Object menuItem = null;
if ( adapter.requiresParent()) {
Object[] args = new Object[ 1 ];
args[ 0 ] = menu;
menuItem = ReflectionHelper.constructViaReflection( basePackageName + XPage.MENUITEM, args );
}
else {
menuItem = Class.forName( basePackageName + XPage.MENUITEM ).newInstance();
}
if ( menuStyle != null ) {
adapter.setBackground( menuItem, menuBkColor );
adapter.setForeground( menuItem, menuTextColor );
adapter.setFont( menuItem, menuFont );
}
((XTextHolder)menuItem).setText( componentFactory.translate( menuText ));
if ( menuItem instanceof XAttributedComponent ) {
// Should these values be translated?
((XAttributedComponent)menuItem).setAttribute( "image", componentFactory.translate( itemNode.getAttribute( "image" )));
((XAttributedComponent)menuItem).setAttribute( "name", componentFactory.translate( itemNode.getAttribute( "name" )));
}
menu.append( menuItem, itemNode.getAttribute( "name" ) );
String attribStr = itemNode.getAttribute( "enabled" );
if (( attribStr != null ) && attribStr.equals( "false" ))
adapter.setEnabled( menuItem, false );
attribStr = itemNode.getAttribute( "visible" );
if (( attribStr != null ) && attribStr.equals( "false" ))
adapter.setVisible( menuItem, false );
}
else
menu.addSeparator();
}
}
}
/**
* Adds validation rules to the components
* @param page the page
* @param model the Validations XML element
*/
protected void addValidations( PageSupport page, XmlElement model )
{
Vector validations = model.getChildren();
int numValidations = validations.size();
for ( int i = 0; i < numValidations; i++ ) {
XmlElement childNode = ( XmlElement )validations.elementAt( i );
Object target = page.findComponent( childNode.getAttribute( "target" ));
String whenAttrib = childNode.getAttribute( "when" );
int whenAttribValue = FocusEvent.FOCUS_LOST;
if ( whenAttrib != null ) {
if ( whenAttrib.toLowerCase().compareTo( "mouseclicked" ) == 0 )
whenAttribValue = MouseEvent.MOUSE_CLICKED;
}
try {
page.addValidation( target, childNode.getAttribute( "rule" ), childNode.getAttribute( "method" ), whenAttribValue, childNode );
}
catch ( Exception e ) {
DebugLogger.logError( "BUILDER", "Could not create the validation - " + childNode.getAttribute( "rule" ) );
}
}
}
/**
* Store the scripts in the page
* @param page the current page
* @param scriptsNode the scripts xml node
*/
public void addScripts( PageSupport page, XmlElement scriptsNode )
{
page.setAttribute( "source", "scripts", scriptsNode.getContent().trim() );
}
/**
* Iterate through the attributes and set the attributes for a component
* @param comp the component
* @param attribs the attributes.
*/
protected void setComponentAttributes( String compType, Object comp, Hashtable attribs )
{
String compName = page.getComponentName( comp );
Enumeration e = attribs.keys();
while ( e.hasMoreElements() ) {
try {
String key = ( String )e.nextElement();
String value = ( String )attribs.get( key );
Object evaluatedAttribute = evaluateAttribute( page, value );
page.setAttribute( key, compName, evaluatedAttribute );
// Set a couple of key attributes
if ( key.compareTo( "visible" ) == 0 )
adapter.setVisible( comp, value.equals( "true" ) );
else if ( key.compareTo( "enabled" ) == 0 )
adapter.setEnabled( comp, value.equals( "true" ) );
else {
int rc = -1;
ComponentAdapter ca = componentFactory.getComponentAdapter( compType );
if ( ca != null )
rc = ca.setProperty( comp, key, value, null );
if (( rc < 0 ) && ( comp instanceof XAttributedComponent )) {
if ( comp instanceof XAttributedComponentEx )
rc = ((XAttributedComponentEx)comp).setAttribute( currentProject, key, evaluatedAttribute );
else
rc = ((XAttributedComponent)comp).setAttribute( key, evaluatedAttribute );
if ( rc < 0 )
rc = XAttributedComponentHelper.setAttribute( currentProject, comp, key.toLowerCase(), evaluatedAttribute );
}
/** @todo add a return type to the XAttributedComponent interface and check it
* so that if the attribute is not set try to use the bean api/reflection to
* set the attribute based on the attribute name */
if ( rc != 0 ) {
try {
ReflectionHelper.setViaReflection( "set" + key.substring( 0, 1 ).toUpperCase() + key.substring( 1 ),
comp, evaluatedAttribute );
}
catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
}
catch ( Exception ex ) {
ex.printStackTrace();
}
}
if ( comp instanceof XMultiAttributedComponent )
((XMultiAttributedComponent)comp).allAttributesSet();
}
/**
* Gets a reference to a menu object
* @param name the name of the menu item
* @return the named manu item
*/
protected Object getMenuItem( String name )
{
return menuBar.getObject( name );
}
/**
* Construct a validation factory appropriate to this builder
* @param validationFileName the validations file to read
* @return the validation factory
*/
protected XValidationFactory getValidationFactory( String validationFileName )
{
if (( validationFileName != null ) && ( validationFileName.length() > 0 )) {
try {
XValidationFactory vf = ( XValidationFactory )validationFactories.get( validationFileName );
if ( vf == null ) {
String validationFactName = currentProject.getStartupParam( "ValidationFactory" );
if (( validationFactName != null ) && ( validationFactName.length() > 0 )) {
Object[] params = new Object[ 1 ];
params[ 0 ] = currentProject;
vf = (XValidationFactory)ReflectionHelper.constructViaReflection( validationFactName, params );
}
else
vf = new XValidationFactory( currentProject );
vf.addConfigFile( "Project", validationFileName, true );
validationFactories.put( validationFileName, vf );
}
return vf;
}
catch ( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "BUILDER", "Unable to read the validations file: " + ex.getMessage() + ", " + ex.getMessage());
}
}
return null;
}
/**
* Convert a string to an int or else return the default value
* @param s the number as a string
* @param def the default value
* @return the converted value
*/
protected int getInt( String s, int def )
{
try {
return new Integer( s ).intValue();
}
catch ( NumberFormatException ex ) {
}
return def;
}
/**
* Get the table of component attributes
* @return the attributes hash table.
*/
public static Hashtable getCurrentAttributes()
{
return currentAttributes;
}
/**
* A method that the editor can overload to keep track of includes
*/
public void pushIncludeReference( String includeFileName )
{
}
/**
* A method that the editor can overload to keep track of includes
*/
public void popIncludeReference( String includeFileName )
{
}
/**
* A method that the editor can overload to keep track of repeats
*/
public void pushRepeatReference( String includeFileName )
{
}
/**
* A method that the editor can overload to keep track of repeats
*/
public void popRepeatReference( String includeFileName )
{
}
/**
* Get the page loader type - a unique name identifying the loader
* @return "xui"
*/
public String getType()
{
return "xui";
}
}