Page History
...
A further use of diagram types is for the selection of layout algorithms: a layout algorithm may declare that is is especially suited to process diagrams of certain type t. If the diagram type t is assigned to a diagram viewer, the most suitable layout algorithm is chosen automatically for that viewer.
semanticConfig
A semanticConfig
element registers a subclass of SemanticLayoutConfig:
...
language | xml |
---|
...
The following diagram types are predefined in KIML:
- de.cau.cs.kieler.
...
- layout.diagrams.stateMachine – All kinds of state machines, statecharts, etc.
- de.cau.cs.kieler.
...
Similarly to staticConfig
entries, the class
attribute refers to which model elements the configuration is applied. However, only domain model (a.k.a. semantic model) classes may be referenced. The config
attribute names a concrete implementation of the semantic layout configurator.
The advantage of this kind of configuration compared to staticConfig
declarations is that it may perform arbitrary analyses of the domain model. For instance, different option values may be computed depending on certain properties of the domain model elements. This approach can be used to enable annotations of domain model elements. When the domain model is stored with a textual format, e.g. defined with Xtext, such annotations can be written in the source file that specifies the model:
Code Block |
---|
@portConstraints FIXED_SIDE
@minWidth 20.0
@minHeight 15.0
entity IdentityActor
{
@portSide WEST
port Input;
@portSide EAST
port Output;
} |
The source file annotations can be translated to KIML layout options with a semantic layout configurator, which is registered to each domain model class where annotations can occur.
customConfig
This extension element can be used to register arbitrary implementations of ILayoutConfig. However, this is required only for some experimental configurators used in research. Tool developers normally do not need to use this kind of extension element.
Using Volatile Configurators
The class VolatileLayoutConfig is meant for programmatic layout configuration. It stores layout option values in a hash map. Values are either set globally, that means they are applied to all graph elements, or with a specific context. Global values are easy to configure:
Code Block | ||||
---|---|---|---|---|
| ||||
DiagramLayoutEngine.INSTANCE.layout(workbenchPart, diagramPart,
new VolatileLayoutConfig()
.setValue(LayoutOptions.ALGORITHM, "de.cau.cs.kieler.klay.layered")
.setValue(LayoutOptions.SPACING, 30.0f)
.setValue(LayoutOptions.ANIMATE, true)); |
If multiple configurators are passed to the DiagramLayoutEngine, the layout is computed multiple times: once for each configurator. This behavior can be used to apply different layout algorithms one after another, e.g. first a node placer algorithm and then an edge router algorithm, as in this example:
...
theme | Eclipse |
---|---|
language | java |
...
- layout.diagrams.dataFlow – All kinds of data flow diagrams, e.g. actor diagrams, block diagrams, certain component diagrams, etc.
- de.cau.cs.kieler.layout.diagrams.classDiagram – Class diagrams as defined by the UML, but also meta model diagrams such as the Ecore format.
- de.cau.cs.kieler.layout.diagrams.usecaseDiagram – UML use case diagrams.
- de.cau.cs.kieler.layout.diagrams.boxes – Unconnected boxes (graphs with no edges), e.g. parallel regions in statecharts.
semanticConfig
A semanticConfig
element registers a subclass of SemanticLayoutConfig:
Code Block | ||
---|---|---|
| ||
<semanticOption
class="de.cau.cs.kieler.synccharts.Scope"
config="de.cau.cs.kieler.synccharts.diagram.custom.AnnotationsLayoutConfig">
</semanticOption> |
Similarly to staticConfig
entries, the class
attribute refers to which model elements the configuration is applied. However, only domain model (a.k.a. semantic model) classes may be referenced. The config
attribute names a concrete implementation of the semantic layout configurator.
The advantage of this kind of configuration compared to staticConfig
declarations is that it may perform arbitrary analyses of the domain model. For instance, different option values may be computed depending on certain properties of the domain model elements. This approach can be used to enable annotations of domain model elements. When the domain model is stored with a textual format, e.g. defined with Xtext, such annotations can be written in the source file that specifies the model:
Code Block |
---|
@portConstraints FIXED_SIDE
@minWidth 20.0
@minHeight 15.0
entity IdentityActor
{
@portSide WEST
port Input;
@portSide EAST
port Output;
} |
The source file annotations can be translated to KIML layout options with a semantic layout configurator, which is registered to each domain model class where annotations can occur.
customConfig
This extension element can be used to register arbitrary implementations of ILayoutConfig. However, this is required only for some experimental configurators used in research. Tool developers normally do not need to use this kind of extension element.
Using Volatile Configurators
The class VolatileLayoutConfig is meant for programmatic layout configuration. It stores layout option values in a hash map. Values are either set globally, that means they are applied to all graph elements, or with a specific context. Global values are easy to configure:
Code Block | ||||
---|---|---|---|---|
| ||||
DiagramLayoutEngine.INSTANCE.layout(workbenchPart, diagramPart, new VolatileLayoutConfig() .setValue(LayoutOptions.ALGORITHM, "de.cau.cs.kieler.klay.forcelayered"), new VolatileLayoutConfig( .setValue(LayoutOptions.SPACING, 30.0f) .setValue(LayoutOptions.ALGORITHMANIMATE, "de.cau.cs.kieler.kiml.libavoid"true)); |
If you want to use multiple configurators in the same layout computation, use a CompoundLayoutConfigare passed to the DiagramLayoutEngine, the layout is computed multiple times: once for each configurator. This behavior can be used to apply different layout algorithms one after another, e.g. first a node placer algorithm and then an edge router algorithm, as in this example:
Code Block | ||||
---|---|---|---|---|
| ||||
DiagramLayoutEngine.INSTANCE.layout(workbenchPart, diagramPart,
CompoundLayoutConfig.of(config1, config2, ...)); |
Setting layout option values with a specific context is done with this method of VolatileLayoutConfig:
Code Block | ||||
---|---|---|---|---|
| ||||
public <T, C> VolatileLayoutConfig setValue(final IProperty<? super T> option, final C contextObj, new VolatileLayoutConfig() .setValue(LayoutOptions.ALGORITHM, "de.cau.cs.kieler.klay.force"), new VolatileLayoutConfig() final IProperty<? super C> contextKey, final T value) |
Don't be scared by the rather cryptic declaration. The arguments contextKey
and contextObj
determine in which context the option value is to be applied. For instance, using LayoutContext.DOMAIN_MODEL
as context key and a specific domain model element as context object, the value is applied exactly to the graph element that is linked to that model element. If you want to refer to an element of the diagram viewer, i.e. the concrete syntax, use LayoutContext.DIAGRAM_PART
as context key. The return value is the volatile layout configurator itself, allowing for a builder pattern.
Configuration During Layout Graph Construction
Volatile configurators are also useful for the implementation of diagram layout managers (IDiagramLayoutManager). These implementations are responsible for creating layout graphs following the KGraph meta model from a given diagram viewer (method buildLayoutGraph(
…)
). For some layout options it is reasonable to determine concrete values while the layout graph is built, e.g. for the minimal width and height of nodes:
Code Block | ||||
---|---|---|---|---|
| ||||
KNode childLayoutNode = KimlUtil.createInitializedNode();
KShapeLayout nodeLayout = childLayoutNode.getData(KShapeLayout.class);
Dimension minSize = nodeEditPart.getFigure().getMinimumSize();
nodeLayout.setProperty(LayoutOptions.MIN_WIDTH, (float) minSize.width);
nodeLayout.setProperty(LayoutOptions.MIN_HEIGHT, (float) minSize.height); |
The problem is that the layout option manager that applies all configurators to the layout graph removes any option values that have been set directly on the graph elements, hence the configuration done in the previous example has no effect on the layout process. But do not fear, for salvation is near:
Code Block | ||||
---|---|---|---|---|
| ||||
mapping.getLayoutConfigs().add(VolatileLayoutConfig.fromProperties(mapping.getLayoutGraph(), PRIORITY)); |
The variable mapping
refers to the LayoutMapping instance created in buildLayoutGraph(
…)
. The static method fromProperties(
…)
offered by VolatileLayoutConfig creates a configuration that contains all the layout option values that have previously been seen directly on the graph elements. By adding this configuration to the layout mapping, we make sure it is considered by the layout option manager and the options are applied to the graph elements exactly as we have specified. Happy end.
...
.setValue(LayoutOptions.ALGORITHM, "de.cau.cs.kieler.kiml.libavoid")); |
If you want to use multiple configurators in the same layout computation, use a CompoundLayoutConfig:
Code Block | ||||
---|---|---|---|---|
| ||||
DiagramLayoutEngine.INSTANCE.layout(workbenchPart, diagramPart,
CompoundLayoutConfig.of(config1, config2, ...)); |
Setting layout option values with a specific context is done with this method of VolatileLayoutConfig:
Code Block | ||||
---|---|---|---|---|
| ||||
public <T, C> VolatileLayoutConfig setValue(final IProperty<? super T> option, final C contextObj,
final IProperty<? super C> contextKey, final T value) |
Don't be scared by the rather cryptic declaration. The arguments contextKey
and contextObj
determine in which context the option value is to be applied. For instance, using LayoutContext.DOMAIN_MODEL
as context key and a specific domain model element as context object, the value is applied exactly to the graph element that is linked to that model element. If you want to refer to an element of the diagram viewer, i.e. the concrete syntax, use LayoutContext.DIAGRAM_PART
as context key. The return value is the volatile layout configurator itself, allowing for a builder pattern.
Configuration During Layout Graph Construction
Volatile configurators are also useful for the implementation of diagram layout managers (IDiagramLayoutManager). These implementations are responsible for creating layout graphs following the KGraph meta model from a given diagram viewer (method buildLayoutGraph(
…)
). For some layout options it is reasonable to determine concrete values while the layout graph is built, e.g. for the minimal width and height of nodes:
Code Block | ||||
---|---|---|---|---|
| ||||
KNode childLayoutNode = KimlUtil.createInitializedNode();
KShapeLayout nodeLayout = childLayoutNode.getData(KShapeLayout.class);
Dimension minSize = nodeEditPart.getFigure().getMinimumSize();
nodeLayout.setProperty(LayoutOptions.MIN_WIDTH, (float) minSize.width);
nodeLayout.setProperty(LayoutOptions.MIN_HEIGHT, (float) minSize.height); |
The problem is that the layout option manager that applies all configurators to the layout graph removes any option values that have been set directly on the graph elements, hence the configuration done in the previous example has no effect on the layout process. But do not fear, for salvation is near:
Code Block | ||||
---|---|---|---|---|
| ||||
mapping.getLayoutConfigs().add(VolatileLayoutConfig.fromProperties(mapping.getLayoutGraph(), PRIORITY)); |
The variable mapping
refers to the LayoutMapping instance created in buildLayoutGraph(
…)
. The static method fromProperties(
…)
offered by VolatileLayoutConfig creates a configuration that contains all the layout option values that have previously been seen directly on the graph elements. By adding this configuration to the layout mapping, we make sure it is considered by the layout option manager and the options are applied to the graph elements exactly as we have specified. Happy end.
If you are uncertain about which value to use for PRIORITY
, take something like 25.
Adding Support for the Layout View
The Layout View empowers users to directly modify the layout configuration for the currently viewed diagram. This power, however, comes with a price. Tool developers implementing a IDiagramLayoutManager additionally have to provide an implementation of IMutableLayoutConfig that loads and saves layout option values in a way that they can be stored persistently with the respective diagram. Good examples of such configurators are GmfLayoutConfig and GraphitiLayoutConfig for GMF and Graphiti diagrams, respectively. The GMF implementation stores option values as styles in the GMF Notation model, while the Graphiti implementation stores the values as properties in the Graphiti Pictogram model. If you are developing an editor based on GMF or Graphiti, simply reuse these implementations and you're fine. Otherwise, read this section.
Step 1: Implement a Mutable Layout Configurator
A mutable layout configurator is one that can not only read option values, but also write them. Most interface methods are rather self-explanatory, therefore we will consider only the getContextValue(IProperty, LayoutContext)
method here. This method receives a LayoutContext and should return a value that corresponds to the given property, if possible, and null
otherwise. The starting point is usually the current value of LayoutContext.DIAGRAM_PART
in the given context, called the diagram part, which refers to the currently selected diagram element in the viewer (the abstract syntax element). From this the method should extract more information considering the following other context properties:
LayoutContext.DOMAIN_MODEL
– The domain model element linked to the current diagram part.LayoutContext.CONTAINER_DIAGRAM_PART
– The diagram part that corresponds to the graph or subgraph that contains the current diagram part. This is called the container. If The current diagram part is already the top-level element of the diagram, then there is no container andnull
should be returned.LayoutContext.CONTAINER_DOMAIN_MODEL
– The domain model element linked to the container.LayoutContext.OPT_TARGETS
– A set containing the kind of graph element that corresponds to the current diagram part, referenced with the enumeration LayoutOptionData.Target. If the diagram part is a node, for example, the set should contain the valueNODES
. If the node is also a container for a subgraph, the set should additionally contain the valuePARENTS
.DefaultLayoutConfig.HAS_PORTS
– If the current diagram part is a node, the returned value for this property should betrue
orfalse
depending on whether the node has any ports or not. Ports are explicit connection points for edges; they occur frequently in data flow diagrams.DefaultLayoutConfig.CONTENT_HINT
– If the diagram contains an annotation about which layout algorithm to use for the content of the current diagram part, the returned value for this property should be the identifier of that algorithm. This is the same kind of annotation that is accessed throughgetOptionValue(
…)
, i.e. a value set by the user with the Layout View.DefaultLayoutConfig.CONTAINER_HINT
– The same as forCONTENT_HINT
, but referring to the container.