# 3

## JCTabButton and JCTabManager

Introduction · Sample Program Code · Changing the Active Tab

Controlling Tab Display · Tab Button Properties · Events

Property Listing · Example Program

### Introduction

Tabbed dialogs enable the programmer to create a "layer" of dialogs which the user can access through a set of tabs. Based on the visual metaphor of a sequence of file folders, users click a tab to display the contents of a specific file folder. Tabbed dialogs provide an easy way to provide users with a convenient and intuitive way of accessing option contained within with a well-organized interface.

The Java Development Kit (JDK) does not implement tab dialogs. `JCTabButton` dialogs look and behave like their MS Windows 95 equivalents. `JCTabButton` dialogs are created and controlled by `JCTabManager`, which is a container that organizes its children into pages to simulate a sequence of file folders. The page components are defined as children of the `JCTabManager`; a property is then used to associate a page with a particular tab button. Page components can be of any class (including any container). The tabs are subclassed from `JCButton`, which can contain multiple lines of text, images, or contain both text and images. `JCTabButton` dialogs uses the new event model to update the tabbed page display.

#### Behavior

`JCTabButton` dialogs behave in the following manner:

- if a tab is clicked, the tab and its associated page is brought to the front, and any text appearing in the tab is rendered in a bold font.
- while the tab has focus, a border appears around its label
- tabs can be traversed using the cursor keys
- the TAB key can be used to traverse between the active tab and the contents of its page.

### Sample Program Code

To program tabbed dialogs, you need to create the following:

- a Tab Manager container (`JCTabManager`) to control the display and organization of tabs
- one or more Tab Button components (`JCTabButton`) to define tabs for your dialog
- page components to be stored in the tabbed dialog.

Together, the `JCTabManager` and `JCTabButton` simulate a sequence of file folders. The page components are defined as children of the `JCTabManager`; a constraint property is then used to associated a page component with a particular `JCTabButton`. Page components can be of any component or container.

The following illustration illustrates the anatomy of a typical tabbed dialog.

#####

##### Anatomy of a tabbed dialog

The following code fragment creates a `JCTabManager` container, then adds several tabs and pages as its children:

    package jclass.bwt.examples;
    import jclass.bwt.BWTEnum;
    import jclass.bwt.JCCheckbox;
    import jclass.bwt.JCCheckboxGroup;
    import jclass.bwt.JCContainer;
    import jclass.bwt.JCGridLayout;
    import jclass.bwt.JCItemEvent;
    import jclass.bwt.JCItemListener;
    import jclass.bwt.JCLabel;
    import jclass.bwt.JCTabButton;
    import jclass.bwt.JCTabManager;
    import jclass.bwt.JCTabManagerEvent;
    import jclass.bwt.JCTabManagerListener;
    import jclass.contrib.ContribFrame;
    import jclass.util.JCString;
    import jclass.util.JCUtilConverter;
    import java.awt.*;
    import java.util.Date;

    /**
     * This example creates a JCTabManager which displays some of the other
     * examples.
     */
    public class tabManager extends java.applet.Applet
    implements Runnable, JCTabManagerListener, JCItemListener {

    JCLabel label = new JCLabel();
    JCTabManager tab_manager;
    transient Thread updater;

    // JCItemListener method
    public void itemStateChanged(JCItemEvent ev) {
    	JCCheckboxGroup group =
    		(JCCheckboxGroup) ((Component)ev.getSource()).getParent();

    	if (group.getTitle().equals("Shape"))
    		tab_manager.setTabShape(group.getValue());
    	else if (group.getTitle().equals("Side"))
    		tab_manager.setTabSide(group.getValue());
    }

    /*
     *  JCTabManagerListener methods
     */

    // Sets the page when the Date or Vendor tab is clicked
    public void tabManagerChangeBegin(JCTabManagerEvent ev) {
    	JCTabButton tab = ev.getNextTab();
    	if (tab.getName().equals("Date")) {
    		label.setLabel(""+new Date());
    		start();
    		return;
    	}

    	// Stop date thread if it is running
    	stop();
    	if (tab.getName().equals("Vendor")) {
    		String url = System.getProperty("java.vendor.url");
    		JCString s = JCString.parse(this, "[COLOR=blue][href=" + url + " TARGET=_blank]" + url);
    		label.setLabel(s);
    	}
    }
    public void tabManagerChangeEnd(JCTabManagerEvent ev) {}

    public Insets insets() { return new Insets(5,5,5,5); }

    static String side_labels[] = { "Top", "Bottom" };
    static int side_values[] = { BWTEnum.TOP, BWTEnum.BOTTOM } ;

    static String shape_labels[] = { "Rectangular", "Slanted" };
    static int shape_values[] = { BWTEnum.RECTANGLE, BWTEnum.SLANTED };

    public void init() {
    	// Force tab manager to be same size as applet
    	setLayout(new GridLayout(1,1));
    	tab_manager = new JCTabManager();
    	tab_manager.addTabManagerListener(this);
    	setBackground(Color.lightGray);

    	JCCheckboxGroup sides = JCCheckbox.makeGroup(side_labels, side_values, true);
    	sides.setTitle("Side");
    	sides.addItemListener(this);
    	JCCheckboxGroup shapes = JCCheckbox.makeGroup(shape_labels, shape_values, true);
    	shapes.setTitle("Shape");
    	shapes.addItemListener(this);

    	JCContainer panel = new JCContainer();
    	panel.setInsets(new Insets(0, 20, 0, 20));
    	panel.setLayout(new JCGridLayout(1, BWTEnum.VARIABLE, 10, 10));
    	panel.add(sides);
    	panel.add(shapes);
    	tab_manager.addPage("Tab Styles", panel);

    	labels l = new labels(this);
    	l.init();
    	l.setBackground(Color.yellow);
    	tab_manager.addPage("Labels", l);

    	buttons b = new buttons(this);
    	b.init();
    	tab_manager.addPage("Buttons", b);

    	/*
    	 * Add tabs which share the same page. The page contents will be set
    	 * in the listener method when the tab is clicked.
    	 */
    	label.setFont(new Font("TimesRoman", Font.BOLD, 20));
    	int pos = tab_manager.addPage("Java Vendor", label);
    	tab_manager.getTab(pos).setName("Vendor");

    	pos = tab_manager.addPage("Current Date", label);
    	tab_manager.getTab(pos).setName("Date");

    	add(tab_manager);
    }

    public void start() {
    	if (updater == null) {
    		updater = new Thread(this);
    		updater.start();
    	}
    }

    public void stop() {
    	if (updater != null) {
    		updater.yield();
    		updater.stop();
    	}
    	updater = null;
    }

    /** Writes the current time every second. */
    public void run() {
    	while (true) {
    		try {
    			Thread.sleep(1000);
    		} catch (Exception e) {}

    		if (!Thread.currentThread().isAlive() || updater == null)
    			return;
    		label.setLabel(""+new Date());
    	}
    }

    public static void main(String args[]) {
    	ContribFrame frame = new ContribFrame("TabManager");
    	tabManager s = new tabManager();

    	s.init();
    	frame.add(s);
    	frame.pack();
    	frame.show();
    }
    }

This creates the following tabbed dialog display:

#####

##### A sample JCTabManager with child JCTabButtons

This application consists of a Tab Manager, with four `JCTabButtons` defined as its children. Each `JCTabButton` has a page associated with it. Each page, in turn, has other BWT components defined as its child; in more complicated real-life applications, additional container components are defined as children of the pages.

To create a multi-level file folder, define another `JCTabManager` as a page component.

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

### Changing the Active Tab

The `JCTabManager` component provides two methods to control the display of the tab manager and its children:

- `setCurrentTab` which sets the current tab, and calls `JCTabManagerEvent`
- `setCurrentPage` sets the current page.

##### Tab Events

`JCTabManager` can be notified when a page has been changed and can be set at run-time; in other words, a number of tabs could share the same page and `JCTabManager` could set the page contents after the user has clicked a tab.

The `JCTabManagerInfo` constructor defines actions to be invoked whenever the value of `TABMANAGER` changes, which can be set either interactively or programmatically. This enables you to control page display.

Each `TABMANAGER` property is passed the following structure:

    public JCTabManagerInfo(Event ev,
    					Component current,
    					Component next)

Each event is called both before and after the page change takes place. reason indicates which event is occurring, and is either `BEGIN` (before page change) or `END` (after page change).

The new page component and its number are specified by the `current_page`and `next_page` variables. These members can be modified, which allows you to control page changes in a `JCTabManager`. The `doit` field provides an easy way to suppress page changes. If `doit` is set to `false` if stage is set to `BEGIN`, the page change does not occur.

### Controlling Tab Display

`JCTabManager` enables you to control the following tab display features:

- tab resizing
- tab stretching
- tab shape
- tab color
- tab placement/orientation.

##### Tab Resizing

The `TabResize` property specifies whether all tabs should be resized to the width or height of the largest tab in the same row. If `TabResize` is `true` (default), resizing is performed; if `false`, each tab is only as large as necessary to display its label.

#####

##### Tab resizing

##### Tab Stretching

The `TabStretch` property specifies whether all tabs should be stretched if necessary to fill the entire side.

#####

##### Tab stretching

To ensure that the tabs take up all the available visible space and are of the same size, set `TabResize` and `TabStretch` to `true`.

##### Tab Shape

The `TabShape` property sets the shape of the tab. There are two available values: `RECTANGLE` (default), or `SLANTED`. The effects of both values are depicted in the following illustration:

#####

##### The two values of TabShape illustrated

##### Tab Color

The `TabColorPolicy` property sets the color for individual tabs within `JCTabManager`. `TabColorPolicy` does not directly set the color for an individual tab, instead it either reads the color value from the tabbed page, or sets the tab's color to a value defined within the tab manager. The two values for `TabColorPolicy` are `COLOR_PAGE`, which sets the tab's color to the page's color (default), and `COLOR_INHERIT`, which sets the tab's color to the tab manager's color.

##### Tab Placement

The `TabSide` property sets the placement for the displays of tabs within `JCTabManager`. There are two values for `TabSet`: `TOP` and `BOTTOM`. The effects of both values are depicted in the following illustration:

#####

##### The two values of TabSide illustrated

### Tab Button Properties

The following sections describe how to use the `JCTabButton` component.

#### Altering the Tab Button Font

The `CurrentTabFont` property sets the current tab's font (default: bold version of the default font). It can be altered by specifying a different valid Java font name with the property, as in the following code fragment:

    public void init() {
            JCImageCreator im = new JCImageCreator(this, 16, 16);
            im.setColor('X', Color.red);
            im.setColor('o', Color.black);
            im.setColor('.', Color.white);
            siteImage = im.create(site_icon);
            // Force tab manager to be same size as applet
            setLayout(new GridLayout(1,1));
            setBackground(Color.lightGray);
            tab_manager = new JCTabManager();
            tab_manager.setBackground(Color.lightGray);
            tab_manager.setCallback(BWTCallback.TABMANAGER, this);
            // set the font for the selected Tab.
            Font newFont = new Font("Courier", Font.PLAIN, 16);
            tab_manager.setCurrentTabFont(newFont);
            theFTPPanel = new FTPPanel(this);
            for (int i=0; i<tabName.length; i++) {
                    JCString        name = new JCString();
                    name.add(siteImage);
                    name.add(tabName[i]);
                    tab_manager.setTabPage(i+1, name, theFTPPanel);
            }
            setTextFields(tab_manager.getCurrentTab());
            tab_manager.setTabStretch(true);
            add(tab_manager);
    }

The result of this code can be seen in the following illustration:

#####

##### Changing Fonts within the Tabs

This example uses a JCString to insert images within the tab buttons. For more information on JCStrings, see Appendix B: JCString Properties.

#### Adding an Image to a Tab Button

To specify a image for a `JCTabButton`, specify an object in the `JCTabButton` constructor. The `JCTabButton` constructor can be passed a String, image or JCString.

The following code fragment displays how to add an image file as an object, and a subsequent tab displays a JCString.

    / This example uses a memory image
    // Static Variables
    static String tabName[] = {
            "Guru", "Gonzo", "KLG's ftp site",
    };
    static final String site_icon[] = {
    "   oooooooooo   ",
    "  o..........o  ",
    "  o..XXXXXX..o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o.X......X.o  ",
    "  o..XXXXXX..o  ",
    "  o..........o  ",
    "  o....XXXXX.o  ",
    "  o..........o  ",
    "  oooooooooooo  ",
    "   o........o   ",
    "   o........o   ",
    "   oooooooooo   "};
    public void init() {
            JCImageCreator im = new JCImageCreator(this, 16, 16);
            im.setColor('X', Color.red);
            im.setColor('o', Color.black);
            im.setColor('.', Color.white);
            Image siteImage = im.create(site_icon);
            // Force tab manager to be same size as applet
            setLayout(new GridLayout(1,1));
            setBackground(Color.lightGray);
            tab_manager = new JCTabManager();
            tab_manager.setBackground(Color.lightGray);
            tab_manager.setCallback(BWTCallback.TABMANAGER, this);
            theFTPPanel = new FTPPanel(this);
            for (int i=0; i<tabName.length; i++) {
                    JCString        name = new JCString();
                    name.add(siteImage);
                    name.add(tabName[i]);
                    tab_manager.setTabPage(i+1, name, theFTPPanel);
            }
            setTextFields(tab_manager.getCurrentTab());
            tab_manager.setTabStretch(true);
            add(tab_manager);
    }

The image is constructed within the code and not via a .GIF image file. The results can be seen in the following illustration .

#####

##### Inserting images into tab buttons

#### Text and Pixmap Positioning

Text and images can be aligned within a `JCTabButton` by using the `Alignment` property which has nine possible values: `TOPLEFT`, `TOPCENTER`, `TOPRIGHT`, `MIDDLELEFT`, `MIDDLECENTER`, `MIDDLERIGHT`, `BOTTOMLEFT`, `BOTTOMCENTER`, and `BOTTOMRIGHT`. All nine values are used with text strings in the following code sample, whose results can be seen in the following illustration.

#####

##### Tab Button text and pixmap layouts

The default is `MIDDLECENTER`.

Text and images can also be aligned using JCStrings. This approach is limited to the three values possible with `ALIGN`: `TOP`, `BOTTOM` and `MIDDLE`. The following code fragment shows how to insert JCStrings within tab labels.

    // Using a JCString with alignment information
                    JCString s = JCString.parse(this, "[ALIGN=TOP]"+tabName[i]);
                    tab_manager.setTabPage(i+1, s, theFTPPanel);

#### Specifying Tab Button and Page Colors

Each `JCTabButton` component obtains its color specifications from the page component with which it is associated. To specify your own `JCTabButton` colors, change the appropriate color properties (such as `foreground`) after associating a page component with the `JCTabButton`.

The shadow colors for each page component are, in turn, obtained from the `JCTabButton` color specifications.

### Events

A class can be notified before and after a new `JCTabManager` page is displayed by implementing the `JCTabManagerListener` interface and registering itself with the `tabManager` via `addTabManagerListener`, as the following code demonstrates:

    public interface JCTabManagerListener {
            // Invoked before the page is changed. The event's values can be modified via its setValue method.
            public void tabManagerChangeBegin(JCTabManagerEvent e);
            // Invoked after the page is changed. Any changes made to the event are ignored.
            public void tabManagerChangeEnd(JCTabManagerEvent e);
    }
    public class JCTabManagerEvent {
            // Returns the component where the event originated.
            public Object getSource()
            // Returns the event type.
            public int getId()
            // Gets the current page (null at initialization).
            public Component getCurrentPage()
            // Gets the page that will be displayed.
            public Component getNextPage()
            // Gets the current tab (null at initialization).
            public JCTabButton getCurrentTab()
            // Gets the tab that will be displayed.
            public JCTabButton getNextTab()
            // Sets the page that will be displayed.
            public void setNextPage(Component page)
            // Determines whether the page should change.
            public boolean getChangePage()
            // Determines whether the page should change (default: true).
            public void setChangePage(boolean v)
    }

### Property Listing

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

#### jclass.bwt.JCTabManager

#####

Name | Method | Inherited from
--- | --- | ---
`Alignment` | `setAlignment` | `jclass.bwt.JCTabManager`
`Background` | `setBackground` | `jclass.bwt.JCContainer`
`CurrentTabFont` | `setCurrentTabFont` | `jclass.bwt.JCTabManager`
`FirstVisibleTab` | `setFirstVisibleTab` | `jclass.bwt.JCTabManager`
`Font` | `setFont` | `jclass.bwt.JCContainer`
`Foreground` | `setForeground` | `jclass.bwt.JCContainer`
`Insets` | `setInsets` | `jclass.bwt.JCContainer`
`PreferredSize` | `setPreferredSize` | `jclass.bwt.JCContainer`
`TabColorPolicy` | `setTabColorPolicy` | `jclass.bwt.JCTabManager`
`TabResize` | `setTabResize` | `jclass.bwt.JCTabManager`
`TabShape` | `setTabShape` | `jclass.bwt.JCTabManager`
`TabSpacing` | `setTabSpacing` | `jclass.bwt.JCTabManager`
`TabStretch` | `setTabStretch` | `jclass.bwt.JCTabManager`
`UserData` | `setUserData` | `jclass.bwt.JCContainer`

### Example Program

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

         java jclass.bwt.examples.tabManager