Sunteți pe pagina 1din 91
Swi Swi ng-XML ng-XML Author Author ing ing T T oo oo l l v.

SwiSwing-XMLng-XML AuthorAuthoringing TTooooll

v. 0.5.5

User Guide

by Paolo Marrone http://www.swixat.org

Nov 15, 2006

The Swing XML Authoring Tool User Guide

Table of Contents

Introduction

4

Chapter 1: The MVC Paradigm

5

How the MVC pattern is implemented in SwiXAT

6

The View

8

The Controller

9

The Command Binding mechanism

9

Scripting

11

Application Context based mechanism

11

Direct importing based mechanism

12

Meaning of the Returned Value

13

Automatic declarations

14

Imported Packages

14

Predefined Objects

14

Events Handling

15

Window's Events

15

Components' Events

17

Indirect Command Binding: the <Action> tag

19

Special ActionCommands

21

Reserved words

21

Static method invocation

22

Multiple command support

23

Invoking a command from within script code

23

The Model

23

DataSources

24

The 'origin' attribute

24

Origin attribute in JButton and JMenuItem

24

Origin attribute in button groups

25

The 'render' attribute

25

The DataSource's common attributes

26

The <ContextDataSource>

27

The <ScriptingDataSource>

27

The <XPathDataSource>

27

The <ObjectDataSource>

28

The <DOMDataSource>

29

How to use XPath

29

The Context

31

The 'current' context

32

The 'shared' context

34

Context's keys accessors methods

34

Updating the model: the UpdateOrigin command

35

Using the 'update(

)'

command

36

Page 2

The Swing XML Authoring Tool User Guide

The Model's events handling

37

Chapter 2: Special Features

41

Support for MDI applications

41

The <WindowMenu> tag

41

The <MDIDesktopPane> tag

42

The <ModalInternalFrame> tag

43

Support for JComboBox and JList components

43

The <ComboModel> and <ListModel> tags

43

The <ComboBoxRenderer> tag

44

The ComboBox's “values” attribute

45

Support for JTree components

45

The <TreeModel> and <TreeCellRenderer> tags

45

The <NestedTreeModel> and <TreeNode> tags

49

The enhanced Renderer mechanisms

50

The <XPanel>, <XMenuBar> and <XToolBar> tags

51

The <DatePanel> and <DateField> tags

52

The <TableChooser> tag

53

Support for JTable component

54

The <WizardPanel> tag

57

The <CardPanel> tag

60

Support for DockingPanels

62

Support for PopPup Menus

64

Threaded Action Commands

65

Support for Testing

67

Chapter 3: The Application Context XML file

68

How to launch a SwiXAT based application

69

How to write the Application Context

69

The Application­specific beans

69

The Application bean

70

The Command beans

73

The Application­independent beans

74

The ScriptManager bean

74

The TagLibrary extensions

75

The SetterFactory bean

76

Chapter 4: Getting Started

78

How to build SwiXAT from Source

78

How to create a SwiXAT based Sample Application

79

The Hello World example

82

Example 1: The static Hello World example

82

Example 2: Inserting a Button

83

Example 3: Adding a DataSource

85

Example 4: Passing parameters between two frames

86

Example 5: Validating the user's input

88

Chapter 5: Extending the framework

90

How to add new commands

90

Page 3

The Swing XML Authoring Tool User Guide

Introduction

Introduction

This document aims to explain the functional details of the SwiXAT framework (Swing­XML Authoring Tool – http://www.swixat.org), in order to permit anyone interested to use all the features of the framework.

What is SwiXAT? SwiXAT is the name of the framework built with the aim of providing a powerful User Interface framework based on Swing and XML. It allows new Java applications to be build simply by writing XML parameters and scripted Java code.

Why use SwiXAT if a GUI application can be simply written by using Java­Swing? It takes a lot of work to develop a Swing application, laying out and configuring GUI components, and then integrating them with the application functionality. SwiXAT addresses both of these issues by providing a framework based on a complete implementation of the MVC architectural pattern.

The benefits obtained by a such framework are the followings:

1. Architectural Correctness: By adopting a true MVC (Model View Controller) based framework, it is very easy to correctly implement any UI application. It's not difficult to write a Java/Swing application, but what's very difficult is to build a good, well designed Swing application, where the adoption of the MVC paradigm permits to reduce the maintenance costs, thanks to the clean separation between the view and the application logic.

2. Development Speed: The adoption of a framework reduces the development cost by providing out­of­box, well integrated and easy to use common features, like wizards, plugins, support for

MDI interfaces, etc. Moreover, the use of XML to define the user interface, as well as the

adoption of an interpreted scripting language, permits to implement the 'Code&Test' development

style,

where the compilation time is reduced to zero.

3. Reuse: The net separation between the view and the control logic permits to write reusable

Code

modules that can be combined in several manners. The developer is naturally induced to modularize the application and write reusable code, minimizing the effort of building new applications or adding new functionality to existing ones.

To accomplish the above goals we don't need to implement a monolithic application, but rather thought to develop a powerful framework where the user can assemble pre­built building blocks to implement the required application.

SwiXAT is all the above, and we hope you'll appreciate our effort.

Page 4

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

Chapter 1: The MVC Paradigm

What we need is the possibility to define the UI purely in terms of writing external parameters, for instance by modifying XML files. Consequently we need a Java library to define a swing user interface through XML tags. The idea is as follows:

We need to start with the definition of the MVC architectural pattern, as depicted in the following figure:

Model

4 5
4
5
2
2
   

1

    1  
 

View

View 3 Controller

3

Controller

 
  1   View 3 Controller   Method call Event notification The View represents the

Method call Event notification

The View represents the user interface (frames, panels, etc) containing all the available controls (buttons, labels, text boxes, etc).

The Model represents the objects and the entities handled by the application (i.e. the internal representation of the business model).

The Controller acts like a gateway between the View and the Model. This provides a mechanism to notify the Model about modifications made by the user, and to display changes to the model in the corresponding View.

The continuous­black arrows represent method calls, whereas the dotted­red arrows represent event notifications.

The internal pattern mechanism works as follows:

We'll start from a situation where a View is already displayed to the user, and s/he starts to interact with it. Follow the numbered arrows in the above figure:

Page 5

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

1. The View notifies the Controller about a user's action (like a button click).

2. The Controller calls the corresponding methods on the Model's objects to execute the changes the user has requested (the start of a download from a remote server, for instance).

3. The Controller shows the corresponding View in response to the user's action (a panel containing the progress bar, for instance). When displayed, the View registers itself as a Model's events listener.

4. The Model notifies all the registered Views about any changes within it (for instance, the download of a percentage of bytes).

5. In response of the above notification, the View gets from the Model all the informations it needs to show itself (for instance, the current downloaded bytes).

We will not discuss all the benefits of the MVC pattern at this time, because anyone who is interested can read a lot of documentation on Internet. We will instead concentrate on the implementation of the MVC modules within the framework.

How the MVC pattern is implemented in SwiXAT

Before to start to explain all the features of SwiXAT, we believe it's very important to give you an overview about how this framework is organized and what are the main modules interested. The following picture illustrates the overall architecture on which SwiXAT is based, in terms of used libraries and needed external parameter files:

Model Business Data Model Model DataSource Adapters JXPath Spring View Controller SwiXML BeanShell XML XML
Model
Business
Data
Model
Model
DataSource Adapters
JXPath
Spring
View
Controller
SwiXML
BeanShell
XML
XML XML View
XML XML
ScVripietws View
Views View

Page 6

XML

Application

Context

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

As clearly shown, SwiXAT represents only the glue between the different technologies/frameworks used. The main goal is to permit the developers to write an entire application by writing only XML and scripting code. The necessity for compiled java code is almost totally eliminated, resulting in an improved developing speed, ease of testing, code reusability and readability.

The authors of SwiXAT have made what any conscientious application designer should always do:

to define an overall architecture based on well known design patterns, and then choose the best OS frameworks that permit to implement easily such design patterns. The paradigm is: do not start from scratch, but climb on the shoulders of the Giants. We have simply written the code needed to put it all together, hoping you'll appreciate our choices (being it an Open Source project, you're invited to participate, in order to change/improve the things you don't like).

The main elements involved in any application built on top of SwiXAT are the following:

The View is based on the XUL paradigm, where the design of the UI interface is made by writing XML tags instead of Swing Java code. XML permits to write less code respect to the equivalent java statements needed to build the same user interface. SwiXML is the XUL framework chosen for this purpose, mainly due to its fundamental characteristics like the robustness and extensibility.

The Controller handles requests and creates or prepares the response. Typically controllers need access both to the View and to the business logic (the Model). Controllers handle the request by instantiating a command object, passing it request parameters. Controllers handle the response by delegating to a view and optionally populating a model. Controllers need to be configured with the Spring IoC framework. The Controller can delegate the execution of the control logic to script code based on the BeanShell interpreter (as of SwiXAT 0.3.0 we have added the support for the Groovy language). The use of scripting code permits us to write very fastly all the control (NOT the business) logic of our application. For our choice, all the script code is separated by the XML used to describe the views; in this manner we guarantee a clean separation between the view and the controller, avoiding to build strange mixtures of XML/JavaScript that make the application very hard to read and maintain. This decoupling also guarantees a strong reusability of the defined views (i.e. the same view used in different contexts might need a different logic behind it). Of course the use of script code is not mandatory, because the developer is free to implement the control's logic within standard (compiled) java classes.

The Model, represented by your own data model and/or object model, is accessed by specific data sources, that represent the bridge between the Model and the View/Controller parts. Some pre­built data sources already exist (and many others will be implemented in the next releases), but they're easily extensible, and anyone can build a new one to access to any specific data format. In order to permit to navigate the business model obtained by a data source, we use XPath, a very powerful query language used to traverse DOM trees. As an object model can be viewed as a hierarchical tree, we use JXPath ­ a free java implementation of the XPath language ­ to navigate our own specific object model

Page 7

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

All the above components are kept together by the Spring Framework, a complete and powerful implementation of the “Inversion of Control” pattern. The Spring IoC implementation permits to define within an XML file all the components needed by the application (along with all their dependencies). In this manner Spring represents a powerful mechanism to define and access to all the needed parameters (the so called “Application Context”), permitting in this manner to write within external resources all the dependencies between the different pieces of our application (as an example, the binding between the UI components and the associated commands is defined within the Spring XML file)

In order to build an application, the developers need only to write the external files containing the needed XML (to define both the application context and the views) and JavaScript code (to write the control logic), depicted in the above figure with white boxes.

The following chapters will explain all the details of the above architecture.

The View

In order to be able to easily define a View without writing Java code, the user interface will be defined by XML tags as in the following example. The following code might be contained in a file named ControlPanel.xml.

<Panel name=”Control Panel”> <button text=”Start” <button text=”Stop”

</Panel>

/>

/>

In this manner we could write several useful reusable panels that the user could connect together to build the final user interface. Of course the user can build new panels if needed. Several panels could be assembled within a frame (or a any other Container object) just by using an appropriate tag built to 'include' one panel within another. This tag has been named <XPanel> (standing for eXternal Panel) and used in this manner:

<Frame

<SplitPane orientation=”HORIZONTAL”> <Xpanel xml=”ControlPanel.xml”/> <Xpanel xml=”ProgressBar.xml”/> <SplitPane/> </Frame>

>

In this case we have placed two panels within a JSplitPane, but either of the panels could be included in another frame, making them prebuilt, reusable UI objects. This leaves the freedom of choice about the desired user interface to the user.

To define a Swing interface using XML code, we have chosen SwiX ml , an Open Source framework downloadable from http://www.swixml.org/, hence you need to read the SwiXML available documentation in order to learn more about it.

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

The Controller

We need a mechanism to execute a command in response to a user's action. To do this, we need to write a Java class containing the code of the action and a mechanism to connect it to the corresponding user interface control. We could use the tag parameter ActionCommand to define the corresponding action:

<button name=”Start” ActionCommand=”StartDownload”/>

At this point we need a mechanism to link the ActionCommand string with the component that implements the required action.

The Command Binding mechanism

In order to bind the ActionCommand with the code that will execute the corresponding action, we have defined an interface named org.swixat.commands.Binder. This interface exposes three properties (along with the corresponding getter/setter methods):

Type: (optional) contains the name of the component that executes the invoked action. If defined, it can point either to a custom java class, or a file containing Java interpreted code. See the paragraph 'Scripting' below.

Output: (optional) contains the name of the XML file describing the new View to show in response to an user's action. If declared, the InternalFrame described in the XML will be shown after the execution of the action.

OnError: (optional) contains the name of the XML file describing the view to show in case of the executed actions returns an error. If declared, the InternalFrame described in the XML will be shown after the execution of the action, in case of error.

The Binder interface is actually implemented by the org.swixat.commands.CommandBinder class. However you don't need to call directly the CommandBinder's methods, because we have implemented an easy mechanism to declare the needed command bindings, simply by using XML tags written within a configuration file (named also 'Application Context'. See the 'Inversion of Control (IoC)' section to learn more about the XML Application Context syntax and content).

In order to declare a command used to respond to the user's actions, we need to write within the XML application Context:

<bean id="commandName" class="org.swixat.commands.CommandBinder"> <property name="type"> <value>some/path/command.bsh</value> </property> <property name="output"> <value>somepath/outputFrame.xml</value> </property> <property name="onError">

Page 9

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

<value>somepath/errorFrame.xml</value>

</property>

</bean>

The basic rule for the interpretation of the value of the tag 'type' is the following:

If the ‘type’ property contains a string terminating with ‘ .bsh ’, then that string
If the ‘type’ property contains a string terminating with ‘ .bsh ’, then that string

If the ‘type’ property contains a string terminating with ‘.bsh’, then that string is interpreted as the name of the file containing the scripting code (with the file path relative to the classpath of the application), otherwise the string is interpreted as the class name of the object implementing the GuiCommand interface (that must also be present in the classpath).

as the class name of the object implementing the GuiCommand interface (that must also be present
as the class name of the object implementing the GuiCommand interface (that must also be present
as the class name of the object implementing the GuiCommand interface (that must also be present
as the class name of the object implementing the GuiCommand interface (that must also be present
as the class name of the object implementing the GuiCommand interface (that must also be present

In this manner we let the developer free to choose how to implement the controller's logic of the application. In fact it isn't mandatory to write only script code, because, for some specific tasks, the developer can choose to implement the logic within classic java classes. Both the 'type' and the 'output' properties are optional (although at least one of the above tags must be present) because we could have the following three situations:

<bean id="open" class="org.swixat.commands.CommandBinder"> <property name="type"> <value>bsh/checkSelection.bsh</value> </property> <property name="output"> <value>xml/custDetailsFrame.xml</value> </property> <property name="onError"> <value>xml/errorNoSelectionFrame.xml</value> </property> </bean>

<bean id="exit" class="org.swixat.commands.CommandBinder"> <property name="type"> <value>org.swixat.commands.ExitCommand</value> </property> </bean>

<bean id="about" class="org.swixat.commands.CommandBinder"> <property name="output"> <value>xml/AboutFrame.xml</value> </property> </bean>

The first command named 'open' is used to open a new frame (custDetailsFrame.xml) after having verified (by invoking the script contained in the checkSelection.bsh file) that the user has made some selection on the current frame. In case of error (no selection), an error panel is displayed (errorNoSelectionFrame.xml).

Page 10

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

The command 'exit' is used to close the application, hence only the 'type' tag is declared, within which the class org.swixat.commands.ExitCommand is invoked (as the corresponding value doesn't terminates with '.bsh', the ExitCommand references a java object declared in the framework's classpath).

The last example shows the 'about' command used to open the about box of the application. It uses the tag 'output' to open the frame described by AboutFrame.xml.

Now it should be clear how to link the ActionCommand of a UI component to the corresponding command associated to it.

Scripting

One of the main goals of this framework is to provide easy customization of the application through the writing of external scripts/parameters. Therefore, a powerful mechanism to obtain this goal is represented by scripting code used in response of any user action.

We have chosen the BeanShell (http://www.beanshell.org/) interpreter which allows Java code (not only JavaScript) to be executed from a file. As of SwiXAT 0.3.0 we have refactored the scripting mechanism in order to make it easily extensible. Thanks to that refactoring, the Groovy (http://groovy.codehaus.org/) language support has been added (see the ScriptManager declaration in the 'Application­independent properties' section of this document to know how to activate the desired interpreter).

We have implemented two distinct mechanisms that can be used in order to invoke a script code in response of a user's action.

Application Context based mechanism

Whenever we need to execute some code, in response of which we want to show either an output view or an error view, and when the above association controller/output­view is known a priori, we can declare that association within the Application Context XML file, as already described in the above section.

To do this, we have to specialize the content of the ‘type’ property of the Binder interface. Where we want to execute Java code in response of an action, the value of that tag must be a string representing the name of a file containing the code to execute.

If we need to execute the code contained into the file ‘path/start.bsh’ in response of the action ‘Start’, and then show the 'path/startView.xml' view, we would write in the Application Context XML:

<bean id="Start" class="org.swixat.commands.CommandBinder"> <property name="type"> <value>path/start.bsh</value> </property> <property name=”output”> <value>path/startView.xml</value> </property>

Page 11

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

</bean>

and then we could reference the above command in any UI actionCommand:

<Button text=”Start” actionCommand=”Start”/>

Note: the script file declared within the <type> property must contain NOT only functions (i.e. not

fact, the

only script code contained within a function's body 'funcName() {

framework will execute only the code written outside any function's body. That code, however, can

invoke whatever function declared within the same script file, if needed.

}').

In

Direct importing based mechanism

As of SwiXAT 0.3.5 we have added the possibility to directly import a script file within any XML view in this manner:

<Frame

> <Script id=”script” src=”/some/path/script.bsh”/>

<button id=”b1” text=”Start” actionCommand=”start()”/>

</Frame>

note that the button's ActionCommand parameter contains the string “start()”, that must be the name of a function declared in the script previously imported (the ActionCommand parameter, in this case, must contain a function call terminating either with “)” ­ or “);” ­ in order to permit the framework to discriminate between the two script invocation methods).

The script.bsh file will contain something like this (written in BeanShell syntax):

start() { // Your own code here

}

Of course a single script file can contain any number of functions. In this manner we have eliminated the existing constraint represented by the necessity to write a single function within each script file.

In this case, if the script needs to open, as response, a new view, it must return a org.swixat.framework.OutputView object, by instantiating it with the name of the file containing the view's XML, as in this example:

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

return new OutputView(“/some/path/to/nextView.xml”);

}

Note: the script file imported with the <script> tag must contain only functions (i.e. only script

code contained within a function's body 'funcName() {

control the moment at which the code outside any function will be executed, obtaining uncertain and undesired behavior.

This is because we cannot

}').

You can also pass whatever parameter to the invoked function, like in the following example:

<Frame

> <Script id=”script” src=”/some/path/buttons.bsh”/>

<button id=”b1” text=”1” actionCommand=”buttonHandler(1)”/> <button id=”b2” text=”2” actionCommand=”buttonHandler(2)”/> <button id=”b3” text=”3” actionCommand=”buttonHandler(3)”/>

</Frame>

if the buttons.bsh file contains the following code:

buttonHandler(int x) { System.out.println(“You have pressed the key '”+x+”'”);

}

then, whenever a button will be pressed, the program will print the corresponding number on the standard output console.

Meaning of the Returned Value

Regardless of the used invocation method, a script code can return a value to the caller application. The value returned is a java.lang.Object, so you can put into it whatever value/object. The returned value is used in a different manner, depending on the context within which the script is excuted:

Within a script invoked by the Controller, the returned object can be used to indicate the result of the elaboration: it contains an instance of the Integer class containing either the value 0 in case of success, or 1 in case of error. In this last case, if the script was invoked by a command declared within a CommandBinder, the associated 'onError' view is shown. As for SwiXAT 0.3.5 we have extended this behavior by permitting to return, optionally, a org.swixat.framework.OutputView class. If returned, this class must contain the name of the XML file describing the view to show in response of the invoked script code. Example:

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

In this manner the developer can dynamically choose which view must be shown in response of an ActionCommand.

Indeed the OutputView class exposes other two different constructors:

1. OutputView(String view, String key, Object value) – the 'key' and 'value' parameters, if not set to null, represent a value that we need to pass to the new view by inserting it within the current context, indexed by the 'key' string. 2. OutputView(String view, Map context) – In this case the 'context' parameter contains not only a single key­value pair, but an entire context, represented by an instance of the java.util.Map class. All the keys defined within the Map will be inserted in the current context of the called view.

By using one of the above contructors, the developer can pass whatever parameter to the new view that will be shown in response of the command. The new view will be able to access to those parameters simply by reading the corresponding keys of the current context, either by using a

<ContextDataSource context=”current”

tag from within the XML view, or by

using the 'currentContext' variable from within script code (see the 'Automatic declarations' section below). For commands declared in the XML Application Context, the above two constructors can be called also by setting the view's name to null; in this case we want simply to

invoke the new view (the name of which is declared in the XML application context) by setting its initial context with some key­value pairs.

>

Within a script invoked by a ScriptingDataSource (see the 'Model' section below), instead, the returned value is used as root object returned by the data source. In this manner we can access to whatever property of that object by using an XPath expression in order to bind whatever returned value to any UI control.

Automatic declarations

The framework provides the user with some pre­declared objects/packages useful to access to some internal feature from within a script code:

Imported Packages

In order to declare that some packages have to be imported by default, you can add the corresponding 'import' statement within the ScriptManager declaration, as described in the 'Application­independent properties' section of this document.

In this manner you don't need to declare every time the complete package name, in order to instantiate the most frequently used classes.

Predefined Objects

The framework declares also the following objects:

currentContext: points to an org.swixat.model.Context object containing all the internal variables declared in the application in the form key­value pairs. You can access to any declared value by calling currentContext.getData(“key”) (to learn more about this object, read

Page 14

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

the 'Current Context' paragraph). It contains the following predefined methods:

1. “getWidget”: permits to access to the map containing all the UI components declared in

ID. Example.:

the

current

frame,

indexed

by

their

currentContext.getWidget(“someID”)

2. “getFrame”: returns an instance of the org.swixat.framework.AbstractFrame class, that is the frame that contains the current view. This property is useful in order to be able to call some useful method of the AbstractFrame class, as for instance the executeCommand method. Example: if we need to close the current view from within the script code invoked in response to a command, we can use the following syntax:

currentContext.getFrame().executeCommand(“cancel”)

3. “getShared”: when a new frame is opened, if in the parent frame's context the key 'shared' is present (i.e. it has been set with the setShared(someValue) method), then its value is copied within the newly created frame's context with the same key. Useful to share contexts between childs of the same parent frame.

4. “getParent”: within a frame invoked by another frame, this method returns the caller's

idMap. Example: currentContext.getParent().get(“someParentID”)

application: points to the Application object, as declared in the 'application' bean in the XML IoC properties file, so that you can easily access to the application­specific properties. (See the 'Application­specific properties' section of this document).

context: points to the instance of ContextBinder, which is the container of all the existing contexts declared within our own application. (See the paragraph 'Context' below).

Events Handling

Other than the user's actions, a GUI normally needs to handle specific events raised by the UI components themselves. In order to accomplish this goal, we have implemented a mechanism very similar to that one used to handle the user actions.

Window's Events

In order to handle all the window's events, we have extended the SwiXML tag library with the following new tags:

Tag name

Attributes

Notes

<WindowEvents>

onOpened

(*) The onClosed event can be annulled by the user (see description below)

onClosing

onClosed (*)

onActivated

 

onDeactivated

onIconified

onDeiconified

<WindowFocusEvents>

onGainedFocus

 

onLostFocus

Page 15

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

Tag name

Attributes

Notes

<WindowStateEvents>

onStateChanged

 

They are inserted, normally, within a Frame (or InternalFrame), in the following manner:

<Frame title=”Some title”

>

<WindowEvents id=”windowEvents” onOpened=”actionOnOpenedonClosing=”actionOnClose” /> <WindowFocusEvents id=”focusEvents” onGainedFocus=”actionGainedFocus” />

</Frame>

The value of the above properties contains the name of the action to execute when the corresponding event is raised, exactly as already explained for the ActionCommand property of any UI component. The meaning and purpose of the above events is clear, I think, but a consideration must be done for the WindowEvents' onClosing attribute. While all the above events must be considered just as simple 'notifications' of the corresponding event (i.e. they cannot be annulled), the onClosing event is the only one that can be annulled, giving the user the possibility to avoid the window closing, when requested. The rule is that if the value returned by the invoked action is equal to zero, then the action is confirmed, and the frame is closed (and then the onClosed event is raised and the corresponding action executed, if declared), otherwise the close action is annulled.

Look at the following example, where we have the following frame:

<Frame

> <WindowEvents id=”events” onClosing=”askForClose”>

</Frame>

and the askForClose action points, within the XML application context, to the askForClose.bsh script file, within which the following code is written:

return javax.swing.JOptionPane.showConfirmDialog(null, "Close the Window?", // Message "Close Confirmation", // Title JOptionPane.YES_NO_OPTION, JoptionPane.QUESTION_MESSAGE);

then, when the user closes the above window, a panel asking for the closing confirmation will appear:

Page 16

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

XML Authoring Tool User Guide Chapter 1: The MVC Paradigm as the value returned by the

as the value returned by the script will contain 0 only if the user presses the 'Yes' button, the application frame will be closed only if the user confirms the action.

Components' Events

Also for each UI component we can intercept and handle some events, other than the already declared ActionCommand, as illustrated in the following table:

Tag name

Attributes

Notes

<MouseEvents>

onClicked

 

onDblClicked

onEntered

onExited

onPressed

onReleased

<MouseMotionEvents>

onDragged

 

onMoved

<MouseWheelEvents>

onWheelMoved

 

<KeyEvents>

onPressed

 

onReleased

onTyped

<ItemEvents>

onStateChanged

Applies only to Swing components that inherit the AbstractButton class.

<FocusEvents>

onFocusGained

 

onFocusLost

<InputMethodEvents>

onCaretPositionChanged

 

onInputMethodTextChanged

<ComponentEvents>

onHidden

 

onMoved

onResized

onShown

Page 17

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

Tag name

Attributes

Notes

<ChangeEvents>

onChange

Applies to AbstractButton, JTabbedPane, Jspinner, Jslider,

Viewport, JProgressBar,

and

whatever else Swing component

that exposes 'addChangeListener'

<TableEvents>

onTableChanged

Applies to JTable components

<TreeSelectionEvents>

onValueChanged

Applies to JTree components

<ContainerEvents>

onAdded

 

onRemoved

<PropertyChangeEvents>

onChange propertyName (*)

(*) The propertyName attribute must be set with the name of the component's property to monitor

(ex: propertyName=”text”)

<VetoableChangeEvents>

onChange

 

<DocumentEvents>

onChangeUpdate onChangeInsertUpdate onRemoveUpdate onModified (*)

Applies only to Swing components that inherit the JTextComponent class.

(*) If declared along with other specific event attributes, it's called after all others. Example:

 

if onChangeUpdate and onModified are used together, the onModified action is invoked after onChangeUpdate.

<CaretEvents>

onCaretUpdate

Applies only to Swing components that inherit the JTextComponent class.

<HyperlinkEvents>

onHyperlinkUpdate

Applies only to Swing components that inherit the JTextComponent class.

<ListSelectionEvents>

onValueChanged

Applies only to JList components

All the above tags must be inserted as child of the UI component for which the corresponding event must be handled, as in the following example:

Page 18

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

<TextField id=”name”

<MouseEvents id=”mouse” onDblClicked=”dblClickAction”/> <FocusEvents id=”focus” onFocusGained=”focusGainedAction”/> </TextField>

>

The script invoked by the corresponding event will be able to access to the instance of the associated event (java.awt.event.FocusEvent or java.awt.event.MouseEvent in the above example) by invoking the method “getArgument()” of the current context, as in this example:

event = currentContext.getArgument();

As the description of the meaning of all the above events is out of the scope of this document, we recommend you to read the corresponding documentation available both on Internet and on several technical books.

Indirect Command Binding: the <Action> tag

Sometimes it's useful to associate both the same attributes and the same behavior to different UI components. Think, for example, to the 'Save' command accessible both from a menu item in the File menu and from a button in the toolbar. Of course they must share the same text (eventually translated according to the locale setting), as well as the same state (the 'Save' command must be disabled if there isn't any document opened).

But if we declare the 'Save' command in the following manner:

<MenuItem id="saveItm" text="txtSave" icon="imgSave" mnemonic=”mnSave” accelerator=”accSave” ActionCommand="save"/>

<Button id="saveBtn" text=”txtSave” mnemonic=”mnSave” accelerator=”accSave” ActionCommand="save"/>

we have duplicated a lot of code, because as you can say, the 'text', the 'mnemonic' and the 'accelerator' attributes are declared in both the places with the same values.

Moreover, we have some problem when we try to enable/disable the command, because we should call the setEnabled method on each Button/MenuItem connected to that ActionCommand.

The <Action> tag come in our aid by providing a simple mechanism to share the same command between different UI controls. We can rewrite the previous code in the following manner:

<Action id=”saveAct” text="txtSave" mnemonic=”mnSave” accelerator=”accSave” command=”save”/>

<MenuItem id="saveItm" icon="imgSave" ActionCommand="saveAct"/>

<Button id="saveBtn" ActionCommand="saveAct"/>

Page 19

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

As you can see, all the shared attributes now are declared only in the Action tag. The ActionCommand attribute of each UI component points to the ID of the Action element, and its 'command' attribute indicates which command must be invoked for this Action. Not only we have written the shared attributes only once, but now we can disable the Save command (and consequently all the associated UI controls) simply by writing a single row of script code:

currentContext.getData(“idMap”).get(“saveAct”).setEnabled(false);

The advantages of using the Action tag aren't finished here, because this mechanism permits also to easily reuse the same panel within different contexts.

Imagine we have the necessity to save a file in different formats (say binary or XML) depending on the frame (i.e. the context) from within the 'Save' command is invoked; moreover, imagine that we have built a reusable panel that contains the Save button, that will be displayed within the two different frames (imagine a frame where the panel is displayed alone, while in another one the same panel is displayed together with other panels, for instance within a side of a SplitPane).

You know we can use the XPanel tag to import the same panel within different frames, but a problem arises when we try to determine the content of the Save button's ActionCommand attribute declared within the imported panel.

Imagine we have declared the following commands in the application context:

<bean id="saveAsXML" class="org.swixat.commands.CommandBinder"> <property name="type"><value>saveAsXML.bsh</value></property> </bean> <bean id="saveAsBinary" class="org.swixat.commands.CommandBinder"> <property name="type"><value>saveAsBinary.bsh</value></property> </bean>

we cannot link the Save button's ActionCommand to any of the above commands, because the button will be used in different contexts. You'll have guessed that by using the Action tag we can resolve easily the dilemma, simply by writing, in the Frame_A.xml:

<Action id=”saveAct” text=”txtSaveAsXML” mnemonic=”mnSave” accelerator=”accSave” command=”saveAsXML”/>

<XPanel xml=”xml/myPanel.xml”/>

and in the Frame_B.xml:

<Action id=”saveAct” text=”txtSaveAsBinary” mnemonic=”mnSave” accelerator=”accSave” command=”saveAsBinary”/>

<XPanel xml=”xml/myPanel.xml”/>

whereas, in the myPanel.xml, we can simply write:

Page 20

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

<Button id=”saveBtn” actionCommand=”saveAct” />

Note that, thanks to this mechanism, we've been able also to differentiate the text displayed in the Save button ('txtSaveAsXML' in the Frame_A and 'txtSaveAsBinary' in the Frame_B, both declared in the locale property file).

Special ActionCommands

Reserved words

In order to specify some specific behavior in response of an ActionCommand, we have declared the following reserved words:

Cancel: when a component's ActionCommand contains the string 'Cancel', the corresponding command will close the current frame. The onClosing and onClosed events will be raised, if declared. The following button:

<Button text=”Cancel”/>

when pressed, will close the frame where it appears, without the necessity to write any external script code. In this case we don't need to declare the ActionCommand attribute because by default the button's text represents also the name of the associated ActionCommand.

RefreshView: this ActionCommand will refresh the content of the current frame's UI components, by re­reading all the declared DataSources. We can use this command in different manners:

refreshView ­ refreshes all components

refreshView() ­ refreshes all components

refreshView($id) ­ refreshes the component having the given id

refreshView("id") ­ refreshes the component having the given id

refreshView($id1, $id2, $id3,

refreshView($id1, "id2", "id3",

) ­ refreshes all the components in argument

) ­ refreshes all the components in argument

RefreshViewPattern: similar to refreshView, refreshes the components having the id that matches one or more patterns:

refreshViewPattern("pattern");

refreshViewPattern("pattern1", "pattern2", "pattern3",

);

The “pattern” strings must contain a valid regexp expression.

example: refreshViewPattern("^.*?ButtonPanel$"); refreshes all the components with id like 'PersonButtonPanel', or 'CompanyButtonPanel'

RefreshData: this command clears the content of all the cacheable DataSources within the current frame. See the chapter 'Data Sources' in order to learn more about cacheable data sources.

Page 21

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

Static method invocation

As for the version 0.4.5, we have introduced the possibility to invoke whatever static public method of any class declared in the classpath of the application. The syntax is the following:

ActionCommand=”SomeClass.someMethod($someSource)”

SomeClass is the used class, and the framework searches for this class by using the 'basedir' property declared in context.xml as the package name, after having substituted each '/' with '.'

If basedir = “my/package/name/”, the class fully qualified name is constructed like this:

my.package.name.ClassName

If the class is not found within the package pointed by 'basedir', the class is searched without any package.

The 'someMethod' is searched and invoked for that class. Of course the invoked method must be declared as static.

In the Java class you can have declared more arguments than in the XML code, as in this example:

public class MyClass { public static void myMethod ( Application app, AbstractFrame parentFrame, String dataFromMyDataSource){

}

}

while the XML view contains:

<Button id=”btn” actionCommand=”MyClass.myMethod($myDataSource)”/>

as you can see, the first two arguments are declared only in the java class, while the XML code contains only one argument. The first parameters can belong only to some specific types, so that they can be substituted by the corresponding objects' instances in the framework:

org.swixat.framework.Application

org.swixat.framework.Frame

org.swixat.model.Context

when the action is invoked, respectively the current Application, Frame or Context is passed to the method, according to the matching data type. We also search the missing arguments in _share, idmap and _parent context, in order to call correctly the Java method.

All the remaining parameters declared in the XML view are considered as the name of some

Page 22

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

DataSource declared in the current Frame, so that the corresponding value will be passed to the invoked method (to learn more about DataSources, read the following chapter 'The Model').

As for the version 0.5.0, we can use $e as one of the parameters in the XML call, where $e represents a pointer to the raised event intercepted by the ActionCommand. Of course the method must have declared a corresponding parameter belonging to a compatible type.

If the method returns void, then new Integer(0) is returned, otherwise is the same thing that with any other invoked script function (i.e. the method can return, for example, an instance of OutputView, if needed).

Multiple command support

You can have more than one action in action command, each action must be separate by ';'.

example:

<Button

actionCommand="update($textfield/text, $MyObject/name);

refreshView" />

Invoking a command from within script code

Sometimes it could be useful to invoke a command directly from within script code, for example when we want to execute some action before to invoke the command.

To do that, we can simply write:

currentContext.getData(“_frame”).executeCommand(“command”);

Of course the command string can represent a command declared in the application context file, a script function imported in the current frame, or one of the reserved commands (either 'cancel' or 'refreshView'). The reserved key '_frame' in the current context returns a pointer to the current AbstractFrame class, hence you can call whatever else public method on it.

The Model

This is represented by the object model of the calling application, hence we do not need to build any new class to implement it. We do however need a mechanism to permit a View to get all the data it needs to fill its internal UI controls (see the arrow #5 in the MVC schema).

To do this, we have defined a mechanism based on DataSources.

Page 23

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

DataSources

By looking at the SwiXAT's MVC implementation presented at the beginning of this document, you'll have noticed that the object model of our application is accessed by a layer named 'DataSource'. It represents the bridge between the Model and the View/Controller modules. All the problems inherent the access to specific sources of data are delegated to some specific DataSource implementation.

SwiXAT provides the user with some pre­built DataSource, but new ones can be added simply by implementing the org.swixat.databinding.DataSource interface. The use of the above interface permits the application to access in the same manner to whatever source of data, regardless its nature and/or location. This feature frees us from being worried about the kind of data we need to access to.

The 'origin' attribute

Any DataSource implementation must have a property named 'id', that indicates the DataSource's name used by the Swing UI components in order to be linked to the corresponding data source, as explained in the following example:

<ContextDataSource id=”DSName

/>

The Swing component that needs to be filled by the above data source must declare the property 'origin', setting its value to the id of the corresponding data source:

<label id=”name” origin=”$DSNamedefault=”some/XPath”

/>

In this way a View is able to get the required Model's data by simply connecting the UI control to the corresponding DataSource using the parameter tag 'origin'. When a View is displayed, the framework will invoke all the getData methods on the defined DataSource objects. The 'origin' attribute can contain also a XPath expression, in order to navigate and access to a particular property of the object tree returned by the DataSource, like in the following example:

<Label origin=”$Customer/address/city”/>

Read the “How to use Xpath” paragraph in order to learn more about Xpath expressions.

If the 'default' attribute is found, the value returned by the corresponding XPath is used as the component's origin in case the actual origin's value returns null. Ignored if the origin's value is not null.

Origin attribute in JButton and JMenuItem

As for the version 0.5.0, the 'origin' attribute can be applied also to JButton and JMenuItem

Page 24

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

components, but in this case the behavior is slightly different. For these two components, in fact, the value returned by the DataSource pointed by the origin attribute is used to enable/disable the corresponding button or menu item: if the value returned is either a non­null value or a non­empty result set, the component is enabled. Otherwise it is disabled. The component is also disabled if the value returned by the origin data source is Boolean.FALSE.

Origin attribute in button groups

If the button has the buttonGroup attribute, then the button is added to the specified buttonGroup (creation of the buttonGroup is automatic if needed). The value returned by the origin attribute changes the button's state:

Boolean.FALSE or null = unchecked

Boolean.TRUE or not null = checked

The 'render' attribute

As for the version 0.5.0 we have added also the 'render' attribute, that permits to set the content of a UI component by applying whatever valid XPath function. Let's explain with an example: suppose an origin's XPath expression used for a JLIST or some such reads as follows:

<List origin="$company/department[@name=$dept]/employee">

where $company and $dept are variables that reference previously established xpath data sources. Imagine we would like the widget to display, on each line of the list, the full name of each employee e.g. John Doe, obtained from the @firstname and @lastname attributes of employee.

Our solution has been to add a new render attribute to the GUI component that contains an optional XPath expression that renders the desired result. So, in this instance:

<List origin=”

render = “concat(./@first, ' ', ./@last)”>

As you can see, the '.' (dot) is used to reference the object pointed by the 'origin' attribute. For those that may not know, XPath 1.0 contains a number of handy string manipulation routines, and many other besides that can serve to format content. concat() can be thought of as a sprintf or println equivalent, with much greater expressive power relative to data retrieval, as nested xpath expressions can be employed as done in the example. The scheme is very general, and applies to widgets that either handle lists (set attribute iterate="true", as explained below) or single strings.

Moreover, whenever a render attribute is encountered, the node set (a List when iterate=true) obtained by evaluating the origin xpath expression is saved in the component's "originNodes" client

Page 25

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

property, so you can access to the 'origin' data from within script code by writing the following code:

originData = Component.getClientProperty(“originNodes”);

where Component is a pointer to the GUI component obtained by its ID (see the 'current context' paragraph).

The DataSource's common attributes

All the DataSources components have the following common attributes:

The 'path' attribute This attribute contains the XPath used to get the needed value. It uses as root the object pointed by the data source. In order to learn more about how to use this attribute, read the section 'How to use XPath' below.

The 'iterate' attribute This boolean attribute specifies if the object returned by the application of the xpath expression contains a 'scalar' value (false ­ the default), or a 'vectorial' value (true). This attribute makes sense if we think that an XPath operates on a DOM tree. In some circumstances the xpath expression could return multiple nodes, so in these cases it could be useful to set to true the 'iterate' attribute, in order

to get all the instances found in the document.

For example, for the following XML data source (but the same concept applies also for other types

of data sources):

<developpers>

<person><name>paolo</name></person>

<person><name>benjamin</name></person>

</developpers>

the XPath “/developpers/person/name” returns:

the List [paolo, benjamin] if iterate is true

the String “paolo” otherwise

The 'cacheable' attribute Each DataSource can be declared cacheable, by setting to true the property “cacheable” (false by default). After the first invocation, a cacheable data source stores its data within an internal buffer, avoiding so to extract the data at each call of the DataSource.getData method. This is a very useful feature when the data access/extraction is very expensive in terms of elaboration time or resources occupied, and the source of data doesn't change very often. Of course this property doesn't make sense for every existing DataSources, so in some cases its value doesn't affect the behavior of the corresponding DataSource.

A cacheable DataSource can be cleared by calling the 'refreshData' command (either within a

component's actionCommand attribute, or within script code). After a refreshData command, the

Page 26

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

next call to the DataSource's getData will re­read from the original source.

The <ContextDataSource>

<ContextDataSource id="DSname" cacheable=”true|false” context="contextName" source="sourceObjName" path="some/XPath/selectedProperty" iterate="true|false"

/>

The ContextDataSource is used to get the data from an application's context, and owns the following properties:

context: a string containing the name of the context from which the data is taken. There is one context already declared ­ “current” ­ that contains all the UI Swing components declared in the XML file of the current frame (see the 'current context' section below).

source: a string containing the key of the object stored within the declared context.

path: a string containing the XPath used to get the needed value. It uses as root the object pointed by the declared 'source' within the 'context'.

The <ScriptingDataSource>

<ScriptingDataSource id="DSname" cacheable=”true|false” script="somePath/scriptFile.bsh" path="some/XPath/selectedProperty" iterate="true|false"

/>

The ScriptingDataSource is used to get the data by using interpreted BeanShell java code, and owns the following properties:

script: a string containing the name and path of the file containing the scripting code. Within the script code, the returned object must be put in the predefined 'retValue' variable.

path: a string containing the XPath used to get the needed value. It uses as root the object returned by the invoked script code.

iterate: a boolean value indicating if the value returned by the data source is a scalar value (false) or contains an array of values (true).

The <XPathDataSource>

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

/>

The XPathDataSource is used to get the data from another DataSource, and owns the following property:

path: a string containing the XPath used to get the needed value. It MUST begin with the reference to the DataSource ID that will return the root object on which the remaining XPath expression will be applied.

This DataSource is useful in situations where we need to traverse many times the same object tree, in order to extract different objects/properties, starting from the same root object pointed by another DataSource. This permits us to reuse the same source of data avoiding to repeat many times the same xpath expression, like illustrated in the following example:

<!­ The root CUSTOMER object ­­> <ScriptingDataSource id="EMPLOYEE" script="queryData.bsh" path=”department[@name=$dept]/employee”/>

<!­­ References to the CUSTOMER object's properties ­­>

<XPathDataSource id=”FIRSTNAME” path=”$EMPLOYEE/firstName”/> <XPathDataSource id=”LASTNAME” path=”$EMPLOYEE/lastName”/>

<XPathDataSource id=”ADDRESS”

path=”$EMPLOYEE/address”/>

<Label origin=”$FIRSTNAME”/> <Label origin=”$LASTNAME”/> <Label origin=”$ADDRESS”/>

In this manner we decouple the GUI component from the corresponding data source, so we're able to reuse the same GUI (for example by using the XPanel tag) with different data sources.

The <ObjectDataSource>

<ObjectDataSource id="DSname" cacheable=”true|false” source="spring_Bean_ID" path="some/XPath/selectedProperty"

/>

This DataSource uses as source of data an instance of the object declared in the Spring XML application context, pointed by ID contained in the 'source' attribute.

Its attributes are:

source: a string containing the ID of the object declared within the Spring application context.

path: a string containing the XPath used to get the needed value. It uses as root the bean pointed by the declared 'source' object.

Page 28

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

The <DOMDataSource>

<DOMDataSource id="DSname" cacheable=”true|false” source="spring_DOM_ID" path="some/XPath/selectedProperty" iterate="true|false"

/>

This DataSource accesses to the DOM obtained by the parsing of a resource containing a well formed XML file. The XML resource name must be declared in the Spring application context and is pointed by the 'source' parameter.

source: a string containing the ID of the DOM object, declared within the Spring application context. It must point to a bean belonging to one of the following classes:

String (containing a valid URI)

java.net.URL

java.io.InputStream

path: a string containing the XPath used to get the needed value. It uses as root the DOM instance pointed by the declared 'source' object.

iterate: a boolean value indicating if all the instances found must be returned (false by default)

This DataSource is very useful to get, for example, XML data from an HTTP server, on which the

XML could be formatted dynamically by, for instance, JSP, PHP, language.

other server technology or

any

How to use XPath

Within each DataSource component, the 'path' tag contains a string that points to the property of the object extracted by the corresponding data source. It must contain a path according to the W3C standard XPath syntax 1 (see

XPath is a very powerful mechanism that permits to traverse hierarchical structures. It was thought to navigate XML files (i.e. DOM structures), but an object tree is comparable to a DOM structure and can be traversed very easily using JXPath (http://jakarta.apache.org/commons/jxpath/), a library built to permit to apply XPath to whatever Java object tree.

Let we have the following two java objects in our own object model:

public class Employee { public String getName(){

}

public Address getHomeAddress(){

}

1 A good starting point to learn more about XPath is the W3Schools tutorial at http://www.w3schools.com/xpath

Page 29

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

}

public class Address { public String getStreetNumber(){

}

}

We can access to the StreetNumber of the current Employee simply by using the following XPath:

homeAddress/streetNumber

Of course in the above example the root object is an instance of the class Employee.

Having as root object, instead, a container class containing a list of employees:

public class Employees { public ArrayList getEmployees(){

}

}

We could select a particular employee having the name 'Fred' with the following XPath:

employees[name=”Fred”]/streetNumber

As the complete syntax of the XPath expressions is out of the scope of this paper, we recommend you to read the available JXPath documentation on the corresponding web site.

What we want to illustrate here is how to use XPath within the SwiXAT framework. Continuing with the above example, if we have in the current context a list of employees, we could extract the street number of the employee named 'Fred' by using the following data source:

<ContextDataSource id="DSStreetNumber" context="current" source="employees" path="employees[name='Fred']/StreetNumber"/>

To display the extracted street number within a label, we can write, in the same XML file:

<Label id=”streetNum” origin=”$DSStreetNumber” />

It's important that the data source referenced by the 'origin' property is declared within the same frame/panel containing the swing component that uses it.

The 'origin' parameter can contain also an XPath, so we can easily reuse the same data source by pointing to different objects belonging to the same object tree, as in the following example:

<ContextDataSource id="DS1" context="current" source="employees" path="employees[name='Fred']”/>

Page 30

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

<Label id=”name” origin=”$DS1/name”/> <Label id=”streetNum” origin=”$DS1/homeAddress/streetNumber”/>

In this case we have used a DataSource in order to extract the entire instance of the Empoyee named 'Fred'; after that, the two labels access to two different properties of the extracted object, by using two different XPaths (in the form '$DataSourceName/some/XPath').

Remember: Wherever in the XML view a value of an attribute starts with “$”, then the string is interpreted and evaluated as an XPath expression.

Note: The origin string must always begin with the '$' character, regardless of the presence of a path after the DataSource's ID.

We can also reuse a previously declared data source as key within whatever else XPath:

<ContextDataSource id="NAME" context="current" source="parent" path="name"/> <ContextDataSource id="EMPLOYEES" context="myContext" source="employees"/>

<Label id=”streetNum” origin="$EMPLOYEES/employees[name=$NAME]/StreetNumber"/>

In the above example we have declared the data source NAME, that extracts the wanted name from a TextField contained in the previous frame (the “parent”), and then we have used that data source by referencing it within the Label's 'origin' property, in order to extract the corresponding street number of the Employee having the selected name.

The real value and usefulness of the above mechanism will be clearest after having read the next paragraph about what are and how to use the Contexts.

The Context

To permit the passing of parameters between the Model and the View (and between two or more Views), a context can be created and handled.

Each context is represented by a data structure that stores all the parameters in the form key­value pairs, permitting get/set operations based on that name.

In order to be able to differentiate parameters with the same name, but declared in different Views, we have implemented a mechanism to store different contexts, each one identified by a context name. Consequently we have implemented a 'context by name' accessing mechanism, based on the ContextBinder component.

Page 31

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

The writing/reading of whatever context's value can be done from within scripting code in the following manner:

myObject = context.getContext("contextName").getData("objID");

where:

The implicit variable 'context' points to the container of all the declared contexts (represented in the framework by the org.swixat.model.ContextBinder class)

The string “contextName” is the name of the context to which we want to access. Use the string 'current' to access to the context containing all the UI components of the calling frame. This parameter is omitted if we want to access to the 'default' context (which one created by the framework itself).

The string “objID' is the key identifying the object within the context. For the 'current' context, use the 'id' of the needed Swing component (as declared in the frame's XML file)

If the context name is null, then the 'default' context is returned. The 'default' context is created by the framework when the application is started, so you can use it to temporary store/retrieve your own data.

In order to create a new context, you can write within script code:

newContext = context.setContext(“contextName”, new GenericContext());

and then, to put a key­value pair within it:

newContext.setData(“newKey”, value);

or:

context.getContext(“contextName”).setData(“newKey”, value);

NOTE: because the global contexts, if not accurately cleaned from the old unused values, can create memory leaks, you're invited to avoid to use this global mechanism of memory storage. In any case, remember to deallocate the resources when not more used, by setting to 'null' the corresponding key:

to remove a context's key, use:

context.removeData(“key”)

to remove an entire context, instead, use:

context.setContext(“contextName”, null)

Use instead the current context, as described in the next section.

The 'current' context

As said, the 'current' context contains all the declared variables of our application (in the form key­

Page 32

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

value pairs). It can be accessed either by the ContextDataSource tag within the XML view (using “current” as context name), or from within any script code by using the predefined variable currentContext.

There is a different current context for each frame opened within our application. This means that, when a frame is closed, the corresponding context is destroyed, and its content is passed to the invoked frame within the key “parent”. Hence in any given moment, each frame can access both to its own context and the caller frame's context.

In fact the current context contains the following predefined keys:

idMap”: a java.util.Map containing all the UI components declared in the current frame,

indexed by their ID. Example.: currentContext.getData(“idMap”).get(“someID”)

parent”: within a frame invoked by another frame, this key points to the caller's idMap.

Example: currentContext.getData(“parent”).get(“someParentID”)

The following scheme illustrates how the context is managed by the framework when two frames need to share some UI control's content:

The numbers indicate the steps involved:

CurrentContext A CurrentContext B idMap Key Value parent 3 Key Value name “XYZ” name “XYZ”
CurrentContext A
CurrentContext B
idMap
Key
Value
parent
3
Key
Value
name
“XYZ”
name
“XYZ”
4
2
Frame A
Frame B
Name:
XYZ
Name: XYZ
OK
1

1. The user fills the text field in the Frame A and then pushes the button 'OK' (in the configuration file, the ActionCommand linked to that button opens a new window named 'Frame B').

2. In response of the button's ActionCommand, before to open the Frame B, the framework stores all the UI components in the “idMap” of the current context, in the form of key­value pairs (this is a default action always executed by the framework). Note: even if in the context table we have indicated the content of the text field (the string 'XYZ'), indeed in the idMap the framework stores a reference to the TextField component itself.

3. The framework, before to open the new frame, creates a new context (that will become the current context of the new opened frame), and inserts into it a reference to the Frame A's idMap, with the key “parent” (note: it's a reference, NOT a copy).

Page 33

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

4. The framework, in the initialization code of the Frame B, fills the UI components with the values got from the declared data sources, according the tags written in the frame's XML description file.

The code used in the previous example should be:

In the FrameA.xml:

<TextField id=”name”/>

<Button id=”ok” text=”OK” ActionCommand=”openFrameB”/>

In the FrameB.xml:

<ContextDataSource id=”DSName” context=”current” source=”parent” path=”name/text”/>

<Label id=”custName” origin=”$DSName”/>

So, when this second panel will be displayed, the getText method will be invoked on the TextField component of the Frame A (that one having 'name' as id), and the label 'custName' will be filled with the returned text.

The 'shared' context

In some cases, it could be useful to share some values between more frames, all of them descendants of a unique parent frame. We have resolved this requirement by adding a reserved context's key named '_shared'.

When a new frame is opened, if in the parent frame's context the key '_shared' is present, then its value is copied within the newly created frame's context with the same key.

Context's keys accessors methods

As of SwiXAT 0.5.5, in order to simplify the access to interesting context values, we have defined the following methods:

ctx.getParent():Context returns the context of the parent frame

ctx.getShared():Context returns the shared context

ctx.containsData("key"):boolean checks if the key has been defined in the context

ctx.getFrame():AbstractFrame returns the frame associated with this context

ctx.getWidget(id):Object method to access directly to the Widget registered with 'id' in XML context file

The following JavaScript code:

if (currentContext.getData("idMap").get("id").getSelectedIndex() == ­1)

Page 34

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

{

can be written as:

if (currentContext.getWidget("id").getSelectedIndex() == ­1)

{

Changes introduced in SwiXAT 0.5.5 Note: currentContext.getData(“someKey”) returns now Context.UNINITIALIZED if “someKey” doesn't exist in the context. This permits to differentiate between a null value put by the user, and no existing key.

Consequently, the following JavaScript code:

if (currentContext.getData(“key”) != null) {

doesn't work anymore, so it must be rewritten as:

if (currentContext.containsData(“key”)) {

Updating the model: the UpdateOrigin command

This new command is used to update the origin, or whatever other thing pointed by an XPath expression, when the corresponding event is thrown. It must be inserted within an xxxEvents tag in the XML View. We have prepared some examples in order to explain how does this mechanism work.

Example 1: the TextField's origin is used as target.

<TextField id="TF" origin="$DataSource/someProperty"> <DocumentEvents onChangedUpdate="UpdateOrigin" onInsertUpdate="UpdateOrigin" onRemoveUpdate="UpdateOrigin"> <UpdateOrigin source="$TF/text"/> </DocumentEvents> </TextField>

As you can see, the UpdateOrigin command is executed in response to some document's events. When the command is executed, the <UpdateOrigin> tag is searched, and its 'source' attribute is parsed in order to extract the data used to update the property pointed by the origin's XPath expression. In the above example the DataSource.someProperty will be updated with the value from the text property of the TextField component named 'TF').

Example 2: we use a specifique target because the List's origin is used as list model.

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

target="$AppObject/some/attribute"/>

</MouseEvents>

</List>

Same as the previous example, but in this case the <UpdateOrigin> tag contains also a 'target' attribute. This is because the List's origin attribute cannot be used, as it points to a ListModel, not to an Object's property.

Example 3: here “checkForAttributeValidity” is the actionCommand executed in order to verify some condition: if 0 is returned, then the UpdateOrigin is performed, else nothing is done.

<TextField id="TF" origin="$AppObject/xpath/to/attribute"> <DocumentEvents onChangedUpdate="UpdateOrigin" onInsertUpdate="UpdateOrigin" onRemoveUpdate="UpdateOrigin"> <UpdateOrigin condition="checkForAttributeValidity" source="$TF/text"/>

</DocumentEvents>

</TextField>

If a type conversion is needed between source and target values, you can write and put a specific converter by calling:

org.apache.commons.beanutils.ConvertUtils.register(Converter converter, Class clazz);

The UpdateOrigin tag accepts also an actionCommand attribute. If present, then the declared actionCommand is executed after the update action is performed.

Using the 'update(

UpdateOrigin can be replaced simply by the “update(

)' command

)” command:

update searches UpdateOrigin component in caller if caller is the Container that must perform the update

update(xpathSource) the destination is the origin attribute on the parent component

update(xpathSource, xpathTarget) both source and target are indicated

update(xpathSource, xpathTarget, postActionCommand) same as above, along with the command to execute after the updating is done

update(preConditionCommand, xpathSource, xpathTarget, postActionCommand) the preConditionCommand is executed before the updating is done. Must return 0 if the update must be performed, 1 otherwise.

Example: a selection in the ComboBox changes the value in the TextField, and vice­versa.

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

actionCommand="update($combo/selectedValue/price,

$field/text)"

/> <TextField id="field"> <DocumentEvents onModified="update($field/text,$combo/selectedValue/price)"

/>

</TextField>

In the above example we can see the importance to keep the real object in Swing components, and not the String representation. In the above example we didn't check the price before updating the object, if we want to check the price, we can use a specific UpdateOrigin XML element, as illustrated in the following example:

<ComboBox id="combo" origin="$articles" actionCommand="update($combo/selectedValue/price, $field/text)"/> <TextField id="field"> <DocumentEvents onModified="update(Util.checkStringIsNumber($field/text), $field/text, $combo/selectedValue/price, '')"/>

</TextField>

If the condition in the update returns 0, then the update is done.

The Model's events handling

Someone will have noticed that we still didn't speak about the handling of the model's events, as contemplated by the MVC pattern, and as described by the arrow #4 in the MVC schema shown at the beginning of this document.

As of SwiXAT 0.3.0 we have added a mechanism to handle any event raised by any business object of our model.

The model's event handling is based on a custom class that must be written by the developer. This class represents a 'bridge' between the business object that raises the event and the corresponding framework's class that handles that event. Thanks to this mechanism, the business objects used by our application are not aware of SwiXAT, as they don't need to be coupled with the framework in any way.

The 'bridge' class must implement the interface of the business object's events listener. Moreover, it must extend the org.swixat.events.AbstractModelEvents class.

The mechanism is adherent to the Observer design pattern, and is described in the following schema:

Page 37

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

XML Authoring Tool User Guide Chapter 1: The MVC Paradigm The classes in the above schema

The classes in the above schema belong to the StockPicker example that you can find within the samples directory of the SwiXAT distribution package.

StockListener is an existing interface in the application's object model, and describes the interface to implement to write a model's event listener. The AbstractModelEvents class is declared in the framework, and must be extended by the custom event handler class, that in this example is represented by the StockListenerImpl. The following listing shows its source code:

public class StockListenerImpl extends AbstractModelEvents implements StockListener { private static String PRICE_CHANGED = "onPriceChanged";

/** Specific StockListener's event.

* Inherited from the StockListener interface

*/ public void onChange(PriceChangedEvent pce) { ModelEvent event = new ModelEvent(PRICE_CHANGED, pce.getSource(), pce); fireOnEvent(event);

}

/** Methods invoked by the framework in order to register this wrapper as

* model's event listener.

*/ public void registerAsListener() { ((StockPicker)getSource()).addStockListener(this);

}

/** Methods invoked by the framework in order to unregister this wrapper as

* model's event listener.

*/ public void unregisterAsListener() { ((StockPicker)getSource()).removeStockListener(this);

}

}

Page 38

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

As you can see, we have implemented only three methods:

The 'registerAsListener' and 'unregisterAsListener' methods, that are invoked by the framework in order to permit the wrapper to be registered/unregistered as the model's event listener. As the mechanism used to register a model's listener is dependent on the model's implementation, we need to write here custom code, according to the object model we're using. In the example we call the business object's addStockListener method, passing as parameter a reference to the wrapper itself (this is possible because the wrapper implements the StockListener interface, as expected by that method). The model object to which the wrapper needs to be registered is contained within the 'source' property of this class, and points to the object referenced by the XPath written in the 'origin' parameter of the corresponding tag where this listener has been declared (see view's XML code below).

The 'onChange' method is the specific event handler invoked by the business object when the requested event is raised. It is declared within the StockListener interface and its signature can change depending on your own business model. Within this event handler we need to instantiate a ModelEvent object (the event object expected by the wrapper's listener) passing as constructor's parameters the name of the captured event, along with a reference to the object that has generated the event (in our example we get it by calling the event.getSource() method, but also this can change, and depends on the specific behavior of your business model). After that, we must invoke the fireOnEvent method, that is inherited by the AbstractModelEvents class. This method will permit the SwiXAT framework to notify the listener of this wrapper (i.e. the current View), in order to permit the execution of the corresponding action.

That's all. As you can see, the code you need to write is really simple and is composed only by few rows of java code. Of course this class must be compiled and inserted within the classpath of your application.

In order to be instantiated, this class must be associated to a new tag, and to do it, we need to extend the tag library by writing in the XML application context, within the “newTags” bean (read the Chapter 3 ­ The Application Context XML file – to learn more about it), the following code:

<!­­ TagLibrary extensions ­­> <bean id="newTags" class="org.swixat.framework.TagLibraryExt"> <property name="newTags"> <map> <entry key="StockPickerEventHandler"> <value>org.swixat.samples.stockPicker.model.StockListenerImpl</value> </entry> </map> </property> </bean>

So we can instantiate and use the listener within a view's frame (or internal frame) in this manner:

<Frame

>

<!­­ The source business object ­­> <ContextDataSource id="getStock" context="current" source="stockPicker"/>

Page 39

The Swing XML Authoring Tool User Guide

Chapter 1: The MVC Paradigm

<!­­ Model's Event Handler ­­> <StockPickerEventHandler origin="$getStock" onPriceChanged="refreshView"/>

Now we have all the pieces of the puzzle in the right place, so let's show how the entire mechanism does work:

1. The tag <StockPickerEventHandler> is parsed by the framework when the corresponding view is invoked

2. The corresponding class (StockListenerImpl) is registered as a listener of the business object declared by the 'origin' attribute (an instance of the StockPicker class, in the above example returned by the ContextDataSource named 'getStock'). We know that the registration is made by invoking the method registerAsListener, where the programmer will have written the corresponding code

3. When the business object will raise the 'priceChanged' event, the 'onChange' event handler will be invoked, within which the 'fireOnEvent' method will be invoked, causing the execution of the command declared in the 'onPriceChanged' attribute of the <StockPickerEventHandler> tag ('refreshView' in the above example).

Within the command invoked by the corresponding event handler, it's possible to reference the original model's event object simply by accessing to the '_arg' key of the current context (like already seen in the UI component's event handling). This is very useful in all the situations where the raised model's event contains some custom property to which we need to access.

As you can see, it's very simple to use this powerful mechanism. All you need to do is to write the simple class that implements your own business object's listener, along with few rows of XML code.

As already said, the business model doesn't need to know anything about the SwiXAT framework, because the wrapper creates the needed uncoupling between the model and the framework. This is useful in order to permit to reuse whatever existing business object without modifications.

That wrapper is the only class the developer needs to write, because all the remaining parameters have to be written simply within the corresponding XML parameter files.

Page 40

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

Chapter 2: Special Features

Being SwiXAT based on SwiXml, all the tags defined in that framework can be used within the XML that describes a view. To see a list of all the accepted tags along with their attributes, go to http://www.swixml.org/tagdocs/index.html.

SwiXAT, however, can be extended with new tags, in order to add whatever new feature to a view. Other than some specific tags, like those that permit to declare a data source, that will be explained

in detail in the next chapters, let's explain here what are the tags we have declared to add some

specific UI control to a view.

Support for MDI applications

SwiXAT provides a strong support for MDI ­ Multi Document Interface ­ applications, particularly with the availability of the <InternalFrame> tag, used to instantiate a JinternalFrame.

In order to declare a MDI application, you need to insert a <DesktopPane> tag within the Frame

XML view, and declare the ID of that pane within the XML application context (see the 'Application bean' paragraph in the Chapter 3). After that, you can use all the tags illustrated in this paragraph, in order to use all the features

SwiXAT provides you.

The <WindowMenu> tag

A useful feature, for MDI applications, is to have a menu containing the list of the open internal

frames, along with some tool to adjust automatically the size and position of those frames. The tag <WindowMenu> permits to add such a menu within whatever menu bar, like in the following example:

<menubar>

<WindowMenu id="menuWindow" text="Window" />

</menubar>

The above view, when displayed, will generate a 'Window' menu like this:

Page 41

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

XML Authoring Tool User Guide Chapter 2: Special Features As you can see, it contains the

As you can see, it contains the list of the opened internal frames, where the user can either choose the frame to bring to front, or align the internal frames in two predefined manners (cascade or tile). Whenever an internal frame is opened or closed, the above list is updated to reflect the frames existing in the main window. All the above features are available out­of­box, without writing any line of code! As the class instantiated by the 'WindowMenu' tag extends the Swing's Menu class, it accepts all the attributes permitted for the <Menu> tag, like 'mnemonic', 'accelerator', etc.

The <MDIDesktopPane> tag

Another useful feature for MDI applications is the possibility to have a scrollable desktop pane, so that, when an internal frame is moved outside the visible window's area, a scrollbar is displayed. That desktop pane is obtained by using the tag <MDIDesktopPane> instead of <DesktopPane>, like in the following example:

<Frame

>

<ScrollPane constraints="BorderLayout.CENTER"> <MDIDesktopPane id="desktop" opaque="false"/> </ScrollPane> </Frame>

Note that the MDIDesktopPane, in order to work properly, must be inserted within a ScrollPane component.

This is the visual behavior of a MDIDesktopPane when an internal frame is moved beyond the external border of the main window

Page 42

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

XML Authoring Tool User Guide Chapter 2: Special Features as you can see, a horizontal scrollbar

as

you can see, a horizontal scrollbar appeared.

Of course a vertical scrollbar would be appeared if we had moved the internal frame beyond the

lower edge of the window.

The <ModalInternalFrame> tag

By default, all the internal frames declared with the tag <InternalFrame> are instantiated as no­ modal frames. No­modal frames permit the user to click anywhere in the application's window, outside the no­modal frame, in order to choose/activate whatever else available feature. Although the above behavior is the preferred in many situations within a MDI application, sometimes it's useful to display an internal frame without giving the user the possibility to activate other frames/functionalities of the application until that frame is not closed. This kind of frame is called 'modal', and can be instantiated in SwiXAT by using the tag <ModelInternalFrame>, like in the following example:

<ModalInternalFrame id="aboutFrame" size="350,180" title="About Box" layout="BorderLayout" Maximizable="false" Closable="true">

</ModalInternalFrame>

The 'About Box' is a classical example of a modal frame, and as shown by the above example, the tag ModelInternalFrame can be used exactly as you'd use any InternalFrame tag. The unique difference is that in this manner you create a 'modal' internal frame.

Support for JComboBox and JList components

The <ComboModel> and <ListModel> tags

We have already seen, in various examples, that the 'origin' attribute of a GUI component points to

Page 43

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

the DataSource that extracts and returns the data used to fill the content of the GUI component. This is true also for JList and JComboBox components, because we can fill them by using a DataSource that returns an array of values. Sometimes, instead, we need to interpret the 'origin' attribute as 'the value to use as current value for the component'. In order to accomplish this requirement, as for the version 0.5.0, the support for the JComboBoxModel and JListModel has been added. Let's show how to use them with an example (we'll use a JComboBox, but the same syntax can be used for a JList):

<ComboBox origin=”$DS1/some/path/selectedValue”> <ComboBoxModel origin=”$DS2/some/path/listOfValues”/> </ComboBox>

As you can see, we have two 'origin' attributes:

That one at the level of the ComboBoxModel tag points to the list of values used to fill the content of the ComboBox, while the ComboBox's origin attribute points to the current selected value in the list. This is very useful when, for example, we extract the list of possible choices from a column of a table in a data base, and the current value is read, instead, from the query made on a different table. Of course the two 'origin' attributes can point indifferently either to the same or to different DataSources.

The <ComboBoxRenderer> tag

The ComboBoxRenderer tag permits to encapsulate real Renderers. To learn more about renderers, see the java documentation about javax.swing.ListCellRenderer interface. The real renderer must be a child of this tag in the XML description. This permits to use whatever renderer implemented for a normal swing application in a very simple manner, like in this example:

<ComboBox origin=”$Data”> <ComboBoxRenderer> <MyDefaultRenderer/> <MyPersonRenderer type="Person" childsPropertyName="address/city"/> <MyAddressRenderer type="Address" childsPropertyName="city"/> <MyStringRenderer type="String"/> </ComboBoxRenderer> </ComboBox>

As you can see, you can use different renderers for the same GUI component. In the above example:

1. MyDefaultRenderer is used when no other renderer is found.

2. MyPersonRenderer is used for data belonging to the class Person, and the value displayed will be the value returned by Person.getAddress().getCity()

3. MyAddressRenderer is the same thing, only for instances of the Address class.

Page 44

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

4. MyStringRenderer is the same thing for String objects.

The real renderer used will be that one having the 'type' attribute corresponding to the class of the data pointed by the 'origin' attribute. If there isn't any matching renderer, that one without the 'type' attribute will be used. If no empty renderer is found, the javax.swing.BasicComboBoxRenderer class will be used. Each xxxRenderer tag listed in the XML view must be declared in the XML application context, within the 'newTags' section (see 'The TagLibrary extensions' paragraph), and must point to a class

implementing the javax.swing.ListCellRenderer interface.

The ComboBox's “values” attribute

If values="

You can use an XPath expression for each value.

"

is found on ComboBox tag, it's used as the model. The values are comma separated.

Example:

<ComboBox values='"String","Int","Float",$DS/type'/>

We have also added the support for empty first element: we have added the boolean “firstNull” attribute to permit to have an empty row at the first position:

<ComboBox firstNull="true"

>

Support for JTree components

For JTree components, we have implemented several mechanisms useful to fill the internal tree, starting from the custom object model of the application.

Normally, if the 'origin' attribute declared within the <Tree> tag points to a DataSource that returns a TreeModel instance, that model will be simply used as the tree's model.

Beside this simple basic mechanism, we have implemented two different techniques to set the content of a JTree, as illustrated in the following paragraphs.

The <TreeModel> and <TreeCellRenderer> tags

In order to permit to use a JTree, and fill its internal model with a tree that is loaded starting from some hierarchical structure mirroring our own business model, we have inserted the <TreeModel> tag. Its syntax is the following:

<Tree id="names" origin="$xpath/to/tree/root"> <TreeModel childsPropertyName="rootPropName"> <TreeModelMapping type="some.path.to.subTreeClass" childsPropertyName="subTreePropName"/> </TreeModel>

<TreeCellRenderer textPropertyName="textPropName"

Page 45

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

toolTipTextPropertyName="toolTipPropName"> <TreeCellRendererMapping type="some.path.to.subTreeClass" textPropertyName="subTreeTextPropName" toolTipTextPropertyName="subTreeToolTipPropName"/> </TreeCellRenderer> </Tree>

As you can see, the TreeModel and TreeCellRenderer tags must be inserted within the <Tree> tag of which they describe both the model and the appearance. The 'childsPropertyName' attributes must contain the name of the getter properties that permit to 'traverse' the object tree for data belonging to the class described in the 'type' atribute, whereas the textPropertyName and toolTipTextPropertyName contain the methods that return respectively the description and the tool tip text of each kind of 'type' node.

As example, let's have the following java classes:

public class Animals { private static final Animal rootAnimal = createAnimals();

private static final Animal createAnimals() { Animal root = new Animal("Animals"); root.setChilds(new ArrayList()); // Elements linked by the 'childs' property Animal mammals = new Animal("mammals"); root.getChilds().add(mammals); mammals.setChilds(new ArrayList()); mammals.getChilds().add(new Animal("rabbit")); mammals.getChilds().add(new Animal("dog"));

// Elements linked by the 'subCategories' property NoneAnimal mystic = new NoneAnimal("mystic"); root.getChilds().add(mystic); mystic.setSubCategories(new ArrayList()); mystic.getSubCategories().add(new NoneAnimal("hydra")); mystic.getSubCategories().add(new NoneAnimal("pegasus")); return root;

}

public Animal getRootAnimal() { return rootAnimal;

}

}

public class Animal { private Collection childs;

public Collection getChilds() { return this.childs;

}

Page 46

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

public String getName() { return this.name;

}

}

public class NoneAnimal { private Collection subCategories;

public Collection getSubCategories() { return this.subCategories;

}

public String getDescription() { return this.description;

}

}

The above three classes represent our own object tree:

1. The Animals class builds the entire Animals' tree, and its getRootAnimal method returns the Animal's instance representing the root of the tree.

2. The Animal class represents a kind of nodes of the tree, and the getChilds method points to its childs nodes, constituted themselves by instances of the Animal class.

3. Finally, the NoneAnimal class represents another kind of nodes belonging to the same tree, and the getSubCategories method returns its childs, constituted by instances of the NoneAnimal class.

In order to fill a JTree with the above object tree, we need first of all to write a script that creates and returns the instance of the Animals class (bsh/getAnimals.bsh):

return new Animals();

Now we need to instantiate a JTree having as model the above created object tree:

<ScriptingDataSource id="ANIMALS" script="bsh/getAnimals.bsh"/>

<ScrollPane constraints="BorderLayout.CENTER"> <Tree id="names" origin="$ANIMALS/rootAnimal"> <TreeModel childsPropertyName="childs"> <TreeModelMapping type="org.swixat.samples.baseApp.model.tree.NoneAnimal" childsPropertyName="subCategories"/> </TreeModel>

<TreeCellRenderer textPropertyName="name" toolTipTextPropertyName="name"> <TreeCellRendererMapping type="org.swixat.samples.baseApp.model.tree.NoneAnimal" textPropertyName="description"

Page 47

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

toolTipTextPropertyName="description"/>

</TreeCellRenderer>

</Tree>

</ScrollPane>

In this example the XPath expression written in the JTree's origin attribute points to the rootAnimal property of the Animals class returned by the ScriptingDataSource.

The TreeModel, in order to fill the entire tree, will traverse the object model by calling the 'getChilds' property for each node of kind Animal, and the 'getSubCategories' property for each node of kind NoneAmimal, as declared by the childsPropertyName attributes. The 'getName' and 'getDescription' methods, instead, are used to get the text and tool tip text for the two kinds of node objects.

The resulting tree is the following:

kinds of node objects. The resulting tree is the following: We can also fill a multi­root

We can also fill a multi­root tree by using the same <TreeModel> tag. The unique difference is represented by the root of the tree, that in this case must be a Collection containing all the roots of our tree. To do it, we'll change the XML view in this manner:

<ScriptingDataSource id="ANIMALS" script="bsh/getAnimals.bsh"/>

<ScrollPane constraints="BorderLayout.CENTER"> <Tree id="names" origin="$ANIMALS/rootAnimal" rootVisible="false"> <TreeModel childsPropertyName="childs"/>

</Tree>

</ScrollPane>

Note that the unique difference is represented by the 'rootVisible' JTree's property, set to false

Page 48

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

in order to make the JTree a multi­root tree.

The result of the above changes are displayed in the following figure:

of the above changes are displayed in the following figure: With this simple mechanism we're able

With this simple mechanism we're able to fill a JTree with any kind of hierarchical object tree, regardless of the internal structure of our object model.

The TreeCellRenderer tag accepts also the closedIcon, leafIcon and openIcon attributes, that must contain the icons' paths used for the different kind/state of each tree's node. No resource key is supported at the moment.

The <NestedTreeModel> and <TreeNode> tags

We have implemented a new TreeModel, named NestedTreeModel, to permit to display more easily

a business model's tree of objects in situations where some nodes represent simply the category's name (not derived by real object's instances) within which some child nodes must be grouped.

If

If

we have an object 'Person' like this:

grouped. If If we have an object 'Person' like this: we want to display one person

we want to display one person as Root TreeNode, and somethink like this for tree:

George Brown­+ +­ Parents ­+

|

+­ Mother

Page 49

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

|

+­ Father

Children Friends ­+ +­ Sam Black +­ Ralph White

where the 'Parents', 'Children' and 'Friends' nodes don't derive directly from some object's callable method.

We can write within the XML view:

<Tree id="tree" name="tree"> <NestedTreeModel id="treeModel">

<TreeNode id="rootTreeNode" origin="$Person"> <TreeNode name="Parents">

<TreeNode treeOrigin=" </TreeNode> <TreeNode name="Children">

/

"

childsPropertyName="parents"/>

<TreeNode treeOrigin=" </TreeNode> <TreeNode name="Friends">

/

"

childsPropertyName="childs"/>

<TreeNode treeOrigin=" </TreeNode> </TreeNode> </NestedTreeModel> </Tree>

/

"

childsPropertyName="friends"/>

We get the following interesting features:

We can put any number of TreeNodes in a TreeNode.

treeOrigin take orgine from another TreeNode, only

childsPropertyName contains an XPath pointing to a property belonging to the node's origin pointed by treeOrigin

We can put the origin attribute in any TreeNode, if needed

It's very easy to find the TreeNode associated with any user object. On NestedTreeModel, you have getNode(userObject):TreeNode method (if the same userObject is used more than once, the last is returned). This permits, within script code, to select easily Nodes in a Tree when we have a pointer to one of the used user objects

is permitted or

/

/

, etc

As label of each node, the value returned by the DataSource pointed by the 'origin' attribute is used, if declared. Otherwise treeOrigin.childsPropertyName is used; finally, the 'name' attribute in treeNode is used, if none of the above applies.

The enhanced Renderer mechanisms

As of SwiXAT 0.5.5 (thanks to the great work made by Benjamin Poussin), a new enhanced items rendering mechanism has been implemented. By using it, now it's possible to choose a different renderer based on the class each single item belongs to. This mechanism works for JList, JComboBox, JTree and JTable components.

Page 50

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

The corresponding tags are:

<ListRenderer> and <DefaultListCellRenderer>

<ComboBoxRenderer> and <DefaultComboBoxRenderer>

<TreeRenderer> and <DefaultTreeRenderer>

<TableRenderer> and <DefaultTableCellRenderer>

For example, we can have, for a JTree object:

<Tree id="tree" name="tree"> <NestedTreeModel id="treeModel">

<TreeNode

/>

</NestedTreeModel> <TreeRenderer> <DefaultTreeRenderer type="some.package.Person" childsPropertyName="firstname" toolTipPropertyName="firstname"/> <DefaultTreeRenderer type="some.package.Company" childsPropertyName="name"/>

</TreeRenderer>

</Tree>

in this case we have different renderers for different Classes (Person and Company in the example).

We can also write something like this if all the objects in the tree expose the same property ('name' in the example)

<Tree id="tree" name="tree" renderer="name"> <NestedTreeModel id="treeModel">

/>

<TreeNode

</NestedTreeModel>

</Tree>

The <XPanel>, <XMenuBar> and <XToolBar> tags

Whenever we need to reuse some panel, menu bar or tool bar, we can use these three tags, that permit to import the corresponding GUI definition fragment from an external file.

Their syntax is the following:

<XToolBar xml=”path/to/aToolBar.xml”/> <XMenuBar xml=”path/to/aMenuBar.xml/> <XPanel xml=”path/to/aPanel.xml”/>

Page 51

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

As you can see, all the above tags accept an attribute named 'xml', that must point to the name of the XML file containing the corresponding GUI definition fragment. Of course the root element within each external file must be of a type compatible with the type expected by the corresponding import statement, as in the following examples:

aToolBar.xml:

<toolbar orientation="HORIZONTAL"

>

</toolbar>

aMenuBar.xml:

<menubar>

<menu

>

</menubar>

aPanel.xml:

<panel layout=”GridBagLayout”

</panel>

>

The <DatePanel> and <DateField> tags

The possibility to choose a date from a user friendly calendar­like panel, instead of inserting directly the date by hand, is very useful for many applications that need to ask the user for a date. SwiXAT permits to do it thanks to two tags, named respectively DatePanel and DateField. They are used in the following manner:

<DatePanel id=”someID” origin=”$xpath/to/aDate” date=”mm/dd/yyyy” />

the 'origin' and the 'date' attributes are both optional and mutually exclusive, because both they can be used to set the initial displayed date (set to today by default), respectively in a dynamic or static manner. The resulting component shown in the view is the following:

The resulting component shown in the view is the following: The DateField tag is similar, because

The DateField tag is similar, because it accepts the same attributes of the above component. The unique difference is that it displays a single date field, similar to a combo box, and the calendar

Page 52

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

panel is displayed only when the arrow near the field is pressed. The above two components are derived by the Nachocalendar project (http://sf.net/projects/nachocalendar), hence you can read the project documentation in order to learn more about these components.

The <TableChooser> tag

This component extends a JTable, where one of the columns is reserved to show a check box. The TableChooser is useful whenever we want to show a list of items composed by different fields (displayed within different columns of the table), and want to permit the user to choose some rows of the table by clicking on the corresponding check box.

The TableChooser component can be instantiated in the following manner:

<TableChooser id="TChooser"

/>

columnsName="ColName1|ColName2|

checkBoxCol="n"

origin="$DataSourceID

"

It exposes the following properties:

columnsName: The list of columns' names separated by the character '|'. If omitted, the columns will be named Column 1, Column 2, etc.

checkBoxCol: An integer indicating which column will be reserved to contain the check boxes

origin: Points to the ID of the data source that will return the data contained in the table. The returned value must be a 2D array of Objects. The number of the table's columns will be equal to the number of columns of the array + 1 (that one containing the check boxes)

For example, if we have a DataSource named “CUSTOMERS” that returns the following 2D array of Strings:

Ralph White

White Street, 44 London

Sam Black

Black Street, 55 New York

Tom Yellow

Yellow Street, 66 Paris

Paul Green

Green Street, 77 Rome

and our XML view contains the following code:

<ScrollPane> <TableChooser id="TChooser" columnsName="Name|Call|Address" checkBoxCol="2" origin="$CUSTOMERS"/> </ScrollPane>

Page 53

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

the following TableChooser will be shown:

Special Features the following TableChooser will be shown: As you can see, the second column, that

As you can see, the second column, that contains the check boxes, has been added by the TableChooser itself, as our original table was composed by a 2 columns array. In order to get the list of selected rows, we can write the following script code:

chooser = currentContext.getData(“idMap”).get(“TChooser”); Boolean[] selections = chooser.getCheckData();

obtaining so an array of Booleans where each element is true only if the corresponding table's checkbox is checked.

Support for JTable component

As for SwiXAT 0.5.5 we have added the possibility to easily fill a Table by declaring the source of data with the 'origin' attribute and a TableModel tag.

Example 1:

<table origin="$DS/datas" renderer="name"/>

origin is used as data for DefaultTableModel, must be a 2D array, or a Collection<Collection>

renderer is used to render data. The value is used as property name to access to the model

Example 2:

<table origin="$DS/selected"> <tableModel origin="$DS/list" columns="name, firstname, address/city" columnNames="Name, Firstname, City" columnEditables="false, false, true"/>

</table>

origin in table permits to select rows in table

origin in tableModel is a List of Objects

column is an XPath list, one XPath for each column

columnNames is used as the table header, if missed the column xpaths are used

Page 54

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

columnEditable permits to indicate which columns are editable

Example 3:

<table> <tableModel origin="$DS/number" column="$DS/person$[row]/name, $DS/person$[row]/firstname,$DS/person$[row]/address/city" columnName="Name, Firstname, City"/> </table>

in this case origin is just used to know how many rows the table must have

each column gets all its own data from the indicated XPath. When the table asks for data, each XPath is evaluated by setting the $row variable to the current row, and $o to the current origin object

Example 4:

<table>

<tableModel>

<MyTableModel>

</tableModel>

</table>

in this case MyTableModel is an existing table model (the data access is cabled in code)

Example 5:

<table> <tableModel origin="$Persons"> <column title="Name" property="name" editable="false" type="String" actionEdit="update($e/value, $e/object/name)"/> <column title="Firstname" property="firstname"/> <column title="City" property="address/City" editable="true" type="String"/> <column title="Developer" property="jobs/developer" editable="true" type="boolean"/> <column title="Project" property="project" renderer="concat(name, ' ', startDate)"/> </tableModel> </table>

title is used as column name

property is used to take the value for a cell, property is an XPath that starts from current origin's row

editable is used to make the cell editable

type permits to use easily the default editor registered on the table

renderer permits to define the string representation for the cell; renderer is an XPath that

Page 55

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

starts from the current cell value. We can have renderer defined directly on tableModel, in this case it is used if there is no specific renderer on column.

when a change is made on the column Name, the corresponding value in object person is

directly modified (actionEdit=

)

For actionEdit in $e variable in the command we have:

$e/object: object for the current row

$e/value: new value entered by the user

$e/row: the row that changed.

$e/column: the column that changed

Another example of actionEdit:

<scrollPane constraints="tableConfig"> <table id="tableConfig"> <tableModel origin="entrySet(my.package.SomeObject.getProperties())"> <column title="Property" property="key"/> <column title="Value" property="value" editable="true" actionEdit="my.package.SomeObject.setProperty( $e/object/key, $e/value)"/>

</tableModel>

</table>

</scrollPane>

Example 6:

You can use the attribute layDown="true" in the Table tag to reverse columns and rows:

<table layDown="true"> <tableModel origin="

">

<column title="first"

>

<column title="second"

>

<column title="third"

>

The result is:

first

second

third

Page 56

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

The <WizardPanel> tag

SwiXAT provides a powerful and easy to use mechanism to define wizards, i.e. sequential panels that drive the user to complete some kind of functionalities by asking him the needed informations in a user friendly manner. An auto installer setup program is a classical example of a wizard.

Normally a wizard must respect some simple rules:

The path to reach the final goal (as, for instance, the correct installation of an application) must follow a predefined sequence of panels

The user cannot 'jump' forward to any panel beyond the next in the sequence

The user can go back to the previous panels in order to review his own choices

The user can abort the operation in any moment, regardless of the number of covered panels

A panel can contain informations that depend on the previous choices made in any previous panel

We have implemented the 'wizard' mechanism in SwiXAT by respecting all the above rules, but as we'll show you, some of them can be easily changed.

Let's show how a wizard can be built. As the title of this section indicates, we must use the <WizardPanel> tag, put within whatever frame (either IndependentFrame or InternalFrame), as in the following example:

<internalFrame id="wizardFrame" title="Simple Wizard" size="450,350" layout="BorderLayout" Maximizable="false" Closable="true">

<panel constraints="BorderLayout.NORTH" layout="BorderLayout"> <panel constraints="BorderLayout.NORTH"/> <WizardPanel id="wizpnl" xml="xml/wizPanel.xml" onChange="newTab()"/> </panel> <panel constraints="BorderLayout.CENTER"> <button id="prev" text="Prev" actionCommand="prev" enabled="false"/> <button id="next" text="Next" actionCommand="next"/> <button id="finish" text="Finish" actionCommand="finished()" enabled="false"/> <button text="Cancel" actionCommand="cancel"/> </panel> </panel>

</internalFrame>

The above frame contains the WizardPanel along with the buttons normally used in any wizard:

'prev', 'next', 'finish' and 'cancel'. Their meaning is clear, I think.

Page 57

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

Note that both the 'prev' and 'finish' buttons are initially disabled, as it doesn't make sense to go to a panel before the first one, and also the user cannot finish the wizard (at least in this example) without having traversed all the wizard's panels.

As you can see, there isn't any predefined layout, because you're free to define whatever look&feel for your wizard simply by using the usual SwiXML syntax.

The WizardPanel tag contains two attributes:

xml – indicates the name of the resource containing the XML describing the layout of the wizard (i.e. all the panels that compose it)

onChange – points to the command to execute whenever the user changes the panel (in both the two directions). As always, it can be either a command defined in the application context file, or the name of a function defined within some script file imported in the view with the <Script> tag

Let's show what the file pointed by the 'xml' attribute contains:

<panel name="wizpnl"> <tabbedpane id="tabPane"> <panel name="Panel 1"> put here the content of the first panel </panel> <panel name="Panel 2"> put here the content of the second panel </panel> </tabbedPane> </panel>

It's composed by a panel containing a JtabbedPane component. Each panel within the TabbedPane represents a panel of our wizard, and we must simply put within them all the UI components we need to compose our wizard. The 'name' attribute of each panel will be the label of the corresponding tab within the TabbedPane.

Here is a simple wizard that you can see by launching the baseApp sample application distributed with SwiXAT:

Page 58

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

XML Authoring Tool User Guide Chapter 2: Special Features Once again, you're free to define your

Once again, you're free to define your own layout for each panel in your wizard. Simply put the needed XML tags within the panels contained in the TabbedPane.

What happens when the user click either on the 'next' button or on the tab of the next panel? As said, the command defined in the 'onChange' attribute is executed.

Here is a simple skeleton that you can use as starting point to define the control logic of your wizard:

int newTab() { // Gets the pointers to the wizard's buttons prev = currentContext.getData("idMap").get("prev"); next = currentContext.getData("idMap").get("next");

finish = currentContext.getData("idMap").get("finish"); tabPane = currentContext.getData("idMap").get("tabPane"); // Gets the direction of the tab change (+1, ­1) step = currentContext.getData("_step").intValue(); // Gets the tab selected by the user tab = tabPane.getSelectedIndex(); if (tab > 0) { /* Checks if the user can go to the selected panel */

{

if (

some

condition

)

return ­1; // Error. The selected tab is not activated

}

prev.setEnabled(true); } else { prev.setEnabled(false);

}

// Enables/disables the next and finish buttons

Page 59

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

if (tab == tabPane.getTabCount()­1) { next.setEnabled(false); finish.setEnabled(true); } else { next.setEnabled(true); finish.setEnabled(false);

}

return tab; // All OK, returns the tab # to activate

}

As you can see, we have the complete control over any aspect of the wizard's behavior:

We can read which tab has been selected by the user, along with the direction of the tab change (see the variable 'step' in the above listing, that gets its value from the key '_step' in the current context: it will contain +1 if the user is going forward in the wizard, otherwise ­1).

The script must return an integer containing the index of the tab to activate. It normally is set to the value returned by TabbedPane.getSelectedIndex(), but by returning a different value we can select whatever else tab, forcing in this manner some particular path in the wizard when some specific condition is verified.

We can also check if the user can activate the chosen panel, having the possibility to block the action, in case of error, by returning the value ­1 (in this case the selected tab remains unchanged).

We can also access to whatever component of our panels, having the possibility to enable/disable whatever UI control depending on any condition.

Look at the source code of the wizard implemented in the baseApp example in ordere to learn all the possibilities of this useful buil­in feature.

The <CardPanel> tag

This panel is just a JPanel with a CardLayout manager. This widget is useful if used along with the CardPanelModel. To change the displayed panel, just change state in CardPanelModel.

By default, when the current panel changes, refreshView is called. But you can change this beaviour by declaring the refreshCommand attribute with the following contents:

refreshView(id)

refreshViewPattern(pattern)

any other command (script, static java, xpath:, you can also deactivate the view refreshing by using refreshCommand="" (empty string)

)

You can invoke any action when the current panel changes with

<CardPanel onChange="

code

">

Page 60

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

This component, if used along with CardPanelModel, can be useful to easily implement wizard panels.

example:

<frame id="myWizard" visible="true" Size="400,100" title="myWizard">

<ContextDataSource id="wizardModel" context="current" source="wizardModel"/>

<cardPanel origin="$wizardModel" refreshCommand="refreshViewPattern('navBut.*')">

<panel constraints="begin">

</panel>

<panel constraints="step1">

</panel>

<panel constraints="step2">

</panel>

<panel constraints="end">

</panel>

<panel constraints="AnotherPossibleTerminalState"> </cardPanel>

<button id="navButPrec" text="Prec" origin="not($wizardModel/begin)" actionCommand="prev"/> <button id="navButNext" text="Next" origin="not($wizardModel/end)" actionCommand="next"/> <button id="navButFinish" text="Finish" origin="$wizardModel/end"

</panel>

actionCommand="

my command

"/>

<button text="Cancel" actionCommand="cancel"/> </frame>

You can use your own actionCommand if you don't have overloaded prec, next, and finish methods in your own model. In this case your actionCommand must change the property “state” of the model in order to change the visible page.

If you don't need to skip steps and don't have different choices (more than one final step), you don't need to use any specific CardPanelModel.

example:

<frame id="myWizard" visible="true" Size="400,100" title="MyWiard">

<cardPanel id="wizardPanel"> <panel constraints="begin">

</panel>

<panel constraints="step1">

</panel>

<panel constraints="step2">

</panel>

Page 61

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

<panel constraints="end">

</panel>

</cardPanel> <button text="Prec" origin="not($wizardPanel/begin)" actionCommand="prev"/> <button text="Next" origin="not($wizardPanell/end)" actionCommand="next"/> <button text="Finish" origin="$wizardPanel/end"

actionCommand="

your

method

"/>

<button text="Cancel" actionCommand="cancel"/>

</frame>

If you use CardPanelModel, you can create your own child implementation to use as model, and add some specific method to set the properties in this model in order to collect informations during the wizard usage in conjunction with UpdateOrigin (or update).

Support for DockingPanels

We have added the support for docking panels by integrating the FlexDock (https://flexdock.dev.java.net/) framework. The docking panels (known also as floating windows) permit to move the frames within a multi­ panel GUI simply by dragging the title bar of each frame. They can be moved around and manipulated by the user (in terms of size, position, and stacking). This type of configurable UI where views can be snapped into place is typically referred to as a docking UI. Complex UIs such as Eclipse and Netbeans have a docking UI.

You can define a docking UI with the following syntax:

<DockingPort? shadowBorder="true" floatingEnabled="true"> <GradientDockablePane id="ID1" title="Root docking panel" dock="root" layout="BorderLayout"> <!-- First panel's UI components here --> </GradientDockablePane> <GradientDockablePane id="ID2" title="Second docking panel" dock="ID1" region="SOUTH" ratio="20"> <!-- Second panel's UI components here --> </GradientDockablePane> <GradientDockablePane id="explorer" title="Explorer" dock="ID1" region="WEST" ratio="30" layout="BorderLayout"> <!-- Third panel's UI components here --> </GradientDockablePane> </DockingPort>

The container of all the docking panels is represented by a <DockingPort> tag.

Page 62

The Swing XML Authoring Tool User Guide

Chapter 2: Special Features

Each dockable panel must be declared with a <GradientDockablePane> tag. Each dockable panel must be identified by an id, because we can refer to it when inserting other panels, by means of the attributes dock="parentID" and region="NORTH|SOUTH|WEST|EAST". The ratio attribute, if present, contains the panel's size in percentage.

If region is omitted, the new panel is stacked within the parent panel.

A dockable panel with dock="root" must be ALWAYS inserted, and corresponds to the root panel,

i.e. the panel that is 'child' of the DockingPort?, and is the parent of all the other docking panels.

Instead of GradientDockablePane (that displays panels with a gradient title bar and a pin to hide the panel), we can use also DockableView, having the same attributes, but displayed without the pin, with a flat­color title bar.

See the example in /samples/docking directory of the SwiXAT package.

Example:

The following XML code:

<DockingPort shadowBorder="true" floatingEnabled="true"> <GradientDockablePane id="editor" title="Document1.txt" dock="root" layout="BorderLayout"> <ScrollPane constraints="BorderLayout.CENTER"> <TextArea text="This is the text of the Document 1 </ScrollPane> </GradientDockablePane> <GradientDockablePane id="output" title="Output" dock="editor" region="SOUTH" ratio="20"/> <GradientDockablePane id="explorer" title="Explorer" dock="editor" region="WEST" ratio="30" layout="BorderLayout"> <ScrollPane constraints="BorderLayout.CENTER"> <Tree/> </ScrollPane> </GradientDockablePane> <GradientDockablePane id="editor2" title="Document2.txt" dock="editor" layout="BorderLayout"> <ScrollPane constraints="Borde