Chapter 7. GUI Elements

Table of Contents

Components
AttributeEditor
Navigator
SlidePanel
Containers
Injecting User-Defined Containers
Document Implementation Classes
SwingMDIComponent
Defining the Container Layout
Injecting Custom Containers
Toolbar
Adding ToolBars
StatusBar

Components

AttributeEditor

The GuiAPI provides default implementations of the AttributeEditor for both the Swing and SWT windowing toolkits and will be discussed in the following section. The AttributeEditor interface was presented in detail in section Attribute Editor.

SwingAttributeTable

Class SwingAttributeTable is a Swing-based implementation of the AttributeTable interface. This has been realized by extending the JTable class.

A typical SwingAttributeTable showing the attributes of a VisualNode object might look like this:

Figure 7.1. Screenshot SwingAttributeTable

Screenshot SwingAttributeTable

To embed the table in a Swing-based application you can benefit by using the AttributeTablePanel class, which wraps this table in a JPanel instance.

This implementation supports the following settings, which can be changed using an AttributeEditorProperties object:

  • String PROPERTYNAME_AUTOEXPANDCATEGORIES

    If this value is true, all categories will be expanded when showing the AttributeTree for the first time. Additionally, no stored tree state is available for the current element type. Default = FALSE

  • String PROPERTYNAME_DYNAMICROWHEIGHT

    Set this property to true in order to enable different row heights. For example, some of the renderers for attribute types need more vertical space. Default = FALSE

  • String PROPERTYNAME_ENABLE_WRITEPROTECTION

    The method isMutable(String) is called to determine the mutable state of an Attribute when this property is enabled. Note: Attributes that are returned from the AttributableOnSet should not be set to mutable by the editor. Only mutable attributes may be changed to immutable to prevent the user from editing. Default = FALSE

  • String PROPERTYNAME_MERGEELEMENTTYPES

    Use this property to merge the element types so that Attributes from different types of AttributableOnSets can be edited in a multi-selection, even though the root element of the structure - which usually represents the name of the type - is different. Default =FALSE

  • String PROPERTYNAME_RENAMINGALLOWED

    Set this property to true if the user should be able to rename attributes in the tree, for example by pressing F2 or clicking in the first column of a selected line. Default = TRUE

  • String PROPERTYNAME_SHOWCATEGORIES

    If this property is set to false, all category elements in the tree are hidden. Default = TRUE

  • String PROPERTYNAME_USEEXACTMATCHING

    If this property is set to true, attribute editor states will exactly match the selected AttributableOnSet instance. Default = TRUE

A SwingAttributeTable uses the mutable state of an Attribute to set the editable state of the corresponding table cell.

To create an instance of this class you have to pass a reference to an initialized UIManager.

The following example will create an SwingAttributeTable that is editable.

Example 7.1. SwingAttributeTable Creation

ApplicationFrame appFrame = null;
//  The application has to provide an UIManager to resolve the texts
//  for the popup menu items. Usually you can retrieve the UIManager
//  from the ApplicationFrame or the GraphApplication.
UIManager uiManager = appFrame.getUIManager();
// create a editable SwingAttributeTable 
SwingAttributeTable table = new SwingAttributeTable(uiManager, true);

SwingAttributeTree

This class is an implementation of interface AttributeTree as presented in section AttributeTree.

As the name would suggest, The SwingAttributeTree class is a Swing-based implementation of the AttributeTree interface. This has been achieved by extending the JTable class.

A typical SwingAttributeTree showing the attributes of a VisualNode object might look like this:

Figure 7.2. Screenshot SwingAttributeTree

Screenshot SwingAttributeTree

It is possible to rename attributes by clicking on their name when selected or by pressing the F2 key. When pressing the CTRL and + keys, the columns of the table can be resized by dragging or resized to show more or less information. To expand an entire category or complex attribute, the user can click on the + symbol while pressing the CTRL key.

REVIEWJAVADOCS [SwingAttributeTree.java]: Why are the configuration settings from class AttributeEditorProperties listed here again?

This implementation supports the following configuration settings, which can be changed using the AttributeEditorProperties object:

  • String PROPERTYNAME_AUTOEXPANDCATEGORIES

    If this value is true, all categories will be expanded when showing the AttributeTree for the first time. Additionally, no stored tree state is available for the current element type. Default = FALSE

  • String PROPERTYNAME_DYNAMICROWHEIGHT

    Set this property to true in order to enable different row heights. For example, some of the renderers for attribute types need more vertical space. Default = FALSE

  • String PROPERTYNAME_ENABLE_WRITEPROTECTION

    The method isMutable(String) is called to determine the mutable state of an Attribute when this property is enabled. Note: Attributes that are returned from the AttributableOnSet should not be set to mutable by the editor. Only mutable attributes may be changed to immutable to prevent the user from editing. Default = FALSE

  • String PROPERTYNAME_MERGEELEMENTTYPES

    Use this property to merge the element types so that Attributes from different types of AttributableOnSets can be edited in a multi-selection, even though the root element of the structure - which usually represents the name of the type - is different. Default =FALSE

  • String PROPERTYNAME_RENAMINGALLOWED

    Set this property to true if the user should be able to rename attributes in the tree, for example by pressing F2 or clicking in the first column of a selected line. Default = TRUE

  • String PROPERTYNAME_SHOWCATEGORIES

    If this property is set to false, all category elements in the tree are hidden. Default = TRUE

  • String PROPERTYNAME_USEEXACTMATCHING

    If this property is set to true, attribute editor states will exactly match the selected AttributableOnSet instance. Default = TRUE

In addition these properties are added in this specific implementation:

  • String PROPERTYNAME_SHOWMENU_MERGETYPEROOT

    This AttributeEditorProperties key changes the visibility of the menu item in the popup menu that controls the merging of the type root. If this value is true (or omitted), the menu entry to merge type roots is shown. Type = Boolean Default = TRUE

  • String PROPERTYNAME_SHOWMENU_SHOWCATEGORIES

    This AttributeEditorProperties key changes the visibility of the menu item in the popup menu that controls if the categories are shown. If this value is true (or omitted), the menu entry to show/hide categories is shown. Type = Boolean Default = TRUE

  • String PROPERTYNAME_SHOWMENUITEM_EDITACCESSSTATE

    This AttributeEditorProperties key changes the visibility of the menu item in the popup menu that shows the editor for the access state (write protection and visibility) of the attributes in the editor. If this value is true (or omitted), the menu entry to edit the access state of attributes is shown. Type = Boolean Default = TRUE

A SwingAttributeTree handles the mutable state of an Attribute, the undefined state caused by a multiselection containing different values and also the state of the tree (selection, expanded nodes and scroll position) when changing all AttributableOnSet objects.

To create an instance of this class you have to pass a reference to an initialized UIManager instance. In addition, you can enable or disable the persistence mechanism which stores the configuration and set the filename that should be used.

Example 7.2. SwingAttributeTree Creation

//  The application has to provide an UIManager to resolve the texts
//  for the popup menu items. Usually you can retrieve the UIManager
//  from the ApplicationFrame or the GraphApplication.
UIManager uiManager = appFrame.getUIManager();

SwingAttributeTree tree = 
    new SwingAttributeTree(uiManager, 
        true,   // <- The editor is editable
        false); // <- Do not save properties

SwtAttributeTree

SwtAttributeTree is the SWT counterpart to the SwingAttributeTree class. It is used to display and edit the attributes of one or more selected VisualGraphObject instances. The attributes themselves are organized in a treelike fashion while different editors are used to assist users in changing their values.

During a multiple selection, the tree tries to combine common attributes. If this is not possible, for example in the case of disparate values, each attribute is listed individually.

Please refer to SwingAttributeTree for a list of supported AttributeEditorProperties.

Below is a screenshot of a typical SwtAttributeTree:

Figure 7.3. Screenshot from a SwtAttributeTree

Screenshot from a SwtAttributeTree

As you can see, an SwtAttributeTree instance uses a TableTree as its basic Composite. Since this widget is deprecated with the release of SWT version 3.1, it is likely that this design will change in future framework versions.

Similar to the Swing-based class, the SWT version is based on an implementation of the AttributeTreeModel. For more information please refer to class SwtAttributeTreeModel.

Finally the code snippet below shows you how a SwtAttributeTree could be used:

Example 7.3. Creating a SwtAttributeTree

		// retrieve the ui manager from the application frame				
		UIManager uiManager = swtAppFrame.getUIManager();
		// the parent of the tree component is a dialog shell, i.e.
		// the attribute tree is embedded into the dialog
        Shell dialog = createDialog();
        SwtAttributeTree swtAttrTree = new SwtAttributeTree(dialog,uiManager);        
        // fill the attribute tree with attributes of an arbitrary VisualGraphObject
        swtAttrTree.setAttributableOnSet(aVisualGraphObject);
        // finally set some properties
        swtAttrTree.getEditorProperties().setProperty(
                AttributeEditorProperties.PROPERTYNAME_RENAMINGALLOWED, Boolean.FALSE);
        swtAttrTree.getEditorProperties().setProperty(
                AttributeEditorProperties.PROPERTYNAME_ENABLE_WRITEPROTECTION, Boolean.FALSE);

Navigator

Here we introduce the Navigator components available in the GuiAPI. Each component type takes care of a particular responsibility in a running application.

NavigatorPanel

The NavigatorPanel is a JPanel-based Swing component that uses a CompositeNavigator, so that it can be used within the application GUI. Moreover, it contains a Renderer and a renderer configuration so that the level of detail and the interaction behavior can be altered.

SwingNavigatorContainer

REVIEWJAVADOC (SwingNavigatorContainer.java) This class responsibility description needs a different formulation. Moreover, the text below has more to do with how this thing can be used!

A NavigatorContainer implementation that contains an instance of a NavigatorPanel and can be used in GUIs like the skeleton where it can be returned in the getNavigatorContainer().

These methods can be used to access the underlying objects:

  • CompositeNavigator getCompositeNavigator()

  • NavigatorPanel getNavigatorPanel()

    Returns the internally used NavigatorPanel. Users of this class might need it to add themselves as ZoomValueListener.

SwtNavigator

Instances of SwtNavigator are responsible for providing the means for displaying a CompositeNavigator in SWT-based applications.

An instance initializes itself with a default rendering configuration It is possible, however, to change it by retrieving the renderer configuration attribute set (see getRendererConfiguration()) and modifying that object.

The graphical display of CompositeNavigatorProvider content is performed by delegating to an instance of class CompositeNavigator. This instance can be retrieved by calling the getCompositeNavigator() method.

The following methods allow you to modify various CompositeNavigator colors:

  • void setNavigatorBackground(int)

    Sets the Color value for the navigator background.

  • void setViewRectBackground(int)

    Sets the Color value for the navigator view rectangle background

  • void setViewRectBorder(int)

    Sets the Color value for the navigator view rectangle border.

SwtNavigatorContainer

Class SwtNavigatorContainer represents the default SWT implementation of the NavigatorContainer interface.

After creating a new instance, you are required to call its init() method before calling any others. Furthermore, no assumption can be made as to which type of Layout is set in the parent AbstractSwtToolContainer class. It is therefore the callers responsibility to set this layout data.

This class uses a Label in order to display the container title (see setTitle(String)) as well as a SwtNavigator instance.

The managed SwtNavigator instance can be accessed by calling the getNavigator() method.

Call the dispose() method to release the resources associated with an object so that it may be properly garbage collected.

SlidePanel

A SlidePanel is a generic parent container for multiple child container windows. This vertically-oriented control provides a title for each slide, each of which contains a child component which is exclusively visible or non-exclusively closed.

Both vertical and horizontal tabbed window controls have major visualization deficiencies. Besides taking up too much space and cluttering up the user-interface, the navigational advantages turn into severe disadvantages as soon as a large number of tabs are present.

The SlidePanel from Tensegrity solves these problems by combining the listbox and tabbed window pane functionalities. Tabs are essentially replaced by items in the list. When a user selects a text item, a content view becomes present underneath it. A previously visible content pane is closed first, so that only one pane is visible at a time.

Creating a Swing SlidePanel

Follow these steps in order to create and use an instance:

  1. Creation: Use one of these available constructors:

    • SlidePanel(UIManager)

      Constructor for top level slide panels specifying the UIManager to be used to fetch the title. This constructor should not be used for nested SlidePanel instances.

    • SlidePanel(UIManager, SlidePanel)

      Use this constructor if the SlidePanel should be nested inside another instance, otherwise the outer panel cannot redraw itself appropriately.

  2. Invoke the addSlideComponent method in order to add a component to a SlidePanel slide.

Below is a screenshot of a typical SlidePanel:

Figure 7.4. Screenshot from a SlidePanel

Screenshot from a SlidePanel

The figure above shows a SlidePanel with two slides: “Simple Shapes” and “Complex Shapes”. Creating it is done like this:

Example 7.4. Creating a SlidePanel with 2 nested SlidePanels

// required to obtain localized strings for the slide titles.
UIManager uiManager= new DefaultUIManager();
 
// the main slide container.
SlidePanel mainSlide= new SlidePanel(uiManager);
 
// the slide, which will contain the simple- and complex Shapes
// and be nested in the main slide.
SlidePanel shapesSlide= new SlidePanel(uiManager, mainSlide);
 
// create a panel for the simple shapes...
RepositoryItemPanel simpleShapesSlide= 
    new RepositoryItemPanel();
 
// ...and add it to the shapes slide
shapesSlide.addSlideComponent(
    GUIItem.SLIDEPANEL_REPOSITORY_SIMPLE_SHAPES_TITLE_IDS,
    simpleShapesSlide);
 
// create a panel for the complex shapes.
RepositoryItemPanel complexShapesSlide=
    new RepositoryItemPanel();
 
// and the second one...
shapesSlide.addSlideComponent(
    GUIItem.SLIDEPANEL_REPOSITORY_COMPLEX_SHAPES_TITLE_IDS,
    complexShapesSlide);
 
// takes 3 arguments: the constant to be used by the 
// UIManager to retrieve the title string and the action to be 
// invoked when users click on the cross icon of the SlidePanel.  
mainSlide.addSlideComponent(
    GUIItem.SLIDEPANEL_REPOSITORIES_TITLE_IDS,
    shapesSlide, 
    new AbstractAction()
    {
        public void actionPerformed(ActionEvent e)
        {
            // Your code to be executed when the main slide 
            // should be hidden, because the user pressed the 
            // "[x] button" */
        }
    }
);

Creating a SWT SlidePanel

Class SwtSlidePanel is the SWT-based implementation of a gui container responsible for displaying several child containers. These child containers are added within a so-called slide, which can be resized, expanded and collapsed.

The parent SWT-based class Composite is ultimately responsible for the correct layout. Therefore, it is usually a good idea for the parent to register itself as a SlideListener and adjust its layout after receiving expand and collapse events.

The following constructors are provided for this class:

  • SwtSlidePanel(Composite, int, String, boolean)

    REVIEWJAVADOC : (SwtSlidePanel.java) I started to correct this javadoc but realized I dont get the bit about the "already localized" title. Also, where are the styles documented? This SwtSlidePanel constructor requires a Composite parent and style since a SwtSlidePanel is a SWT Composite and an "already localized" title. The last parameter indicates whether or not the SwtSlidePanel can be closed. Note that the parent composite is responsible for the correct layout. I.e. it is usually a good idea for the parent to register itself as a SlidePanelListener and adjust its layout on expand and collapse events.

One might find it difficult to create nested instances of class SwtSlidePanel that are properly laid out when resized, collapsed or expanded. We have therefore provided two classes which make this task easier. These classes are SwtSlidePanelContainer and SwtSlidePanelContent:

  1. Class SwtSlidePanelContainer is responsible for managing child SwtSlidePanel instances. Because a SWT-Composite must be resized whenever a SwtSlidePanel it contains is expanded or collapsed, this class implements interface SlidePanelListener and updates its layout whenever notified.

    Instances of class SwtSlidePanelContainer use a FormLayout in order to "hide" and "show" some of their components.

    Please note that no assumption is made upon the layout of the parent, which means that no layout data is internally set for the SwtSlidePanelContainer instance.

    It is possible to nest instances of class SwtSlidePanelContainer by calling the addSlidePanel(String) and addSlidePanel(String, boolean) methods. Note that when calling them, each SlidePanelListener of the parent SwtSlidePanel is also registered on the newly created SwtSlidePanel. This is required in order to ensure the correct layout when slide panels are expanded and collapsed.

  2. Class SwtSlidePanelContent is a SWT-based Composite designed to be used as the content for SwtSlidePanel instances.

    Within the Tensegrity Graph Framework, SwtSlidePanelContent instances are typically used to contain repository items or layout command items.

    In order to properly lay out items when they are resized, SwtSlidePanelContent instances are initialized with a RowLayout.

    Two methods are also provided in order to add repository instances of class VisualGraphObjectSwtRepositoryItem}). While one creates the item icon "on the fly " using its associated composite data , the other method gives the user a chance to set the icon by providing an image file:

    REVIEWJAVADOC (SwtSlidePanelContent): Have a look at the sources for the following two methods...which method parameter allows you to set the icon? The parameter named uiMapValue is not even used in the method!!!

    • AbstractSwtRepositoryItem addItem(String, String, String, int, int)

      Adds the specified repository item to the content.

    • AbstractSwtRepositoryItem addItem(String, String, String, String, Class, int, int)

      Adds the specified repository item to the content.

The following code snippet shows how to create nested SWT SlidePanels and how to add items to one of them:

Example 7.5. Creating and populating nested SWT SlidePanels:

//Create the UIManager 
UIManager uimanager = new SwtDefaultUIManager();
          
//Ensure that your text is localized 
uimanager.setText("mainSlidePanelId", "main swt slide panel");        
uimanager.setText("nestedSlidePanelId", "nested slide panel");       
uimanager.setText("repositoryNodeId", "A node");        
uimanager.setText("YourCommandId", "A command");        

          
//Create a SwtSlidePanelContainer, a container for SwtSlidePanels
panel = new SwtSlidePanelContainer(
        getParent(),//the parent composite
        SWT.NONE,
        uimanager);

//Create the main SwtSlidePanel. This one is not closeable.
SwtSlidePanel mainSlidePanel = 
    panel.addSlidePanel("mainSlidePanelId", false);
         
//The content of a SwtSlidePanel created using addCategoryContainer() 
//is a SwtSlidePanelContainer
SwtSlidePanelContainer content = 
    (SwtSlidePanelContainer)mainSlidePanel.getSlideContent();

//Nested SwtSlidePanel 
SwtSlidePanel nestedSlidePanel = 
    content.addSlidePanel("nestedSlidePanelId");

//Create the SwtSlidePanelContent 
SwtSlidePanelContent nestedSlidePanelContent = 
    new SwtSlidePanelContent(
            nestedSlidePanel,
            SWT.NONE,
            getDragContext(),//Required for repository items
            5,5);

//Update the SwtSlidePanel content
nestedSlidePanel.setContent(nestedSlidePanelContent);
          
//Add the command 
nestedSlidePanelContent.addCommandItem(
        new Command()
        {
            public void setEnabled(boolean enabled)
            {}
            public boolean isEnabled()
            {return true;}

            public String getPerformDescription()
            {return null;}
        
            public String getDescription()
            {return null;}
        
            public String getId()
            {return "YourCommandId";}
        
            public void perform(Object args)
            {
                //Your code to be executed when the command item
                //is selected
            }
        },
        uimanager.getText("YourCommandId"),
        "YourCommandId",
        "icons/dialog/tensign.gif",
        GUIResource.class,
        AbstractSwtRepositoryItem.DEFAULT_WIDTH_AND_HEIGHT,
        AbstractSwtRepositoryItem.DEFAULT_WIDTH_AND_HEIGHT);
          
          
//Add a repository item
nestedSlidePanelContent.addItem(
        "Transducer",//name defined into the elements.xml definition file
        uimanager.getText("repositoryNodeId"),
        "repositoryNodeId",
        AbstractSwtRepositoryItem.DEFAULT_WIDTH_AND_HEIGHT,
        AbstractSwtRepositoryItem.DEFAULT_WIDTH_AND_HEIGHT);
          
          
//Add a basic Composite
Composite cp1 = new Composite(nestedSlidePanelContent,SWT.NONE);
cp1.setBackground(cp1.getDisplay().getSystemColor(SWT.COLOR_BLUE));
RowData rowlayoutData1 = new RowData();
rowlayoutData1.height=AbstractSwtRepositoryItem.DEFAULT_WIDTH_AND_HEIGHT;
rowlayoutData1.width=AbstractSwtRepositoryItem.DEFAULT_WIDTH_AND_HEIGHT;
cp1.setLayoutData(rowlayoutData1);