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 )
{}
}