Stepping through a site navigator applet

Enhance your Web site with a convenient, hierarchial interface

Navigation tools can be used to improve the accessibility of a Web site by providing a clean, simple interface through which visitors can locate the deepest, darkest recesses of the site, without having to negotiate a maze of links, or having to wait for a search engine to imagine the most improbable page that happens to have a particular search string in it.

This article includes the following sections:

Overview of the problem

The navigator applet operates by opening a window displaying a list of the Web site contents. Users can easily navigate this list and select pages; the navigator displays further information about each selected page, and offers the user an option of opening up the selected page in a browser window.

Design-wise, the navigator applet should be

  • Accessible -- a user should be able to launch the navigator with a minimum of effort.
  • Non-intrusive -- the navigator's presence in a Web site should not affect visitors who don't want to use it.
  • Easy to use -- a novice should be able to use the navigator.
  • Efficient -- code size should be kept to a minimum to reduce download time.
  • Customizable -- the navigator should be easy to configure for different Web sites.

In the rest of this article, we will first describe the solution that we create, and then explain the workings of classes that comprise this solution.

Using navigator

The navigator is fairly easy to use. Clicking on the navigator applet brings up the navigator window, which displays a hierarchical view of its Web site.

Elements of the navigator tree are either folders or documents. Clicking on a closed folder will open the folder, revealing the contents of the folder (more documents and folders). Clicking on an open folder will close the folder.

When you click on any element of the tree, a brief description is displayed at the bottom of the navigator window. If you wish to view the selected page, simply click "Go!" (or double-click on the item). Folders and documents can both correspond to pages on the Web site.

Applet parameters

There are two aspects to configuring the navigator applet: the applet parameters and the site map file. Here's a rundown of the supported applet parameters:

  • bgcolor -- the applet background color, e.g. "#ffffff"; default gray
  • image -- the applet background image, e.g. "mySextant.gif"; default "images/sextant.gif"
  • target -- the target frame name, e.g. "aSubFrame"; default "_new". Used to drive frames; otherwise use the default for a new browser window
  • title -- the navigator window title, e.g. "My Site"; default "Sextant Navigator"
  • map -- the site map file, e.g. "myMap.txt"; default "siteMap.txt" (don't call it "site.map" or Apache Web servers will attempt to parse it as an image map file)
  • doc -- the document image, e.g. "myDoc.gif"; default "images/doc.gif"
  • dir -- the closed folder image, e.g. "myDir.gif"; default "images/dir.gif"
  • open -- the open folder image, e.g. "myOpenDir.gif"; default "images/openDir.gif"

For example, the parameters for the sample applet at the top of this page are:

<applet width=73 height=61 code="Sextant">
<param name="bgcolor" value="#ffffff">
<param name="image"   value="images/jwNav.gif">
<param name="title"   value="JavaWorld Site Map">
<param name="map"     value="/javaworld/jw-12-site-map.txt">
<param name="doc"     value="images/doc.gif">
<param name="dir"     value="images/dir.gif">
<param name="open"    value="images/openDir.gif">
</applet>

Site map file

Rather than choosing an elegant, rich, and parenthesized format for the site map file, we use an ugly, simple, but convenient format. While the former may be more aesthetically pleasing, the latter has the advantage of being easy to create and easy to parse.

Each entry in the map file must be on a separate line; each line consists of three parts separated by pipes (|). The first part is the URL for the navigator entry, the second part is the name that will appear in the navigator tree, and the third part is a description that will be displayed at the bottom of the navigator window. The tree structure is specified by preceding each line by a number of hyphens (-) that indicate the tree depth of the entry in the tree.

{ - }
<URL> | <name> | <description>

All entries in the site map file with no preceding hyphens will thus appear at root of the navigator tree. If you want an entry to be contained within a folder, simply place it following the parent and add one more hyphen. The site map for the adjacent navigator tree follows:

http://prominence.com/ | Prominence Dot Com | Prominence Dot Com Inc.
-http://prominence.com/java/ | Java Applets | ...
--http://prominence.com/java/poetry | Electromagnetic Poetry | ...
--http://prominence.com/java/doctor | Therapy | ...
-http://prominence.com/course/ | Intensive Java | ...
--http://prominence.com/course/outline.html | Outline | ...
http://www.att.com/ | AT&T | ...
http://www.dorchester.com/ | Dorchester | ...
-http://www.doorknob.com/ | Goonyards | ...

Overview of navigator classes

The navigator applet that we develop consists of four separate classes. The first, Sextant, is the actual navigator applet. This applet is embedded in a Web page, and displays an image that the user can click on to bring up the navigator.

The next class, Navigator, is the navigator window; this is a standalone Frame that displays a list of the Web site contents.

Instead of using the built-in List class for displaying a list of the Web site contents, we use our own custom widget. Two classes perform this task: Page

a simple Canvas, displays a hierarchical view of the site contents using a helper class, Element which represents the entries in the site list.

The details of these classes are given in the following sections. If you wish to skip this, simply follow this link.

Class Sextant

Class Sextant

The Sextant class is an applet that displays a background image, and brings up a navigator window when the user clicks on it. We used a similar technique described in an earlier JavaWorld article, using the Class.forName().newInstance() method to delay the loading of the extra navigator classes until the user actually clicks on the applet.

import java.awt.*;
import java.applet.*;
public class Sextant extends Applet {

This class extends Applet so that it can be embedded in a Web page.

  Image image;
  Frame frame;

The image variable holds the background image for this applet; the frame variable holds a reference to the actual navigator window when it is created.

  public void init () {
    System.out.println ("Sextant Navigator, merlin@prominence.com, http://prominence.com/\n" +
                        "Copyright (c) 1996 Prominence Dot Com Inc. All Rights Reserved.");
    String bgcolor = getParameter ("bgcolor");
    if (bgcolor != null) {
      try {
        setBackground (new Color (Integer.parseInt (bgcolor.substring (1), 16)));
      } catch (NumberFormatException ex) {
        System.out.println ("Invalid format for bgcolor: " + bgcolor);
      }
    }
    image = getImage (getDocumentBase (),
                      getParameter ("image", "images/sextant.gif"));

In the init() method, we set a background color based on the "bgcolor" parameter, and pick up a background image based on the "image" parameter. We don't create a navigator window here; we will delay creating the navigator until the user clicks on the applet.

  public String getParameter (String param, String def) {
    String result = getParameter (param);
    if (result != null)
      return result;
    else
      return def;
  }

This method returns the specified applet parameter, or the specified default value if the parameter is not defined.

  public void paint (Graphics g) {
    if (image != null) {
      int x = image.getWidth (this), y = image.getHeight (this);
      g.drawImage (image, (size ().width - x) / 2, (size ().height - y) / 2, this);
    }
  }

The paint() method displays the background image in the center of the applet.

  public boolean mouseDown (Event e, int x, int y) {
    if (frame == null) {
      showStatus ("Loading...");
      try {
        frame = (Frame) Class.forName ("Navigator").newInstance ();
      } catch (ClassNotFoundException ex) {
        System.out.println (ex);
      } catch (InstantiationException ex) {
        System.out.println (ex);
      } catch (IllegalAccessException ex) {
        System.out.println (ex);
      }
      frame.postEvent (new Event (frame, -1, this));
      frame.pack ();
    }
    frame.show ();
    return super.mouseDown (e, x, y);
  }
}

The mouseDown() method is perhaps the only interesting method in this class. If the frame variable is null then we must create a new navigator window. We display a status message to indicate that something is happening, and then we use Class.forName().newInstance() to create an instance of the Navigator class, catching the exceptions that can be thrown.

By using this mechanism to create the navigator, the Java runtime will not automatically download the Navigator class when the user visits a Web page with this applet. This makes the page load faster, and reduces the impact on visitors who don't wish to use the applet.

The Navigator class requires a reference to our applet in order to be able to pick up parameters and easily download images. We send the navigator a new Event, through its postEvent() method, with this as the argument of the event. This indirectly supplies the navigator with a reference to our applet, and again, bypasses the need for the Navigator class to be downloaded automatically with this class.

After we have created the navigator, we can pack and show the window. The pack() method resizes the navigator window to its preferred size.

  public void stop () {
    if (frame != null)
      frame.hide ();
  }

The navigator operates by calling the showDocument() method of class AppletContext. When the user leaves a page with a particular applet present, most browsers proceed to ignore any further requests that it makes to display new pages; this typically is accompanied by the browser calling the applet's stop() method.

Because our navigator will be inactive after the stop() method is called, we hide the window to prevent the users from becoming frustrated. This may be inappropriate for some browsers that stop applets that are simply no longer visible, but if this becomes a problem then we can simply remove this method.

Class Navigator

Class Navigator

The Navigator class is a frame that contains a navigator tree with an associated scrollbar, a label that displays further information about the currently selected navigator item, and a button marked "Go!".

This class automatically downloads the site map file in a separate thread using the URL class; download errors are displayed in the information label.

import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
public class Navigator extends Frame implements Runnable {

This class is a standalone Frame; we implement the Runnable interface in order to download the site map in a separate thread.

  Sextant parent;
  Page page;
  Scrollbar bar;
  Label status;
  Button go;
  String target;

The parent variable refers to the parent applet; page is the navigator page; bar is the navigator's scrollbar. Information about the current selection is displayed in the status label; the go button causes the current selection to be displayed in a browser frame identified by target.

  public Navigator () {
    super ("Sextant Navigator");
    setBackground (Color.black);
    setLayout (new BorderLayout (1, 1));
    Panel top = new Panel ();
    top.setBackground (Color.white);
    top.setLayout (new BorderLayout ());
    add ("Center", top);
    bar = new Scrollbar (Scrollbar.VERTICAL);
    top.add ("East", bar);
    page = new Page (bar);
    page.setFont (new Font ("Helvetica", Font.BOLD, 14));
    top.add ("Center", page);
    Panel bottom = new Panel ();
    bottom.setBackground (Color.white);
    bottom.setLayout (new BorderLayout ());
    add ("South", bottom);
    status = new Label ("Loading...");
    status.setForeground (Color.blue);
    status.setFont (new Font ("Helvetica", Font.PLAIN, 14));
    bottom.add ("Center", status);
    go = new Button ("Go!");
    go.setFont (new Font ("Helvetica", Font.BOLD, 14));
    bottom.add ("East", go);
  }

In the constructor we lay out the user interface. The layout is somewhat unusual in an effort to achieve a black line separating the top and bottom of the user interface.

We set the frame background to black and set a BorderLayout with a single-pixel inter-component spacing. We then add a white panel with some components to the top, and another white panel with some components to the bottom. The layout manager leaves a single-pixel gap between the panels, through which the black background shows.

  public void init (Sextant parent) {
    this.parent = parent;
    target = parent.getParameter ("target", "_new");
    if (parent.getParameter ("title") != null)
      setTitle (parent.getParameter ("title"));
    page.init (parent);
    new Thread (this).start ();
  }
1 2 3 Page 1
Page 1 of 3