blob: 7e397d19fb9456391843bdbcc182d0baece8ca49 [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>Using styles</title>
<link href="../book.css" rel="Stylesheet" type="text/css">
<link href="../code.css" rel="Stylesheet" type="text/css">
</head>
<body>
<h1>Using Styles</h1>
<p>Sometimes graphical tools give the user the possibility to freely change the
graphical attributes to paint each shape (color, line-width, …). But more often
all shapes of the same kind shall be painted in the same way.</p>
<p>For example in a Ecore editor it makes sense, that all EClasses look identical.
The user might still have the possibility to change the color of a EClass, but then
the color of all other EClasses should be changed, too.</p>
<p>The graphics framework supports this by providing &quot;styles&quot;. A style is a container
for graphical attributes (color, line-width, …), which can be associated by a graphics
algorithm. A style can have a parent-style, from which a style can &quot;inherit&quot; graphical
attributes (similar to cascading style sheets).</p>
<p>Concretely the value of a graphical attribute is determined by finding the first
value which is not null in the following order:</p>
<ol>
<li>The graphics algorithm itself</li>
<li>The style assigned to the graphics algorithm, if style exists</li>
<li>The parent-style(s) of the style, if parent-style(s) exists</li>
</ol>
<p>It has several advantages if the same style is associated by many graphics algorithms:</p>
<ul>
<li>When a graphical attribute value of the style is changed, all graphics algorithms
are repainted using this new style</li>
<li>A tool could provide a predefined set of styles from which the user can
choose (similar to the &quot;themes&quot; available in many programs)</li>
<li>Redundant storage of identical information is avoided</li>
</ul>
<h2>Creating a Style Utility Class</h2>
<p>In this example we want to associate the same style to the graphics algorithms
of all EClasses. The graphical attributes (color, line-width, …) are then set on
the style and no longer on the different graphics algorithm.</p>
<p>Additionally we will provide functionality to change the color-value of that
style, and as a result all EClasses will be painted in this color.</p>
<p>We start by implementing a utility class for the handling of styles.</p>
<p>We store the styles in the diagram with a given ID. The utility class has methods
to return a specific style by either finding it in the diagram or by creating a
new style and assigning it to the diagram.</p>
<p>Note, that we have two styles: one main style for all graphics algorithms of
the EClass, and one child style for the Text of the EClass. The reason is, that
we want to have a different color for the text and for the lines, but in both cases
the color is stored a &quot;foreground&quot; color.</p>
<p>You can see the complete implementation of the style utility class 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;<br>&nbsp;<br>
<span class="keyword">public class</span> StyleUtil {<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;
<span class="keyword">&nbsp;new</span> ColorConstant(51, 51, 153);<br>&nbsp;<br>&nbsp;&nbsp;
<span class="keyword">&nbsp;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(255, 102, 0);<br>&nbsp;<br>&nbsp;&nbsp;
<span class="keyword">&nbsp;private static final</span> IColorConstant
<em class="string">E_CLASS_BACKGROUND</em> =<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">private static</span> String <span class="string">
<em>DEFAULT_FONT</em></span> = <span class="string">&quot;Arial&quot;</span>;<br>&nbsp;<br>&nbsp;&nbsp;
<span class="keyword">&nbsp;public static</span> Style getStyleForEClass(Diagram
diagram) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">final</span> String styleId = <span class="string">
&quot;E-CLASS&quot;</span>;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Style style = <em>findStyle</em>(diagram, styleId);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IGaService gaService = Graphiti.getGaService();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (style == <span class="keyword">null</span>)
{ <span class="comment">// style not found - create new style</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style = gaService.createStyle(diagram, styleId);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setForeground(gaService.manageColor(diagram,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="string"><em>E_CLASS_FOREGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setBackground(gaService.manageColor(diagram,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="string"><em>E_CLASS_BACKGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setLineWidth(2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">return</span>
style;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;
<span class="keyword">&nbsp;public static</span> Style getStyleForEClassText(Diagram
diagram) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">final</span> String styleId = <span class="string">
&quot;E-CLASS-TEXT&quot;</span>;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// this is a child style of the e-class-style</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Style parentStyle = getStyleForEClass(diagram);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Style style = <em>findStyle</em>(parentStyle, styleId);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (style == <span class="keyword">null</span>)
{ <span class="comment">// style not found - create new style</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IGaService gaService = Graphiti.getGaService();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style = gaService.createStyle(getStyleForEClass(diagram), styleId);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// &quot;overwrites&quot; values from parent style</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setForeground(gaService.manageColor(diagram,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="string"><em>&nbsp;E_CLASS_TEXT_FOREGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setFont(gaService.manageFont(diagram, <span class="string"><em>DEFAULT_FONT</em></span>,
8,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">false</span>, <span class="keyword">true</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">return</span>
style;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="comment">// find the style with a given id in the style-container,
can return null</span><br>&nbsp;&nbsp;&nbsp; <span class="keyword">private
static</span> Style findStyle(StyleContainer styleContainer, String id)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">//
find and return style</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Collection&lt;Style&gt; styles = styleContainer.getStyles();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (styles != <span class="keyword">null</span>)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">for</span> (Style style : styles) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (id.equals(style.getId())) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">return</span> style;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp; <span class="keyword">return
null</span>;<br>&nbsp;&nbsp;&nbsp; }<br>}<br></p>
</div>
</div>
<p>&nbsp;</p>
<!-- End code ------------------------------------------------------------------------------- -->
<p>&nbsp;</p>
<p>Additionally we have to associate the styles to the graphics algorithms in the
<span class="inlinecode">add</span>method of the <span class="inlinecode">TutorialAddEClassFeature</span>.</p>
<p>We do this exactly at those places, where previously the graphical attributes
were set directly on the graphics algorithms.</p>
<p>You can see the changed <span class="inlinecode">add</span> method in the following
code snippet:</p>
<!-- Begin code ------------------------------------------------------------------------------- -->
<p>&nbsp;</p>
<div class="literallayout">
<div class="incode">
<p class="code"><span class="keyword">public</span> PictogramElement add(IAddContext
context) {<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span class="comment">// ...
EXISTING CODING ...<br></span><br>&nbsp;&nbsp;&nbsp; IGaService gaService
= Graphiti.getGaService();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;
RoundedRectangle roundedRectangle; <span class="comment">// need to access
it later</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create invisible outer rectangle expanded by<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// the width needed for the anchor</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Rectangle invisibleRectangle =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.createInvisibleRectangle(containerShape);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(invisibleRectangle,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
context.getX(), context.getY(), width + <span class="string"><em>INVISIBLE_RECT_RIGHT</em></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
height);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set visible rectangle inside invisible
rectangle</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; roundedRectangle
=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.createRoundedRectangle(invisibleRectangle, 5, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setStyle(StyleUtil<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
.<em>getStyleForEClass</em>(getDiagram()));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(roundedRectangle, 0, 0, width, height); <br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create link and wire it</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link(containerShape, addedClass);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="comment">// SHAPE WITH LINE</span><br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create shape for line</span><br>&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;
<span class="comment">// create and set graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Polyline polyline =<br>&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; polyline.setStyle(StyleUtil.<em>getStyleForEClass</em>(getDiagram()));<br>&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span class="comment">// SHAPE WITH TEXT</span><br>&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">//
create shape for text</span><br>&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;
<span class="comment">// create and set text graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Text text = gaService.createText(shape, addedClass.getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setStyle(StyleUtil.<em>getStyleForEClassText</em>(getDiagram()));<br>&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;
text.setVerticalAlignment(Orientation.<em class="string">ALIGNMENT_CENTER</em>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(text, 0, 0, width, 20);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create link and wire it</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link(shape, addedClass);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// provide information to support direct-editing directly<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// after object creation (must be activated additionally)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IDirectEditingInfo directEditingInfo =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
getFeatureProvider().getDirectEditingInfo();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// set container shape for direct editing after object
creation</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; directEditingInfo.setMainPictogramElement(containerShape);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// set shape and graphics algorithm where the editor
for<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // direct editing shall
be opened after object creation</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
directEditingInfo.setPictogramElement(shape);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
directEditingInfo.setGraphicsAlgorithm(text);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="comment">// add a chopbox anchor to the shape<br><br>&nbsp;&nbsp;&nbsp;
// ... EXISTING CODING ...</span><br><br>&nbsp;&nbsp;&nbsp; rectangle.setStyle(StyleUtil.<em>getStyleForEClass</em>(getDiagram()));<br>
<br>&nbsp;&nbsp;&nbsp; <span class="comment">// ... EXISTING CODING ...</span><br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">return</span> containerShape;<br>}<br></p>
</div>
</div>
<p>&nbsp;</p>
<!-- End code ------------------------------------------------------------------------------- -->
<p>To test the just implemented styles we have to create a small
<a href="custom-feature.htm">custom feature</a>, which allows changing the foreground
color or background color of the style.</p>
<p>The implementation can be seen 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> TutorialChangeColorEClassFeature
<span class="keyword">extends</span> AbstractCustomFeature {<br>&nbsp;<br>&nbsp;&nbsp;
<span class="keyword">&nbsp;private boolean</span> <span class="string">
background</span>;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; <span class="keyword">
public</span> TutorialChangeColorEClassFeature(IFeatureProvider fp,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">boolean</span> background) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">super</span>(fp);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">this</span>.<span class="string">background </span>
= background;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; @Override<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public</span> String getName() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
String colorType = <span class="string">background</span> ?
<span class="string">&quot;&amp;background&quot;</span> : <span class="string">&quot;&amp;foreground&quot;</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">return</span> <span class="string">&quot;Change &quot;</span>
+ colorType + <span class="string">&quot; color&quot;</span>;<br>&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; @Override<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public</span> String getDescription() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
String colorType = <span class="string">background</span> ?
<span class="string">&quot;background&quot;</span> : <span class="string">&quot;foreground&quot;</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">return</span> <span class="string">&quot;Change the &quot;</span>
+ colorType + <span class="string">&quot; color&quot;</span>;<br>&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; @Override<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public boolean</span> canExecute(ICustomContext context)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PictogramElement[] pes =
context.getPictogramElements();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (pes == <span class="keyword">null</span>
|| pes.<span class="string">length</span> == 0) { <span class="comment">
// nothing selected</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">return false</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// return true, if all elements are EClasses<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// note, that in execute() the selected elements are not even accessed,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// so theoretically it would be possible that canExecute() always<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// returns true. But for usability reasons it is better to check<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// if the selected elements are EClasses.</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">for</span> (PictogramElement pe : pes) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">final</span> Object bo = getBusinessObjectForPictogramElement(pe);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (!(bo <span class="keyword">instanceof</span>
EClass)) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;return false</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;&nbsp;
<span class="keyword">return true</span>;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public void</span> execute(ICustomContext context)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Style style = StyleUtil.<em>getStyleForEClass</em>(getDiagram());<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// let the user choose the new color</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Color currentColor;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (<span class="string">background</span>)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
currentColor = style.getBackground();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
} <span class="keyword">else</span> {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
currentColor = style.getForeground();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Color newColor = ExampleUtil<em>.editColor</em>(currentColor);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (newColor == <span class="keyword">null</span>)
{ <span class="comment">// user did not choose new color</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;return</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// set new color</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if</span> (<span class="string">background</span>)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setBackground(newColor);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
} <span class="keyword">else</span> {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
style.setForeground(newColor);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp; }<br>}<br></p>
</div>
</div>
<p>&nbsp;</p>
<!-- End code ------------------------------------------------------------------------------- -->
<p>Finally the feature provider has to deliver our newly created custom feature
(overwrite the method
<a href="../../../javadoc/org/eclipse/graphiti/features/IFeatureProvider.html#getCustomFeatures(org.eclipse.graphiti.features.context.ICustomContext)">
getCustomFeatures</a>).</p>
<p>This implementation can be seen here:</p>
<!-- Begin code ------------------------------------------------------------------------------- -->
<p>&nbsp;</p>
<div class="literallayout">
<div class="incode">
<p class="code">@Override<br><span class="keyword">public</span> ICustomFeature[]
getCustomFeatures(ICustomContext context) {<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">return new</span> ICustomFeature[] {
<span class="keyword">new</span> TutorialRenameEClassFeature(<span class="keyword">this</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new</span> TutorialDrillDownEClassFeature(<span class="keyword">this</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new</span> TutorialAssociateDiagramEClassFeature(<span class="keyword">this</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new</span> TutorialChangeColorEClassFeature(<span class="keyword">this</span>,
<span class="keyword">true</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new</span> TutorialChangeColorEClassFeature(<span class="keyword">this</span>,
<span class="keyword">false</span>) };<br>}<br></p>
</div>
</div>
<p>&nbsp;</p>
<!-- End code ------------------------------------------------------------------------------- -->
<h2>Test: Change background color of all EClasses</h2>
<p>Now start the editor and test this:</p>
<ol>
<li>create or open a new diagram</li>
<li>create several new EClasses</li>
<li>open the context menu on one of the EClasses; choose &quot;Change background
color&quot;</li>
<li>verify that the color of all EClasses is changed accordingly</li>
</ol>
<p>&nbsp;</p>
</body>
</html>