Sie sind auf Seite 1von 43

Spray User Guide

Spray A quick way of creating Graphiti


User Guide Authors: Jos Warmer, Karsten Thoms, Joerg Reichert Contents 1. Spray - A quick way of creating Graphiti 2. Introduction 3. Installation 1. Install Spray 2. Upgrade from CI build to release 3. Uninstalling Spray 4. Getting Started 1. 5-Minutes Tutorial 1. Create a new project 2. Define Spray Model 3. Test the editor 2. 15-Minutes Tutorial 1. Implement a custom behavior 5. Spray DSL 1. A Spray based example language 2. Diagram 1. Imports 2. Diagram 3. Referencing Ecore Classes 4. Ecore models the development workspace 5. Create Behavior 6. Class Icon Following the referenced EClass name an icon representing the class can be defined with the @icon@ keyword. The path to the icon is quoted as a string. 3. Layout 1. Colors 4. Shapes 1. Container 2. Text 3. Line 6. Style DSL Guide 1. An example for a style 2. Style Key Facts 3. Default Values 4. Style Elements 1. Description 2. Transparency

3. Background 4. Line 5. Font 7. Shape DSL Guide 1. An example for a shape 2. Shape Key Facts 3. Shape Visualisation 4. Shape Elements 1. Anchor 5. Shape Default Values 1. Text 2. Line 3. Polyline 4. 2D Shape 5. Ellipse 6. Rectangle 7. RoundedRectangle 8. Polygon 6. Practise Examples 1. UML - Example 2. BPMN - Example 7. Connections 1. Placing 2. ConnectionType 8. Spray Extensions Guide 1. Basic extensions: Generation Gap Pattern 9. Cookbook 1. Features 1. Zest Layout 2. The Spray Grammar

Introduction
The Graphiti framework is a new approach to create highly sophisticated visual editors on top of the GEF framework. Graphiti can easily be integrated with EMF as the domain modeling framework. The creation of visual editors is done in Java, programming against the Graphiti framework API. It is fairly simple, but yet repetitive, which makes it a candidate to be supported by the means of model-driven development. This project aims to provide one or more Domain Specific Languages (DSL) (for example with Xtext) to describe Visual DSL Editors against the Graphiti runtime, and provide code generation (for example with Xtend2) to create the boilerplate code for realizing the implementation against the Graphiti framework. Potentially the Spray DSL can be used to generate code for other frameworks as well. The generated code is structured in such a way that one can always extend/overwrite the generated code with handwritten Java to add advanced Graphiti features that are not supported directly by the Spray DSL. With the help of the tools created in this project Graphiti based diagram editors can be created much faster and reliable than doing it purely by hand. A short introduction to Spray can be found in the downloads section. The code is in early state and subject to change.

Installation
Install Spray
A very short introduction on how to install spray. Install Eclipse Indigo IDE. Eclipse Classic or Eclipse Modeling Tools are appropriate Eclipse packages. Start a new workspace Open Help / Install New Software Add the Spray Update Site and press enter For the latest release: http://spray.eclipselabs.org.codespot.com/git.distribution/releases For the latest stable build: https://spray.ci.cloudbees.com/job/spray-ci-build/lastSuccessfulBuild/artifact/ releng/org.eclipselabs.spray.repository/target/repository/ Check Spray / Spray SDK Feature

If the Eclipse distribution does not include PDE (e.g. Eclipse for Java IDE), check also 3rd Party / Eclipse Plugin Development Environment

The PDE version hosted at Spray requires Eclipse 3.7.1 to be installed. Start installing the features Restart Eclipse when asked

Upgrade from CI build to release


For release versions, the additional timestamp qualifier is removed from the feature and plugin version strings. This way it is clear whether you have installed a release or integration build version of Spray. Unfortunately Eclipse recognizes the release version to be older than integration build versions. As a consequence, if you want to upgrade from a CI build to the release build of the same version prefix (e.g. CI version 0.3.0.201111010020 to release 0.3.0), you need to uninstall the Spray SDK before installing the feature again from the Spray Release repository.

Uninstalling Spray
Spray can be uninstalled in Eclipse by choosing Eclipse / About Eclipse SDK / Installation Details. Select the Spray SDK Feature und press uninstall.

Getting Started
5-Minutes Tutorial
Create a new project
Create a new Spray project by using the Spray Project Wizard. Open File / New / Project / Spray / Spray Project.

Enter the project name org.eclipselabs.spray.examples.busmod. On the first page you will have to select a EMF metamodel to work with. Click the Browse Registered Packages button to see the EPackages registered in your platform. Choose http://www.mod4j.org/busmod

Spray requires that it can find the corresponding genmodel for the EPackage. If it can be found in the registry it will be added automatically.

Press Next (or Finish to skip the next page) The next page lets you modify some settings for Sprays code generator, like package names to use. Leave the defaults and press Finish for now.

Define Spray Model


After finishing the project wizard the Spray model editor opens. Paste this model into file busmod.spray: diagram busmod import BusinessDomainDsl.* class BusinessClass: container ( fill=RGB(217,228,255) ) { text ( ) { "<<"+eClass.name+">> " + name}; line ( color=black width=2); reference properties attribute dataType; line (width=1 color=blue); reference businessRules; // will use name property by default

line (width=1 color=blue); text () "::" + description; } references { superclass : connection(); } behavior { create palette "Shapes"; }

class Association: connection () { from source; to target; toText text() targetMultiplicity.name; } behavior { create palette "Connections" ; } After saving the model the editor sources will be automatically generated to the src-gen folder of the project.

Replace the plugin.xml in the project root with the plugin.xml from src-gen.

Test the editor


Start a Runtime Eclipse instance with Run As / Eclipse Application. A new Eclipse instance starts with the plugins deployed.

Create a new project. The type of project does not matter, but for simplicity choose new Java Project and name it BusmodTest. Right-click on the src folder, choose File / New / Other -> Examples / Graphiti / Graphiti Diagram

Choose the Diagram Type "busmod"

Your new diagram editor opens!

15-Minutes Tutorial
In this section we will extend the example from the 5-Minutes Tutorial further. Follow the steps mentioned above first.

Implement a custom behavior


Extend the busmod.spray model like this: class BusinessClass:

... behavior { create palette "Shapes"; // add custom behavior showInfoForBusinessClass "Show Information"; } ...

Right-click on BusmodCustomShowInfoForBusinessClassFeature from the features package. Select Spray -> Move to source folder for manual extension. The file is moved from src-gen to srcand opens in the editor. Implement the execute() method to open a message dialog. @Override public void execute(ICustomContext context, EObject object) { MessageDialog.openInformation(Display.getDefault().getActiveShell(), "Information", "Selected object of type "+object.eClass().getName()); }

After restarting you can invoke an action Show Information from the context menu of a BusinessClass shape.

Spray DSL
A Spray based example language
import BusinessDomainDsl.* import org.eclipse.graphiti.util.IColorConstant diagram mod4j for BusinessDomainModel behavior samen { doit "Do it" } class BusinessClass { container ( fill=dark_green ) { text ( ) { "<<"+eClass.name+">> " + name} line ( color=black width=2) reference properties attribute dataType line (width=2 color=RGB(255,138,141)) reference businessRules // will use name property by default line (width=2 color=IColorConstant::DARK_BLUE) // attribute description text () "::" + description line (width=1 } references { superclass : connection() } behavior { create into types palette "Shapes" doWithBusinessClass "Do It With" group samen } } class Association (icon "connection16.gif") { connection () { from source to target fromText text() "source " + source.name connectionText text() targetMultiplicity.name toText text() name } behavior { create into associations palette "Connections" group samen } }

Diagram
Imports
Referenced Java types and EClasses can be imported with the import keyword. This allows to use simple names later in the Spray model. The imports section is at the beginning of a Spray file: import BusinessDomainDsl.* import org.eclipse.graphiti.util.IColorConstant // all the rest follows here...

Diagram
The beginning of a Spray model is introduced by the diagram keyword, followed by an identifier for the diagram. This is the name of the diagram type specified by the Spray model, and its name will be reflected in the generated code. The diagram name is followed by the specification of a model root element, prefixed by the keyword for. This is the name of the EClass that is the root element a diagram represents. All other elements on the diagram must be insertable into a containment reference of the model root type. import BusinessDomainDsl.* diagram mod4j for BusinessDomainModel h2. MetaClass

Referencing Ecore Classes


The class keyword is followed by the (qualified) name of an EClass. You can either fully qualify the name of the EClass, or you can import the EClass with an import statement before and then just use its simple name. class BusinessDomainDsl.BusinessClass : // full qualified name import BusinessDomainDsl.* // wildcard import import BusinessDomainDsl.BusinessClass // single import ... class BusinessClass : // simple name

The content assist will propose the names of all known EClasses:

Ecore models the development workspace


In the likely case that you want to use a metamodel whose .ecore file is in the development workspace, it is necessary that Xtext indexes the Ecore file and its content. To enable indexing of Ecore files from the workspace, the project containing the .ecore file must have the Xtext nature enabled. If it does not have it yet (the project would have an X overlay image), you can configure the nature by right-clicking on the project and choose Configure / Add Xtext Nature.

Create Behavior
To allow the creation of new MetaClass instances, a Create Behavior must be specified for the class. This is done in the behavior section, starting with the create keyword. Followed by this, the containment reference of the containing EClass (currently always the model root element associated to the Diagram) must be specified. The keyword into is just for readability to specify that the instance will be inserted into the following containment reference. diagram mod4j for BusinessDomainModel class BusinessClass: container () { ... } behavior { create into types "Business Class" palette "Shapes"; }

This example above allows the creation of instances of type BusinessClass to be created. The containment reference is named types, which is defined by the Diagram model root type BusinessDomainModel. The label in the tool palette is Business Class, and the creation tool is inserted into the palette group named Shapes. Both the label and palette are optional. If left out, the label is the EClass name, and the creation tool is inserted into a generic palette group.

Class Icon Following the referenced EClass name an icon representing the class can be defined with the icon keyword. The path to the icon is quoted as a string.
class BusinessClass icon "ecore/EClass.gif"

The specified path is relative to a folder named icons/ in your project. It is checked that the folder icons exists in your project. If the specified relative path of the icon file does not exist, a warning will be raised. The content assist can help you entering the known icon paths. It will also show the icons.

The icon folder must be added to the bin.includes property of the build.properties file. If you created the project with the Spray project wizard, the icon folder was already initially created and added to build.properties. ... bin.includes = META-INF/,\ .,\ plugin.xml,\ model/,\ plugin.properties,\ icons/

Layout
This section describes the configuration of Layouts for shapes.

Colors
<shape> (color=<Color>) Implicit Colors By default, Spray will allow to use the constants defined in org.eclipse.graphiti.util.IColorConstant as simple names with lower case. For example, IColorConstant::DARK_GREEN will be available as dark_green. Example: text (color=dark_green) Explicit Colors Colors can be referred to by qualified names of the static fields. Example:

text (color=org.eclipse.graphiti.util.IColorConstant::BLACK) With import of the contants type this can be shortened: import org.eclipse.graphiti.util.IColorConstant class <...> text (color=IColorConstant::BLACK) RGB Color Colors can be defined by their RGB values: text (color=RGB(255,50,0)) If you invoke content assist it will offer you an option Pick color..., which will open the systems colors dialog.

Shapes
Container
A Container Shape is a container for other shapes.

Text
A shape that displays a computed text. text [alias <aliasname>] ([layout]) <expression>; The displayed text is an Xbase expression, in the simplest case a static string. text () "Foo"; text () "element "+this.name;

Line
Displays a line. line (); // width 1 pixel, black line (width=2); line (color=blue width=2); h3. Alias names Each shape allows to specify an alias name. The alias name is reflected in generated code and will be used for variable and method names when referring to a specific shape. If not specified, the shape name will be computed from the containment hierarchy and types of used shapes. class MyEClass : container alias rootContainer () { line alias line1 (); }

Style DSL Guide


This chapter describes how to define global Graphiti styles for an Spray Project. A style describes the referenced figures generally. Attributes like background color and line style can be set and they will be finally mapped with a name. Afterwards the styles can be referenced with their name. The reference will be possible in one hand globally for the whole spray project and can be overwritten in the other hand from a class, a shape and/or a shape element (as ellipse, rectangle, ...). If the style will not be referenced at all the default spray style will be taken. The style helps to generate a nice graphiti editor for a given color schema and supports to adjust all element styles as your own necessity.

An example for a style


style BlackAndWhiteStyle { description = "A style for white background and black foreground." transparency = 0.95 background-color = white line-color = black line-style = solid line-width = 1 font-color = black font-name = "Tahoma" font-size = 10 font-italic = yes font-bold = no }

Style Key Facts


style BlackAndWhiteStyle A style starts with the keyword style. After the keyword a unique id (name) for the style will be set. It is very important, that this name is unique for the whole project scope. At the same time the style id will become the name of the generated Java class as well. public class BlackAndWhiteStyle extends DefaultSprayStyle implements ISprayStyle For every defined style a Java class will be generated. The interface ISprayStyle provides two methods which will be defined for every style. The inherited class DefaultSprayStyle is the super class of all styles and provides default attributes. The inheritance could be overwritten in the DSL. public Style getStyle(Diagram diagram); public Color getFontColor(Diagram diagram); The first method getStyle() returns a Style (org.eclipse.graphiti.mm.algorithms.styles.Style) of the graphiti meta model plugin. This style will have all attributes set which are defined in the DSL. The second method (getFontColor()) becomes necessary because graphiti allows just one color for the foreground. The foreground color could be a line color and a font color at the same time. This method helps the user to define a font-color that is different from the line color.

Default Values
If the user doesnt specify any value for one or more attribute the default values will be gained. The default values are. Attribute Type Range Default Value transparency float 0.0 1.0 1.0

background color line color line width line style font name font color font size font italic font bold

Color Color integer LineStyle String Color integer boolean boolean

RGB (r,g,b), predefined color or transparent RGB (r,g,b), predefined color or transparent >0 solid, dot, dash, dash-dot, dash-dot-dot RGB (r,g,b) or predefined color >= 0 yes or no yes or no

white black 1 solid Arial black 1 no no

There are predefined colors available. They are following white very-light-gray light-gray gray dark-gray black red light-orange orange dark-orange yellow green light-green dark-green cyan light-blue blue dark-blue

Style Elements
Description
description = "A style for white background and black foreground." The description should describe the style with a sentence. This attribute is required and have to be defined. It is recommended to use a description of at least 20 characters.

Transparency
transparency = 0.95 The transparency defines the visibility of the whole shape. The value is a floating value within the interval 0.00 and 1.00. The value 1.00 defines that the shape is fully visible and 0.00 describes that the whole shape is invisible. All values between 0 and 1 can be used here to define the right transparency value.

Background
background-color = white

The background-color defines the background of the shapes. All shape elements will be of this color. Therefore predefined color values can be used or if no predefined color applies to the wanted color then the RGB values can be filled. Following text sequence should be used: RGB(RED,GREEN,BLUE). The values RED,GREEN,BLUE are integer values between 0 and 255. Finally if a transparent background is wanted then the value transparent can be used.

Line
line-color = black The line-color is mapped to the foreground color in Graphiti. It defines the foreground elements on the shapes. The foreground elements are e.g. border of shapes, lines and font. Same as on the background-color predefined color values can be used or if no predefined color applies to the wanted color then the RGB values can be filled. Following text sequence should be used: RGB(RED,GREEN,BLUE). The values RED,GREEN,BLUE are integer values between 0 and 255. Finally if a transparent foreground is wanted then the value transparent can be used. line-style = solid The line style defines the style type of the line. There are possible values as solid, dot, dash, dash-dot and dash-dot-dot. All lines will be created with this style. line-width = 1 The line width defines the width of foreground elements (e.g. lines and shape borders). Therefore a simple integer value of 0 or bigger (>= 0) can be used. If 0 is used then no lines and shape borders will be drawn.

Font
font-color = black The font color is almost the same as the line-color but it doesnt allow to set a transparent font-color. The font color is as the line color a foreground color. Therefore the generated Java class provides a own method for this. This color will be finally used on all fonts. If no font-color is set, the line-color will be gained. font-name = "Tahoma" The font name is a simple String that defines the name of the font family on the computer. If the given String can not be found on the machine a warning will be shown in the Eclipse UI Style Editor. font-size = 10 The font size is a simple integer with a value of 1 or bigger (>= 1). This defines the font pixels of the font. font-italic = yes font-bold = no The font style italic and bold can be set with the attributes font-italic and font-bold. Therefore a yes or no boolean can be used. "yes" defines the the font will be drawn with this style, "no" defines that this style will not be got.

Shape DSL Guide


this chapter describes how to define global graphiti shapes for a spray project. The shape DSL is a geometric description for the visual representation of a figure. A figure mostly consists of at least one or more geometric forms which are implemented in graphiti the graphiti framework. If a more complex figure is needed basic forms can be nested together.

An example for a shape


shape Usecase (java.lang.String textline) style org.eclipselabs.spray.styles.NoTransparency { size-min(width=100, height=100) size-max(width=200, height=200) stretching(horizontal=true, vertical=true) proportional=true ellipse { size(width=200, heigth=100) position(x=5,y=5) style(background-color=blue line-color=red) text { align(horizontal=center,vertical=bottom) style(font-color=black) "Paul" } } }

Shape Key Facts


shape Usecase A shape definition starts with the keyword shape for every figure. After the keyword a unique name (id) will be set, which identify the shape for the whole project. Shapes with the same name are not valid and will be displayed as error. The name of a figure will be the name for the generated java class. public class Usecase implements ISprayShape for ever defined shape a Java class will be generated. The interface ISprayShape provide one method which will be define for every class. public ContainerShape getShape(Diagram diagram); The implemented method getShape returns a ContainerShape (org.eclipse.graphiti.mm.pictograms.ContainerShape) this container comprised all elements of the defined figure/shape.

Shape Visualisation
shape Usecase style BlackAndWhiteStyle Every shape definition can reference a custom style for their visual behavior. The style will be inherited to the nested shape elements. If a custom style on a nested shape is needed a separate style can be referenced too. shape Usecase style BlackAndWhiteStyle {

ellipse { style(background-color=blue line-color=red) } } The nested style only affects the referenced shape without inheritance. If element values are not set, the graphiti default value will be set.

Shape Elements
A complex figure could have multiple level for their visualisation. The brackets { } represents a separator for each level of a figure. shape Usecase { ellipse {} } If elements are at the same level like a ellipse and a text there will be defined among each other, so shapes can be multiple nested. shape Usecase { ellipse {} text {} } Every figure got the attributes size-min, size-max, stretching and proportional that can be set for each definition. The size-min / size-max is the minimum/maximum bound of a figure to assure to display them correctly. The attributes streching and proportional affects the resize abilities of a shape. streching got an attribute for horizinal and vertical stretching of the figure. proportional handles if the resize proportion between height and width is kept or not. shape Usecase (java.lang.String textline) { size-min(width=100, height=100) size-max(width=200, height=200) stretching(horizontal=true, vertical=true) proportional=true }

Anchor
Every shape has the ability to place different types of anchors with the keyword anchor. An anchor is specified at the first level of an shape and give the shape the possibility place a connection. There are four options to place an anchor. The first 2 options are dynamic and can be set with a keyword anchor = center or anchor = corners. Does not matter what kind of shape is chosen the anchor will be placed in the center or at the corners where the shape is drawn onto. If an ellipse is defined, this shape will be drawn on a invisible rectangle so the corners of the anchor are the one from the rectangle. There are two more options to define an anchor a relative and fix one. A relative anchor type can look like this. anchor { position(xoffset=0.1,yoffset=0.0) position(xoffset=0.8,yoffset=1.0) } Every position entry represent a anchor point for a connection.In this case the anchor got an attribute position with two values xoffset and yoffset. The xoffset/ yoffset is the distance from the upper left corner to given value. anchor { position(x=5, y=10) position(x=50, y=100) } This example defines a fixed anchor, where the coordinates for the position are with a fixed value.

Shape Default Values


If the user doesnt specify any value for one or more attribute the default values will be gained. The default values are. Attribute Type Range Default Value proportional stretching - vertical stretching - horizontal size-min - width size-max - width size-min - height size-max - height textfield align - horizontal align - vertical (textvalue) line/polyline/polygon point - x point - y 2d shapes size - width size - height position - x position - y RoundedRectangl curve - width curve - height boolean boolean boolean integer integer integer integer yes or no yes or no yes or no >= 0 >= 0 >= 0 >= 0 false (no) true (yes) true (yes) ??? ??? ??? ???

boolean boolean String

yes or no yes or no -

false (no) true (yes) ""

integer integer

>= 0 >= 0

0 0

integer integer integer integer

>= 0 >= 0 >= 0 >= 0

0 0 0 0

integer integer

>= 0 >= 0

0 0

Text
The keyword text represents a shape element which text { A text field has one obligatory and one optional attribute. The first attribute is the alignment(align) separated in horizontal and vertical. For both values are enumeration values referenced. The First value can be left,right or center and the second one top, middle or bottom. The optional attribute can set the "text" value of the shape. text { align(horizontal=center,vertical=bottom) "text"

Line
The keyword line represents a line shape element line {

This shape needs a pair of point which define the startpoint and an endpoint of a line. Each point has their x=/ y= coordinates. line { point(x=25,y=20) point(x=25,y=20)

Polyline
The keyword polyline represents a polyline shape element polyline { } A polyline definition required a set of point to specify every start and end of a route. Each point has their x=/ y= coordinates. polyline { point(x=50,y=0) point(x=50,y=10) point(x=60,y=10)

2D Shape
All 2d shape definitions have two obligatory attributes size and position. The size defines the width and height of a 2d shape. The position defines the x and y coordinate where the figure is displayed.

Ellipse
The keyword ellipse represents a ellipse shape element. ellipse { }

An ellipse element is able to represent every kind of ellipses and also circles, when the with and height attribute got the same value. ellipse { size(width=200, height=100) position(x=5,y=5)

Rectangle
The keyword rectangle represents a rectangle shape element rectangle { } The rectangle can present all types of rectangles and also squares, when the with and height attribute got the same value. rectangle { size(width=100, height=100) position(x=0,y=0)

RoundedRectangle
The keyword roundedrectangle represents a roundedrectangle shape element roundedrectangle { The roundedrectangle definition is similar to the rectangle definition. There is just one optional attribute named curve which set the curve of the corners

roundedrectangle { size(width=100, height=100) position(x=0,y=0) curve(width=30, height=30

Polygon
The keyword polygon represents a polygon shape element polygon { A polygon is shape with n-sides. This figure is bounded by a closed path, this mean the startpoint is connected to the end point. Every side is defines by two point with there x and y coordinates. polygon { size(width=100, height=100) position(x=0,y=0) point(x=50,y=0) point(x=50,y=10) point(x=60,y=10) }

Practise Examples
To get more experience in defining some complex figures, we set up some examples figures from UML (Unified Modeling Language) and BPMN (Business Process Model and Notation).

UML Example
This example shows how to create an actor with the shape dsl. At first we need to define a shape with the name UML_UC_Actor. After that we will define the geometric from of this figure and add an ellipse. This ellipse is a circle, because the value for width and height are the same. The circle represents the head of the actor and is displayed at top of the shape. shape UML_UC_Actor { ellipse { // Head position(x=0,y=0) size(width=50,height=50) } } Then we add two line-shapes for the body and the hands of the actor. The coordinates starts from left upper corner (x=0/ y=0) to the right bottom corner. We want to place the body below the head so we need to set 50 (length of the head) for the y values and 25 (middle of the head) for first x value. The length of the body part will be decided by the distance between the both y-point values which is 50. The second line defines the hands of the actor which is displayed 20 beneath the body starts. The length of the hands are equal to the size of the head. shape UML_UC_Actor { ellipse { // Head position(x=0,y=0) size(width=50,height=50) } line {point(x=25,y=50) point(x=25,y=100)} // Body line {point(x=0,y=70) point(x=50,y=70)} // Hands } The last step will complete our actor. Therefore we need to define a polyline for the feet. We also want to place the feet below the body so we need to add the y-values first. This mid point has 100 (y-head + y-body) as y-value and

25 (middle of head) as x-value which is the boundary point between the body and feet. The two other points of the polyline are connected to boundary point and decide the length of the feet which is the square root of 50. The start and the end of the polyline is based on the headsize in this example from x=0 to x=50. shape UML_UC_Actor { ellipse { // Head position(x=0,y=0) size(width=50,height=50) } line {point(x=25,y=50) point(x=25,y=100)} // Body line {point(x=0,y=70) point(x=50,y=70)} // Hands polyline {point(x=0,y=150) point(x=25,y=100) point(x=50,y=150)} // Feet }

BPMN Example
This example shows how to create an envelope with the shape dsl. The hole figure is inside a circle so our custom shape starts with an ellipse where width and height got the same value. After that we specify the edge of the envelope with a rectangle. The position of the rectangle is slightly indented to display it in the center of the ellipse. Now we need to add a triangle shape to complete the envelope. For this case we need a polygon that consist out of three point. The triangle is equal-sided that mean that two points got the same y. The difference between those both x values define the length of upper edge. The third point is connected to the other two and an triangle is created. There are more than one way to specify a custom shape e.g this shape could also be realized with line instead of polygon. shape BPMN_EventMail { ellipse { size(width=50, height=50) position(x=0, y=0) rectangle { size(width=30, height=20) position(x=10, y=15) polygon { point(x=0,y=0) point(x=15,y=10) point(x=30,y=0) } } } }

Connections
A connection is an element to connect two or more shapes which each other. Every definition starts with the keyword connection followed by a unique name. An element definition could look like that. connection BPMN_DefaultFlow { placing { position(offset=1.0,distance=0,angle=0,active=false) polygon { point(x=-10,y=10) point(x=0,y=0) point(x=-10,y=-10) style(background-color=black) } } placing {

position(offset=0.05,distance=0,angle=0,active=false) line{ point(x=0,y=-10) point(x=5,y=10) } } }

Placing
If a custom visual behavior around the connection element is needed, a placing could be used. Each placing describes the content that is placed arround of a connection. Every placing requires an element named position where the value for the alignment will be set. position(offset=1.0,distance=0,angle=0,active=false) A position attribute got four diffrent values offset, distance, angle and active. The offset is the position value among the line from left(offset=0.0) to right(offset=1.0), the distance is the gap with a specified angle between the connection and the element which is placed. The angle can be specified in degree from 0 to 360. Imagine a circle with 4 quadrants, then the first quadrant is from 0 to 90 degree, the second is from 90 to 180 and so on. The last value of the position is the active which is a boolean value. If the active is true the placing element can be move belatedly, if not the position is fixed.

ConnectionType
The type of the connection can be set with the attribute connection-type. There are two diffrent types connection-type=manhattan and connection-type=freeform which are available.

Spray Extensions Guide


Basic extensions: Generation Gap Pattern
The code generated by Spray can be extended (and even fully overwritten) by the developer. For this, Spray uses the Generation Gap Pattern. More specifically we use Conditional Generation 1 (with one gen folder), as described in Generation Gap Pattern by Heiko Behrens. In short, the concrete, empty, subclasses that are meant as extension points are generated in the src-gen/ folder. When you want to extend them, you need to move the file to the src/ folder. The generator will recognize whether an extension point file is in the src folder and in that case not generate it again. Read Heikos blog for a more elaborate explanation. The classes that can be extended derive from classes with the same name with suffix Base. The files generated to the src-gen/ folder are furthermore marked as derived within Eclipse. Thus, if you accidently try to edit them, a warning dialog pops up.

The Spray UI facilitates this repeating task by adding a context menu action on extension point files. For example, right click on the Feature Provider class:

Now choose from the context menu Spray / Move to source folder for manual extension:

After doing this the class is moved to the src/ folder. The derived flag is removed and you can extend the class now.

If you accidently moved the file to the src/ folder and want to let it be generated again, just removed it. With the next generator run it will appear again in the src-gen/ folder.

Cookbook
This chapter collects samples how to use and extend Spray based editors.

Features
Zest Layout
The ZestLayoutDiagramFeature custom feature class allows to layout the diagram with a layout algorithm from the Zest Visualization Toolkit. Add org.eclipselabs.spray.runtime.graphiti.zest to the required bundles in MANIFEST.MF Extend the FeatureProvider class and override getCustomFeatures() @Override public ICustomFeature[] getCustomFeatures(ICustomContext context) { List<ICustomFeature> features = new ArrayList<ICustomFeature>(Arrays.asList(super.getCustomFeatures(context))); ZestLayoutDiagramFeature zestLayoutFeature = new ZestLayoutDiagramFeature(this); if (zestLayoutFeature.canExecute(context)) { features.add(zestLayoutFeature); } ... return Iterables.toArray(features, ICustomFeature.class); }

Your diagram will now have a context action Layout with Zest:

When choosing this action a selection dialog pops up that lets you select an Layout Algorithm:

The diagram will be layouted, e.g. like this:

h1. Reference

The Spray Grammar

grammar org.eclipselabs.spray.xtext.Spray with org.eclipse.xtext.xbase.Xbase import "platform:/resource/org.eclipselabs.spray.mm/model/spray.ecore" import "http://www.eclipse.org/emf/2002/Ecore" as ecore import "platform:/resource/org.eclipse.xtext.common.types/model/JavaVMTypes.ecore" as types

Diagram : 'diagram'

name = ID

imports+=Import* ( behaviourGroups += BehaviourGroup )* ( metaClasses += MetaClass )* ; Import: 'import' importedNamespace=QualifiedNameWithWildCard; SprayElement : Shape | MetaReferenceAsShape | MetaAttributeAsShape; MetaClass : 'class' type=[ecore::EClass|QualifiedName] ('alias' alias=ID)? ('icon' icon=STRING)? ":" representedBy=Shape ( "references" "[" (references += MetaReference2 ";")* "]" )? ( "behavior" "[" ( ("group" behaviourGroups += [BehaviourGroup] ";" ) | (behaviours += Behaviour ";" ) )* "]" )? ; MetaReference : "reference" reference=[ecore::EReference] ":" representedBy=Connection ; MetaReference2 returns MetaReference: reference=[ecore::EReference] ":" representedBy=Connection

MetaAttribute : (pathsegments+=[ecore::EReference] '.')* attribute=[ecore::EAttribute]; MetaReferenceAsShape returns MetaReference : 'reference' reference=[ecore::EReference] ("attribute" labelProperty = [ecore::EAttribute] MetaAttributeAsShape returns MetaAttribute : 'attribute' attribute=[ecore::EAttribute];

)? ;

BehaviourGroup: "behaviour" name=ID "[" (behaviours += Behaviour ";")+ "]" ; Behaviour : StandardBehaviour | CustomBehaviour; StandardBehaviour : type=BehaviourType

(label = STRING)? ('palette' paletteCompartment = STRING)?;

CustomBehaviour : name = ID (label = STRING); enum BehaviourType : CREATE_BEHAVIOUR = 'create' ; Shape : (Rectangle | Text | Container | Connection | Line) ; Layout : { Layout } '(' ( & & & & & ) ')' ; EString returns ecore::EString: STRING | ID; ( ( ( ( ( ( 'width' '=' lineWidth 'color' '=' lineColor 'fill' '=' fillColor 'figure' '=' figure bold ?= 'bold' )? italic ?= 'italic' )? = = = = INT )? Color)? Color)? STRING)?

Rectangle returns Rectangle: {Rectangle} "rectangle" layout = Layout // name=EString ; Connection returns Connection : {Connection} 'connection' layout = Layout ( '[' 'from' from=[ecore::EReference] ";" 'to' to =[ecore::EReference] ";" ( ('fromText' fromLabel = Text ";")? & ('connectionText' connectionLabel = Text ";")? & ('toText' toLabel = Text ";")? ) ']' )? ; Color: ColorConstantRef | RGBColor ; ColorConstantRef: (type=JvmTypeReference '::')? field=[types::JvmField|ValidID] ; RGBColor: 'RGB' '(' red=INT ',' green=INT ',' blue=INT ')' ; Text returns Text: {Text} 'text' layout = Layout value = XExpression ; QualifiedNameWithWildCard returns ecore::EString : QualifiedName ('.' '*')?; Line returns Line : {Line} 'line' layout = Layout ; Container returns Container: { Container } 'container' layout = Layout '[' (parts+=SprayElement ";" )* ']';

StaticFieldQualifier: QualifiedName '::' ValidID ;

Das könnte Ihnen auch gefallen