You are hereAria User Guide / Section III: In Depth / Navigation and Page Management

Navigation and Page Management


By luano - Posted on 14 January 2009

Aria provides all the infrastructure necessary to manage pages within an application whether the pages are created with XML or via Java. The page manager at the heart of Aria also provides support for framesets and page history management.

The page management function is separated from the application and from the individual pages to provide independence of the underlying widget set.

Navigation

In Aria each page can be regarded as a discrete entity displayed by the application or applet. All pages must be derived from the basic Page class and this class interacts with the PageManager class to provide several methods of changing the displayed page. The page manager acts to maintain references to pages so that they do not need to be recreated whenever they are displayed, hidden or redisplayed.

In order to get a reference to the PageManager for the current project the call below can be used.

Retrieving the PageManager for the current project

  1. ProjectManager.getPageManager();

The main methods are showPage and showPrevious , which unsurprisingly show a new page and redisplay the previously selected page.

To invoke these methods it is necessary to add a way of initiating the navigation action. Normally this is accomplished by having a button or hostpot on the page with a text or graphic to indicate that a click will cause, say the next page to be displayed.

In the example below the user can initiate the navigation action by clicking on a button.

Setting up the navigation button and response event

  1. <Page class="myPackage.MyCustomPageClass">
  2. <Components>
  3. ...
  4. <Button name="btnProceed" x="40" y="10" w="60" h="20" content="Proceed"/>
  5. </Components>
  6. <Events>
  7. ...
  8. <Event method="proceed" target="btnProceed" type="ActionHandler"/>
  9. </Events>

The page must then implement the proceed response method. The Page class contains a reference to the PageManager for the current Project and can be used directly from subclassed Pages as shown below:

Implementing the response method

  1. package myPackage;
  2.  
  3. import org.formaria.aria.*;
  4. import org.formaria.swing.*;
  5. import org.formaria.aria.data.*;
  6. import org.formaria.aria.helper.*;
  7.  
  8. public class MyCustomPageClass extends Page
  9. {
  10.  
  11. public MyCustomPageClass()
  12. {
  13. }
  14.  
  15. ...
  16.  
  17. public void proceed()
  18. {
  19. pageMgr.showPage( "Page2");
  20. }
  21. }
  22.  

The page manager

The Aria page manager provides a mechanism for loading and displaying pages. It takes care of managing the page's lifecycle so that you need not be concerned with when and how a page is loaded or destroyed.

When an application requests a page by calling the showPage method the actual loading of the page is delegated to the page manager. The page manager will then attempt to load an XML file corresponding by name to the requested page. If an XML file is not found then the page manager will attempt to load a Java class of that name (and failing that, a dummy page can be created).

The page manager also takes care of the page lifecycle, calling the pageCreated, pageActivated and pageDeactivated methods as appropriate.

As the pages are separated from one another and from the applet class through this page manager mechanism the pages can be loaded independently of each other (unless explicit links or references are inserted). Furthermore, as the page manager is also separate from the applet and the widget set it is possible to code a large variety of utility functions so that they can work with different widget sets such as Swing and AWT.

Showing a page

A few simple methods are provided to allow loading and display of pages. It is generally assumed that all page handling will be delegated to the page manager and this is the case whenever the Page 's methods are used to display pages and this is the case for the normal response methods used in Aria applications.

The showPage method simply takes the name of a page. An alternative form of the showPage method can also take a second parameter indicating the target area (but more on this later). The showPage method loads the page as described above and requests that the applet displays the page. Implicitly in this process any currently visible page is deactivated and hidden.

Once a page has been shown it is regarded as the current page and at any point the current page can be referenced by calling the page manager's getCurrentPage method.

The showPage call can also include a URL so that the page can be loaded from a remote source. In fact most resource specifications in Aria can include URLs in this way.

Targets

Aria supports the notion of framesets similar to those used in HTML. Like HTML the framesets in Aria are defined in a separate frames file (pointed to by the startup properties file).

Each of the areas referenced by the frames file is known as a target area. Most of the page management methods include versions that take a target area name as a parameter and these functions affect the named area. Thus if you use the showPage method with a target area name, the area named in the method call is updated instead of the application's entire content area.

In cases where a frameset is used it is still possible to call the single argument versions of the page management functions. It is then assumed that the target area name defaults to ` content'.

Generally this default name works well where the frameset is being used to provide navigation facilities and other long lived facilities such as banners and footer. (see also Framesets.)

Page history

In addition to the showPage method Aria also provides the showPrevious method. As a page is shown, the history/order of the displayed pages is saved and the showPrevious method allows you to reverse through this order of pages. The showPrevious method works in much the same way as showPage and in fact relies on the same mechanisms to update the application.

Page history should be used with caution as it does not necessarily correspond to the end user's notion of what the previous page was. Furthermore if the user has navigated through a loop of pages then over use of the showPrevious method could lead to confusion.

Frequently there may be a need for multiple navigation mechanisms to help avoid such situations. It may be that it is just the user's perception of the order of pages that is out of sync with the way things are implemented and therefore we recommend adding visual feedback to your application to help support navigation.

Visual feedback should let the user know where they are within the application, how far they have progressed and how far they have to go to completion. The type of feedback used will of course vary from application to application and will also depend on the visual styles employed but whatever the detail, such hints greatly aid usability.

Resetting the page cache

On rare occasions it may be necessary to reset the page cache and page history. Some instances of this occur whenever the bound data is changed or reloaded from a different source, when a language changes or when it is necessary to reset all pages, removing user inputs.

To reset the page cache in this way use the following code:

Reset the page cache

  1. // Use the Page's member variable pageMgr!
  2. pageMgr.reset();

Page loaders

Aria employs an extensible method of loading pages. The page manager normally loads pages from XML or from Java classes if it cannot find a suitable XML page. This process can be altered by setting up secondary page loaders. The page loader is described by the PageLoader interface and can be configured through the startup property value for BuilderClass and NumBuilderClasses. Aria includes several page loaders including Aria's default page loader, an HTML page loader (see Importing HTML.) and a generic page loader for loading forms and other file formats (see Importing forms.).

Dataset defined navigation

When applications which use pages in a particular sequence are being written such as application forms consisting of multiple pages or wizard applications it is possible to define those pages in a static XML dataset file. For example in the code sample below, pages are defined within in a dataset file for a wizard type application.

  1. <Datasets>
  2. <dataset id="navigation">
  3. <dataset id="wizardpages">
  4. <data value="welcome"/>
  5. <data value="projectinit" desc="WIZ_PROJ_SET"/>
  6. <data value="languagepage" desc="WIZ_PROJ_LANG"/>
  7. <data value="colourscheme" desc="WIZ_PROJ_LAYOUT"/>
  8. <data value="finish" desc="WIZ_PROJ_FINISH"/>
  9. </dataset>
  10. </dataset>
  11. </Datasets>
  12.  

This dataset file needs to be referenced from the datasources file which is in turn loaded from the ModelData startup property. For more on loading datasets see See Data management.. Once loaded, the application will have access to these definitions via the DataModel for the project. There are three possible paths declared in this wizard dataset, `wizardpages', `generationpages' and `buildpages'. The relevant path can be set upon clicking a button, a menu or seleting a radio button.

A singleton class can then be written which takes care of the navigation and of course the pages referenced by the value attribute of the model nodes need to exist on the classpath.

NavigationManager Singleton class

  1. public class NavigationManager {
  2.  
  3. BaseModel navMdl;
  4. protected int currentNode = 0;
  5. BasePage currentPage;
  6. private static NavigationManager navMgr;
  7.  
  8. private NavigationManager( String navPath ) {
  9. navMdl = ( BaseModel ) ProjectManager.getModel().get( "navigation/wizardpages" );
  10. }
  11.  
  12. public static NavigationManager getInstance()
  13. {
  14. if ( navMgr == null )
  15. navMgr = new NavigationManager()
  16.  
  17. return navMgr;
  18. }
  19.  
  20. public static void next()
  21. {
  22. getInstance.showNextPage();
  23. }
  24.  
  25. public static void prev()
  26. {
  27. getInstance.showPrevPage();
  28. }
  29.  
  30. public void showPrevPage()
  31. {
  32. currentNode--;
  33. showpage();
  34.  
  35. }
  36.  
  37. public void showNextPage()
  38. {
  39. if ( currentPage == null ) {
  40. BaseModel mdl = (BaseModel) navMdl.get( currentNode );
  41. String pagename = (String) mdl.get();
  42. currentPage = (BasePage) ProjectManager.getPageManager().getPage( pagename );
  43. }
  44. if ( currentPage.checkValidations() == 0 ) {
  45. currentNode++;
  46. showpage();
  47. }
  48. }
  49.  
  50. public void showHomePage()
  51. {
  52. currentPage = null;
  53. currentNode = 0;
  54. BaseModel mdl = (BaseModel) navMdl.get( currentNode );
  55. String pagename = (String) mdl.get();
  56. currentPage = (BasePage) ProjectManager.getPageManager().showPage( pagename );
  57. }
  58.  
  59. private void showpage()
  60. {
  61. BaseModel mdl = ( BaseModel ) navMdl.get( currentNode );
  62. String pagename = ( String ) mdl.get();
  63. currentPage = ( BasePage ) ProjectManager.getPageManager().showPage( pagename );
  64. }
  65.  
  66. }

This mechanism can be used in conjunction with Library Functions to manage the page navigation in a simple and easy to maintain way. Take the following XML page declaration for example.

A navigation page XML declaration

  1. <Page class="net.co.test.NavPanel" style="Heading">
  2. <Components>
  3. <Image name="nextButton" x="564" y="51" w="19" h="18" content="right.gif"/>
  4. <Image name="prevButton" x="60" y="54" w="19" h="18" content="left.gif"/>
  5. </Components>
  6. <Events>
  7. <Event method="net.co.test.NavigationManager.next" target="nextButton" type="MouseHandler"/>
  8. <Event method="net.co.test.NavigationManager.prev" target="prevButton" type="MouseHandler"/>
  9. </Events>
  10. </Page>
  11.  

This code will call the static methods of the NavigationManager class and the NavigationManager will take care of presenting the correct page. Of course this can be extended to take care of multiple routes through an application or to repeat certain pages which will bind to different parts of the model and it should be obvious that pages can be added or rearranged without any difficulty.

Mapping page names

A page name can now be paramaterized or mapped, so that a frames file or startup.properties file can specify a key instead of a page name. This key can then be mapped to a specific page depending on the context or on startup parameters.

Setup the application lifecycle listener to set the initial page name

  1. // In startup.properties specifc the Lifecycle object
  2. // LifeCycleListener=my.project.ProjectListener
  3.  
  4. // In that object map the "START_PAGE" page name
  5. public class ProjectListener implements LifeCycleListener
  6. {
  7. /**
  8.   * Called when the application/applet has been created and initialized.
  9.   * @param project the owner project
  10.   */
  11. public void initialize( Project p )
  12. {
  13. String[] args = (String[])project.getObject( "StartupArgs" );
  14. // Set the start page to the 3rd command-line parameter
  15. p.getPageManager().mapPageName( "START_PAGE", args[ 3 ] );
  16. }
  17. }

and instead of hardcoding a page name in the frames file it can be replaced with the appropriate key:

Set the content using a key instead of a page name

  1. // In the frames.xml include the "START_PAGE" key
  2. <Frame name="content" constraint="content" width="500" height="200"
  3. content="START_PAGE" title="Home" icon="ac0036-16.png" sidebar="west"/>