Package net.xoetrope.xui

Source Code of net.xoetrope.xui.XApplicationContext

package net.xoetrope.xui;

import java.lang.reflect.Method;
import java.net.URL;

import java.awt.BorderLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
import java.util.Vector;

import net.xoetrope.data.XDataSource;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.debug.XLogWriter;
import net.xoetrope.registry.ComponentCustomizer;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.helper.ReflectionHelper;

/**
* @todo MAKE SURE TO CHECK THE TODOs BEFORE USING THIS CLASS!!!!s
* Change the use of XApplet within XProject to use this class instead
* /
*
* /**
* <p>This class that handles the setup and initialization of a XUI application.
* A reference to the application is stored in the project as "AppContext".
* <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003<br>
* License:      see license.txt
* @version $Revision: 1.8 $
*/
public class XApplicationContext implements XPageDisplay, WindowListener
{
  /**
   * The page manager
   */
  protected XPageManager pageMgr;
 
  /**
   * true if a popup window is in use
   */
  protected boolean bUseWindow;
 
  /**
   * The model data source
   */
  protected XDataSource modelDataSource;
 
  /**
   * The default model data source class
   */
  protected Class defaultSourceClass = net.xoetrope.data.XDataSource.class;
 
  /**
   * The Applet/Application/Startup instance
   */
  protected XStartupObject startupObject;
 
  /**
   * The width of the client area
   */
  protected int clientWidth = 800;
 
  /**
   * The height of the client area
   */
  protected int clientHeight = 600;
 
  protected XProject currentProject;
 
  protected String defaultTargetClass;
  protected WidgetAdapter adapter;
  protected String widgetSet;
 
  private static Object shutdownHook;
 
  /**
   * A default constructor. Most of the setup work is actually done by the initialize
   * method and is called by the main method or the init method depending on
   * whether or not an application of applet is being launched.
   * @param startObject the invoking startup object
   * @param args the optional command line arguments
   * <ol>
   * <li>the relative path to the startup file, defaults to startup.properties if no arguments are provided</li>
   * <li>the package name for the widgets e.g. "net.xoetrope.swing"</li>
   * </ol>
   */
  public XApplicationContext( XStartupObject startObject, String[] args)
  {
    this( startObject, "net.xoetrope.xui.XTarget", args );
  }
 
  /**
   * A default constructor. Most of the setup work is actually done by the initialize
   * method and is called by the main method or the init method depending on
   * whether or not an application of applet is being launched.
   * @param startObject the invoking startup object
   * @param defTargetClass the class name for the default target areas/containers
   * @param args optional arguments are (in order)
   * <ol>
   * <li>the relative path to the startup file, defaults to startup.properties if no arguments are provided</li>
   * <li>the package name for the widgets e.g. "net.xoetrope.swing"</li>
   * </ol>
   */
  public XApplicationContext( XStartupObject startObject, String defTargetClass, String[] args )
  {
    startupObject = startObject;
    currentProject = XProjectManager.getCurrentProject( startupObject );
    currentProject.setObject( "AppContext", this );
    currentProject.setObject( "StartupArgs", args );
    defaultTargetClass = defTargetClass;
   
    adapter = WidgetAdapter.getInstance();
    setup( args, true );
  }
 
  /**
   * <p>Load a secondary project. A secondary project is loaded at the behest of
   * the main project, and it is the main project's settings that control the
   * application's appearance with the secondary project(s) contribution content
   * and resources.</p>
   * <p>Secondary projects are specified as part of the projects resources, in a
   * 'projects.xml' file that contains an entry for each project to load </p>
   * @param projectElememt the xml element for the new project
   * @return 0 on successful loading, non zero otherwise.
   */
  protected int loadSecondaryProject( XmlElement projectElememt )
  {
    XProject mainProject = currentProject;
    try {
//      URL startupFile = new URL( currentProject.findResource( "startup.properties" ), projectElememt.getAttribute( "path" ) + "/resources/startup.properties" );
//      String argStr = projectElememt.getAttribute( "args" );
//      String classpathStr = projectElememt.getAttribute( "classpath" );
      String[] args = new String[ 0 ];
     
      XProject secondaryProject = currentProject = new XProject();
      URL path = new URL( currentProject.findResource( "startup.properties" ), projectElememt.getAttribute( "path" ) + "/");
      URL urls[] = new URL[ 7 ];
      urls[ 0 ] = path;
      urls[ 1 ] = new URL( path, "resources/" );
      urls[ 2 ] = new URL( path, "pages/" );
      urls[ 3 ] = new URL( path, "build/classes/" );
      urls[ 4 ] = new URL( path, "classes/" );
      urls[ 5 ] = new URL( path, "lang/" );
      urls[ 6 ] = new URL( path, "src/" );
           
      ClassLoader projectClassLoader = (ClassLoader)ReflectionHelper.constructViaReflection(
              "net.xoetrope.optional.resources.XProjectClassLoader",
              new Object[]{ currentProject, getClass().getClassLoader() });    
      ReflectionHelper.setViaReflection( "Urls", projectClassLoader, urls, URL[].class );     
           
      XProjectManager.setCurrentProject( secondaryProject );
      setup( args, false );     
    }
    catch ( Exception e ) {
      e.printStackTrace();
    }
    currentProject = mainProject;
    return 0;
  }
 
  /**
   * Setup the applet by setting paths and then initializing the applet. This
   * method is a stand-in for the main method, processing the commandline
   * parameters, so that its work is reusable and
   * does not needed to be redone by derived classes. This method should not be
   * called directly by user code.
   * @param args the optional command line arguments
   * <ol>
   * <li>the relative path to the startup file, defaults to startup.properties if no arguments are provided</li>
   * <li>the package name for the widgets e.g. "net.xoetrope.swing"</li>
   * </ol>
   * @param isMainProject true if this is the main project
   */
  protected void setup( String[] args, boolean isMainProject )
  {
    widgetSet = startupObject.getWidgetClassPackage();
    String classPackageName = ( args.length > 1 ) ? args[ 1 ] : widgetSet;
    currentProject.setPackageName( classPackageName );
    currentProject.setWidgetPackageName( classPackageName );
   
    setResourceFile(( args.length > 0 ) ? (String)args[0] : "startup.properties" );
    addSecondaryClassLoaders( classPackageName );
   
    String icon = currentProject.getStartupParam( "Icon" );
    if ( icon != null )
      startupObject.setIcon( currentProject.getImage( icon ) );
   
    String lafClass = currentProject.getStartupParam( "LAF" );
    if (( lafClass != null ) && !lafClass.equals( "System" )) {
      try {
        Class lafInstaller = Class.forName( lafClass.trim() );
        Class[] params = new Class[ 0 ];
        Method installMethod = lafInstaller.getDeclaredMethod( "installLaf", params );
        installMethod.invoke( null, (Object[])null );
      }
      catch ( Exception ex ) {
        if ( BuildProperties.DEBUG )
          System.out.println( "The Look and Feel installer is not configured correctly. The " + lafClass + " class could not be created and invoked. Please check the classpath and the LAF startup properties." );
      }
    }
   
    if ( isMainProject ) {
      try {
        BufferedReader projectsReader = currentProject.getBufferedReader( "projects.xml" );
        if ( projectsReader != null ) {
          XmlElement projects = XmlSource.read( projectsReader );
          if ( projects != null ) {
            Vector childProjects = projects.getChildren();
            int numChildProjects = childProjects.size();
            for ( int i = 0; i < numChildProjects; i++ ) {
              XmlElement childProject = (XmlElement)childProjects.elementAt( i );
             
              // Initialize the new project
              loadSecondaryProject( childProject );
            }
          }
        }
      }
      catch ( Exception e ) {
        e.printStackTrace();
      }
    }

    if ( currentProject.getStatus() == XProject.RESTARTING ) {
      Object mo = currentProject.getObject( "MenuBar" );
      startupObject.setApplicationMenuBar( mo );
    }
   
    initialise();
    currentProject.setStatus( XProject.STARTED );
  }
 
  /**
   * Shutdown and exit the application
   */
  public void shutdown()
  {
    if ( canClose())
      System.exit( 0 );
  }
 
  /**
   * <p>Construct a new builder and set the default package. XUI sometimes uses
   * additional class loaders to find the resources needed in a project. By default
   * XUI uses the XuiBuilder class loader to convert XML files to Java classes.</p>
   * <p>A custom class loader can be referenced in the startup properties file
   * using the 'BuilderClass' property. Once this property has been determined
   * this method will instantiate an instance of that class if necessary.
   * @param packageName the name of the default widget package e.g. net.xoetrope.awt,
   * this is normally defined as a result of choosing the appropriate version of
   * the XApplet class
   */
  protected void addSecondaryClassLoaders( String packageName )
  {
    XPageManager pageMgr = currentProject.getPageManager();
    String numBuilderClassesStr = currentProject.getStartupParam( "NumBuilderClasses" );
    int numBuilderClasses = 0;
    if ( numBuilderClassesStr != null )
      numBuilderClasses = Math.max( new Integer( numBuilderClassesStr ).intValue(), 0 );

    boolean defaultLoader = false;
    for ( int i = 0; i <= numBuilderClasses; i++ ) {
      String builderClass;
     
      if ( i == 0 )
        builderClass = currentProject.getStartupParam( "BuilderClass" );
      else
        builderClass = currentProject.getStartupParam( "BuilderClass" + new Integer( i-1 ).toString());
     
      XPageLoader pageLoader = null;
      if ( builderClass != null ) {
        try {
          pageLoader = (XPageLoader)ReflectionHelper.constructViaReflection( null, builderClass, XProject.class, currentProject );
        }
        catch ( Exception ex ) {
          DebugLogger.logError( "Unable to load builder class: " + ex.getMessage());
        }
      }
     
      // Load the default class if nothing else loaded
      if (( pageLoader == null ) && !defaultLoader ) {
        pageLoader = (XPageLoader)ReflectionHelper.constructViaReflection( null, "net.xoetrope.builder.XuiBuilder", XProject.class, currentProject );
        defaultLoader = true;
        Vector projectClassLoaders = currentProject.getCustomerClassLoaders();
        if (( projectClassLoaders != null ) && ( projectClassLoaders.size() > 0 )) {
          ClassLoader classLoader = ( ClassLoader )projectClassLoaders.elementAt( 0 );
          String startPackage = currentProject.getStartupParam( "StartPackage" );
          String startClass = currentProject.getStartupParam( "StartClass" );
          String classStr = startPackage + "." + startClass;         
         
          for ( int j = 0; j < projectClassLoaders.size(); j++ ) {
            ClassLoader cl = ( ClassLoader )projectClassLoaders.elementAt( j )
            try {
              if ( cl.loadClass( classStr ) != null ) {
                classLoader = cl;
                break;
              }             
            }
            catch ( Exception ex )
            {}
          }          
         
          pageLoader.setClassLoader( classLoader );       
        }
      }
     
      if ( pageLoader != null ) {
        pageLoader.setPackageName( packageName );
        if ( pageLoader != null )
          pageMgr.addSecondaryLoader( pageLoader );
      }
    }
  }
 
  /**
   * Sets the default datasource class. The default data source will be used to
   * provide any initial data for the XModel. Normally this data is static data
   * that will be used to populate things like lists and provide default values.
   * @param className the name of the datasource class
   * e.g. net.xoetrope.data.XDataSource.class, this class reads data from an XML file
   */
  public void setDefaultDataSource( String className )
  {
    try {
      defaultSourceClass = Class.forName( className.trim() );
    }
    catch ( ClassNotFoundException ex ) {
    }
  }
 
  /**
   * Setup the default resource file for the application and load some of the
   * information in it. The resource file is the startup properties file
   * @param startFile The name of the file to be loaded, by default startup.properties
   */
  protected void setResourceFile( String startFile )
  {
    currentProject.initialise( startFile );
   
    try {
      String sUseWindow = currentProject.getStartupParam( "UseWindow" );
      bUseWindow = sUseWindow.compareTo( "true" ) == 0 ? true : false;
      String temp = currentProject.getStartupParam( "ClientWidth" );
      if ( temp != null )
        clientWidth = Integer.parseInt( temp );
     
      temp = currentProject.getStartupParam( "ClientHeight" );
      if ( temp != null )
        clientHeight = Integer.parseInt( temp );
     
      // Check for subclassing of the datasource/model
      temp = currentProject.getStartupParam( "XDataSourceClass" );
      if ( temp != null )  {
        try {
          defaultSourceClass = Class.forName( temp.trim() );
        }
        catch ( Exception ex ) {
        }
      }
     
      // Create the startup objects
      int soCounter = 0;
      String soClassName = null;
      do {
        soClassName = (String)currentProject.getStartupParam( "StartupObject" + soCounter++ );
        if ( soClassName != null ) {
          try {
            int pos = soClassName.indexOf( ';' );
            String soName = soClassName.substring( 0, pos );
            soClassName = soClassName.substring( pos + 1 );
            pos = soClassName.indexOf( ';' );
            if ( pos > 0 ) {
              soClassName = soClassName.substring( 0, pos );
              Object so = ReflectionHelper.constructViaReflection( soClassName, XProject.class, currentProject );
              currentProject.setObject( soName, so );             
            }
            else {
              Class soClass = Class.forName( soClassName.trim() );
              currentProject.setObject( soName, soClass.newInstance());
            }
          }
          catch ( Exception ex ) {
            if ( BuildProperties.DEBUG )
              DebugLogger.logError( "Unable to create the startup object: " + soClassName );
          }
        }
      } while ( soClassName != null );
    }
    catch ( Exception ex ) {}
  }
 
  /**
   * Invoked when used as an applet. Sets up the startup file and initialises
   * the application. Reads the applet parameters and calls initialize.
   */
  public void init()
  {
    String classPackageName = startupObject.getWidgetClassPackage();
    currentProject.setPackageName( classPackageName );
    currentProject.setWidgetPackageName( classPackageName );
   
    setResourceFile( startupObject.getParameter( "StartFile" ) != null ? startupObject.getParameter( "StartFile" ) : "startup.properties" );
    addSecondaryClassLoaders( classPackageName );
    initialise();
  }
 
  /**
   * <p>Generic function which is called from the constructor if it's an application
   * or from start if its an applet.</p>
   * The initialization process proceeds in the following order<br>
   * <ol>
   * <li>Register the component factories</li>
   * <li>Setup the project class</li>
   * <li>Setup the page manager</li>
   * <li>Setup the resource manager</li>
   * <li>Setup the style manager</li>
   * <li>Size the main window</li>
   * <li>Set the layout</li>
   * <li>Add a shutdown hook</li>
   * <li>Display the main window</li>
   * </ol>
   * the style manager
   */
  protected void initialise()
  {
    boolean initialized = ( currentProject.getStatus() > XProject.INITIALIZED );
    if ( !initialized ) {
      // Setup a background log writer if specified
      String logWriter = currentProject.getStartupParam( "LogWriter" );
      if ( logWriter != null ) {
        try {
          Object logger = Class.forName( logWriter.trim() ).newInstance();
          DebugLogger.setOutputWriter( (XLogWriter)logger );
          Object errorLogger = Class.forName( logWriter.trim() ).newInstance();
          ((XLogWriter)errorLogger).setStream( true );
          DebugLogger.setErrorWriter( (XLogWriter)errorLogger );
        }
        catch ( Exception e )
        {
          if ( BuildProperties.DEBUG )
          {
            if ( logWriter.indexOf( "XQueueLogWriter" ) > 0 )
              DebugLogger.logWarning( "XQueueLogWriter requires JDK 1.5" );
          }
          e.printStackTrace();
        }
      }

      register();
    }
   
    try {
      URL db = startupObject.getDocumentBase();
      if ( db != null )
        currentProject.setDocumentBase( db );
    }
    catch ( Exception e ) {}
   
    startupObject.setupWindow( this, currentProject, clientWidth, clientHeight );
   
    if ( !initialized )
      addShutdownHook();
   
    setContent( initialized );
   
    startupObject.refresh();
  }
 
  /*
   * Add the shutdown hook if defined by the startup file
   */
  protected void addShutdownHook()
  {
    if ( !BuildProperties.BUILD_JDK_118 ) {
      // Try to create the shutdown hook, this is not supported on all VMs
      try {
        if ( shutdownHook == null )
          shutdownHook = ReflectionHelper.constructViaReflection( null,
              "net.xoetrope.xui.build.conditional.ShutdownHook",
              XProject.class,
              currentProject );
      }
      catch ( Exception ex ) {
        ex.printStackTrace();
      }
    }
  }
 
  /**
   * Add the lifecycle listener to the current project based upon the <code>LifeCycleListener</code>
   * startup parameter/property
   */
  public void addLifeCycleListener()
  {
    try {
      // Try to register a listener for the startup and shutdown events.
      String lifeCycleObjectName = currentProject.getStartupParam( "LifeCycleListener" );
      if (( lifeCycleObjectName != null ) && ( lifeCycleObjectName.length() > 0 )) {
        XLifeCycleListener lifeCycleObject = (XLifeCycleListener)Class.forName( lifeCycleObjectName.trim() ).newInstance();
       
        Class params[] = new Class[ 1 ];
        Object args[] = new Object[ 1 ];
        params[ 0 ] = XLifeCycleListener.class;
        args[ 0 ] = lifeCycleObject;
        Method method = shutdownHook.getClass().getMethod( "addLifeCycleListener", params );
        method.invoke( shutdownHook, args );
      }
    }
    catch ( InvocationTargetException ex ) {
      ex.getCause().printStackTrace();
    }
    catch ( Exception ex ) {
      ex.printStackTrace();
    }
  }
 
  /**
   * Can the application close? If a life cycle listener has been added then
   * its canClose method is invoked
   */
  public boolean canClose()
  {
    try {
      Class params[] = new Class[ 1 ];
      Object args[] = new Object[ 1 ];
      params[ 0 ] = XProject.class;
      args[ 0 ] = currentProject;
      Method method = shutdownHook.getClass().getMethod( "canClose", params );
      Object obj = method.invoke( shutdownHook, args );
      if ( obj != null )
        return ((Boolean)obj).booleanValue();
    }
    catch ( InvocationTargetException ex ) {
      ex.getCause().printStackTrace();
    }
    catch ( Exception ex ) {
      ex.printStackTrace();
    }
   
    return true;
  }
 
  /**
   * Load the componentFactories by reading the factory names from the startup
   * file. The value of the 'NumComponentFactories' is first read and then
   * the value of ComponentFactory<X> (i.e. ComponentFactory0, ComponentFactory1)
   * where <X> is the number, starting at zero, of the factory. Each factory is
   * then instantiated and will be called upon to construct components in the
   * order in which the factories were registered.
   */
  protected void register()
  {
    int numFactories = 0;
    String numFactoriesStr = currentProject.getStartupParam( "NumComponentFactories" );
   
    if ( numFactoriesStr != null )
      numFactories = new Integer( numFactoriesStr ).intValue();
   
    for ( int i = 0; i < numFactories; i++ ) {
      String factoryName = currentProject.getStartupParam( "ComponentFactory" + i );
      try {
        if ( factoryName != null ) {
          XComponentConstructor ctor = (XComponentConstructor)ReflectionHelper.constructViaReflection( null,
              factoryName,
              XProject.class,
              currentProject );
          XComponentFactory.registerComponentFactory( factoryName, ctor );
        }
      }
      catch ( Exception ex ) {
        if ( BuildProperties.DEBUG )
          DebugLogger.logError( "Factory not loaded: " + ex.getMessage());
      }
    }
   
    try {
      String widgetFamily = widgetSet.substring( widgetSet.lastIndexOf( '.' ) + 1);
      if ( !"awt".endsWith( widgetFamily )) {
        String factoryName = widgetFamily.substring( 0, 1 ).toUpperCase() + widgetFamily.substring( 1 ).toLowerCase() + "ComponentFactory";
        String factoryClass = "net.xoetrope." + widgetFamily.toLowerCase() + "." + factoryName;
        XComponentConstructor ctor = (XComponentConstructor)ReflectionHelper.constructViaReflection( null,
            factoryClass,
            XProject.class,
            currentProject );
        XComponentFactory.registerComponentFactory( factoryName, ctor );
      }
    }
    catch ( Error ex ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logError( "Factory not loaded: " + ex.getMessage());
    }
  }
 
  /**
   * Load the content into the model. In the process an instance of the default
   * model data source class is instantiated and reads data from a file pointed
   * to by the 'ModelData' startup parameter.
   */
  protected void setContent( boolean initialized )
  {
    if ( !initialized ) {
//    boolean sourceExists = false;
      try {
        modelDataSource = (XDataSource)ReflectionHelper.constructViaReflection( null, defaultSourceClass, XProject.class, currentProject );
        currentProject.setObject( "ModelDataSource", modelDataSource );
      }
      catch ( Exception ex2 ) {
        return;
      }

      try {
        String fileName = currentProject.getStartupParam( "ModelData" );
        if ( fileName != null ) {
          try {
            modelDataSource.read( currentProject.getBufferedReader( fileName, null ) );
          }
          catch ( Exception ex3 ) {
            if ( BuildProperties.DEBUG )
              DebugLogger.logError( "Could not access file:" + fileName );
          }
        }
      }
      catch ( Exception ex ) {
        if ( BuildProperties.DEBUG )
          DebugLogger.logError( "Exception in setContent" );
      }

      addLifeCycleListener();
    }
   
    startupObject.setAppTitle( currentProject.getStartupParam( "Title" ) );
    setHome();
  }
 
  /**
   * Set the home page using the startup properties. The home page is established
   * by combining the two startup properties 'StartPackage' and 'StartClass'. By
   * default 'StartClass' is set to a value of 'home. Both startup parameters
   * are optional. Load the first page for the application.
   */
  public void setHome()
  {
    try {
      String packageName = currentProject.getStartupParam( "StartPackage" );
      String homePage = currentProject.getStartupParam( "StartClass" );
      if (( packageName == null ) && (( homePage == null ) || ( homePage.length() == 0 )))
        homePage = "home";
     
      if ( packageName != null )
        packageName += ".";
     
      pageMgr = currentProject.getPageManager();
      pageMgr.setPackageName( packageName );
      pageMgr.setPageDisplay( this );
     
      if (( homePage != null ) && !homePage.equals( "NONE" ))
        pageMgr.showPage( homePage );
    }
    catch ( Exception ex ) {
      ex.printStackTrace();
    }
  }
 
  /**
   * Called when a page has been added or shown via the XPageManager. The page manager
   * then requests that the applet/application then displays the page in the
   * appropriate location.
   * @param page The XPage which has been loaded.
   * @return the page being displayed
   */
  public Object displayPage( PageSupport page )
  {
    return displayPage( page, null );
  }
 
  /**
   * <p>Called when a page has been added or shown via the XPageManager. The page manager
   * then requests that the applet/application then displays the page in the
   * appropriate location.</p>
   * <p>
   * The sequence with which the page transition occurs is as follows:
   * </p>
   * <li>Find the appropriate target area</li>
   * <li>Ask the page to make its components non visible (to avoid flicker during the page update)</li>
   * <li>Set the page size</li>
   * <li>Save the current page's data by calling 'saveBoundComponentValues</li>
   * <li>Mark the current page as deactivated, and call the page's deactivated() method</li>
   * <li>Remove the old page from the container</li>
   * <li>Add the new page</li>
   * <li>Update the new page's bindings by calling updateBindings()</li>
   * <li>Update the new page's data by calling updateBoundComponentValues()</li>
   * <li>Layout the container and request it to repaint</li>
   * <li>Show the new page</li>
   * <li>Mark the new page as activated, and call its pageActivated method</li>
   * <ol>
   * </ol>
   * @return the page being displayed
   * @param pageObj the page to display
   * @param target the area to update
   */
  public Object displayPage( PageSupport pageObj, String target )
  {
    return displayPage( pageObj, target, null );
  }
 
  /**
   * <p>Called when a page has been added or shown via the XPageManager. The page manager
   * then requests that the applet/application then displays the page in the
   * appropriate location.</p>
   * <p>
   * The sequence with which the page transition occurs is as follows:
   * </p>
   * <li>Find the appropriate target area</li>
   * <li>Ask the page to make its components non visible (to avoid flicker during the page update)</li>
   * <li>Set the page size</li>
   * <li>Save the current page's data by calling 'saveBoundComponentValues</li>
   * <li>Mark the current page as deactivated, and call the page's deactivated() method</li>
   * <li>Remove the old page from the container</li>
   * <li>Add the new page</li>
   * <li>Update the new page's bindings by calling updateBindings()</li>
   * <li>Update the new page's data by calling updateBoundComponentValues()</li>
   * <li>Layout the container and request it to repaint</li>
   * <li>Show the new page</li>
   * <li>Mark the new page as activated, and call its pageActivated method</li>
   * <ol>
   * </ol>
   * @param pageObj the page to dosplay
   * @param target the name of the target area to update
   * @param attributes attributes for use by the new page / taregt
   * @return the page being displayed
   */
  public Object displayPage( PageSupport pageObj, String target, Object attributes )
  {
    PageSupport page = pageObj;
    startupObject.restoreViews();
    XContentHolder targetContainer = (XContentHolder)findTarget( target );
    if ( targetContainer == null )
      return null;
   
    adapter.setSize( page, clientWidth - ( bUseWindow ? 0 : 8 ), clientHeight - ( bUseWindow ? 0 : 34 ));
   
    adapter.setVisible( page, true );
   
    PageSupport lastPage = null;
    try {
      lastPage = (PageSupport)targetContainer.getChildComponent( 0 );
    }
    catch ( Exception e )
    {}
   
    if ( page != lastPage ) {
      targetContainer.setNextAttributes( attributes );
      targetContainer.add( page, BorderLayout.CENTER );
      page.pageAdded();
     
      if ( lastPage != null ) {
        lastPage.saveBoundComponentValues();
        targetContainer.remove( lastPage );
        page.setStatus( XPage.DEACTIVATED );
        try {
          lastPage.pageDeactivated();
        }
        catch ( Exception ex1 ) {
          if ( BuildProperties.DEBUG )
            DebugLogger.logError( "The pageDeactivated method could not be invoked due to an exception" );
        }
      }
     
      try {
        page.updateBindings();
        page.updateBoundComponentValues();
      }
      catch ( Exception ex2 ) {
        if ( BuildProperties.DEBUG )
          DebugLogger.logError( "The page (" + pageObj.getName() + ") bindings caused an exception and the page did not fully initialize" );
      }
     
      targetContainer.doLayout();
      adapter.doLayout( page );
    }
    else {
      page.updateBindings();
      page.updateBoundComponentValues();
    }
   
    targetContainer.doLayout();
    adapter.setVisible( page, true );
    adapter.repaint( page );
   
    /** @todo fix */
    //adapter.validate( page );
    adapter.doLayout( page );
   
    ComponentCustomizer customizer = (ComponentCustomizer)currentProject.getObject( "ComponentCustomizer" );
    customizer.activateCustomize();
   
    page.setStatus( XPage.ACTIVATED );
    try {
      page.pageActivated();
    }
    catch ( Exception ex )
      {
      if ( BuildProperties.DEBUG ) {    
        DebugLogger.logError( "The pageActivated method could not be invoked due to an exception" );
        ex.printStackTrace();
      }
    }
    page.setStatus( XPage.DISPLAYED );
   
    return page;
  }
 
  /**
   * Display a window decoration, for example a toolbar
   * @param page the new page
   * @param constraint a value controlling how and where the decoration is
   * displayed, this value is application type specific
   * @return the page being displayed
   */
  public Object displayDecoration( PageSupport page, String constraint )
  {
    return startupObject.displayDecoration( page, constraint );
  }
 
  /**
   * Update the page display layout
   */
  public void doLayout()
  {
    adapter.doLayout( startupObject.getContentPaneEx());
  }
 
  /**
   * Remove the page from container. The page is simply removed and the container validated.
   * @param page the page to hide
   */
  public void hidePage( PageSupport page )
  {
    PageSupport lastPage = null;
    Object container = startupObject.getContentPaneEx();
   
    try {
      lastPage = (PageSupport)adapter.getComponent( container, 0 );
     
      if (( lastPage != null ) && ( page != lastPage )) {
        adapter.remove( container, lastPage );
       
        page.setStatus( XPage.DEACTIVATED );
        page.pageDeactivated();
       
        adapter.doLayout( container );
        startupObject.validate();
      }
    }
    catch ( Exception e ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logError( "The page could not be hidden due to an exception: " + e.getMessage() );
    }
  }
 
  /**
   * Finds the target area for a page display request, this only applies to a
   * frameset. If there is no frameset the main area or default area is named
   * 'content' and this area is used if null is used as the target name.
   * @param target the target area name
   * @return the container to be updated
   */
  public Object findTarget( String target )
  {
    Object targetContainer = startupObject.getContentPaneEx();
    if ( target == null )
      target = BuildProperties.CONTENT_TARGET;
   
    int numChildren = adapter.getComponentCount( targetContainer );
    for ( int i = 0; i < numChildren; i++ ) {
      Object comp = adapter.getComponent( targetContainer, i );
      String name = adapter.getName( comp );
      if (( name != null ) && name.equals( target ))
        return comp;
    }
    return null;
  }
 
  /**
   * Get the target for a page display request. The target areas are stored in
   * the order in which they were declared or added.
   * @param idx the target area
   * @return the container to be updated
   */
  public Object getTarget( int idx )
  {
    Object targetContainer = startupObject.getContentPaneEx();
    return adapter.getComponent( targetContainer, idx );
  }
 
  /**
   * Get the number of targets in the container
   * @return the number of targets
   */
  public int getNumTargets()
  {
    Object targetContainer = startupObject.getContentPaneEx();
    return adapter.getComponentCount( targetContainer );
  }
 
  /**
   * Setup frameset. This method is called prior to the addition of any target
   * areas in the framset and prior to the display of any pages
   * @param params the framset parameters if any
   */
  public void setupFrameset( Hashtable params )
  {
    startupObject.setupFrameset( params );
  }
 
  /**
   *@todo cleanup return type
   */
  /**
   * Add a new frame or target area to a frameset
   * @param name the frame name
   * @param constraint the BorderlayoutConstraint
   * @param preferredWidth the preferred width
   * @param preferredHeight the preferred height
   * @param params extra parameters for the target
   * @return the selected target
   */
  public net.xoetrope.xui.XContentHolder addTarget( String name, Object constraint, int preferredWidth, int preferredHeight, Hashtable params )
  {
    Object root = startupObject.getContentPaneEx();
    XContentHolder container = null;
    try {
      Class contentHolderClass = Class.forName( defaultTargetClass.trim());
      container = (XContentHolder)contentHolderClass.newInstance();
    }
    catch ( Exception e ) {
      Throwable t = e.getCause();
      if ( t != null )
        t.printStackTrace();
      DebugLogger.logWarning( "Could not load the frame/target from the classpath" );
    }
   
    if ( container == null ) {
      try {
        if ( adapter.requiresParent()) {
          Object[] args = new Object[ 1 ];
          args[ 0 ] = root;
          container = (XContentHolder)ReflectionHelper.constructViaReflection( defaultTargetClass, args );
        }
        else {
          Class contentHolderClass = startupObject.getClass().getClassLoader().loadClass( defaultTargetClass );
          container = (XContentHolder)contentHolderClass.newInstance();
        }
      }
      catch ( Exception e )
      {
        e.printStackTrace();
      }
    }
   
    if ( container != null ) {
      /** @todo this adjustment should really be made in the editor as there is
       *no proper way of making the adjustment at runtime */
      int deltaH = 0;
      if ( ((String)constraint).equalsIgnoreCase( "CENTER" ) && !bUseWindow )
        deltaH = 34;
      container.setup( name, preferredWidth - ( bUseWindow ? 0 : 8 ), preferredHeight - deltaH, params );
      adapter.add( root, container, constraint );
      return container;
    }
    return null;
  }
 
  /**
   * Remove all frames/targets from the current frameset
   */
  public void removeAllTargets()
  {
    adapter.removeAll( startupObject.getContentPaneEx());
  }
 
  /**
   * Set the name of the default target class
   * @param clsName the class name
   */
  public void setDefaultTargetClass( String clsName )
  {
    defaultTargetClass = clsName;
  }
 
  /**
   * Exit the application
   * @param e the window event
   */
  public void windowClosing( WindowEvent e )
  {
    if ( canClose()) {
      currentProject.setStatus( XProject.CLOSING );
      boolean canExit = !( "false".equals( currentProject.getStartupParam( "ExitOnClose" )));   
      currentProject.setStatus( XProject.TERMINATED );     
      if ( canExit )
        System.exit( 0 );
      else
        e.getWindow().dispose();
    }
  }
 
  /**
   * Get the width of the main window. Retrieved from the startup file or
   * defaulted
   * @return the client width
   */
  public int getClientWidth()
  {
    return clientWidth;
  }
 
  /**
   * Get the height of the main window. Retrieved from the startup file or
   * defaulted
   * @return the client height
   */
  public int getClientHeight()
  {
    return clientHeight;
  }
 
  /**
   * Template method, unused at present
   * @param e the window event
   */
  public void windowActivated( WindowEvent e )
  {}
 
  /**
   * Template method, unused at present
   * @param e the window event
   */
  public void windowClosed( WindowEvent e )
  {}
 
  /**
   * Template method, unused at present
   * @param e the window event
   */
  public void windowDeiconified( WindowEvent e )
  {}
 
  /**
   * Template method, unused at present
   * @param e the window event
   */
  public void windowDeactivated( WindowEvent e )
  {}
 
  /**
   * Template method, unused at present
   * @param e the window event
   */
  public void windowIconified( WindowEvent e )
  {}
 
  /**
   * Template method, unused at present
   * @param e the window event
   */
  public void windowOpened( WindowEvent e )
  {}
}
TOP

Related Classes of net.xoetrope.xui.XApplicationContext

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.