# 7

# JCOutliner

Introduction · Concepts · Sample Program Code

Color and Fonts Properties · Outliner Sizing · Column and Row Display Properties

Row and Column Visibility · Scrollbar Properties · Setting the Selection Mode

Node Properties · Folder Appearance · Events

Property Listing · Example Program

## Introduction

Outliners (also known as "trees") are standard Graphical User Interface (GUI) components common to most windowing systems which enable the display of hierarchically-organized data. The data items can be organized into columns for easier display. The `JCOutliner` component enables Java developers to display hierarchical data such as file systems, catalogs, ordered lists, and organization charts in the form of a tree. Each item is either a folder (a tree branch) or an item (a tree leaf). Each folder or item is displayed with an icon to its left. The appearance of each node is specified by a style. Column labels can also be optionally added. `JCOutliner` has many features including column resizing and reordering. There is no equivalent to `JCOutliner` in the classes provided with the AWT.

The user can control whether the data contained in a folder is to be displayed. The user can collapse or uncollapse a folder by either double-clicking on the folder, hitting the space key, or clicking on an optional shortcut button displayed to the left of the folder. Typing a character will cause the first item which starts with the character to be made visible and selected. If no item can be found, no action is taken.

The following illustration shows examples of the kinds of data that can be displayed using `JCOutliner`.

Example JCOutliner application

#### Behavior

The data displayed by the `JCOutliner` component is assumed to be in the form of a tree. Each item of data is either a folder (a branch of the tree) or an item (a leaf of the tree).

Data displayed in a tree

The end-user can control whether the data contained in a folder is to be displayed or not; if the data is not displayed, the folder is collapsed. The end-user can collapse or un-collapse a folder by either clicking on the folder or clicking on the shortcut button. `JCOutliner` follows standard Windows 95 behavior in this regard.

The shortcut button contains a character that indicates whether a folder is collapsed. If the button contains a "+" character, the folder is collapsed. If it contains a `"`--`"` character, the data contained in a folder is displayed.

Shortcut button behavior

#### Keyboard traversal

The cursor keys can be used within a `JCOutliner` to navigate through its various nodes and folders. The UP and DOWN cursor keys enable the user to move between items. If the user is over a closed folder and clicks the RIGHT cursor key, `JCOutliner` opens the folder and displays its children. Alternately, clicking the ENTER key toggles the state of the folder that has focus. The PAGE UP and PAGE DOWN keys move focus to the top and bottom of the displayed outline respectively, and the HOME and END keys take the user to the top and bottom of the outline respectively.

## Concepts

The `JCOutliner` component is a component that displays hierarchical information in the form of a tree. Each item of data in the tree is called a node ; the node data itself consists of one or more text strings called node labels . The area in which nodes are displayed is called the node area .

Nodes are of two types: items and folder nodes . The only difference between these two types of nodes is that a folder node can have zero or more children. Each node is indented to the right of its parent, and a root node must exist. The root node need not be visible, in which case all of its children are displayed at the right margin. There are two different node types in `JCOutliner`: the `JCOutlinerNode` object, which represents an item, and the `JCOutlinerFolderNode` object, which represents a folder node. The `JCOutlinerFolderNode` object is subclassed from the `JCOutlinerNode` object, which means that `JCOutlinerFolderNode` can use methods defined for `JCOutlinerNode`.

The following figure illustrates these components and objects, and the tree concept.

Outliner terminology

## Sample Program Code

The best way to describe many of the common features in JClass BWT `JCOutliner` is to examine the code in a sample program that uses it. The following code builds a simple, interactive Outline using `JCOutliner` components:

    package jclass.bwt.examples;
    import jclass.bwt.BWTEnum;
    import jclass.bwt.JCItemEvent;
    import jclass.bwt.JCOutliner;
    import jclass.bwt.JCOutlinerEvent;
    import jclass.bwt.JCOutlinerFolderNode;
    import jclass.bwt.JCOutlinerListener;
    import jclass.bwt.JCOutlinerNode;
    import jclass.bwt.JCOutlinerNodeStyle;
    import jclass.contrib.ContribFrame;
    import jclass.util.JCUtilConverter;
    import jclass.util.JCVector;
    import java.awt.*;
    /**
     * This example demonstrates the use of a JCOutliner and its events.
     */
    public class outliner extends java.applet.Applet implements JCOutlinerListener {
    final static String[] column_labels = {
    	"Name", "Title", "Address", "Phone", "Salary"
    };
    final static String dept[] = { "Management", "Accounting", "R&D" };
    final static String mgmt_items[] = {
    "John Kricfalusi|President|983 Nickelodeon Street, Rexdale Ontario|(414) 999-9876|$10,000",
    "Hikaru Takei|VP|134 Adelaide Street, Suite 204, Toronto Ontario|(416) 594-1026|$23K",
    "James Q. Doohan|Director|1701 Planetia Blvd., Anytown, U.S.A.||$245,000"
    };
    final static String accounting_items[] = {
    "Hikaru I. Takei|Payroll|134 Adelaide Street E., Suite 204, Anytown, U.S.A.|(999) 594-1026",
    "Melissa A. Truman|Receivable|475 Woodview Line, Anytown, U.S.A.|(999) 555-9030|$50,250",
    "Stephanie L. Truman|Payroll|388 Appleby Road, Anytown, U.S.A.|(999) 555-2642|$85,750"
    };
    final static String rd_items[] = {
    "James Q. Doohan|Engineer|1701 Planetia Blvd., Anytown, U.S.A.||$245,000",
    "John F. Kricfalusi|Physicist|983 Nickelodeon Street, Anytown, U.S.A.|(999) 555-9876|$10,000",
    "Marc Lenard|Engineer|6 Gene Crescent, Anytown, U.S.A.|(999) 555-1212|$10/hr.",
    "Hikaru I. Takei|Musician|134 Adelaide Street E., Suite 204, Anytown, U.S.A.|(999) 594-1026|50%",
    "Melissa A. Truman|QA|475 Woodview Line, Anytown, U.S.A.|(999) 555-9030|$50,250",
    "Stephanie L. Truman|Technical Writer|388 Appleby Road, Anytown, U.S.A.|(999) 555-2642|$85,750",
    "Bill West|System Analyst|1001 Spumco Way, Anytown, U.S.A.|(999) 555-9966|$17,500"
    };
    final static String[][] item_data = { mgmt_items, accounting_items, rd_items };
    Image content_icon;
    /**
     * JCOutlinerListener methods
     */
    /*
     * Adds items to a folder if it is opened, and destroys them
     * when it is closed.
     * It simulates the reading of the data from a database.
     */
    public void outlinerFolderStateChangeBegin(JCOutlinerEvent ev) {
    	JCOutlinerFolderNode folder = (JCOutlinerFolderNode) ev.getNode();
    	JCOutliner outliner = (JCOutliner) ev.getSource();
    	// Ignore root node
    	if (folder == outliner.getRootNode())
    		return;
    	// Create and add children to folder
    	else if (ev.getNewState() == BWTEnum.FOLDER_OPEN_ALL) {
    		if (folder.getChildren() != null)
    			return;
    		int pos = ((Integer)folder.getUserData()).intValue();
    		String[] items = item_data[pos];
    		JCOutlinerNodeStyle style = new JCOutlinerNodeStyle();
    		style.setItemIcon(content_icon);
    		for (int i=0; i < items.length; i++) {
    			JCVector label = outliner.getConverter()
    				.toVector(this, items[i], '|', false);
    			JCOutlinerNode newItem = new JCOutlinerNode(label);
    			newItem.setStyle(style);
    			folder.addNode(newItem);
    		}
    	}
    	// Destroy folder's nodes
    	else if (ev.getNewState() == BWTEnum.FOLDER_CLOSED) {
    		folder.setChildren(null);
    	}
    	outliner.folderChanged(folder);
    }
    public void outlinerFolderStateChangeEnd(JCOutlinerEvent ev) {}
    public void outlinerNodeSelectBegin(JCOutlinerEvent ev) {}
    public void outlinerNodeSelectEnd(JCOutlinerEvent ev) {}
    public void itemStateChanged(JCItemEvent ev) {}
    public void init() {
    	Image folder_opened = JCUtilConverter.toImage(this, "../images/foldero.gif");
    	Image folder_closed = JCUtilConverter.toImage(this, "../images/folderc.gif");
    	Image top = JCUtilConverter.toImage(this, "../images/top.gif");
    	content_icon = JCUtilConverter.toImage(this, "../images/content.gif");

    	// Force outliner to be same size as applet
    	setLayout(new GridLayout(1,1));
    	setBackground(Color.lightGray);
    	JCOutlinerNodeStyle style = new JCOutlinerNodeStyle();
    	style.setFolderOpenIcon(top);
    	style.setFolderClosedIcon(top);
    	JCOutlinerFolderNode root = new JCOutlinerFolderNode(null, "Personnel");
    	root.setStyle(style);
    	JCOutlinerNodeStyle folder_style = new JCOutlinerNodeStyle();
    	folder_style.setFolderClosedIcon(folder_closed);
    	folder_style.setFolderOpenIcon(folder_opened);
    	folder_style.setShortcut(true);
    	JCOutlinerFolderNode f = null;
    	for (int i=0; i < dept.length; i++) {
    		f = new JCOutlinerFolderNode(null, BWTEnum.FOLDER_CLOSED, dept[i]);
    		f.setUserData(new Integer(i));
    		f.setStyle(folder_style);
    		root.addNode(f);
    	}
    	JCOutliner outliner = new JCOutliner(root);
    	outliner.getOutliner().setBackground(Color.white);
    	outliner.setPreferredSize(400, 300);
    	outliner.setColumnLabels(column_labels);
    	outliner.setNumColumns(column_labels.length);
    	outliner.getDefaultNodeStyle().setShortcut(true);
    	outliner.addItemListener(this);
    	// Open last folder
    	outliner.setNodeState(f, BWTEnum.FOLDER_OPEN_ALL, true);
    	add(outliner);
    }

    public Insets insets() {
    	return new Insets(5,5,5,5);
    }
    public static void main(String args[]) {
    	ContribFrame frame = new ContribFrame("Outliner");
    	outliner o = new outliner();
    	o.init();
    	frame.add(o);
    	frame.pack();
    	frame.show();
    }
    }

When this code is inserted into a program, it produces the following results:

A sample program containing JCOutliner components

This sample code is incorporated into the example file outliner.class provided with JClass BWT. For information on how to run this program, see the " Example Program " section at the end of this chapter.

## Color and Fonts Properties

There are several properties which can be used to customize the display of a `JCOutliner`. The `Background` and `Foreground` properties can be used to set the color of the background and text/foreground elements of a `JCOutliner`. `Foreground` not only sets the color of any alphanumeric characters contained in the node label, but also of the arrow buttons and of the cursor within the text field.

The display of fonts within a `JCOutliner` is controlled by the `Font` property. For a listing of available fonts, see .

## Outliner Sizing

The size of a `JCOutliner` can be set using the `PreferredSize` property which sets the container's preferred size. If either dimension is set to `NOVALUE`, it is calculated by the subclass.

The individual `PreferredWidth()` and `PreferredHeight()` methods each deal with the subclass' preferred width (default: `100`). The subclass should not include the inset sizes in its calculation, as these are added by `JCOutliner`.

Whenever possible, the `JCOutliner` component is sized to its preferred width when displayed. If this is not possible, the width of the node area is reduced accordingly. If the width of the component is greater than the preferred width, the node area is stretched accordingly. If a multi-column display is defined, the last column is stretched.

## Column and Row Display Properties

The display of the text contained within a `JCOutliner` is controlled by the `VisibleRows` and the various `Column` properties (`ColumnAlignments`, `ColumnButtons`, `ColumnLabels`, `ColumnLeftMargin`, `ColumnRightMargin`, and `ColumnWidths`).

`VisbleRows` takes an integer value equal to the number of rows to be displayed. If `VisibleRows` is set to `0` (default), the text field attempts to resize itself so that all of its items are visible.

The `ColumnAlignments` property is used to set a column's alignment. It uses the parameter `align`, which can take one of the following values: `TOPLEFT`, `TOPCENTER`, `TOPRIGHT`, `MIDDLELEFT`, `MIDDLECENTER`, `MIDDLERIGHT`, `BOTTOMLEFT`, `BOTTOMCENTER` or `BOTTOMRIGHT`. By default, `ColumnAlignments` is set to `MIDDLELEFT`.

To add labels to a column, use the `ColumnLabels` property, which takes a string value or a JCString. To create labels that look and behave like buttons, use the `ColumnButtons` property instead. This property turns each label into a button that the user can interact with. There are cases when it desirable to allow the user to sort the information contained within an outliner. The `ColumnLabelSort` property is used to specify whether a column is sorted when its button is clicked (default: `true`).

Instead of adding string values for each label, it is also possible to assign vectors or `JCVectors` as labels to the node.

Margin values for `JCOutliner` columns can be explicitly set using the `ColumnLeftMargin` and `ColumnRightMargin` properties. Each sets the column's respective margins as a pixel value. They take an integer value corresponding to the column being set, and the value in pixels of the column margin. By default, both are set to `5` pixels.

To set the width of the columns appearing in a `JCOutliner`, use the `ColumnWidths` property. If a column's value is set to `VARIABLE`, the width of the column is set to the widest value contained within in the column.

The spacing between rows is set by the `Spacing` property (default: `0`).

## Row and Column Visibility

The `VisibleRows` property sets the number of rows that are visible in a `JCOutliner`. If set to `0` (default), the list will attempt to resize itself so that four items are visible. If it is set to another value, only the number of rows specified will be displayed. `VisibleRows` only works if the list is made visible beforehand.

Column visibility in `JCOutliner` is set using the `NumColumns` property. If set to `VARIABLE` (default), all columns are displayed.

## Scrollbar Properties

If an outline is too large to be displayed within the node area, scrollbars are displayed. The end-user can click on these scrollbars to specify the portion of the tree to be displayed in the node area. By default, horizontal scrollbars, vertical scrollbars, or both appear whenever appropriate. These are separate components which are defined as children of the `JCOutliner` component, and are controlled by `ScrollbarDisplay`.

The `ScrollbarDisplay` property is used to determine under what circumstances the scrollbars are to be displayed. `ScrollbarDisplay` can take one of five different values: `DISPLAY_ALWAYS` (scrollbars are always displayed), `DISPLAY_AS_NEEDED` (scrollbars are displayed as necessary), `DISPLAY_VERTICAL_ONLY` (the vertical scrollbar is always displayed), `DISPLAY_HORIZONTAL_ONLY` (the horizontal scrollbar is always displayed), or `DISPLAY_NONE` (never display scrollbars). By default, `ScrollbarDisplay` is set to `DISPLAY_AS_NEEDED`.

The `ScrollbarOffset` property sets the amount of space between the scrollbar and the component for the `JCOutliner` in pixels (default: `5`).

## Setting the Selection Mode

The `AutoSelect` property can be used to set the selection mode for an item or items that have focus with a `JCOutliner`. If set to `true` (default), the node which currently has focus is also selected. If `AutoSelect` is set to `false`, the node which currently has focus is not automatically selected. The latter setting is useful in situations where the user is expected to use the keyboard rather than the mouse to traverse and select multiple items within a `JCOutliner`, as it allows the user to move about the various nodes of the outliner without automatically selecting individual items.

## Node Properties

There are two properties that control the display of nodes within a `JCOutliner`: `NodeHeight` and `NodeIndent`.

`NodeHeight` is used to explicitly set the height of each node in pixels. By default it is set to `0`, at which point the height of the node is determined using the largest font and image height that appears in the list of node styles.

`NodeIndent` is used to set the indentation of each node relative to its parent in pixels (default: `15`).

The appearance of nodes can be changed from the default by using the various properties derived from `JCOutlinerNodeStyle`. Several nodes can share a `JCOutlinerNodeStyle` instance. The following are a list of node style properties that can be used:

- `BackgroundSelected` - sets the node's background color when it is selected (default: outliner's foreground color);
- `FolderClosedIcon` - sets the node's icon if it is a closed folder;
- `FolderClosedSelectedIcon` - sets the node's icon if it is a closed folder and it is selected;
- `FolderOpenIcon` - sets the node's icon if it is an open folder;
- `FolderOpenSelectedIcon` - sets the node's icon if it is an open folder and it is selected
- `Font` - sets the node's font (default: outliner's font);
- `Foreground` - sets the node's foreground color (default: outliner's foreground color);
- `ForegroundSelected` - sets the node's foreground color when it is selected (default: outliner's background color);
- `IconSpacing` - sets the horizontal spacing between the icon and the label (default: `5`);
- `ItemIcon` - sets the node's icon if it is not a folder;
- `ItemSelectedIcon` - sets the node's icon if it is not a folder and it is selected;
- `LineColor` - sets the color of the line connecting a folder to its children (default: outliner's foreground color);
- `Shortcut` - sets whether a shortcut button should be drawn beside a folder (default: `false`).

It should be noted that all nodes should share a common style, so as not to confuse the user.

One additional property, `RootVisible`, is used to specify whether the root node is displayed. If `true` (default), the root node is drawn.

## Folder Appearance

Normally, two states are defined for a folder: closed and open. A folder is closed if its children are not visible. A folder is open if its children are visible. By default, a folder state change (such as a double-click of the mouse button) toggles between these two states.

It is possible to specify additional folder states that are somewhere between completely closed and completely open using the `StateList` property. `StateList` sets a list of values used for double-clicking on a folder or clicking its shortcut button. The folder's state is cycled through the list. `StateList` can take one of five different values: `FOLDER_CLOSED` (the folder is closed and no children are visible), `FOLDER_OPEN_NONE` (the folder is open and no children are visible), `FOLDER_OPEN_FOLDERS` (the folder is open, but only the folder children are visible), `FOLDER_OPEN_ITEMS` (the folder is open, but only the non-folder children are visible, or `FOLDER_OPEN_ALL` (the folder is open, and all children are visible).

## Creating a Node Hierarchy with the setTree Method

You can use the `setTree()` method to create a node hierarchy by parsing a string list. Each line in the list represents a node's label. Tabs at the start of each line supply the tree hierarchy. Lines with the same indentation level are children. Nodes without children are assumed to be items. To create a folder without children, append the string "(FOLDER)" to the line.

The example below creates three folders and two items under Folder1.

    import jclass.bwt.*;
    import java.awt.*;
    import java.applet.*;
    public class treeexample1 extends Applet
    {
    	String[] outlinerNodes = {
    		"Folder1",
    		"	I_am_an_item1",
    		"	I_am_an_item2",
    		"Folder2(FOLDER)",
    		"Folder3(FOLDER)"};
    	public void init()
    	{
    		JCOutliner outliner = new JCOutliner();
    		outliner.setTree(outlinerNodes);
    		add(outliner);
    	}
    	public static void main(String args[])
    	{
    		Frame frame = new Frame("Testing");
    		treeexample1 mytree = new treeexample1();
    		mytree.init();
    		frame.setLayout(new GridLayout(1,1));
    		frame.add(mytree);
    		frame.pack();
    		frame.show();
    	}
    }

When this code is inserted into a program, it produces the following results:

A sample program using the setTree() method

As noted above, if a node has no children, it is assumed to be an item. If we add an extra tab before i_am_an_item2, this will change i_am_an_item1 into a folder. For example:

    import jclass.bwt.*;
    import java.awt.*;
    import java.applet.*;
    public class treeexample2 extends Applet
    {
    	String[] outlinerNodes = {
    		"Folder1",
    		"		I_am_nolonger_an_item1",
    		"	I_am_an_item2",
    		"Folder2(FOLDER)",
    		"Folder3(FOLDER)"};
    	public void init()
    	{
    		JCOutliner outliner = new JCOutliner();
    		outliner.setTree(outlinerNodes);
    		add(outliner);
    	}
    	public static void main(String args[])
    	{
    		Frame frame = new Frame("Testing");
    		treeexample2 mytree = new treeexample2();
    		mytree.init();
    		frame.setLayout(new GridLayout(1,1));
    		frame.add(mytree);
    		frame.pack();
    		frame.show();
    	}
    }

When this code is inserted into a program, it produces the following results:

A sample program using the setTree method

## Events

A class can be notified when the user presses the ENTER key or double-clicks a node within an `JCOutliner` by implementing the `JCActionListener` interface and registering itself with the outliner via `addActionListener`, as the following code demonstrates:

    public interface JCActionListener {
            public void actionPerformed(JCActionEvent e);
    }
    public class JCActionEvent {
            // Returns the component where the event originated.
            public Object getSource()
            // Returns the event type: ACTION_PERFORMED.
            public int getId()
    }

A class can be notified when the user selects an item in a `JCOutliner` by implementing the `JCItemListener` interface and registering itself with the outliner via `addItemListener`:

    public interface JCItemListener {
            public void itemStateChanged(JCItemEvent e);
    }
    public class JCItemEvent {
            // Returns the component where the event originated.
            public Object getSource()
            // Returns the event type: ITEM_STATE_CHANGED.
            public int getId()
            // Returns the node where the event occurred.
            public Object getItem()
            // Returns the state change type which generated the event: SELECTED or DESELECTED
            public int getStateChange()
    }

To receive additional information, a class can implement the `JCOutlinerListener` interface, and register itself with the outliner via `addItemListener`.

    public interface JCOutlinerListener extends JCNodeListener {
            // Invoked before an node is selected. The event's values can be modified via its setXXX methods.
            public void outlinerNodeSelectBegin(JCOutlinerEvent e);
            // Invoked after an node is selected. Any changes made to the event are ignored.
            public void outlinerNodeSelectEnd(JCOutlinerEvent e);
            // Invoked before a folder's state is changed. The event's values can be modified via its setXXX methods.
            public void outlinerFolderStateChangeBegin(JCOutlinerEvent e);
            // Invoked after a folder's state is changed. Any changes made to the event are ignored.
            public void outlinerFolderStateChangeEnd(JCOutlinerEvent e);
    }

It will then be passed to `JCOutlinerEvents`:

    public class JCOutlinerEvent extends JCItemEvent {
            // Gets the node whose state will be changed.
            public JCOutlinerNode getNode()
            // Gets the node's current state
            public int getState()
            // Gets the node's new state.
            public int getNewState()
            // Sets the node's new state. This is ignored if the node is not a folder.
            public void setNewState(int v)
            // Gets the current AllowChange value.
            public boolean getAllowChange()
            // Determines whether the selection or state change should be allowed (default: true).
            public void setAllowChange(boolean v)
    }

## Adding Enhanced Print Functionality

Enhanced printing functionality has been enable under JDK 1.1. The `JCOutliner.print()` method will print the outliner on multiple pages, with repeating header, outliner and all nodes open. Printed outliners do not display scrollbars.

For example, to print an outliner based on a java.awt.Button press, you could write the following code:

    	public boolean handleEvent(Event event) {
    		if (event.id == Event.ACTION_EVENT) {
    		JCOutliner.print();

### Setting Page Layout Properties JCOutlinerPrinter Class

The JCOutlinerPrinter class provides methods for more detailed control of print output from a JCOutliner application or applet. To obtain the JCOutlinerPrinter object associated with the outliner, use:

    JCOutlinerPrinter outlinerPrinter = outliner.getOutliner().getOutlinerPrinter();

#### Outliner Column

The method `setOutlinerOnEachPage()` determines whether the outliner column is repeated on each page when more than one page is required to print all of the columns in the outliner.

#### Print All Nodes

The method `setPrintAllNodes()` prints all nodes open if `true` and as is if `false`.

#### Page Size

The following methods define printed page sizes:

    	getPageDimensions();
    	getPageWidth();
    	getPageHeight();

These methods retrieve page information from the printer.

#### Page Margins

Page margins are set using the `setPageMargins()` method. This method uses the awt.Insets class to set the margins as in the following example:

    outlinerPrinter.setPageMargins(new Insets(54,36,36,54));

By default, JCOutliner sets one margins in pixels based on the printer resolution. To specify margin units in inches, use the variable `MARGIN_IN_INCHES` in the `setMarginUnits()` method:

    outlinerPrinter.setMarginUnits(JCOutlinerPrinter.MARGIN_IN_INCHES);

You can retrieve page margins based on the Insets of the page using the `getPageMargins()` method.

#### Other Print Properties

Use getPageResolution() to get the printer page resolution. The default is 72 pixels per inch.

### Controlling Page Printing

The JCOutliner.print() method will handle basic printing tasks. However, you can use JCOutlinerPrinter class's methods to create your own code to handle custom printing tasks.

The code below demonstrates how to use the JCOutlinerPrinter class to print a range of pages.

    public void print() {
    	PrintJob job = getToolkit().getPrintJob(getFrame(), "Print", null);
    	if(job == null) return;
    	Dimension pd = job.getPageDimension();

    	outlinerPrinter.setPageDimensions(pd.width, pd.height);
    	int pages = outlinerPrinter.getNumPages();
    	Graphics gc;
    	for(int p = 1; p <= pages; p++) {
    		gc = job.getGraphics();
    		if(gc != null) {
    			outlinerPrinter.drawPage(gc, p);
    			gc.dispose();
    		}
    	}
    	job.end();
    }

### Printing Headers and Footers

Headers and footers are applied using `JCOutlinerPrintListener` receiving `JCOutlinerPrintEvent` events. A `JCOutlinerPrintEvent` is posted for each page during printing, and provides a graphic object clipped to the allowable paint region and the page number of the current page:

    	public JCOutlinerPrintEvent(JCOutlinerInterface outliner, Graphics gc, int page, int type)
    	public Graphics getGraphics()
    	public int getPage()

The `JCOutlinerPrintListener` requires that two methods are defined:

    	public void printPageHeader(JCOutlinerPrintEvent e);
    	public void printPageFooter(JCOutlinerPrintEvent e);

The following code would produce a footer:

    	public void printPageFooter(JCOutlinerPrintEvent e) {
    		Graphics gc = e.getGraphics();
    		Rectangle r = gc.getClipRect();
    		FontMetrics fm = gc.getFontMetrics();
    		String page = "Page " + e.getPage();
    		String note = "Use JCOutlinerPrintListener to customize the footer!";
    	// Pad the footer text to the right
    		gc.drawString(page, 0, r.height/2);
    		gc.drawString(note, r.width - fm.stringWidth(note), r.height/2);
    	}

#### Repeating Headers

When more than one page is required to print all of the nodes, `setHeaderOnEachPage()` controls whether the header is repeated at the top of each page.

## Property Listing

The following summarizes the properties of `JCOutliner`. Complete reference documentation is available online in standard javadoc format in jclass.bwt.JCOutliner.html.

### jclass.bwt.JCOutliner

Name | Method | Inherited from
--- | --- | ---
`AutoSelect` | `setAutoSelect` | `jclass.bwt.JCOutliner`
`Background` | `setBackground` | `jclass.bwt.JCContainer`
`ColumnAlignments` | `setColumnAlignments` | `jclass.bwt.JCOutliner`
`ColumnAlignments` | `setColumnAlignments` | `jclass.bwt.JCMultiColumnWindow`
`ColumnLabelSort` | `setColumnLabelSort` | `jclass.bwt.JCMultiColumnWindow`
`ColumnLeftMargin` | `setColumnLeftMargin` | `jclass.bwt.JCMultiColumnWindow`
`ColumnRightMargin` | `setColumnRightMargin` | `jclass.bwt.JCMultiColumnWindow`
`ColumnWidths` | `setColumnWidths` | `jclass.bwt.JCMultiColumnWindow`
`Font` | `setFont` | `jclass.bwt.JCContainer`
`Foreground` | `setForeground` | `jclass.bwt.JCContainer`
`Insets` | `setInsets` | `jclass.bwt.JCContainer`
`NodeHeight` | `setNodeHeight` | `jclass.bwt.JCOutliner`
`NodeIndent` | `setNodeIndent` | `jclass.bwt.JCOutliner`
`NumColumns` | `setNumColumns` | `jclass.bwt.JCOutliner`
`NumColumns` | `setNumColumns` | `jclass.bwt.JCMultiColumnWindow`
`PreferredSize` | `setPreferredSize` | `jclass.bwt.JCContainer`
`RootVisible` | `setRootVisible` | `jclass.bwt.JCOutliner`
`ScrollbarDisplay` | `setScrollbarDisplay` | `jclass.bwt.JCScrolledWindow`
`ScrollbarOffset` | `setScrollbarOffset` | `jclass.bwt.JCScrolledWindow`
`Spacing` | `setSpacing` | `jclass.bwt.JCMultiColumnWindow`
`StateList` | `setStateList` | `jclass.bwt.JCOutliner`
`UserData` | `setUserData` | `jclass.bwt.JCContainer`
`VisibleRows` | `setVisibleRows` | `jclass.bwt.JCMultiColumnWindow`

## Example Program

Demonstration programs and example code containing `JCOutliner` come with JClass BWT. The examples can be viewed in applet form by launching index.html within the /jclass/bwt/examples directory. outliner.class can also be run as a stand-alone Java application from the command prompt by typing:

    	java jclass.bwt.examples.outliner

JCOutliner contains classes that enable end-users to print applications using the outliner. Since printing is not available under JDK 1.0, these classes apply to JDK 1.1 applications only.