# 6

## 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 · Events · Property Listing

Example Program

### Introduction

Outliners (also known as "trees") are standard Graphical User Interface (GUI) components common to most windowing systems, which enables the display 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 enables the user to move between items. If the user is over a closed folder and click the RIGHT cursor key, it 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 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 it parent, and a root node must exist. The root node need not be visible, in which case all of its children are displayed to the right margin. can optionally 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 to be found in JClass BWT `JCOutliner` is to examine the code for a sample program that incorporates

The following code describe how to construct 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 Appendix A: Colors and Fonts.

### 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` , `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 any of the following values: `TOPLEFT` , `TOPCENTER` , `TOPRIGHT` , `MIDDLELEFT` , `MIDDLECENTER` , `MIDDLERIGHT` , `BOTTOMLEFT` , `BOTTOMCENTER` and `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 row 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 set and 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 scrollbars is always displayed), `DISPLAY_HORIZONTAL_ONLY` (the horizontal scrollbar is always displayed), `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 in 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 three 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, however, 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).

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

### Property Listing

The following is a listing of available properties for `JCOutliner`:

#### jclass.bwt.Outliner

#####

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 stand-alone Java applications from the command prompt by typing:

    	java jclass.bwt.examples.outliner