Package net.xoetrope.xui

Source Code of net.xoetrope.xui.MetaContentReader

package net.xoetrope.xui;

import java.io.StringReader;
import java.util.Hashtable;
import java.util.Enumeration;
import java.lang.reflect.Constructor;

import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xui.data.XModel;
import net.xoetrope.xui.helper.XTranslator;
import net.xoetrope.registry.ComponentAdapter;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.helper.XLayoutHelper;

/**
* <p>A component factory. The factory is designed to create components
* for a null layout. The factory will use an incrementing id to name each component.
* When an XPanel is added it will automatically become the parent for subsequent
* components added using the factory. If another parent component is needed then
* the parent can be explicitly set.
* </p>
* <p>
* When components are added their size is checked against that of the parent and
* reduced if they extend beyond the bounds of the parent.
* </p>
* <p>
* The component factory can be extended by registering new XComponentConstructors.
* These constructors are invoked if the build in constructors cannot build the
* specified type.
* </p>
* <p>
* Components can be specified by a type name, an type constant or by a class name.
* The type constants for the built-in components are specified in XPage so as
* to make referencing the constants easier in the client code (subclasses of XPage).
* The package name is set as an attribute of the factory so that various versions
* of the widgets can be create for say Swing and AWT without needing to create
* distinct factories and without need to include such implementation details in
* the client code.
* </p>
* <p>Copyright (c) Xoetrope Ltd., 2002-2003</p>
* <p>License: see license.txt</p>
* $Revision: 2.21 $
*/
public class XComponentFactory
{
  // Built-in component types
  /**
   * A component of a type that is unknown to XUI (i.e. not one of the built in types)
   */
  public final static int XUNKNOWN = -1;
 
  /**
   * A panel / container
   */
  public final static int XPANEL = 0;

  /**
   * A static text
   */
  public final static int XLABEL = 1;
  /**
   * A constant used internally to identify a RadioButton.
   */
  public final static int XRADIO = 2;
  /**
   * A constant used internally to identify a Checkbox.
   */
  public final static int XCHECK = 3;
  /**
   * A constant used internally to identify a Combo Box.
   */
  public final static int XCOMBO = 4;
  /**
   * A constant used internally to identify a List.
   */
  public final static int XLIST = 5;

  /**
   * A constant used internally to identify an image component.
   */
  public final static int XIMAGE = 6;

  /**
   * A constant used internally to identify a Edit field.
   */
  public final static int XEDIT = 7;
  /**
   * A constant used internally to identify a push buttob.
   */
  public final static int XBUTTON = 8;
  /**
   * A constant used internally to identify a container for tagged content.
   */
  public final static int XMETACONTENT = 9;
  /**
   * A constant used internally to identify a RadioButton group.
   */
  public final static int XGROUP = 10;
  /**
   * A constant used internally to identify a scroll panel.
   */
  public final static int XSCROLLPANE = 11;
  /**
   * A constant used internally to identify a scrollable meta content.
   */
  public final static int XSCROLLABLEMETACONTENT = 12;
  /**
   * A constant used internally to identify a hotspot image.
   */
  public final static int XHOTSPOTIMAGE = 13;
  /**
   * A constant used internally to identify a table component.
   */
  public final static int XTABLE = 14;
 
  /**
   * A constant used internally to identify a vector image component.
   */
  public final static int XWMF = 15;
 
  /**
   * A constant used internally to identify an annotated image component.
   */
  public final static int XANNOTATEDIMAGE = 16; // DROPPED -merged with imagemap
 
  /**
   * A constant used internally to identify a MenuBar.
   */
  public final static int XMENUBAR = 17;
 
  /**
   * A constant used internally to identify a Menu.
   */
  public final static int XMENU = 18;
 
  /**
   * A constant used internally to identify a Menu item.
   */
  public final static int XMENUITEM = 19;
 
  /**
   * A constant used internally to identify a multiline text edit component.
   */
  public final static int XTEXTAREA = 20;
 
  /**
   * A constant used internally to identify a password field.
   */
  public final static int XPASSWORD = 21;

  /**
   * A constant used internally to identify an image map.
   */
  public final static int XIMAGEMAP = 22;
 
  /**
   * A constant used internally to identify a tab panel.
   */
  public final static int XTABPANEL = 23;
 
  /**
   * A constant used internally to identify a splitter.
   */
  public final static int XSPLITPANE = 24;

  /**
   * A collection of component factories
   */
  protected static Hashtable componentFactories = new Hashtable();

  /**
   * A collection of component type names and ids used to aid construction of components
   */
  protected static Hashtable typeNames;

  /**
   * A helper to construct various layout managers
   */
  protected static LayoutHelper layoutHelper = new XLayoutHelper();

  /**
   * A flag indicating is the components require the parent object to be passed
   * as an argumnet to the constructor.
   */
  protected static boolean requiresParent = false;

  /**
   * The package to which the widgets belong
   */
  protected String basePackageName;

  /**
   * The translator used for translation
   */
  protected XTranslator translator;

  /**
   * The project that owns this factory
   */
  protected XProject currentProject;

  /**
   * The adapter used for the current package's widgets
   */
  protected WidgetAdapter adapter;

  /**
   * The application's menu bar
   */
  protected Object currentMenuBar;

  /**
   * The current menu. Menu construction is slightly abnormal for the factory and
   * requires additional parameters
   */
  protected Object currentMenu;

  /**
   * The parent panel to which components are added
   */
  protected Object parentPanel;

  protected int parentW, parentH;

  /**
   * Constructs a component factory
   * @param proj The project to which the fctory belongs
   * @param packageName the package name for the components
   */
  public XComponentFactory( XProject proj, String packageName )
  {
    currentProject = proj;
    if ( packageName == null )
      packageName = XPage.XUI_AWT_PACKAGE;

    adapter = WidgetAdapter.getInstance();
    basePackageName = packageName + "." + "X";
    setupTypeNames();
   
    translator = currentProject.getTranslator();
  }

  /**
   * Set the resource bundle for this component factory. The resource bundle is used
   * for translation of text and other content.
   * @param resourceBundleName the resource bundle name
   */
  public void setResourceBundle( String resourceBundleName )
  {
    if ( translator == null )
      translator = currentProject.getTranslator( resourceBundleName );
   
    if ( translator != null )
      translator.setResourceBundle( currentProject.getResourceBundle( resourceBundleName ));
  }

  /**
   * A generic factory for constructing XComponents.
   * @param type a name identifying the type of component to be created
   * @param content the component text/content
   * @return the new component
   */
  public Object constructComponent( String type, String content )
  {
    int id = getTypeCode( type );
    if ( id < 0 )
      return buildRegisteredComponent( type, content );

    Object comp = null;
    try {
      switch ( id ) {
        case XPANEL:
          comp = instantiate( basePackageName + XPage.PANEL );
          if ( parentPanel == null )
            parentPanel = comp;
          break;

        case XLABEL:
          comp = instantiate( basePackageName + XPage.LABEL );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XRADIO:
          comp = instantiate( basePackageName + XPage.RADIO );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XCHECK:
          comp = instantiate( basePackageName + XPage.CHECK );
          ( ( XTextHolder )comp ).setText( translate( content ) );
          break;

        case XCOMBO:
          comp = instantiate( basePackageName + XPage.COMBO );
          break;

        case XLIST:
          comp = instantiate( basePackageName + XPage.LIST );
          break;

        case XIMAGE:
          comp = instantiate( basePackageName + XPage.IMAGE );
          currentProject.getImage( (XImageHolder)comp, content );
          break;

        case XIMAGEMAP:
          comp = instantiate( basePackageName + XPage.IMAGEMAP );
          ( ( XImageHolder )comp ).setImage( currentProject.getImage( content ) );
          break;

        case XEDIT:
          comp = instantiate( basePackageName + XPage.EDIT );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XTEXTAREA:
          comp = instantiate( basePackageName + XPage.TEXTAREA );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XPASSWORD:
          comp = instantiate( basePackageName + XPage.PASSWORD );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XBUTTON:
          comp = instantiate( basePackageName + XPage.BUTTON );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XMETACONTENT:
          comp = instantiate( basePackageName + XPage.METACONTENT );
          if ( content != null )
            setMetaContent( comp, content );
          break;

        case XSCROLLPANE:
          comp = instantiate( basePackageName + XPage.SCROLLPANE );
          break;

        case XSCROLLABLEMETACONTENT:
          comp = instantiate( basePackageName + XPage.SCROLLABLEMETACONTENT );
          setMetaContent( comp, content );
          break;

        case XHOTSPOTIMAGE:
          comp = instantiate( basePackageName + XPage.HOTSPOTIMAGE );
          ( ( XImageHolder )comp ).setImage( currentProject.getImage( content ) );
          break;

        case XTABLE:
          comp = instantiate( basePackageName + XPage.TABLE );
          setTableContent( comp, content );
          break;

        case XWMF:
          comp = instantiate( "net.xoetrope.xui.wmf.XWmf" );
          if ( content != null )
            ((XTextHolder)comp).setText( translate( content ));
          break;

        case XTABPANEL:
          comp = instantiate( basePackageName + XPage.TABPANEL );
          break;

        case XSPLITPANE:
          comp = instantiate( basePackageName + XPage.SPLITPANE );
          break;

        default:
          break;
      }
    }
    catch ( Exception e ) {
      e.printStackTrace();
    }
    return comp;
  }

  /**
   * Instantiate a component using reflection to locate the constructor. This
   * method of creating a component is used where the parent object or some
   * other constructor argument is required to create the component.
   * @param className the class to instantiate
   * @return the new component
   */
  protected Object instantiate( String className )
  {
    try {
      Class clazz = Class.forName( className.trim());
      if ( !requiresParent )
        return clazz.newInstance();
      else {
        Class[] parameterTypes = new Class[ 1 ];
        parameterTypes[ 0 ] = Object.class;
        Constructor ctor = clazz.getConstructor( parameterTypes );
        Object[] args = new Object[ 1 ];
        args[ 0 ] = parentPanel;
        return ctor.newInstance( args );
      }
    }
    catch ( Exception e ) {
      e.printStackTrace();
    }

    return null;
  }

  /**
   * Look up the translation of a key using the current language resource
   * @param key the key string
   * @return the translation
   */
  public String translate( String key )
  {   
    if ( translator != null )
      return translator.translate( key );
    else
      return key;
  }

  /**
   * A generic factory for adding XComponents. The component is constructed,
   * positioned and added to the parent panel if one exists. This method
   * delegates to the registered component factories if any. All built in
   * components are constructed with an ID.
   * When a ScrollPane is addd it becomes the parent.
   * @param type a name identifying the type of component to be created
   * @param x the left coordinate
   * @param y the top coordinate
   * @param w the width
   * @param h the height
   * @param content the component text/content
   * @return the new component
   */
  public Object addComponent( String type, int x, int y, int w, int h, String content )
  {
    Object comp = null;
    try {
      comp = constructComponent( type, content );
      if ( comp == null )
        comp = buildRegisteredComponent( type, content );

      if ( comp == null ) {
        String typeName = type.trim();
        if ( type.indexOf( "." ) <= 0 )
          typeName = basePackageName + typeName;
       
        comp = Class.forName( typeName ).newInstance();
        if ( comp instanceof XTextHolder )
          ((XTextHolder)comp ).setText( content );
      }
      if ( comp == null )
        return null;

      if (( parentW > 0 ) && ( w > 0 )) {
        /**
         * @todo consider using an SWT Component factory so as to remove these
         * nuances of SWT to an SWT specific class.
         */
        String className = parentPanel.getClass().getName();
        if ( className.indexOf( "ScrollPane" ) < 0 )
          adapter.setBounds( comp, x, y, Math.min( w, parentW - x ), Math.min( h, parentH ) );
        else if ( className.indexOf( ".swt." ) > 0 )
          adapter.setBounds( comp, x, y, w, h );
      }
      else if ( w > 0 )
        adapter.setBounds( comp, x, y, w, h );

      if ( comp != null ) {
        addComponent( comp );
        return comp;
      }
    }
    catch ( Exception ex ) {     
      if ( BuildProperties.DEBUG ) {  
        DebugLogger.logWarning( "Could not instantiate type: " + type );       
       
        ex.printStackTrace();
        Throwable t = ex.getCause();
        if( t != null )
          t.printStackTrace();
      }
    }
    return comp;
  }

  /**
   * A generic factory for adding XComponents. The component is constructed,
   * positioned and added to the parent panel if one exists. This method
   * delegates to the registered component factories if any. All built in
   * components are constructed with an ID.
   * When a ScrollPane is addd it becomes the parent.
   * @param type a name identifying the type of component to be created
   * @param pos the constraint
   * @param content the component text/content
   * @return the new component
   */
  public Object addComponent( String type, Object pos, String content )
  {
    Object comp = null;

    try {
      comp = constructComponent( type, content );

      //-------------------------------------------------
      /**
       * @todo check if this block of code is reachable or has an effect as the
       * construct component method calls buildRegisteredComponent.
       */
      if ( comp == null ) {
        comp = buildRegisteredComponent( type, content );
      }
      //-------------------------------------------------
      if ( comp != null ) {
        if ( pos != null )
          addComponent( comp, pos );
        else
          addComponent( comp );

        return comp;
      }
    }
    catch ( Exception e ) {
      e.printStackTrace();
    }
    return comp;
  }

  /**
   * A generic factory for adding registered components via the
   * XComponentConstructor interface or component factories.
   * @param type  a name identifying the type of component to be created
   * @param content the component text/content
   * @return the new component
   */
  protected Object buildRegisteredComponent( String type, String content )
  {
    Enumeration enumeration = componentFactories.keys();
    while ( enumeration.hasMoreElements() ) {
      XComponentConstructor factory = ( XComponentConstructor )componentFactories.get( enumeration.nextElement() );
      Object comp = factory.constructComponent( this, type, content );
      if ( comp != null )
        return comp;
    }
    return null;
  }

  /**
   * Lookup the component adapter for the named type
   * @param type  a name identifying the type of component to be created
   * @return the new component adapter for the type
   */
  public ComponentAdapter getComponentAdapter( String type )
  {
    Enumeration enumeration = componentFactories.keys();
    while ( enumeration.hasMoreElements() ) {
      XComponentConstructor factory = ( XComponentConstructor )componentFactories.get( enumeration.nextElement() );
      ComponentAdapter ca = factory.getComponentAdapter( type );
      if ( ca != null )
        return ca;
    }
    return null;
  }

  /**
   * Add a componentFactory to the static register of component constructors
   * @param name the name by which this factory will be known.
   * @param factory the new componentFactory
   */
  public static void registerComponentFactory( String name, XComponentConstructor factory )
  {
    if ( componentFactories.get( name ) == null )
      componentFactories.put( name, factory );
  }

  /**
   * Notify the component factories that some of their settings may have changed
   */
  public static void updateComponentFactories()
  {
    Enumeration enumeration = componentFactories.keys();
    while ( enumeration.hasMoreElements() ) {
      XComponentConstructor factory = ( XComponentConstructor )componentFactories.get( enumeration.nextElement() );
      factory.update();
    }
  }

  /**
   * Get the component factories
   * @return a the factor store.
   */
  public static Hashtable getFactories()
  {
    return componentFactories;
  }

  /**
   * Add a non-component object to the panel or an element of the panel. This method
   * is invoked is the XuiBuilder fails to construct a component for an XML element
   * @param type the object type
   * @param name  a name identifying the element to be created
   * @param content the component text/content
   * @param attribs the element attributes if any
   * @return the new component
   */
  public Object addElement( String type, String name, String content, Hashtable attribs )
  {
    Enumeration enumeration = componentFactories.keys();
    while ( enumeration.hasMoreElements() ) {
      XComponentConstructor factory = ( XComponentConstructor )componentFactories.get( enumeration.nextElement() );
      Object obj = factory.addElement( this, type, name, content, attribs );
      if ( obj != null )
        return obj;
    }
    return null;
  }

  /**
   * Add a component to the panel.
   * @param c the component to add
   */
  public void addComponent( Object c )
  {
    if (( c != parentPanel ) && ( parentPanel != null ))
      adapter.add( parentPanel, c );
  }

  /**
   * Add a component to the panel.
   * @param c the component to add
   * @param constraint the layout manager constraint
   */
  public void addComponent( Object c, Object constraint )
  {
    if ( c != parentPanel )
      adapter.add( parentPanel, c, constraint );
  }

  /**
   * Sets a LayoutManager for the panel
   * @param cont the container whose layout manager is being set or null to set the parent panel's layout manager
   * @param type the layout manager as defined in the XLayoutHelper class
   * @return the new layout manager instance
   */
  public Object addLayout( Object cont, int type )
  {
    if ( cont == null )
      cont = parentPanel;
    return layoutHelper.addLayout( cont, type );
  }

  /**
   * Change the parent for new components. This method will affect the next component added.
   * @param c the new parent, this should be an instance of java.awt.Container
   */
  public void setParentComponent( Object c )
  {
    parentPanel = c;
    if ( parentPanel != null ) {
      int w = adapter.getWidth( parentPanel );
      int h = adapter.getHeight( parentPanel );
      parentW = w;
      parentH = h;
    }
  }

  /**
   * Get the current parent component
   * @return the parent component.
   */
  public Object getParentComponent()
  {
    return parentPanel;
  }

  /**
   * Get the layout helper
   * @return the layout helper
   */
  public static LayoutHelper getLayoutHelper()
  {
    return layoutHelper;
  }

  /**
   * Set the layout helper
   * @param newHelper the new layout helper
   */
  public static void setLayoutHelper( LayoutHelper newHelper )
  {
    layoutHelper = newHelper;
  }

  /**
   * Set the content for XMetaContentHolder objects
   * @param comp
   * @param content
   */
  private void setMetaContent( Object comp, String content )
  {
    if ( content == null )
      return;

    boolean useContent = false;
    if ( content.indexOf( "<?xml") != 0 )  {
        String res = translate( content );

        if ( res.compareTo( content ) != 0 ) {
          content = res;
          useContent = true;
        }
    }
    else
       useContent = true;

    MetaContentReader cr = new MetaContentReader( currentProject, comp, content, useContent );
    cr.start();
  }

  /**
   * Set the content for XTable objects
   * @param comp
   * @param content
   */
  private void setTableContent( Object comp, String content )
  {
    if ( content != null ) {
      XModel xm = ( XModel )currentProject.getModel().get( content );
      ( ( XModelHolder )comp ).setModel( xm );
    }
  }

  /**
   * Get the type constant associated with a type name
   * @param typeName the type name
   * @return the type constant
   */

  protected static int getTypeCode( String typeName )
  {
    String key;
    setupTypeNames();
    if ( typeName.indexOf( '.' ) > 0 )
      typeName = typeName.substring( typeName.lastIndexOf( '.' ) + 1 );
    if ( typeName.charAt( 0 ) == 'X' )
      key = typeName.substring( 1, typeName.length() );
    else
      key = typeName;

    Object retObj = typeNames.get( key.toUpperCase() );
    if ( retObj == null )
      return -1;

    return ( ( Integer )retObj ).intValue();
  }

  /**
   * Setup a hashtable of type names. This will be moved to a helper class at some stage
   */
  protected static void setupTypeNames()
  {
    if ( typeNames == null ) {
      typeNames = new Hashtable( 34 );
      addTypeName( XPage.PANEL, XPANEL );
      addTypeName( XPage.LABEL, XLABEL );
      addTypeName( XPage.RADIO, XRADIO );
      addTypeName( "RADIOBUTTON", XRADIO );
      addTypeName( XPage.CHECK, XCHECK );
      addTypeName( "CHECK", XCHECK );
      addTypeName( XPage.COMBO, XCOMBO );
      addTypeName( "COMBO", XCOMBO );
      addTypeName( XPage.LIST, XLIST );
      addTypeName( XPage.IMAGE, XIMAGE );
      addTypeName( XPage.IMAGEMAP, XIMAGEMAP );
      addTypeName( XPage.EDIT, XEDIT );
      addTypeName( XPage.TEXTAREA, XTEXTAREA );
      addTypeName( XPage.BUTTON, XBUTTON );
      addTypeName( XPage.METACONTENT, XMETACONTENT );
      addTypeName( XPage.GROUP, XGROUP );
      addTypeName( XPage.SCROLLPANE, XSCROLLPANE );
      addTypeName( XPage.SCROLLABLEMETACONTENT, XSCROLLABLEMETACONTENT );
      addTypeName( XPage.HOTSPOTIMAGE, XHOTSPOTIMAGE );
      addTypeName( "HOTSPOT", XHOTSPOTIMAGE );
      addTypeName( XPage.TABLE, XTABLE );
      addTypeName( XPage.WMF, XWMF );
      addTypeName( XPage.MENUBAR, XMENUBAR );
      addTypeName( XPage.MENU, XMENU );
      addTypeName( XPage.MENUITEM, XMENUITEM );
      addTypeName( XPage.PASSWORD, XPASSWORD );
      addTypeName( XPage.UNKNOWN, XUNKNOWN );
      addTypeName( XPage.TABPANEL, XTABPANEL );
      addTypeName( XPage.SPLITPANE, XSPLITPANE );
    }
  }

  /**
   * Add a type name to the table of types. The type names are used to recognize
   * the xml elements in the page description
   * @param name the type name
   * @param value the corresponding id
   */
  private static void addTypeName( String name, int value )
  {
    typeNames.put( name.toUpperCase(), new Integer( value ) );
  }

  /**
   * Flags whether or not the component constructors require the parent as an
   * argument. Set to false by default.
   * @param b true to pass the parent to the constructor
   */
  public static void setRequiresParent( boolean b )
  {
    requiresParent = b;
  }
}

/**
* Description: Loads the meta content in a background thread</p>
*/
class MetaContentReader extends Thread
{
  private String content;
  private Object comp;
  private boolean useContent;
  private XProject currentProject;

  /**
   * Construct and initialize a new MetaContentReader
   * @param proj the current project
   * @param c the MetaContent component
   * @param source the resource name of the content file.
   * @param useCont true to use the source argument as the content, false to treat it as the name of an external file.
   */
  MetaContentReader( XProject proj, Object c, String source, boolean useCont )
  {
    currentProject = proj;
    useContent = useCont;
    comp = c;
    content = source;
  }

  /**
   * Read and setthe content on a background thread
   */
  public void run()
  {
    try {
      if ( content != null ) {
        XmlElement src;
        if ( !useContent ) {
          src = XmlSource.read( currentProject.getBufferedReader( content, null ) );
          ( ( XMetaContentHolder ) comp ).setContent( content, src );
        }
        else {
          StringReader reader = new StringReader( content );
          src = XmlSource.read( reader );
          ( ( XMetaContentHolder ) comp ).setContent( content, src );
        }
      }
    }
    catch ( Exception ex ) {
      DebugLogger.logWarning( "Unable to load content: " + content );
      DebugLogger.logWarning( "Please check the case of the file name" );
      ex.printStackTrace();
    }
  }
}
TOP

Related Classes of net.xoetrope.xui.MetaContentReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.