blob: 4282ae85ff2a88943c629d0fc458608784d4279b [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>CLASS_TEXT_FOREGROUND</em> </span> =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(51, 51, 153);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant <span
class="string"><em>CLASS_FOREGROUND</em> </span> =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(255, 102, 0);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant <span
class="string"><em>CLASS_BACKGROUND</em> </span> =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(255, 204, 153);<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">CLASS_FOREGROUND</em>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setBackground(manageColor(<span class="string"><em>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>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>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;
text.setVerticalAlignment(Orientation.<span class="string"><em>ALIGNMENT_CENTER</em>
</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">
<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 Graphiti &quot;Test&quot; project into
the diagram Test-1.</p>
<p>&nbsp;</p>
<p>
<img alt="" height="302" src="visio/predefined-eclass.png" width="788">
</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>