| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| |
| <head> |
| <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> |
| <title>Patterns</title> |
| <link href="../book.css" rel="Stylesheet" type="text/css"> |
| <link href="../code.css" rel="Stylesheet" type="text/css"> |
| </head> |
| |
| <body> |
| <h1>Patterns</h1> |
| <p>Patterns are an alternative approach to write graphical tools |
| using Graphiti. The standard Graphiti way to write the functionality |
| for an editor or viewer by providing features should be thoroughly |
| understood before continuing with patterns.</p> |
| <p>In general, features are a very nice concept, because they allow |
| tool builders to structure their coding into small pieces each dealing |
| with a certain aspect or functionality for one specific domain object. |
| On the other hand, the fine granularity and the Java single |
| inheritance limitation make it hard to reuse coding between different |
| features. This is something you will sooner or later (at least for |
| non-trivial diagrams) naturally would like to do. Especially finding |
| the relevant shapes and graphics algorithms inside a diagram for a |
| type of shape is something you will need in several features dealing |
| with one domain object (e.g. add, layout and update features). Using |
| features you need to either re-code the functionality for the |
| different features or extract them to some common utility classes.</p> |
| <p>To enable the reuse in a more convenient way, patterns come |
| really handy: a pattern is one single class that holds all |
| functionality dealing with one domain object. It is used to combine |
| the creation, add, layout, update, direct edit, remove and delete |
| functionality into just one class enabling reuse of common |
| functionality. E.g. is is easy to provide a method to identify the |
| text field showing the name of a domain object to the user; this |
| method can then be reused for update and direct editing. A pattern |
| provides almost all functionality for a specific domain object, almost |
| all because the tool builder is always free to break out of the |
| pattern concept and use a feature for implementing a piece of |
| functionality. Adding a custom feature to a pattern is the most common |
| use case, but all other types of features can be used as well in |
| combination with a pattern and to overrule pattern functionality. The |
| following image shows the basic setup of a feature-based tool on the |
| left and a pattern-based on the right.</p> |
| <img alt="Graphiti diagrams with features and patterns compared" |
| src="images/FeaturesAndPatterns.png"> |
| <p>The following sections describe the steps when building a |
| pattern-based tool and compare them to a feature-based one.</p> |
| <h2>Plug-in Dependencies</h2> |
| <p> |
| One additional plug-in dependency needs to be defined in <i>plugin.xml</i>: |
| the Graphiti framework plug-in <i>org.eclipse.graphiti.pattern</i> |
| must be referenced. |
| </p> |
| <h2>Diagram Type Provider</h2> |
| <p>The entry point to pattern-based tools is as for feature-based |
| tools always a diagram type provider which needs to know the according |
| feature provider. There are no differences to feature-based tools |
| here; the class looks exactly the same and the diagram type needs to |
| be registered in plugin.xml in the same way as a feature-based tool.</p> |
| <!-- Begin code ------------------------------------------------------------------------------- --> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"> |
| <?xml version="1.0" encoding="UTF-8"?><br><?eclipse |
| version="3.0"?><br> <span class="string"><plugin><br> |
| <extension<br> point |
| </span>=<span class="comment">"org.eclipse.graphiti.ui.diagramTypes"</span><span |
| class="string">></span><br> <span |
| class="string"><diagramType</span><br> |
| <span class="string">id</span>=<span class="comment">"org.eclipse.graphiti.patternBasedTool.patternBasedToolDiagramType"</span><br> |
| <span class="string">name</span>=<span class="comment">"PatternBasedTool |
| Diagram Type"</span><br> <span |
| class="string">type</span>=<span class="comment">"patternBasedTool"</span><span |
| class="string">></span><br> <span |
| class="string"> </diagramType><br> |
| </extension><br> <br> <extension<br> |
| point |
| </span>=<span class="comment">"org.eclipse.graphiti.ui.diagramTypeProviders</span>"<span |
| class="string">></span><br> <span |
| class="string"><diagramTypeProvider<br> |
| class |
| </span>=<span class="comment">"org.eclipse.graphiti.patternbasedtool.diagram.PatternBasedToolDiagramTypeProvider"</span><br> |
| <span class="string">id</span>=<span class="comment">"org.eclipse.graphiti.patternBasedTool.patternBasedToolDiagramTypeProvider"</span><br> |
| <span class="string">name</span>=<span class="comment">"PatternBasedTool |
| Diagram Type Provider"</span><span class="string">><br> |
| <diagramType<br> |
| id |
| </span>=<span class="comment">"org.eclipse.graphiti.patternBasedTool.patternBasedToolDiagramType"</span><span |
| class="string">><br> |
| </diagramType><br> |
| </diagramTypeProvider><br> </extension><br> |
| </plugin> |
| </span> |
| </p> |
| <p> </p> |
| </div> |
| </div> |
| <!-- End code ------------------------------------------------------------------------------- --> |
| <!-- Begin code ------------------------------------------------------------------------------- --> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"> |
| <span class="keyword">package </span>org.eclipse.graphiti.patternbasedtool.diagram;<br> |
| <br> <span class="keyword">import</span> |
| org.eclipse.graphiti.dt.AbstractDiagramTypeProvider;<br> <br> |
| <span class="keyword">public class</span> |
| PatternBasedToolDiagramTypeProvider <span class="keyword">extends</span> |
| AbstractDiagramTypeProvider {<br> <br> <span |
| class="keyword">public</span> PatternBasedToolDiagramTypeProvider() |
| {<br> <span class="keyword">super</span>();<br> |
| setFeatureProvider(<span |
| class="keyword">new</span> PatternBasedToolFeatureProvider(<span |
| class="keyword">this</span>));<br> }<br> |
| }<br> |
| </p> |
| </div> |
| </div> |
| <p> </p> |
| <!-- End code ------------------------------------------------------------------------------- --> |
| |
| <h2>Feature Provider</h2> |
| <p>A basic pattern-enabled feature provider implementation looks |
| like this:</p> |
| <!-- Begin code ------------------------------------------------------------------------------- --> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"> |
| <span class="keyword">public class </span>PatternBasedToolFeatureProvider |
| <span class="keyword">extends</span> |
| DefaultFeatureProviderWithPatterns {<br> <br> |
| <span class="keyword">public</span> |
| PatternBasedToolFeatureProvider(IDiagramTypeProvider dtp) {<br> |
| <span class="keyword">super</span>(dtp);<br> |
| addPattern(<span class="keyword">new</span> |
| DomainObjectPattern());<br> }<br> } |
| </p> |
| </div> |
| </div> |
| <p> </p> |
| <!-- End code ------------------------------------------------------------------------------- --> |
| <p> |
| The call to the method <i>addPattern()</i> registers the passed |
| instance of the pattern for the feature provider for a shape-based |
| object. In order to register a pattern for a connection you would have |
| to call the method <i>addConnectionPattern()</i>. After that the |
| feature provider delegates queries for special features to the pattern |
| and executes the functionality offered by the pattern. Internally the |
| Graphiti framework uses special features to wrap the calls of the |
| pattern so that the core framework again works on pure features. But |
| that is mostly hidden for tool developers underneath the pattern API; |
| in certain situations however (e.g. debugging), the tool developer |
| will notice this therefore it should be mentioned at least briefly |
| here. |
| </p> |
| <h2>Pattern implementation for Shapes</h2> |
| <p>The basic implementation of a pattern that deals with a shape |
| looks like this: |
| <p> |
| <!-- Begin code ------------------------------------------------------------------------------- --> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"> |
| <span class="keyword">public class</span> DomainObjectPattern <span |
| class="keyword">extends</span> AbstractPattern <span |
| class="keyword">implements</span> IPattern {<br> <br> |
| <span class="keyword">public</span> |
| DomainObjectPattern() {<br> |
| <span class="keyword">super</span>(<span |
| class="keyword">null</span>);<br> }<br> |
| <br> <span class="keyword">public</span> |
| String getCreateName() {<br> |
| <span class="keyword">return</span> |
| "Domain Object Name";<br> }<br> <br> |
| <span class="keyword">public boolean</span> |
| isMainBusinessObjectApplicable(Object mainBusinessObject) {<br> |
| <span class="keyword">return</span> |
| mainBusinessObject <span class="keyword">instanceof</span> |
| <DomainObject>;<br> }<br> <br> |
| |
| <span class="keyword">protected boolean</span> |
| isPatternControlled(PictogramElement pictogramElement) {<br> |
| Object domainObject = |
| getBusinessObjectForPictogramElement(pictogramElement);<br> |
| <span class="keyword">return</span> |
| isMainBusinessObjectApplicable(domainObject);<br> |
| }<br> <br> <span |
| class="keyword">protected boolean</span> |
| isPatternRoot(PictogramElement pictogramElement) {<br> |
| Object domainObject = |
| getBusinessObjectForPictogramElement(pictogramElement);<br> |
| <span class="keyword">return</span> |
| isMainBusinessObjectApplicable(domainObject);<br> |
| }<br> } |
| </p> |
| </div> |
| </div> |
| <p> </p> |
| <!-- End code ------------------------------------------------------------------------------- --> |
| <p> |
| The method <i>getCreateName()</i> should return the name of the object |
| as it should be shown in the Diagram palette for the name of the |
| object to create. |
| </p> |
| <p> |
| The method <i>isMainBusinessObjectApplicable()</i> must check if the |
| passed object is an instance of the domain object for the pattern. |
| This is used by the Graphiti framework to identify the pattern and to |
| decide if the pattern can handle a shape for a specific domain object. |
| </p> |
| <p> |
| The methods <i>isPatternControlled()</i> and <i>isPatternRoot()</i> do |
| similar task but based upon the pictogram element on the diagram. |
| </p> |
| <p>Besides that the pattern base class provides hooks to define or |
| override the functionality that defines the visualization and behavior |
| of the shape or connection. For that purpose the pattern contains all |
| the methods the different features would provide, but all contained |
| within one class. The following functionality is supported within a |
| pattern:</p> |
| <table width="60%" border="1" frame="void" rules="rows"> |
| <tr> |
| <th align="left">Functionality</th> |
| <th align="left">Provided methods</th> |
| </tr> |
| <tr> |
| <td valign="top">Create</td> |
| <td><i>canCreate()<br>create() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Add</td> |
| <td><i>canAdd()<br>add() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Layout</td> |
| <td><i>canLayout()<br>layout() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Update</td> |
| <td><i>canUpdate()<br>updateNeeded()<br>update() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Resize</td> |
| <td><i>canResizeShape()<br>resizeShape() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Move</td> |
| <td><i>canMoveShape()<br>moveShape() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Direct editing</td> |
| <td><i>canDirectEdit()<br>getEditingType()<br>getInitialValue()<br>getPossibleValues()<br>getValueProposals()<br>isCompletionAvailable()<br>isAutoCompletionAvailaible()<br>completeValue()<br>stretchFieldToFitText()<br>checkValueVaild()<br>setValue()<br>getProposalSupport() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Remove</td> |
| <td><i>canRemove()<br>preRemove()<br>remove()<br>postRemove() |
| </i></td> |
| </tr> |
| <tr> |
| <td valign="top">Delete</td> |
| <td><i>canDelete()<br>preDelete()<br>delete()<br>postDelete() |
| </i></td> |
| </tr> |
| </table> |
| <p>Implementing the functionality for each of the methods follows |
| the same rules and principles as for features, e.g. it offers the same |
| default functionality. Therefore you should have understood how to |
| build a Graphiti-based diagrams using features. In principle it is as |
| easy as copying the coding from the feature methods to the according |
| pattern method to migrate a tool from features to patterns.</p> |
| <h2>Mixing-in Features</h2> |
| <p> |
| Overriding default functionality or adding additional functionality is |
| easily possible. Additional functionality can be added by writing |
| custom features and returning them in the method <i>getCustomFeatures()</i> |
| in the feature provider just the very same as you would do it for a |
| feature-based tool. In case you would like to implement a piece of |
| functionality using a feature (e.g. because you want to change default |
| behavior or have a complete domain object that is implemented with |
| features instead of patterns), you can simply override the according |
| retrieval method in the feature provider, check the input and return |
| the feature if appropriate or delegate to the super implementation in |
| the pattern-aware base implementation of the Graphiti framework. Here |
| is an example that shows how to use a specific add feature for adding |
| a connection to a diagram while the rest of the add functionality is |
| provided by patterns and handled by the Graphiti base class of the |
| patter-aware feature provider. |
| </p> |
| <!-- Begin code ------------------------------------------------------------------------------- --> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"> |
| <span class="keyword">public class</span> |
| PatternBasedToolFeatureProvider <span class="keyword">extends</span> |
| DefaultFeatureProviderWithPatterns {<br> <br> |
| ...<br> <br> <span |
| class="keyword">public</span> IAddFeature getAddFeature(IAddContext |
| context) {<br> if (context |
| <span class="keyword">instanceof</span> IAddConnectionContext |
| && context.getNewObject() <span class="keyword">instanceof</span> |
| <DomainObjectConnection> ) {<br> |
| <span |
| class="keyword">return new</span> |
| AddDomainObjectConnectionConnectionFeature(<span class="keyword">this</span>);<br> |
| }<br> |
| <span class="keyword">return |
| super</span>.getAddFeature(context);<br> }<br> |
| } |
| </p> |
| </div> |
| </div> |
| <p> </p> |
| <!-- End code ------------------------------------------------------------------------------- --> |
| <h2>Patterns for Connections</h2> |
| <p> |
| Writing a pattern that visualizes and defines the behavior of a |
| connection is very similar to what is described above for shape |
| patterns. The main difference is that to pattern should be derived |
| from <i>AbstractConnectionPattern</i> instead of <i>AbstractPattern</i>. |
| There are slightly different methods defined but they correspond to |
| what you would also need to implement for the features of a |
| connection. |
| </p> |
| <div id="idpatterns"></div> |
| <h2>ID Patterns</h2> |
| <p> |
| ID patterns are a special kind of pattern that allow clients to easily |
| tag parts of their shapes (both <i>PictogramElements</i> and <i>GraphicsAlgorithms</i>) |
| with IDs. These IDs are simple strings that can in other methods of |
| the pattern be used to identify the shape. The ID pattern base class |
| itself already does that to a wide extend; on e.g. layout or update |
| the pattern checks if the affected shape has an ID and if yes |
| delegates to a special ID Pattern method that can use the passed ID |
| information and simply do the intended job without having to care |
| about finding the shape or checking the relevance of the shape first. |
| This makes client coding much shorter and effective and spares clients |
| the tedious writing of such boilerplate code. |
| </p> |
| <p>The are two examples for ID Patterns within the Graphiti |
| Filesystem example: <i>File</i> objects are a basic example of the ID pattern |
| usage, while <i>Folder</i>s are a more advanced example that also shows |
| nesting a list of children (files in the example).</p> |
| <p class="Note"><b>Note:</b> The ID Pattern type is still experimental, the API |
| might still evolve and/or change without prior notice! Nevertheless, |
| we try to keep the API stable and encourage you to use this new |
| pattern type and give feedback.</p> |
| </body> |
| </html> |