r2 - 10 Aug 2006 - 13:27:38 - TimPetersonYou are here: TWiki >  GRAPEcluster Web  >  Documentation > GraphicalProgrammingArchitecture

Graphical Programming Architecture

Overview

The Program tab is indended to support multiple views of the functions in the system. To this end, the View class contains the base functionality required to listen for events from all functions. Plugins extending View can be placed in the spiegel.viewcontrol.mapview.plugins.program.views package. However, plugin support is currently unimplemented, instead creating the JGraphView class directly.

View class

The View class handles placing listeners on all functions, groups, inputs, and outputs within its scope. The scope is defined by a FunctionGroup passed to the View constructor. View defines a number of empty methods corresponding to events, which a class extending View can override. These include onNewFunction(), onDelFunction(), and so on. This saves extending classes from having to track all creations and deletions manually in order to add listeners to all objects. Upon creation these methods are called for all objects within the scope, as if they had just been created. Following creation, these methods are called in response to events received from objects in the system. All of the events are also relayed from the View, so listeners can be added directly to the View to receive them.

JGraphView

JGraph

JGraphView uses as its core the JGraph package. This package provides visualization of mathematical graphs, consisting of nodes connected by edges. In this case, the nodes are functions and the edges are the connections between inputs and outputs on the functions. JGraph also supports the concept of ports, which are a way of differentiating the different endpoints on a single node that an edge can connect to, in this case the inputs and outputs.

All nodes, ports, and edges (collectively known as cells) in JGraph inherit from DefaultGraphNode, which provides a common interface for controlling them. All visible properties of cells are controlled by an attribute map, which is a Map from predefined string constants in GraphConstants to appropriately-typed values. The GraphConstants class provides getters and setters which enforce the proper types.

Each object in the function framework has two counterparts in the GUI: a model object and a view object. The former contains the graph information, while the latter handles providing a renderer component to draw the object on-screen. Each Function or FunctionGroup has an associated DefaultGraphCell and VertexView. Each DataInput or DataOutput has a DefaultPort and a PortView. Links between inputs and outputs have only a DefaultEdge and a EdgeView, with no underlying object in the function framework.

JGraph consists of three main classes: JGraph, DefaultGraphModel, and GraphLayoutCache. JGraph serves as the Swing container for the graph. DefaultGraphModel contains the cells of the graph structure. Finally, GraphLayoutCache is a view of the model, following the model-view pattern, handling CellViews which determine the appearance of the cells.

Plugins

JGraphView supports plugins, found in the spiegel.viewcontrol.mapview.plugins.program.views.jgraph.plugins package or in locations specified by the system property spiegel.program.jgraphview.plugins. Plugins must extend the JGraphPlugin class. There are three types of plugins.

Option plugins, extending JGraphOptionPlugin, provide display options that go in a specific category in the Options menu on the JGraphView interface. When the user turns these options on or off, the plugin is notified and can take whatever actions are necessary.

Action plugins, extending JGraphActionPlugin, specify operations that can be performed on the graph. They produce items on the Actions menu, which, when chosen, invoke the plugin.

Control panel plugins, extending JGraphControlPanelPlugin, provide Swing panels that will be displayed as part of the frame around the graph area. They can be used to provide information or controls for the graph.

Attribute layers

Cells' attributes are changed via the GraphLayoutCache.edit() method, which takes, among other arguments, a Map between model cells and the corresponding attribute maps containing the changes to be made to the attributes. JGraphView provides a higher-level interface to editing attributes, using AttributeLayers.

All JGraph attributes used in JGraphView are set by means of AttributeLayers. JGraphView contains a stack of these layers, each of which can supply any attribute for any object in the system. The function-level objects are used for this purpose, not the model or view objects. When two layers specify values for the same attribute on the same object, the one higher on the stack takes precedence (but see the exception below). This allows one layer to selectively override the value provided by a lower layer.

Any option plugin can provide attribute layers, by overriding the getLayers() method from JGraphOptionPlugin. Layers needn't be directly related to options; for example a plugin can have two layers which are both controlled by two separate options simultaneously. The layers from all plugins are stacked in an order specified by the layerorder.lst file in the spiegel.viewcontrol.mapview.plugins.program.views.jgraph package.

Attributes are stored in an ObjectAttributeMap, which is a Map<Object, Map<String, Object>> with extra methods to help manage the data structure. Each object-attribute pair is independent of all others, so each object can have its own set of attributes.

Layers are only allowed to set attributes which they have declared that they will affect. This is done by calling the JGraphView.setAffectedAttributes() method. This takes two parameters: the layer making the call, and an array of strings indicating which attributes may be affected by the layer. This provides some protection from mistakes in writing layers, so that attributes cannot be changed accidentally. It also provides an easy way to remove all attributes from a layer when an option is deactivated. It may also in the future allow for more optimization in the updating of layers, since only the total set of attributes being affected in the stack must be processed, and completely separate layers can be skipped.

Each layer's current attribute values are stored by the JGraphView, and can only be changed when JGraphView updates the stack as a whole. Once a layer has declared its affected attributes, it can request that some of them be updated. This is done through the JGraphView.requestUpdate() method, which takes three arguments in several different forms. The first argument is always the layer on which an update is being requested. The second argument specifies which objects' attributes need to be updated. This can be either a single object reference, an array of objects, or a Class object, in which case all objects of that class will be updated. The third argument specifies which attributes on those objects need updating, as either a single String from the GraphConstants class or an array of Strings.

By default, the layer stack is updated whenever a request is made for an update. However, sometimes multiple request calls are made together, and it would be inefficient to update after each one. Fo this reason JGraphView provides the beginUpdateRequest() and endUpdateRequest() methods. All requests made between these calls will be queued until endUpdateRequest() is called. These calls can be nested, so long as they come in pairs.

JGraphView.update() handles determining which requests must be fulfilled and combining the layers' data to determine the composite attribute map for each object. It does this by iterating over all layers from top to bottom. It keeps track of the current attribute states from the layers it has already processed as well as a map of all changes that have been made during this pass. For each layer, it first calls AttributeLayer.attributesChanged(), passing it the change map. This allows one layer to change in response to changes in higher layers. If desired, attributesChanged() can then call requestUpdate(). If so, these requests are immediately processed. If any requests have been made for attributes which are shadowed by attributes higher in the stack, they are saved for later and not processed now. Then the layer's update() method is called. The first argument is the complete attribute map from the layers above, in case it needs to read from them. The second argument is the map of requests in this layer that must be updated, with null values where data must be stored. Upon returning, the values for this layer are replaced by the values in the second argument's map. For each attribute, if a value is specified it replaces the old value. If it is null, the attribute is removed from the layer. If the mapping was removed during the update(), the old value is retained. When all layers have been processed, the final map of changes made by the layers is applied to the graph.

Normally the topmost layer asserting an attribute gets its way. However, sometimes it is necessary for one layer to change the output of a previous layer. For this reason, layers can set overidden attributes. This is done using the JGraphView.setOverrideAttributes() method, used in the same manner as JGraphView.setAffectedAttributes(). The layer will still receive data from this attribute as input, but whatever it outputs will replace the input from previous layers. This used in the UserFunctionhandler layer which determines the position of the Container function based on the positions of all the other functions in the group.

Options

The JGraphOptionPlugin class defines a method getOptions(), which option-providing plugins override. The return value is a map between option types (found in JGraphView) and lists of JGraphView.Option objects. (A convenience method createOptionMap() is provided to easily create this map.) For plugins with only one option, it is possible for the plugin class to also implement Option. Each option will be displayed in the appropriate menu. When the user clicks on it, either activate() or deactivate() will be called on the Option object.

Options can add listeners to JGraphView to learn of new objects for which updates should be requested. JGraphOptionPlugin provides facilities for doing this for all of a given class of objects, through the nested ObjectTracker class. This class can track functions, groups, inputs, outputs, and links, automatically requesting updates on different sets of attributes for each type. For example, to track functions and automatically request updates on certain attributes, call trackFunctions(attributeArray). If the JGraphOptionPlugin and Option are one and the same for an object, the tracker's methods are available directly. If the options are separate objects, an ObjectTracker must be explicitly created, and the option's activate() and deactivate() methods must be forwarded to it explicitly.

Actions

The JGraphActionPlugin class defines a method getActions(), which action-providing plugins override. The return value is a map between action types (found in JGraphView, but unimplemented at present) and lists of JGraphView.Action objects. (A convenience method createActionMap() is provided to easily create this map.) When the user clicks on the menu item, the Action='s =actionPerformed() method is called, which can do as it likes with the JGraphView.

Control Panels

The JGraphControlPanelPlugin class defines a method getControlPanels(), which control panel-providing plugins override. The return value is a list of Components, each of which is given a tab on one of the sides of the window.

Examples

Read with the source in hand to follow along.

group.GroupDefaultStyle

This is a very simple plugin. It provides no options (and thus is permanently active), and one attribute layer. Upon creation, it activates group tracking and adds a listener to JGraphView for setName events. The tracker handles requesting updates on newly-created groups. The only time the attributes for a group will change after creation is when the group's name changes, so the setName event handler is the only place that calls requestUpdate(). update() simply installs a batch of constant attributes and then sets the name and cell view.

filter.SizeOffsetToBounds

This is a utility layer, occurring at the very bottom of the stack to convert the separate size and offset attributes into the single bounds attribute that JGraph expects. Upon creation, it sets up one affected attribute, the bounds attribute. Whenever it hears that attributes in layers above it have changed, via attributesChanged(), it checks to see if the size or offset attributes were changed on any functions or groups. If they have, it requests an update on the bounds for those objects. This causes update() to be called. For each function or group that needs updating, it reads the size and offset from the input data (from previous layers). It computes the bounding rectangle and sets that on the output map.

layout.SugiyamaFunctionLayout

This plugin provides two options (Horizontal and Vertical) and one layer. The options are nested classes that simply call back to the main class, which also serves as the single AttributeLayer. It doesn't use the tracker, but instead listens to all creation, deletion, connection, and disconnection of functions. Whenever any of these events occur, it requests an update of the positions of all functions. However, it uses a DelayedExecutor so that the request only occurs one second after event activity stops, thus preventing unnecessary layouts during, for example, the loading of a script. Requests are also triggered by any functions or groups changing their size or visibility status. The update() method collects all functions that are visible according to the input data, as well as groups that have no visible children (i.e. groups that have been collapsed). These cells as well as all ports and links are passed to the actual layout algorithm, which computes positions and sets that attribute on all of the visible objects.

Animation

JGraphView provides a hook for plugins to set an animation handler. After each update(), the changes are passed animateEdit(), which uses a GraphAnimator object to process the attributes. The LinearAnimation plugin uses setGraphAnimator()- to install its own handler. =GraphAnimator specifies two methods: beginAnimation() prepares to execute the given attribute edit, and stepAnimation() is called periodically to step through thre animation. It returns true when the animation is complete. The animator should perform reasonably when beginAnimation() is called during a previous animation request, since there is nothing to prevent multiple edits from happening in a short span of time.

Debugging

One of the JGraphView menus is "Debug." This menu contains an "Attribute viewer" entry, which opens a window by the same name. This window displays each of the attributes for any object in each layer. The window opens to show the object that is currently selected, but drop-down lists are provided at the top of the window for browsing other objects. The box on the left selects which category of object to view, while the box on the right lists all objects of that type alphabetically. For each attribute on each layer, there are four possible states:

Filled
A value has been set.
Blank
No mapping; likely this attribute is not among the layer's affected attribute set.
- (hyphen)
Value is not specified (null), indicating that lower attributes will show through.
? (question mark)
Value has been requested but is shadowed by a higher layer, so the value is unknown.

The bottom row of the window shows the composite attributes, i.e. the attributes that are actually applied to the object.

-- TimPeterson - 09 Aug 2006

Edit | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r2 < r1 | More topic actions
General Information
Technology
  • Resources

Documentation
Repository
Related Projects
  • GUI Development
  • MovieMaker?
  • GUI
  • 3D Input Devices
  • Fly Through Path

Related Sites

 
Powered by TWiki
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback