Org.simantics.diagram

From Developer Documents
Jump to: navigation, search

org.simantics.diagram (SVN) offers basic support for diagramming based on the graph database and the 2D ontologies.

Features

Graph-based diagram persistence and synchronization
Offers:
  1. graph → diagram model loading and change tracking
  2. persisting of diagram changes back to the graph
Diagram editor base for Eclipse RCP
Contains a basic example diagram editor for the Eclipse Workbench.
Symbol Library
Provides a symbol library Eclipse View based on SWT and org.simantics.g2d.

Diagrams

Data Model

This section describes different models used to represent diagrams both during runtime and in persistent storage.

Runtime

TODO: describe how diagrams are represented in the 2D/Diagram runtime model defined in svn:2d/trunk/org.simantics.g2d/src/org/simantics/g2d/diagram.

Graph Data Model

This section describes how diagrams are modelled in the semantic graph using Graphical ontology notation.

The diagram level model containing diagrams, layers and diagram elements. (image source)
Example diagrams showing diagram models for simple and branched diagram topologies. (image source)

How It Works

The basic data and interaction flows in the diagram framework. (File:Diagram Dataflow.graphml)

The canvas context has its own thread which is used for manipulation of the context. Diagrams are specified to be single-threaded. The canvas context's thread shall also be used for manipulating the diagram after it is assigned to the context.

Diagram canvas participants are first and foremost responsible for translating user input into operations that change the back-end data model, i.e. the Simantics database contents. The changes are then reflected into the diagram and scene graph through the whole database request → listener → synchronizer chain.

Development

TODO: intro

Interfaces

IDiagramLoader
An interface for loading an IDiagram from the graph. GraphToDiagramSynchronizer is a concrete implementation of this.
ElementFactory
This factory is used for two things:

1. loading an ElementClass from an DIAGRAM.Element type resource in the graph.
2. loading IElement instances from DIAGRAM.Element instance resources in the graph.
Essentially the factory does two things:

  1. create ElementClass for DIAGRAM.Element resources
  2. load the data (hints) of a diagram element according to the graph database properties
To make use of your own factory, just make your element types and instances adaptable to this interface through Resource Adaptation.
ElementLoader
See the source file for a description.
ElementWriter
An interface that an element instance must be adaptable to through Resource Adaptation if it needs to do any custom writing to add or remove itself to/from the graph database. In this case custom means anything else besides the plain old HasTransform property.
IHintSynchronizer
A hint synchronizer is responsible for reflecting the hint values of an element into the back-end system. GraphElementFactory implementations are responsible for setting the synchronizer in elements if necessary using the SynchronizationHints.HINT_SYNCHRONIZER key.

Loading a diagram

    IDiagram loadDiagram(final ICanvasContext canvasContext, RequestProcessor processor, Resource diagramResource,
            ResourceArray structuralPath) throws DatabaseException {
        GraphToDiagramSynchronizer synchronizer = processor.syncRequest(new Read<GraphToDiagramSynchronizer>() {
            public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
                return new GraphToDiagramSynchronizer(graph, canvasContext, createElementClassProvider(graph));
            }
        });
        IDiagram d = requestProcessor.syncRequest(new DiagramLoadQuery(diagramResource, structuralPath, synchronizer, null));
        return d;
    }
 
    protected IElementClassProvider createElementClassProvider(ReadGraph graph) {
        DiagramResource dr = DiagramResource.getInstance(graph);
        return ElementClassProviders.mappedProvider(
                ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new ResourceAdapterImpl(dr.Connection)),
                ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag)
        );
     }

Creating new element types

To create new element types (classes) and to load them into a diagram from the graph, the following is needed:

  1. Define the new element types in your own ontology. New elements must extend DIAGRAM.Element.
  2. Define resource adapters for:
    • defining an ElementClass for your element type
    • loading your element instances (IElement) from the graph database
    • possible custom logic for adding/removing your element type instances to/from the graph database. This is needed if your element has other properties to be synchronized besides an affine transformation.

Example

Define the adapters:

<?xml version="1.0" encoding="UTF-8"?>
<adapters>
	<!-- Customize the element class (ElementClass) that is used for your element type -->
	<target interface="org.simantics.diagram.adapter.ElementFactory">
		<resource uri="http://www.example.org/MyOntology#MyElement"
			class="org.example.elements.MyElementFactory" />
	</target>
 
	<!-- Customize how the element instances (IElement) get constructed from the graph database,
	     i.e. how their hints are loaded
	-->
	<target interface="org.simantics.diagram.adapter.ElementFactory">
		<type uri="http://www.example.org/MyOntology#MyElement"
			class="org.example.elements.MyElementFactory" />
	</target>
 
	<!-- Customize how your element gets added/removed to/from the graph database -->
	<target interface="org.simantics.diagram.synchronization.graph.ElementWriter">
		<resource uri="http://www.example.org/MyOntology#MyElement"
			class="org.example.elements.MyElementWriter" />
	</target>
</adapters>

Define the adapter classes:

public class MyElementFactory implements ElementFactory {
    ...
}
 
public class MyElementWriter implements ElementWriter {
    ...
}

Note that for easier implementation of ElementFactory, you can and should extend SyncElementFactory or at least ElementFactoryAdapter.

Creating new connection types

To create new element types (classes) and to load them into a diagram from the graph, the following is needed:

  1. Define the new element types in your own ontology. New elements can extend DIAGRAM.Connection but it is not absolutely necessary.
  2. Define resource adapters for:

The current diagramming system is fixed to having connections the format defined in #Graph Data Model. The logic of loading connections from the graph is also currently hardcoded in GraphToDiagramSynchronizer. This means that only ElementClass-related aspects and behavior of connections can currently be customized.

The customizable aspects of a connection are:

  • The general appearance of a connection is defined per-connection by a STRUCTURAL.HasConnectionType property attached to a DIAGRAM.Connection instance.
  • The used routing algorithm is defined by DIAGRAM.HasRouting tags in DIAGRAM.Connection instance.
  • A custom inherited DIA.Connection type can be used to customize the ElementClass and loading of corresponding connection elements. Basically this allows customization of all visual/interactive aspects of connection elements.
  • Statically defining start and end arrows for element terminal connectors via EdgeVisualsConfigurer and resource adapters:
<?xml version="1.0" encoding="UTF-8"?>
<adapters>
        <target interface="org.simantics.g2d.connection.EdgeVisualsConfigurer">
                <baseType uri="http://www.simantics.org/Diagram-2.0/HasConnector" />
                <resource uri="http://www.simantics.org/Diagram-2.0/HasPlainConnector"
                          class="org.simantics.diagram.content.ArrowConfigurer">
                        <string>none 0</string>
                </resource>
                <resource uri="http://www.simantics.org/Diagram-2.0/HasArrowConnector"
                          class="org.simantics.diagram.content.ArrowConfigurer">
                        <string>fill 1</string>
                </resource>
        </target>
</adapters>

Example

Define the adapters:

<?xml version="1.0" encoding="UTF-8"?>
<adapters>
	<target interface="org.simantics.diagram.adapter.ElementFactory">
                <!-- Define an adapter for the connection elements. -->
		<type uri="http://www.example.org/MyOntology#MyConnection"
 			class="org.example.connections.ConnectionClassFactory" />
                <!-- Define an adapter for the connection child elements, i.e. edge segments of the branched connection. -->
		<resource uri="http://www.example.org/MyOntology#MyConnection"
			class="org.example.connections.ConnectionEdgeClassFactory" />
	</target>
</adapters>


Visual properties can be specified for connection instances using the STRUCTURAL.HasConnectionType relation to a STRUCTURAL.ConnectionType instance.

TODO: explain HasConnectionType

Supporting Copy-Paste

To support copy paste operations in the diagram, there's a generic diagram participant called CopyPasteHandler. Adding the participant to your canvas context will make your canvas able to handle CUT/COPY/PASTE commands. To provide your domain-specific logic for actually performing the copy operation in the back-end (e.g. graph database), you need to attach a CopyAdvisor to your diagram using the COPY_ADVISOR hint. Note that this means that back-end support for copy-paste is diagram/diagram editor -specific, not element-specific.

See interface CopyAdvisor and its implementation(s):

  • ChainedCopyAdvisor - Simple CopyAdvisor proxy implementation. Takes another advisor and forwards all calls to it.

Not contained in org.simantics.diagram but in org.simantics.modeling are two implementations that provide proper support for copying structural components:

  • ComponentCopyAdvisor - A primitive advisor for copying structural component instances.
  • MappedElementCopyAdvisor - A proxy advisor that
    1. copies a diagram element
    2. if the parameter element has a a structural component mapped to the copied element (with relation MODELING.ElementToComponent) it calls the proxied advisor which can be e.g. ComponentCopyAdvisor.

Example

    /**
     * Setup a copy advisor that primarily copies diagram elements
     * and secondarily components possibly mapped to them.
     */
    void addCopyPasteSupport(ICanvasContext ctx, IActionBars actionBars) {
        ctx.add( new CopyPasteHandler( actionBars.getStatusLineManager() ) );
    }
 
    /**
     * Setup a copy advisor that primarily copies diagram elements
     * and secondarily components possibly mapped to them.
     */
    void setupCopyAdvisor(IDiagram diagram) {
        diagram.setHint(SynchronizationHints.COPY_ADVISOR, new MappedElementCopyAdvisor(new ComponentCopyAdvisor()));
    }

Symbol Library

A screenshot of the Simantics symbol library UI component

The symbol library (SVN) is an Eclipse Workbench ViewPart that shows a set of grouped modelling symbols to the user. The groups are implemented using the Eclipse Nebula PGroup custom SWT widget. The groups show their contained symbols when expanded by clicking the group caption.

The symbols can be selected and dragged on to diagrams to instantiate them as part of your models.

Development

Concepts

There are only a few key concepts (interfaces) which are used for populating the symbol library view. Each interface is very simple and data source independent.

Symbol Group
A composition of symbol items. See interfaces ISymbolGroup and IModifiableSymbolGroup.
Symbol Item
A single symbol that
  1. has a name
  2. belongs to some symbol group
  3. can render itself, using the Image interface
See interface ISymbolItem.
Symbol Manager
(DEPRECATED) For managing the available symbol groups within an active project. See interface ISymbolManager.
Symbol Group Provider
A very simple provider for symbol groups that does not have listening capabilities. See interface ISymbolGroupProvider. In order to contribute symbol groups into the symbol library there's no absolute must to use or implement this interface - using Symbol Manager is enough. The main reason why this interface exists is to enable data-oriented initialization of the symbol library, e.g. based on Resource Adaptation which needs an interface to adapt to that can be used to provide Symbol Groups for the Symbol Manager.

Contributing to the library

In a nutshell, contributing symbols is a matter of modelling contributions in the ontology by attaching symbol contributions to your custom diagram types.

Types and relations to notice:

  • DIAGRAM.Diagram
  • DIAGRAM.HasSymbolContribution
  • DIAGRAM.BasicSymbolContribution
  • DIAGRAM.BasicSymbolContributionHasSymbolLibrary

Things to notice

Download

Version Date SVN
HEAD - svn:2d/trunk/org.simantics.diagram

See Also

Current Development

Plans

Reconnecting

  • For selected connections, display 'gizmos' for each edge ending at connector or branch point
  • Detect drag events for gizmos
  • Detect terminal node while dragging and acquire validation info from server
  • At drop initiate element model change

Contact