blob: 5e2889adf75f1150243995482edfcd1781e809e4 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>Providing add functionality</title>
<link href="../book.css" rel="Stylesheet" type="text/css">
<link href="../code.css" rel="Stylesheet" type="text/css">
</head>
<body>
<h1>Providing Add Functionality</h1>
<p>A detailed description of the architecture and basic concepts of Graphiti can
be found <a href="graphiti-introduction.htm#Architecture_and_Basic_Concepts">here</a>.
</p>
<h2>Architecture: Pictogram Model Linked With Domain Model</h2>
<p>In the terms of&nbsp; Graphiti “add” means to add a graphical representation
of an existing domain model object (= business object) to the diagram. What kinds
of business objects can be added to a diagram of a specific type is decided by the
add features delivered by the feature provider.</p>
<p>For our example the graphical representation of a EClass is illustrated in the
Figure. We want to see a rounded rectangle containing a separator like horizontal
line and above that line the name of the corresponding EClass.</p>
<p>&nbsp;</p>
<p>
<img alt="Graphical representation of a
EClass" height="117" src="visio/package-shape.gif" width="155"> </p>
<p><strong>Figure: Graphical representation of a EClass</strong> </p>
<p>&nbsp;</p>
<p>Graphiti supports a kind of linkage between elements of the domain model and
elements of the model defining the graphical representation – the so called <em>
Pictograms Model.</em> These links are called <em>pictogram links</em>. Each diagram
contains one container for all pictogram links – called <em>diagram link</em>.
</p>
<p>You can see the linkage structure of the example in the Figure: Column one shows
the entity model of the graphical representation of exactly one EClass. A container
shape aggregates two child shapes (a container shape itself can be aggregated in
another container shape or in a diagram). All three shapes themselves aggregate
specific graphics algorithms, providing the complete information to allow the rendering
on a screen. Examples for this information are background color, foreground color,
size, position, visibility and line width. In our example we have a rounded rectangle
providing an additional corner radius, a polyline having defined end- and bendpoints
and a text label containing a text value.</p>
<p>&nbsp;</p>
<p><img alt="" height="350" src="visio/pictogram-model.png" width="557"> </p>
<p><strong>Figure: Linkage structure example</strong> </p>
<p>&nbsp;</p>
<p>The container shape and likewise the shape containing the text label are related
to a corresponding EClass. This relationship is realized through special link objects
(pictogram link) holding references to both sides: to the pictograms side and to
the business side.</p>
<h2>Creating an add feature</h2>
<p>In this example we want to enable the editor’s users to add EClasses to the diagram.
As a result it should be possible to drag an EClass from the tree and drop it on
the diagram. Therefore we have to create an add feature and make it available in
the feature provider.</p>
<p>An add feature has to implement the interface
<a href="../../../javadoc/org/eclipse/graphiti/features/IAddFeature.html">IAddFeature</a>.
Instead of implementing it directly it should extend one of the available base classes.
In this example we extend the base class
<a href="../../../javadoc/org/eclipse/graphiti/features/impl/AbstractAddShapeFeature.html">
AbstractAddShapeFeature</a>. </p>
<p>In this case we have to implement/overwrite two methods:</p>
<ul>
<li>The method
<a href="../../../javadoc/org/eclipse/graphiti/func/IAdd.html#canAdd(org.eclipse.graphiti.features.context.IAddContext)">
canAdd</a> has to check the given context and therefore it decides if a business
object can be added.</li>
<li>The method
<a href="../../../javadoc/org/eclipse/graphiti/func/IAdd.html#add(org.eclipse.graphiti.features.context.IAddContext)">
add</a> finally has to create the pictogram structure described above and has
to establish the linkage to the business object.</li>
</ul>
<p>Additionally we have to create graphics algorithms and place them at the appropriate
location (get location from given context). Additionally, the name of the EClass
has to be set as the text label’s value.</p>
<p>You can see the complete implementation of the add feature here:</p>
<!-- Begin code ------------------------------------------------------------------------------- -->
<p>&nbsp;</p>
<div class="literallayout">
<div class="incode">
<p class="code"><span class="keyword">package </span>org.eclipse.graphiti.examples.tutorial.features;<br>&nbsp;<br>
<span class="keyword">public class</span> TutorialAddEClassFeature
<span class="keyword">extends </span>AbstractAddShapeFeature {<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant
<span class="string"><em>E_CLASS_TEXT_FOREGROUND</em> </span>=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IColorConstant.<span class="string">BLACK</span>;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant
<span class="string"><em>E_CLASS_FOREGROUND</em> </span>=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(98, 131, 167);<br><br>&nbsp;<span class="keyword">&nbsp;&nbsp;
private static final</span> IColorConstant <span class="string"><em>
E_CLASS_BACKGROUND</em> </span>=<br><span class="keyword">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
new</span> ColorConstant(187, 218, 247);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public </span>TutorialAddEClassFeature(IFeatureProvider
fp) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">super</span>(fp);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public </span>boolean canAdd(IAddContext context)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">//
check if user wants to add a EClass</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if </span>(context.getNewObject()
<span class="keyword">instanceof </span>EClass) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// check if user wants to add to a diagram</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if (</span>context.getTargetContainer()
<span class="keyword">instanceof </span>Diagram) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;return true</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;return false</span>;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public </span>PictogramElement add(IAddContext context)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EClass addedClass = (EClass)
context.getNewObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Diagram
targetDiagram = (Diagram) context.getTargetContainer();<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// CONTAINER SHAPE WITH ROUNDED RECTANGLE</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IPeCreateService peCreateService = Graphiti.getPeCreateService();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ContainerShape containerShape =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
peCreateService.createContainerShape(targetDiagram,
<span class="keyword">true</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// define a default size for the shape</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">int </span>width = 100;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">int </span>height = 50; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IGaService gaService = Graphiti.getGaService();<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
RoundedRectangle roundedRectangle =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.createRoundedRectangle(containerShape, 5, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setForeground(manageColor(<em class="string">E_CLASS_FOREGROUND</em>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setBackground(manageColor(<span class="string"><em>E_CLASS_BACKGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setLineWidth(2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(roundedRectangle,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
context.getX(), context.getY(), width, height);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// if added Class has no resource we add it to the
resource <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// of the diagram<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// in a real scenario the business model would have its own resource</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;if</span> (addedClass.eResource() ==
<span class="keyword">null</span>) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
getDiagram().eResource().getContents().add(addedClass);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create link and wire it</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link(containerShape, addedClass);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// SHAPE WITH LINE</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create shape for line</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Shape shape = peCreateService.createShape(containerShape,
<span class="keyword">false</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Polyline polyline =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.createPolyline(shape, <span class="keyword">new int</span>[] {
0, 20, width, 20 });<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
polyline.setForeground(manageColor(<span class="string"><em>E_CLASS_FOREGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
polyline.setLineWidth(2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// SHAPE WITH TEXT</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create shape for text</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Shape shape = peCreateService.createShape(containerShape,
<span class="keyword">false</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set text graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Text text = gaService.createText(shape, addedClass.getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setForeground(manageColor(<span class="string"><em>E_CLASS_TEXT_FOREGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setHorizontalAlignment(Orientation.<span class="string"><em>ALIGNMENT_CENTER</em>
</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// vertical alignment has as default value &quot;center&quot;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setFont(gaService.manageDefaultFont(getDiagram(),
<span class="keyword">false</span>, <span class="keyword">true</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(text, 0, 0, width, 20);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create link and wire it</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link(shape, addedClass);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">return </span>containerShape;<br>&nbsp;&nbsp;&nbsp;
}<br>}<br>&nbsp; </p>
</div>
</div>
<p>&nbsp;</p>
<!-- End code ------------------------------------------------------------------------------- -->
<p class="Note"><strong>Note on graphics algorithms and values:</strong> Graphics
algorithms, which are created with &quot;create&quot;-methods, have suitable default values
as comfort. Default values are defined in the meta model and the framework. The rounded rectangle
has the following default values: {lineWidth: 1, lineStyle: SOLID, filled: &lt;unset&gt;,
lineVisible: &lt;unset&gt;, transparency: 0.0, width: 0, height: 0, x: 0, y: 0}. When
using the &quot;create plain&quot;-methods instead, all values have to be set explicitly.
You can find more details about setting values and styles in chapter
<a href="http://www.spiegel.de/">&quot;Using Styles&quot;</a>,
<a href="default_values.html">&quot;Default Attribute Values of Graphics Algorithms&quot;</a> and in the JavaDoc of
<a href="../../../javadoc/org/eclipse/graphiti/services/IGaCreateService.html">IGaCreateService</a>.</p>
<p class="Note"><b>Note on colors and fonts:</b> In contrast to other graphical
objects like e.g. rectangles or lines, colors and fonts are managed objects. This
means that the Graphiti framework keeps track of these objects and enables reuse
within one diagram: one specific color (the combination of its RGB values) or a
specific font (the name along with its size and the flags for italic and bold) is
stored only once within the diagram and is referenced by all objects using this
specific color or font. This is why they are not simply created as the other objects
but retrieved via the IGaService.manage* methods. </p>
<p class="Note">The default font handled by the convenience methods manageDefaultFont
is simply the standard font Graphiti uses if nothing else is defined; it is defined
as Arial in size 8 in straight representation (no italics, no bold). There might
be special font instances of the default font for italic and/or bold representation.</p>
<p class="Note">Colors and fonts are basically immutable objects; once they are
created there attributes should not be changed again. Instead a new color or font
should be requested by calling the manage* methods and set for the relevant objects.
Fonts and colors that are no longer needed can of course be deleted but this is
not handled by the Graphiti framework and is a task that needs to be implemented
by the tool builder if desired.</p>
<p class="Note"><b>Note on text fields and the fonts they use:</b> Text fields can
be created as above; in this case they do not automatically receive a font, but
the tool builder is able to define and set any desired font. On the other hand text
fields may also be created using the default font; to do this simply use the createDefaultText
methods instead of createText (analogue creation methods for MultiText objects exist).
Changing the font lateron will result in having an additional unused font inside
your diagram unless the tool builder cares about deleting no longer used fonts.
</p>
<h2>Test: Add a EClass</h2>
<p class="Note">Note: if the project wizard for a &quot;<a href="example-projects.htm">New
Graphiti Sample Project</a>&quot; does not work correctly and you can not test the add
feature as described below, please continue with the next chapter and
<a href="create-feature.htm">provide create functionality</a>. That will allow to
test the add feature directly in the diagram. </p>
<p>Now we can start the editor again. It should be possible to drop an EClass from
the tree of the &quot;Graphiti Sample&quot; project into the diagram &quot;Add Feature&quot;.</p>
<p>&nbsp;</p>
<p><img alt="" height="624" src="visio/predefined-eclass.png" width="640"> </p>
<p>&nbsp;</p>
<p><strong>Figure: Add PredefinedEClass to the editor</strong></p>
<p>&nbsp;</p>
<p>Without any further implementations it should be possible to move the EClass
shapes around, resize them, remove them (context menu) and even delete them.</p>
<p>&nbsp;</p>
</body>
</html>