Interface DevTools

Dashboards & Tools Framework Overview

The Dashboards & Tools framework enables you to build interfaces in which a set of UI
components can be edited by end users, saved and later restored.

This includes interfaces such as:

Dashboards: where a library of possible widgets can be created & configured,
arranged into freehand or portal-style layouts, then stored for future use and
shared with other users

Diagramming & Flowchart tools: tools similar to Visio™ which allow users
to use shapes and connectors to create a flowchart or diagram representing a workflow,
equipment or locations being monitored, a storyboard, or any similar interactive &
modifiable visualization.

Form Builders & Development Tools: tools which enable end users to create
new forms or new screens, define interactive behaviors and rules, and add the screens
to an application on the fly

Overview

Dashboards & Tools provides a pattern for end user creation and configuration of UI
components which enables the framework to store and re-create components exactly as the user
configured them.

Unlike simple serialization, Dashboards & Tools is designed to capture only
UI state created directly by end user actions, and not transient or derived state
(for more on this behavior and how it is different from serialization, see "Stored
vs Derived State" below).

To achieve this, user-editable components are created via a special pattern (not just the
usual
new SomeComponent()),
and changes to user-editable components that are meant to be saved are likewise applied via
special APIs (not just direct calls to someComponent.setSomething()).

The main components and behaviors involved in Dashboards & Tools are covered in brief
below - each of these points is covered in more detail in further sections:

User-editable components are created by Palettes. Palettes
create components from PaletteNodes, which are
data records
containing the component's class and default settings. Some Palettes
provide an end user UI for creating components (eg drag a node from a Tree).

An editable component created by a Palette is represented by an
EditNode, which tracks the created component along with the
data necessary
to save and re-create the component.

An EditContext manages a list or Tree of EditNodes,
and provides
APIs for serializing and restoring EditNodes to and from XML and JSON, and
updating the nodes as users make changes.

Many UI components have "edit mode"
behaviors. When "edit
mode" is enabled, when an end user interacts with the component, the component will
save changes to its EditNode or to child EditNodes in the
EditContext. For example, PortalLayout can track and persist changes to
the placement and size of portlets made by end users. EditMode behaviors
are implemented by EditProxies, and different edit
mode behaviors can
be turned on and off for different kinds of tools.

A simple tool based on the Dashboards & Tools framework would typically consist of:

one or more Palettes showing components that the user can create

a main editing area where you can drag things from a Palette to create them. The
editing area is just an ordinary UI component that has been placed into "edit mode"
and provided with an EditContext. Depending on the type of tool, the main
editing area might be a DrawPane (for diagrams), a
DynamicForm (for a
form builder) or various other widgets.

Buttons, Menus and pop-up dialogs providing the ability to load or save. These would
use APIs on EditContext to
obtain XML or JSON Strings
representing the
data to be saved, as well as to
restore saved state from
such Strings.
DataSources can be used to store whatever is being edited: the serialized form is just
an XML or JSON String, so it can be stored as an ordinary DataSourceField value.

Creating editable components: Palettes

User-editable components are created by Palettes.
Palettes
create components from PaletteNodes, which are
data records
containing the component's class and default settings.

Most types of palettes provide a UI for an end user to create components from
paletteNodes. For example, a TreePalette
presents a hierarchical
set of paletteNodes as a tree, and allows end users to drag nodes out in order
to create components. All palettes also support
programmatic creation of components from
paletteNodes.

paletteNodes can be programmatically provided to a Palette, or,
Palettes that are derived from
DataBoundComponents can load
paletteNodes from a
DataSource.

When a component is created from a paletteNode, an EditNode is created
that tracks the live component and the
state needed to re-create
it, called the defaults.

EditContexts & EditProxies

An EditContext manages a Tree of EditNodes,
and provides APIs for
serializing and restoring EditNodes and updating the tree of nodes.

When an EditNode is added to an EditContext, typically it is immediately placed
into "Edit Mode" (see EditContext.autoEditNewNodes for how
this can be controlled). In Edit Mode, components introduce special behaviors, such as the
ability to directly edit the titles of Tabs in a TabSet by double-clicking, or
support for dragging new FormItems into a
DynamicForm. Changes made while a
component is in Edit Mode are saved to the component's EditNode, in
EditNode.defaults.

Each component that has editMode features has a corresponding EditProxy
that implements those features. A component's EditProxy is automatically
created when a component goes into edit
mode, and overrides the
normal behavior of the component. By configuring the EditProxy for a
component, you configure what behaviors the component will have when in edit mode, and which
specific actions on the component will cause changes to be saved to its EditNode.

EditContext & Trees of EditNodes

The EditContext has the capability to manage a Tree of
EditNodes in order to enable tools that create a hierarchy of Smart GWT
components. When you use EditContext.addNode() and add a new EditNode underneath
another EditNode, the EditContext will automatically try to determine how the parent and
child are related and actually call APIs on the widgets to establish a relationship, such as
a Tab being added to a TabSet, or a FormItem being added to a DynamicForm. The
EditContext uses the same approach as is used for Visual Builder Drag and Drop - see
Visual Builder overview for details.

Note that many if not most kinds of tools use only a flat list of EditNodes - for example,
in a collage editor, photos may sometimes be stacked on top of each other, but a
parent/child relationship in the sense of Canvas.children is not established by doing
so. Likewise, although the Mockup
Editor sample allows end
users to create mockups using Smart GWT components, the components never truly become
children of other components. Instead, as is typical of most mockup tools, hierarchy is
achieved visually by simply placing a component on top of another and within its bounding
rectangle.

Most types of tools use a flat list of EditNodes - generally speaking you will
only use the hierarchy management features of Editcontext if you are creating a
tool that actually allows end users to build functioning Smart GWT screens, such as the
Form
Builder example. For such applications, use
EditContext.allowNestedDrops
to enable drag and drop interactions that will allow end
users to place components inside of other components.

Stored vs Derived state

The purpose of having an EditNode for each UI component is to maintain a
distinction between the current state of the live UI component and the state that should
be saved. For example:

a component may have a current width of 510 pixels when viewed within a tool, but what
should persist is the configured width of 40% of available space

a component may have editing behaviors enabled, such as the ability to double-click to
edit labels or titles, which should be enabled in the tool but not at runtime

a tool may allow end users to create a Window, and then drag components into the Window.
Every Window automatically creates subcomponents such as a header, but these should not be
persisted because they don't represent state created by the end user. Only the components
the end user actually dragged into the Window should be persisted

an end user may try out the effect of a property change, then abandon it and revert to the
default value. We don't want the temporary change saved, and we don't even want to save
the reversion to the default value - nothing about the saved state should be changed

By being careful to save only intentional changes made by the user:

the saved state remains minimal in size, and re-creating components from the stored state
is more efficient

the saved state is much easier to edit since it contains only intentional settings, and
not
generated or derived information

the stored state is more robust against changes over time and easier to re-use. When we
avoiding spuriously saving default values that the user has not modified, we avoid
possible conflicts when a saved UI is deployed to a new version or in a different
environment with different defaults

Specifically, only two things affect the state that will be stored for a given component:

Features enabled when a component is in EditMode, configured via the component's EditProxy