User Guide

Once you have an object model you need to interact with it, and the most common way of interacting with an application is:

  • Browse through the network of the objects that compose your model
  • Once you have reached the object you are interested in, send commands to it

This interaction can be mediated using services, and we can identify two distinct set of services: Browsers and Commands.

JavATE ApplicATE offers both interfaces and default implementations for this services.

Browsers

Browsers let you navigate through the web of your object model.

The simplest way of doing this is using a list. You can scroll the list, filter its content and select one (or more) element. So we have ListBrowsers.

But there are other ways. If your objects are naturally organized in a hierarchy, you can browse them using a TreeBrowser. If your objects have a master date you can use a CalendarBrowser. And you can invent others.

Pay attention to not confuse the browser (the service) with the user interface. There can be different views for the same way of browsing your objects. A ListBrowser can be viewed as a table where each row represents an object and each column is an object attribute, but we can view it as a grid with an icon representing a single object in each cell.

ListBrowser

Most of the time you will interact with your object model using a ListBrowser.

ListBrowser is an interface that has methods that allow you to:

  • Retrieve the list of objects you are browsing
  • Filter and order this list
  • Select an object
  • Scroll this selection

    The default implementation of this interface is ListBrowserImpl. This class accept a repository as the source of the objects to be browsed. So, given:

    ListBrowser brw = new ListBrowserImpl(new MyObjectRepository());
    

    you can retrieve all the objects in the repository with

    brw.getList();
    

    If you are interested in a subset of the repository only, you can filter the objects using a Filter, so after:

    MyObjectFilter f = new MyObjectFilter();
    brw.setFilter(f);
    

    a call to getList() will retrieve only the objects that satisfy the filter condition.

    ListBrowserImpl will listen to PropertyChange events sent by the filter and react so to change its content properly. If we do

    f.setMyProperty(value);
    

    a successive call to getList() will probably retrieve a different subset.

    To order the objects we can use the two overloaded setObject() methods. One version takes two parameters: the name of the property on which you want to perform the ordering and a boolean that indicate if you want ascending or descending order.

    The second version takes only the property name. If you call it two times with the same property name the order will be inverted.

    To know if the content of the browser has changed, independently of the way it happened (setting a filter or one of the setOrder methods, etc.) you can listen to the PropertyChanged events of the "list" property in a way like this:

    brw.addPropertyChangeListener(new PropertyChangeListener() {
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("list".equals(evt.getPropertyName())) {
                List<?> newContent = browser.getList();
                // ... do something with the retrieved content
            }
        }
        
    });
    
Browser Selection

ObjectBrowser

An object browser is a wrapper around an object of the model that allows to browse its attributes.

At first an object browser could seem useless. You get an object from the model and you can retrieve its attributes using its methods. Why we need a wrapper?

The answer is that the object browser has features that a plain model object can't have:

  • It can listen to command events and automatically refresh its content from the repository
  • It can listen to another browser selection and change the object it is browsing
  • You can retrieve browsers for associated objects

    Let's start from the first one. Every time a command is done there's the possibility that an object changed its internal state. If you have a view on an object there are two possibilities:

  • The view and the command share the same object so each update are reflected on the view
  • The command save a copy of the object in the repository and send an event, so the listeners can retrieve the new copy from the repository.

    ApplicATE use this second approach, and the object browser act as the listener of the event: every time an object browser receive an event from a command signaling that something happened, it retrieves a fresh copy of its content from the repository and fires a PropertyChangeEvent event. The name of the property in the fired event is "hold" because through this property you can retrieve the full object you are browsing on. The "view" object, finally, can listen to this event to update the screen.

TreeBrowser

If your objects are organized in a tree-like structure (as in the Composite pattern) you can use a TreeBrowser to navigate among them.

You will typically pass the root of the tree to the browser, the you will be able to retrieve direct children using the getChildrenOf() method while a generic node can be retrieved using the getTargetOf() method. The latter takes a TreePath object as a parameter and return the node targeted by this path.

Let see some examples using the DefaultTreeBrowser implementation of the TreeBrowser interface.

Suppose you have a set of entities organized in tree-structure like the following:

public class MyNode extends EntityImpl {
    private MyNode parent;
    private List<MyNode> children;
  
    ........
  
    public MyNode getParent() {
        return parent;
    }
  
    ........
  
    public List<MyNode> getChildren() {
        return children;
    }
  
}

When we instantiate the DefaultTreeBrowser we need to give it a repository to access the entities, the id of the root entity, and the name of the properties used to access the parent and the children of each node:

  TreeBrowser<Long,MyNode> brw = new DefaultTreeBrowser<Long,MyNode>(
                                     RepositoryRegistry.instance().getRepository(MyNode.class),
                                     1L,
                                     "children",
                                     "parent"
                                 );

Now we can retrieve all the children of the root with:

  MyNode root = brw.getRoot();
  List<MyNode> rootChildren = brw.getChildrenOf(root);

Using getPathOf() we can retrieve the path of the root entity and the use it to navigate down the tree. In the following example we will retrieve the path of the second child of the third child of the root and the use this path to retrieve this element.

  TreePath path = brw.getPathOf(root);
  path = path.childrenPath(2).childrenPath(1);
  MyNode target = brw.getTargetOf(path);

You can select a node using both the path or the node itself

  brw.select(path);
  // the same as
  brw.select(target);

and then you can retrieve the selected node or the selected path

  MyNode selectedNode = brw.getSelectedObject();
  TreePath selectedPath = brw.getSelectedPath();

CalendarBrowser

Commands

A command is a way to encapsulate an operation in an object. You can create a command object, set the operation parameters passing them to the constructor or using properties accessor methods, and then execute the operation calling a particular method on the command object.

This approach has various advantages:

  • You can record the list of executed commands so as to undo them subsequently
  • You can create create complex operations composing commands as needed at runtime
  • You can decorate the command so as to add features to it

    In JavATE a command is an instance of the Command interface. This interface has a doCommand() method that is used to execute the command and a cancelCommand() method that is used to undo it.

    The other two methods of the Command interface deal with the command events. Every time a command is executed a CommandEvent is fired and you can listen to these events adding a CommandListener implementation to the command using one of the two addCommandListener methods.

    Normally you won't need to directly implement the Command interface. You can instead extend the AbstractCommand class.

Sessions

Contexts