Org.simantics.browsing.ui

From Developer Documents
Jump to navigation Jump to search

There exists a more tutorial like manual.

Concepts

Query Key
An object that identifies the query to be performed. Query keys are capable of identifying the query processor to be used for actually performing the query. See the base class for all keys:
    /**
     * Do not implement this directly, look at {@link PrimitiveQueryKey} and
     * {@link QueryKey} instead.
     */
    public static interface CacheKey<T> {
        /**
         * This method must return a unique object that is used to decide which
         * QueryProcessor is used to calculate the query result.
         * 
         * The returned value is compared only using object identity (==), not
         * equals.
         * 
         * @return the identifier of this processor
         */
        Object processorIdenfitier();
    }

Basic Usage

  1. Use org.simantics.browsing.ui.GraphExplorerFactory to construct new instances of the SWT-based GraphExplorer control.
  2. Setup layouts for the GraphExplorer control as you normally would in SWT
  3. Initialize data sources (DataSourceProvider) for the graph explorer (GraphExplorer.setDataSource(DataSourceProvider))
    • For example, the graph database is one possible data source.
  4. Initialize an EvaluatorData for your explorer. Preferably use Evaluators.load(...) to do this.
  5. Initialize all needed query processors for your purposes with the previously loaded EvaluatorData as an argument (GraphExplorer.setProcessor(NodeQueryProcessor), GraphExplorer.setPrimitiveProcessor(PrimitiveQueryProcessor))
  6. Set root input (GraphExplorer.setRoot(Object))

Query System

The explorer content production process is based solely on queries. Abstractly speaking, a query is just a request for an answer to a question. Each potentially visible element in a GraphExplorer will have its own node context (see NodeContext). Queries are always performed on a single node context.

Producing content for the visualized graph is generally a matter of doing the following things:

  1. Finding the children of an element that can be shown
  2. Possibly filtering the children
  3. Possibly sorting the children
  4. Producing labels and images for visible elements

All of these steps are done through different named queries. All queries are identified by query keys. Keys can be either singleton instances or parametrized classes. For example the query BuiltinKeys.SELECTED_VIEWPOINT is used to find out the selected viewpoint for an input context that is used to produce the child node contexts of the specified input context. Queries are performed using this interface:

<source lang="java"> public interface NodeQueryManager {

   <T> T query(INodeContext context, QueryKey<T> key) throws NoQueryProcessorException;
   <T> T query(INodeContext context, PrimitiveQueryKey<T> key) throws NoQueryProcessorException;

} </source>

The most important things to know about the query system are:

  1. The query system automatically generates and keeps track of dependencies between queries.
  2. Query results can be updated by the result producer. Updates potentially causes the results of all dependent queries to be updated too. The query manager will propagate these changes automatically and update the UI where necessary.
  3. The whole query system runs in the single UI control thread (SWT thread). Therefore by implementing potentially blocking queries you will also potentially block the UI. This does not differ in any way from standard SWT/JFace.
  4. Contrary to the basic JFace framework, the query system provides support for implementing non-blocking primitive queries by making their completion asynchronous. The goal is to perform the real work in background threads. Asynchronously completing queries will always return a placeholder result immediately and update the query result later once the background thread complete their work. The query system will ensure for you that any queries depending on the particular primitive query result will also be updated.

Internally a GraphExplorer implementation shall also bind certain top-level queries to actual UI elements. If such queries with bound UI elements are updated, the UI elements shall be updated also. For example in the case of a tree this implies updating the label or image of the tree node.

Basic Query hierarchy

WARNING: IMAGE IS OUT OF DATE
Visual query order representation
Visual representation of the order in which the basic graph explorer query processors work to produce and render the explored content on the screen.

Selection handling

A GraphExplorer is an IPostSelectionProvider. Adapt a GraphExplorer into ISelectionProvider or IPostSelectionProvider through GraphExplorer.getAdapter(ISelectionProvider.class).

The selections produced by it will always contain NodeContext instances. These are produced by Viewpoints. The basic implementations of NodeContext are constructed by NodeContextBuilder. A NodeContext must always contain an object value for the BuiltinKeys.INPUT key (see NodeContext.getConstant(ConstantKey<T>)). Note that NodeContext extends IAdaptable which takes all possible measures to adapt the INPUT value into the desired object class.

Resource selection example

<source lang="Java"> ISelectionProvider provider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class); if (provider != null) {

   ISelection selection = provider.getSelection();
   // For single-selection browsers or assuming a single-selection on a multi-select browser
   Resource object = ISelectionUtils.getSinglePossibleKey(selection, SelectionHints.KEY_MAIN, Resource.class);
   // For multi-selections
   List<Resource> objects = ISelectionUtils.getPossibleKeys(selection, SelectionHints.KEY_MAIN, Resource.class);

} </source>

See also