ItemView for the Cluster Category

How to write a Rhino ItemView

Table of Contents



Introduction

This document is a reference for SGI software engineers who will be writing ItemViews for Rhino applications. An ItemView in the Rhino Architecture is a UI Component that displays all relevant information about a particular Item. The ItemView is the user's main source of information about the attributes of an Item, which include both static and dynamic information.

Overview of the ItemView's Sections

Shown below is a picture of an ItemView, with the different sections labeled.

ItemView with sections labeled
Icon Shown in the upper left corner of the ItemView. Typically, the Icon represents the type of Item being viewed, and additionally the state of the Item
Fields Shown in the upper right corner of the ItemView. This section is divided into two columns, the left for the name of the field, and the right for the value of the field. The fields section is designed to show information about the Item that can be represented by fairly short Strings
Additional Info section This section occupies the center of the ItemView. It is an optional section. This section is designed to show information about the Item that can't easily be represented as a single line of text. Examples include ItemTables, graphs, or additional icons. Any Java component can be shown here. If there are no components to show in this section, then the ItemView will not show the Additional Info section.
TaskShelf section This section occupies the bottom of the ItemView. It shows a TaskShelf containing Tasks that can operate on the displayed Item in the Item's current state


Before you begin

Before beginning to create an ItemView for a particular Category, it is necessary to understand the names and terms that the Rhino infrastructure uses in relation to Categories. See the The Names of Categories on the Client and on the Server documentation for more information.

How to create an ItemView for a particular Category

No-Code ItemViews

A No-Code ItemView for the RhinoExampleCategory While in the early stages of writing Categories, it may be desirable to show an ItemView that shows all of the Attributes of an Item. The ItemView supports this idea by means of a "no-code" ItemView. This version of an ItemView is not designed for use in a shipping Rhino application, but can be of great assistance while investigating the Rhino Infrastructure or for giving preliminary demos. No code or resource files need to be written to use the "no-code" ItemView - it can be launched as soon the server side Categories have been written and the Rhino infrastructure has been installed on the client. To turn the ItemView into a shippable ItemView, it is necessary to provide resources that describe the way that the Attributes of the Item are to be displayed. The rest of this document will describe how to accomplish this. To launch a "no-code" ItemView, follow the instructions in the section titled How to launch ItemViews. An example of the "no-code" ItemView for the RhinoExampleCategory is shown to the right.

Analyze Item's attributes

Before writing any code or resource files for the ItemView, begin by analyzing the information that needs to be displayed. Divide the information into two groups: information that will go in the Fields section, and information that will go in the Additional Information section. While there are no absolute rules about what kind of information goes where, here are some suggestions on how to divide the information:

All of the information in a RhinoExampleCategory Item probably belongs in the Fields section, but imagine that the Printer type of Item also had a list of print jobs. Since the list could be quite long, using a comma separated list would not be a practical solution. In this case, it might work to use a JList to implement a scrollable list to display all of the print jobs. This component would be displayed in the Additional Information section).

Customizing the Fields of the ItemView

There are several types of properties that control the look of the ItemView. The properties (in the order that they are described) are:
  1. The field properties - Define names of the fields.
  2. The basedOn properties - Tell the ItemView which Attributes correspond to particular fields.
  3. The label properties - Provide the labels the ItemView will use for the fields.
  4. The method properties - Specify the manner in which the ItemView will use the Item's Attributes to fill in the field.

The field Properties

The pieces of the Item's information that are displayed in the Fields section are completely controlled by a resource file. The most fundamental resources are those that give names to the fields that will be displayed. These names identify the fields so that other resources can refer to particular fields. The resources follow the form <Category name>.ItemView.field<n>, where <Category name> is the name of the Category (see the FIELDS documentation for more info), and <n> represents integers starting at 0 that represent order in which the fields should be displayed. For example, the resource file that controls the RhinoExampleCategory contains the following lines (the letters in the first column are for reference purposes only):

A: com.sgi.rhexamp.category.rhexampRhinoExampleCategory.ItemView.field0=name
B: com.sgi.rhexamp.category.rhexampRhinoExampleCategory.ItemView.field1=type
C: com.sgi.rhexamp.category.rhexampRhinoExampleCategory.ItemView.field2=mode
Because the first part of each line is identical, it is common to use macros to shorten the lines of the resource file and to make the file easier to read. An example of the same resources using macros is shown below.

A: RHINO_EXAMPLE_CATEGORY=com.sgi.rhexamp.category.rhexampRhinoExampleCategory
B: IVprefix=${RHINO_EXAMPLE_CATEGORY}.ItemView
C:
D: ${IVprefix}.field0=name
E: ${IVprefix}.field1=type
F: ${IVprefix}.field2=mode
ItemView with fields properties defined

The three "field" resources (D - F) define the names of the fields and the order in which the fields will be displayed in the ItemView. In this example, the names of the fields correspond exactly with the names of the Attributes in the Item that will be displayed in the field. By naming the fields in this manner, the ItemView can use default behavior and automatically associate the correct Attribute with the field. It is also possible to give the fields names that are not the same as the names of Attributes. In that case, it may be necessary to use the "basedOn" property (defined below) to tell the ItemView which Attribute is associated with a field.

Running an ItemView with the 5 lines described above in the resource file will result in an ItemView that is shown on the right. Notice that the order of the fields is "name", "type", and then "node", which is as specified in the resource file. ItemView has used a default label for each of the fields. Information about how to customize the label is described below. The ItemView is using the default "toString" method (methods are described below). This is the simplest method, and uses the results of calling Java's toString method on the value of the Attribute.

The basedOn Properties

In the example resource file shown above, the names of the fields were defined to be the same as the Item's Attributes that they represented. This allowed the ItemView to automatically show the value of the Attribute in the field. It is sometimes desirable to use different names for the fields than the Attributes that they represent. This can make the resource file more readable or can be required because there may not be a one to one correspondence between the Attributes in the Item and the fields that are displayed.

If a field is given a name that does not correspond to the name of an Attribute, the "basedOn" property is used to tell the ItemView which Attribute the field represents. The "basedOn" resources are defined as: <Category name>.ItemView.basedOn.<field>, where <Category name> is the name of the Category, and <field> is the name of a field. (See the BASED_ON documentation for more info).

The renderer method (as described below) does not require that the field be associated with a particular Attribute. When using this method, it is not necessary to specify the "basedOn" property even if the name of the field does not correspond to an Attribute. All the other methods, including the default "toString" method, require that the field be associated with a particular Attribute of the Item.

For example, suppose that the "name" Attribute should be displayed twice, once at the beginning of the list, and once at the end. A resource file as follows would do just that:

A: RHINO_EXAMPLE_CATEGORY=com.sgi.rhexamp.category.rhexampRhinoExampleCategory
B: IVprefix=${RHINO_EXAMPLE_CATEGORY}.ItemView
C:
D: ${IVprefix}.field0=Name1
E: ${IVprefix}.field1=type
F: ${IVprefix}.field2=node
G: ${IVprefix}.field3=Name2
H:
I: ${IVprefix}.basedOn.Name1=name
J: ${IVprefix}.basedOn.Name2=name
ItemView with 2 name fields.

This would result is the name being shown twice, as is seen to the right:

The label Properties

The next step is to define the strings that will be used as the labels for the fields. The "label" resources are defined as: <Category name>.ItemView.label.<field>.label. (See the LABEL documentation for more info). Optionally, another resource can be specified that gives the name of a glossary entry that will be displayed if the user clicks on the label. This resource is defined as: <Category name>.ItemView.label.<field>.glossary, and if this resource is defined, then the label will appear blue.

For example, define labels for the example ItemView, the following properties would be added to the resource file:

A: RHINO_EXAMPLE_CATEGORY=com.sgi.rhexamp.category.rhexampRhinoExampleCategory
B: IVprefix=${RHINO_EXAMPLE_CATEGORY}.ItemView
C:
D: ${IVprefix}.field0=name
E: ${IVprefix}.field1=type
F: ${IVprefix}.field2=mode
G:
H: ${IVprefix}.label.name.label=Name:
I: ${IVprefix}.label.type.label=Type:
J: ${IVprefix}.label.type.glossary=glossary.Type
K: ${IVprefix}.label.mode.label=Access:
L:
M: glossary.Type = The type of the Item
ItemView showing a glossary label and glossary window

Displaying the ItemView now shows that the desired labels are displayed. Notice that the "type" label is displayed as a link, and the picture shows the glossary window that results when the user clicks on the link.

The method Properties

The next step is to choose what method the ItemView should use to display the field. (In this usage, "method" does not refer to a Java method, but rather to the typical English definition of the word) The "method" resource controls this, and is defined as: <Category name>.ItemView.method.<field> (see the METHOD documentation for more info). Four methods are available:

  1. toString

    The toString method is the default method, and is what the ItemView implicitly uses to display the field if no method is specified in the properties file. The toString method calls Java's toString method on the value of the Attribute that is associated with the field (either by the "basedOn" property or the name of the field if no "basedOn" property is set). If this method is used, no additional resources are needed. For example, to make explicit the fact that the "name" field should use the toString method, include the following in the resource file:
    ${IVprefix}.method.name=toString
  2. lookup

    The lookup method uses the value of the Attribute associated with the field (either by the "basedOn" property or the name of the field if no "basedOn" property is set) as a key to lookup a string in a table of values. This is good for cases when the value of the Attributes comes from a limited set of possible values, and there is a mapping from the Attribute's value to some more easily understandable string. This method is also good when there is a need to localize the text that gets displayed in the field. If the "lookup" type is used, additional "lookup" resources (defined as <Category name>.ItemView.lookup.<field>.<Attribute's value>) should also be provided for each of the possible values of the Attribute. For example, to specify that the "type" field should use the lookup method, and should display the type in Spanish instead of English, include the following in the resource file:
    A: ${IVprefix}.method.type=lookup
    B:
    C: ${IVprefix}.lookup.type.Printer=Impresora
    D: ${IVprefix}.lookup.type.Clock=Reloj
    E: ${IVprefix}.lookup.type.NetscapeExecutable=Netscape
    
    ItemView showing the type in Spanish In this case, the type of the Item will be displayed in it's Spanish equivalent:
  3. richText

    The richText method will display the string value of the Attribute just as the toString method does, but will display it as a link that launches an ItemView. This is generally used to show the relationship between an Item in one Category and an Item in another Category. The example used in this document has one Category, but consider the case where each of the Items in the RhinoExample category had an Attribute in it that specifies the server on which the Item was running. Assume also that there is a second Category, "rhexampServerCategory" with server Items. Consider that the RhinoExample Item has an Attribute with the name "server" that is the name of the server that the RhinoExample is running on, and another Attribute "server_selector" which is the selector of the server in the "rhexampServerCategory" category. (In many cases, the name of the server would be the same as the selector of the server. In that case, substitute "server" for "server_selector" in the following example.) To show a link to the appropriate server from the RhinoExample ItemView, the following would be added to the Resource File:
    A: ${IVprefix}.field3=server
    B: ${IVprefix}.label.server=Server:
    C:
    D: ${IVprefix}.method.server=richText
    E: ${IVprefix}.selector.server=server_selector
    F: ${IVprefix}.category.server=rhexampServerCategory
    ItemView with a link to another ItemView
  4. renderer

    It is sometimes the case that none of the three ways presented so far are adequate to display the state of the Item. Such cases can result when: In any of these cases, the renderer method should be used. This method provides a chance to write a small piece of Java code that will control the display of the field. In the case of the RhinoExample Category, the renderer converts the numeric "mode" Attribute into text that is displayed to the user. For example, the mode "33060" is displayed as "Read Only". See the RhinoExampleCategoryRenderers file for this example.

The missing properties

Depending on the way that the server-side Category is written, there may be cases where a particular Attribute is missing from an Item. For example, consider that the Item can optionally contain the "type" Attribute. If the Item contains that Attribute, then the ItemView should display the name using the lookup method as described above. Otherwise, the ItemView should display some other string, such as "(Unknown)". For this situation, you can use the "missing" resource (defined as <Category name>.ItemView.missing.<field>). The "missing" resource allows you to specify a string that will be displayed if an Attribute is missing from an Item. The "missing" resource can be used with the toString, lookup, or richText methods.

For example, to use the string "(Desconocido)" (Spanish for "Unknown") if the "type" Attribute is missing from the Item, add the following resource:

A: ${IVprefix}.method.type=lookup
B:
C: ${IVprefix}.lookup.type.Printer=Impresora
D: ${IVprefix}.lookup.type.Clock=Reloj
E: ${IVprefix}.lookup.type.NetscapeExecutable=Netscape
F: ${IVprefix}.missing.type=(Desconocido)

Writing an ItemViewFieldRenderer

ItemViews use an instance of the ItemViewFieldRenderer interface to render fields that use the renderer method. There is only one ItemViewFieldRenderer per ItemView, so it must be able to handle all of the fields in the ItemView that are using the renderer method. A class should be written that implements the ItemViewFieldRenderer interface, and placed in the product's "category" package. (The file can actually be placed anywhere, but the "category" package is one logical place). Tell the ItemView how to find the class by naming it in the property file with the "fieldRenderer" property, which is defined as <Category name>.ItemView.fieldRenderer (see the FIELD_RENDERER documentation for more info). For example, the RhinoExampleCategory (whose full name is com.sgi.rhexamp.category.rhexampRhinoExampleCategory) has a class com.sgi.rhexamp.category.rhexampRhinoExampleCategoryRenderers that implements the ItemViewFieldRenderer interface, and so the following line is included in the Category's resource file:
A: ${IVprefix}.fieldRenderer=${RHINO_EXAMPLE_CATEGORY}Renderers
If a field uses the renderer method, but no ItemViewFieldRenderer is defined with the "fieldRenderer" property, then the ItemView will attempt to load a class with the name <Category Name>FieldRenderer. For example, for the RhinoExampleCategory, it would attempt to load the class com.sgi.rhexamp.category.rhexampRhinoExampleCategoryFieldRenderer. If the "fieldRenderer" resource is not specified and the <Category Name>FieldRenderer class is not found, then ItemView will throw an assertion.

The ItemViewFieldRenderer has five methods that must be implemented. See the documentation for ItemViewFieldRenderer about the specifics of each method.

The sequence that the methods will be called in is as follows:
  1. initializeFieldRenderer
  2. getComponentForField (once for each field using the renderer)
  3. renderFields
  4. renderFieldsAgain (zero or more times)
  5. renderFieldsBlank
  6. repeat from step 3 (only if ItemView is used to display another Item)
The initializeFieldRenderer method is responsible for initializing the renderer. The ItemView calls the getComponentForField method once for each field that is using the ItemViewFieldRenderer. The ItemView passes in the name of the field. and the renderer passes back the component that the ItemView should use to display the field. When the ItemView obtains an Item, it passes the Item to renderFields. At this time, the renderer should use the Item to fill in the information that the components are displaying. If the Item changes, the ItemView calls renderFieldsAgain, passing the Item. The renderer should update the components to show the current state. If the Item is deleted, or the ItemView is disposed, the ItemView will call renderFieldsBlank. The renderer should remove any state information from the component, and prepare itself to be garbage collected. In the case that the Item reappears, or the ItemView is set to display another Item, the sequence repeats from step 3 (renderFields).

Writing an ItemViewAdditionalInfoRenderer

The additional info area of the ItemView is completely at the discretion of the programmer, and Java code must be written to display anything. ItemViews use an instance of ItemViewAdditionalInfoRenderer to render the additional info section. Write a class that implements the ItemViewAdditionalInfoRenderer interface, and place it in the product's "category" package. (The file can actually be placed anywhere, but the "category" package is one logical place). Tell the ItemView how to find the class by naming it in the property file with the "additionalInfoRenderer" property, which is defined as <Category name>.ItemView.additionalInfoRenderer (see the ADDITIONAL_INFO_RENDERER documentation for more info). For example, the RhinoExampleCategory (whose full name is com.sgi.rhexamp.category.rhexampRhinoExampleCategory) has a class com.sgi.rhexamp.category.rhexampRhinoExampleCategoryRenderers that implements the ItemViewAdditionalInfoRenderer interface, and so the following line is included in the Category's resource file:
A: ${IVprefix}.additionalInfoRenderer=${RHINO_EXAMPLE_CATEGORY}Renderers
If no ItemViewAdditionalInfoRenderer is defined with the "additionalInfoRenderer" property, then the ItemView will attempt to load a class with the name <Category Name>AdditionalInfoRenderer. For example, for the rhinoExampleCategory, it would attempt to load the class com.sgi.rhexamp.category.rhexampRhinoExampleCategoryAdditionalInfoRenderer. If the "addtionalInfoRenderer" resource is not specified and the <Category Name>AdditionalInfoRenderer class is not found, then ItemView will not display anything in the "Additional Information" section.

The API for the ItemViewAdditionalInfoRenderer is almost identical to that of the ItemViewFieldRenderer. In this case, there are four methods that must be implemented:

The sequence that the methods will be called in is as follows:
  1. initializeAdditionalInfoRenderer
  2. renderInfo
  3. renderInfoAgain (zero or more times)
  4. renderInfoBlank
  5. repeat from step 2 (only if ItemView is used to display another Item)
The initializeAdditionalInfoRenderer method is responsible for initializing the renderer and preparing it for use. The ItemView passes the method a LabelComponentPanel that the renderer should add its components to. When the ItemView receives an Item, it passes the renderInfo method the Item, and the renderer should update the components on the panel as it wishes. If the Item changes its state then the ItemView will call renderInfoAgain and the renderer should update all of the components to show the current state. If the Item is deleted or the ItemView is disposed, then the ItemView will call renderInfoBlank, and in response the renderer should update the components to not show any state and prepare to be garbage collected. In the case that the Item reappears, or the ItemView is set to display another Item, the sequence repeats from step 2 (renderInfo).

Controlling the Icon displayed for an ItemView

The ItemView does not directly control the Icon that is displayed. The Icon is generated by the ResourceBasedIconRenderer. See the tutorial on using ResourceBasedIconRenderer for details on how to control the Icon.

Controlling the title of the ItemView (as displayed on the window's title bar)

The ItemView does not directly control the title that is used. The Title is generated by the ResourceBasedNameRenderer. See the tutorial on using ResourceBasedNameRenderer for details on how to control the title.

Controlling the TaskShelf on the ItemView

The ItemView does not directly control the Tasks shown in the TaskShelf. The Tasks are generated by the TaskRegistry.

How to launch ItemViews

To view an ItemView from the command line, type:

%> java com.sgi.sysadm.manager.RunItemView <package qualified Category name> <Item selector>

For example, to launch an ItemView of the Item "foo" in Category "BarCategory", where the ItemView's resource file is in com/sgi/myProduct/category (relative to classpath), type:

%> java com.sgi.sysadm.manager.RunItemView com.sgi.myProduct.category.BarCategory foo

To launch a "no-code" ItemView, pass the Category selector instead of the fully qualified name:

%> java com.sgi.sysadm.manager.RunItemView BarCategory foo

A "no-code" ItemView will also be displayed if no resources corresponding to the Category are found.

To programmatically launch an ItemView, use one of two methods: To launch an ItemView in a new frame (called an ItemViewFrame), use the launchItemViewFrame method in ItemViewFrame. The launchItemViewFrame method takes a ItemViewLaunchRequestEvent, which encapsulates all the information about which ItemView to launch. For example:

1:   ItemViewFrame.launchItemViewFrame(
2:      new ItemViewLaunchRequestEvent(this,
3:                                     "com.sgi.myProduct.category.BarCategory",
4:                                     "foo"),
5:      new UIContext());

To embed an ItemView in another component, create an ItemView with the createItemView method of ItemView, set Item to display with the setItem method, then call getPanel on ItemView to get a panel that contains the ItemView. For example:
1:   ItemView iv = ItemView.createItemView(_hostContext,
2:                                         "com.sgi.myProduct.category.BarCategory");
3:   iv.setItem("foo");
4:   _panel.add(iv.getPanel());

Typical Resource File for an ItemView

ItemView of the RhinoExampleCategory


A:  # Set up some macros to use in this resource file.  See the
B:  # ResourceStack documentation for more about macros.
C:  RHINO_EXAMPLE_CATEGORY=com.sgi.rhexamp.category.rhexampRhinoExampleCategory
D:  IVprefix=${RHINO_EXAMPLE_CATEGORY}.ItemView
E:  ITprefix=${RHINO_EXAMPLE_CATEGORY}.ItemTable
F:
G:
H:  # Set the width and height of the ItemView.  See the PANEL_WIDTH and
I:  #  PANEL_HEIGHT documentation for more information.
J:  ItemViewPanel.width=333
K:  ItemViewPanel.height=260
L:
M:  # Set up the three fields.  Call the fields "name", "type", and "mode".
N:  ${IVprefix}.field0=name
O:  ${IVprefix}.field1=type
P:  ${IVprefix}.field2=mode
Q:
R:  # Tell the ItemView which Attributes of the Item to use to show the
S:  # appropriate field.  It is not necessary to set the "basedOn" resource
T:  # for a field that is using the "renderer" method, which is why there is
U:  # no "${IVprefix}.basedOn.mode" resource.  In this case, the next two
V:  # lines are unnecessary, because the name of the Attribute is the same
W:  # as the field.  They are included here to make the resource file easier
X:  # to understand and for illustration purposes.
Y:  ${IVprefix}.basedOn.name=name
Z:  ${IVprefix}.basedOn.type=type
AA:
AB: # Sets the labels to be used for the three fields.
AC: ${IVprefix}.label.name.label=Name:
AD: ${IVprefix}.label.type.label=Type:
AE: ${IVprefix}.label.mode.label=Access:
AF:
AG: # Sets the method that the ItemView will use to display the
AH: # three fields.
AI: ${IVprefix}.method.name=toString
AJ: ${IVprefix}.method.type=lookup
AK: ${IVprefix}.method.mode=renderer
AL:
AM: # Resources necessary because the "type" field is using the
AN: # "lookup" method.  See the description of the lookup method for more information.
AO: ${IVprefix}.lookup.type.Printer=Printer
AP: ${IVprefix}.lookup.type.Clock=Clock
AQ: ${IVprefix}.lookup.type.NetscapeExecutable=Netscape
AR:
AS: # Tells the ItemView what classes to use as the
AT: # ItemViewFieldRenderer and the ItemViewAdditionalInfoRenderer.  In this
AU: # case, both renderers are in the same class, but this is not
AV: # necessarily the case.
AW: ${IVprefix}.fieldRenderer=${RHINO_EXAMPLE_CATEGORY}Renderers
AX: ${IVprefix}.additionalInfoRenderer=${RHINO_EXAMPLE_CATEGORY}Renderers
AY:
AZ: # Resources specific to the AdditionalInfoRenderer.  The
BA: # AdditionalInfoRenderer has access the the ResourceStack, so this file
BB: # is a good place to put resources that control the
BC: # ItemViewAdditionalInfoRenderer or ItemViewFieldRenderer.  The names of
BD: # the resources are specific to the code that is written in the
BE: # renderers.
BF: ItemView.AdditionalInfo.marginLeft=0
BG: ItemView.AdditionalInfo.marginTop=0
BH: ItemView.AdditionalInfo.marginBottom=0
BI: ItemView.AdditionalInfo.marginRight=0
BJ: ItemView.AdditionalInfo.layoutType=vertical
BK: ItemView.AdditionalInfo.label=Additional Information:
BL: ItemView.AdditionalInfo.text=This area is available for displaying \
BM:  additional, item-specific Components to represent this item.  In this \
BN:  example, we're just displaying text in a RichTextComponent, but you can \
BO:  put any Component you want in here.