jpasch | bac87cf | 2011-07-21 12:45:27 +0000 | [diff] [blame] | 1 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| 2 | <html> |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 3 | |
| 4 | <head> |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 5 | <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 6 | <title>Providing drill-down behavior</title> |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 7 | <link href="../book.css" rel="Stylesheet" type="text/css"> |
| 8 | <link href="../code.css" rel="Stylesheet" type="text/css"> |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 9 | </head> |
| 10 | |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 11 | <body> |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 12 | |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 13 | <h1>Providing Drill-Down Behavior</h1> |
| 14 | <p>Often the information which is shown in a diagram has a certain abstraction level, |
| 15 | and the further details are shown in a separate diagram. For example if a workflow |
| 16 | connects several sub-workflows, then one overview-diagram might show the complete |
| 17 | workflow without the inner details of the sub-workflows, and several detail-diagrams |
| 18 | show the inner details of each sub-workflow.</p> |
| 19 | <p>In this case the user wants to have an easy possibility to navigate from the |
| 20 | overview-diagram into the detail-diagrams and vice versa. We call this "drill-down" |
| 21 | behavior.</p> |
| 22 | <p>Although going from overview to detail is the most typical example, there are |
| 23 | other examples, where the user navigates to more independent diagrams. </p> |
| 24 | <p>All those use cases have one thing in common: the user wants to navigate to a |
jpasch | bac87cf | 2011-07-21 12:45:27 +0000 | [diff] [blame] | 25 | diagram, which "represents" the selected business object (meaning this business |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 26 | object is central for the diagram). </p> |
| 27 | <p>Graphiti offers the possibility to link business objects to pictogram elements |
| 28 | (including the diagram). The drill-down feature works in a way that it searches |
| 29 | for all diagrams having a given business object associated. Then the user can choose |
| 30 | from the found diagrams to which to navigate (if only one diagram is found, than |
| 31 | this is directly opened).</p> |
| 32 | <p>This is different to a where-used functionality, where the user would search |
| 33 | for all diagrams using a business object, no matter if the diagram really "represents" |
| 34 | the business object.</p> |
| 35 | <h2>Creating a Drill-Down Feature</h2> |
| 36 | <p>In this example we want to enable the users to navigate to the diagram(s) which |
| 37 | have the currently selected EClass associated. Therefore we have to create a drill-down |
| 38 | feature and make it available in the feature provider.</p> |
jpasch | bac87cf | 2011-07-21 12:45:27 +0000 | [diff] [blame] | 39 | <ul> |
| 40 | <li>A drill-down feature is a <a href="custom-feature.htm">custom feature</a> |
| 41 | which can easily be implemented by extending the base class |
| 42 | <a href="../../../javadoc/org/eclipse/graphiti/ui/features/AbstractDrillDownFeature.html"> |
| 43 | AbstractDrillDownFeature</a>.</li> |
| 44 | </ul> |
| 45 | <p>The functionality of the <span class="inlinecode">AbstractDrillDownFeature</span> |
| 46 | is not tool-independent, so the method <span class="inlinecode">getDiagrams()</span> |
| 47 | can be implemented only by the tool efficiently. Furthermore we just overwrite the |
| 48 | <span class="inlinecode">canExecute()</span> method, so that the feature is only |
| 49 | enabled if exactly one EClass is selected.</p> |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 50 | <p>You can see the complete implementation of the drill-down feature here:</p> |
| 51 | <!-- Begin code ------------------------------------------------------------------------------- --> |
| 52 | <p> </p> |
| 53 | <div class="literallayout"> |
| 54 | <div class="incode"> |
| 55 | <p class="code"><span class="keyword">package </span>org.eclipse.graphiti.examples.tutorial.features;<br> <br> |
| 56 | <span class="keyword">public class</span> TutorialDrillDownEClassFeature |
| 57 | <span class="keyword">extends </span>AbstractDrillDownFeature {<br> <br> |
| 58 | <span class="keyword">public </span>TutorialDrillDownEClassFeature(IFeatureProvider |
| 59 | fp) {<br> |
| 60 | <span class="keyword">super</span>(fp);<br> }<br> <br> |
| 61 | @Override<br> <span class="keyword">public </span>String |
| 62 | getName() {<br> |
| 63 | <span class="keyword">return </span><span class="string">"Open associated |
| 64 | diagram"</span>;<br> }<br> <br> |
| 65 | @Override<br> <span class="keyword">public </span>String |
| 66 | getDescription() {<br> |
| 67 | <span class="keyword">return </span><span class="string">"Open the diagram |
| 68 | associated with this EClass"</span>;<br> }<br> <br> |
| 69 | @Override<br> <span class="keyword">public boolean</span> |
| 70 | canExecute(ICustomContext context) {<br> |
| 71 | PictogramElement[] pes = context.getPictogramElements();<br> |
| 72 | <span class="comment">// first check, if one EClass is selected</span><br> |
| 73 | <span class="keyword">if</span> (pes != <span class="keyword">null |
| 74 | </span>&& pes.<span class="string"><em>length</em></span> == 1) {<br> |
| 75 | Object bo = getBusinessObjectForPictogramElement(pes[0]);<br> |
| 76 | <span class="keyword">if</span> (bo <span class="keyword">instanceof</span> |
| 77 | EClass) {<br> |
| 78 | <span class="comment">// then forward to super-implementation, which checks |
| 79 | if<br> |
| 80 | // this EClass is associated with other diagrams</span><br> |
| 81 | <span class="keyword">return super</span>.canExecute(context);<br> |
| 82 | }<br> }<br> |
| 83 | <span class="keyword">return false</span>;<br> }<br> <br> |
| 84 | @Override<br> <span class="keyword">protected </span>Collection<Diagram> |
| 85 | getDiagrams() {<br> Collection<Diagram> |
| 86 | result = Collections.emptyList();<br> |
| 87 | Resource resource = getDiagram().eResource();<br> |
| 88 | URI uri = resource.getURI();<br> URI |
| 89 | uriTrimmed = uri.trimFragment();<br> |
| 90 | <span class="keyword">if</span> (uriTrimmed.isPlatformResource()){<br> |
| 91 | String platformString = uriTrimmed.toPlatformString(<span class="keyword">true</span>);<br> |
| 92 | IResource fileResource = ResourcesPlugin.getWorkspace()<br> |
| 93 | .getRoot().findMember(platformString);<br> |
| 94 | <span class="keyword">if</span> (fileResource != <span class="keyword">null</span>){<br> |
| 95 | IProject project = fileResource.getProject();<br> |
| 96 | result = TutorialUtil.getDiagrams(project);<br> |
| 97 | }<br> }<br> |
| 98 | <span class="keyword">return</span> result;<br> }<br>}<br> |
| 99 | </p> |
| 100 | </div> |
| 101 | </div> |
| 102 | <p> </p> |
| 103 | <!-- End code ------------------------------------------------------------------------------- --> |
jpasch | bac87cf | 2011-07-21 12:45:27 +0000 | [diff] [blame] | 104 | <p>The complete implementation of class <span class="inlinecode">TutorialUtil</span> |
| 105 | can be seen here:</p> |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 106 | <!-- Begin code ------------------------------------------------------------------------------- --> |
| 107 | <p> </p> |
| 108 | <div class="literallayout"> |
| 109 | <div class="incode"> |
| 110 | <p class="code"><span class="keyword">package </span>org.eclipse.graphiti.examples.tutorial;<br> |
| 111 | <br><span class="keyword">public class</span> TutorialUtil {<br> <br> |
| 112 | <span class="keyword">public static</span> Collection<Diagram> getDiagrams(IProject |
| 113 | p) {<br> <span class="keyword">final</span> |
| 114 | List<IFile> files = getDiagramFiles(p);<br> |
| 115 | <span class="keyword">final</span> List<Diagram> diagramList = |
jpasch | da3428a | 2012-05-25 11:10:26 +0200 | [diff] [blame^] | 116 | <span class="keyword">new </span>ArrayList<Diagram>();<br> |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 117 | <span class="keyword">final</span> ResourceSet rSet = |
| 118 | <span class="keyword">new</span> ResourceSetImpl();<br> |
| 119 | <span class="keyword">for</span> (<span class="keyword">final</span> IFile |
| 120 | file : files) {<br> |
| 121 | <span class="keyword">final</span> Diagram diagram = getDiagramFromFile(file, |
| 122 | rSet);<br> |
| 123 | if (diagram != <span class="keyword">null</span>) {<br> |
| 124 | diagramList.add(diagram);<br> |
| 125 | }<br> }<br> |
| 126 | <span class="keyword">return</span> diagramList;<br> }<br> <br> |
| 127 | <span class="keyword">private static</span> List<IFile> getDiagramFiles(IContainer |
| 128 | folder) {<br> <span class="keyword"> |
| 129 | final</span> List<IFile> ret = <span class="keyword">new</span> ArrayList<IFile>();<br> |
| 130 | <span class="keyword">try</span> {<br> |
| 131 | final IResource[] members = folder.members();<br> |
| 132 | <span class="keyword">for</span> (<span class="keyword">final</span> IResource |
| 133 | resource : members) {<br> |
| 134 | <span class="keyword">if</span> (resource <span class="keyword">instanceof</span> |
| 135 | IContainer) {<br> |
| 136 | ret.addAll(getDiagramFiles((IContainer) resource));<br> |
| 137 | } <span class="keyword">else if</span> (resource <span class="keyword">instanceof</span> |
| 138 | IFile) {<br> |
| 139 | <span class="keyword">final</span> IFile file = (IFile) resource;<br> |
| 140 | <span class="keyword">if</span> (file.getName().endsWith(<span class="string">".diagram"</span>)) |
| 141 | {<br> |
| 142 | ret.add(file);<br> |
| 143 | }<br> |
| 144 | }<br> |
| 145 | }<br> } <span class="keyword">catch</span> |
| 146 | (<span class="keyword">final</span> CoreException e) {<br> |
| 147 | e.printStackTrace();<br> }<br> |
| 148 | <span class="keyword"> return</span> ret;<br> }<br> <br> |
| 149 | <span class="keyword"> private static</span> Diagram getDiagramFromFile(IFile |
| 150 | file, <br> |
| 151 | ResourceSet resourceSet) {<br> |
| 152 | <span class="comment">// Get the URI of the model file.</span><br> |
| 153 | <span class="keyword">final</span> URI resourceURI = getFileURI(file, resourceSet);<br> |
| 154 | <span class="comment">// Demand load the resource for this file.</span><br> |
| 155 | Resource resource;<br> |
jpasch | 363344b | 2011-07-04 12:27:23 +0000 | [diff] [blame] | 156 | <span class="keyword">try</span> {<br> |
jpasch | f57b3d2 | 2011-07-04 12:22:21 +0000 | [diff] [blame] | 157 | resource = resourceSet.getResource(resourceURI, <span class="keyword">true</span>);<br> |
| 158 | <span class="keyword">if</span> (resource != <span class="keyword">null</span>) |
| 159 | {<br> |
| 160 | <span class="comment"> // does resource contain a diagram as root object?</span><br> |
| 161 | <span class="keyword">final</span> EList<EObject> contents = resource.getContents();<br> |
| 162 | <span class="keyword">for</span> (<span class="keyword">final</span> EObject |
| 163 | object : contents) {<br> |
| 164 | <span class="keyword">if</span> (object <span class="keyword">instanceof</span> |
| 165 | Diagram) {<br> |
| 166 | <span class="keyword">return</span> (Diagram) object;<br> |
| 167 | }<br> |
| 168 | }<br> }<br> |
| 169 | } <span class="keyword">catch</span> (<span class="keyword">final</span> |
| 170 | WrappedException e) {<br> |
| 171 | e.printStackTrace();<br> }<br> |
| 172 | <span class="keyword">return null</span>;<br> }<br> <br> |
| 173 | <span class="keyword">private static</span> URI getFileURI(IFile file, ResourceSet |
| 174 | resourceSet) {<br> <span class="keyword"> final</span> |
| 175 | String pathName = file.getFullPath().toString();<br> |
| 176 | URI resourceURI = URI.createFileURI(pathName);<br> |
| 177 | resourceURI = resourceSet.getURIConverter().normalize(resourceURI);<br> |
| 178 | <span class="keyword">return</span> resourceURI;<br> }<br> |
| 179 | }<br> </p> |
| 180 | </div> |
| 181 | </div> |
| 182 | <p> </p> |
| 183 | <!-- End code ------------------------------------------------------------------------------- --> |
| 184 | <p>Before we test our drill-down feature, we have link EClasses to our diagrams. |
| 185 | In our small example there is no obvious reasoning, which EClass to assign to a |
| 186 | diagram. Because of that we create a new custom feature, where the user himself |
| 187 | can assign selected EClasses to the current diagram. </p> |
| 188 | <p>You can see the complete implementation of this custom feature here:</p> |
| 189 | <!-- Begin code ------------------------------------------------------------------------------- --> |
| 190 | <p> </p> |
| 191 | <div class="literallayout"> |
| 192 | <div class="incode"> |
| 193 | <p class="code"><span class="keyword">package</span> org.eclipse.graphiti.examples.tutorial.features;<br> <br> |
| 194 | <span class="keyword">public class</span> TutorialAssociateDiagramEClassFeature |
| 195 | <span class="keyword">extends</span><br> AbstractCustomFeature |
| 196 | {<br> <br> <span class="keyword">public </span>TutorialAssociateDiagramEClassFeature(IFeatureProvider |
| 197 | fp) {<br> |
| 198 | <span class="keyword">super</span>(fp);<br> }<br> <br> |
| 199 | @Override<br> <span class="keyword">public </span>String |
| 200 | getName() {<br> |
| 201 | <span class="keyword">return </span><span class="string">"Associate diagram"</span>;<br> |
| 202 | }<br> <br> @Override<br> |
| 203 | <span class="keyword">public </span>String getDescription() {<br> |
| 204 | <span class="keyword">return </span><span class="string">"Associate the |
| 205 | diagram with this EClass"</span>;<br> }<br> <br> |
| 206 | @Override<br> <span class="keyword">public boolean</span> |
| 207 | canExecute(ICustomContext context) {<br> |
| 208 | <span class="keyword">boolean</span> ret = <span class="keyword">false</span>;<br> |
| 209 | PictogramElement[] pes = context.getPictogramElements();<br> |
| 210 | <span class="keyword">if</span> (pes != <span class="keyword">null |
| 211 | </span>&& pes.<span class="string"><em>length</em> </span>>= 1) {<br> |
| 212 | ret = <span class="keyword">true</span>;<br> |
| 213 | <span class="keyword">for</span> (PictogramElement pe : pes) {<br> |
| 214 | Object bo = getBusinessObjectForPictogramElement(pe);<br> |
| 215 | <span class="keyword">if</span> (! (bo <span class="keyword">instanceof</span> |
| 216 | EClass)) {<br> |
| 217 | ret = <span class="keyword">false</span>;<br> |
| 218 | } |
| 219 | <br> }<br> |
| 220 | }<br> <span class="keyword">return</span> |
| 221 | ret;<br> }<br> <br> |
| 222 | <span class="keyword"> public</span> <span class="keyword">void</span> |
| 223 | execute(ICustomContext context) {<br> |
| 224 | PictogramElement[] pes = context.getPictogramElements();<br> |
| 225 | EClass eClasses[] = <span class="keyword">new</span> EClass[pes.<span class="string"><em>length</em></span>];<br> |
| 226 | <span class="keyword"> for</span> (int i = 0; i < eClasses.<span class="string"><em>length</em></span>; |
| 227 | i++) {<br> |
| 228 | eClasses[i] =<br> |
| 229 | (EClass) getBusinessObjectForPictogramElement(pes[i]);<br> |
| 230 | }<br> <br> |
| 231 | <span class="comment">// associate selected EClass with diagram</span><br> |
| 232 | link(getDiagram(), eClasses);<br> }<br> <br>}<br> |
| 233 | </p> |
| 234 | </div> |
| 235 | </div> |
| 236 | <p> </p> |
| 237 | <!-- End code ------------------------------------------------------------------------------- --> |
| 238 | <p>Finally the feature provider has to deliver our newly created custom features |
| 239 | (overwrite the method |
| 240 | <a href="../../../javadoc/org/eclipse/graphiti/features/IFeatureProvider.html#getCustomFeatures(org.eclipse.graphiti.features.context.ICustomContext)"> |
| 241 | getCustomFeatures</a>). </p> |
| 242 | <p>This implementation can be seen here:</p> |
| 243 | <!-- Begin code ------------------------------------------------------------------------------- --> |
| 244 | <p> </p> |
| 245 | <div class="literallayout"> |
| 246 | <div class="incode"> |
| 247 | <p class="code">@Override<br><span class="keyword">public </span>ICustomFeature[] |
| 248 | getCustomFeatures(ICustomContext context) {<br> |
| 249 | <span class="keyword">return new</span> ICustomFeature[] <br> |
| 250 | { <span class="keyword">new</span> TutorialRenameEClassFeature(this),<br> |
| 251 | <span class="keyword">new</span> TutorialDrillDownEClassFeature(this),<br> |
| 252 | <span class="keyword">new</span> TutorialAssociateDiagramEClassFeature(this)};<br> |
| 253 | }<br></p> |
| 254 | </div> |
| 255 | </div> |
| 256 | <p> </p> |
| 257 | <!-- End code ------------------------------------------------------------------------------- --> |
| 258 | <h2>Test: Navigate to Diagram Associated with a EClass</h2> |
| 259 | <p>Now start the editor and test this new drill-down feature:</p> |
| 260 | <ol> |
| 261 | <li>create or open two diagrams</li> |
| 262 | <li>in the first diagram create a new EClass</li> |
| 263 | <li>use "copy & paste" to copy this EClass to the second diagram (the underlying |
| 264 | business object is remains the same!)</li> |
| 265 | <li>open the context menu on the EClass in the second diagram; choose "Associate |
| 266 | diagram"</li> |
| 267 | <li>save both diagrams and close the second diagram</li> |
| 268 | <li>open the context menu on the EClass in the first diagram; choose "Open associated |
| 269 | diagram"</li> |
| 270 | <li>now the second diagram is opened again</li> |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 271 | </ol> |
jpasch | bac87cf | 2011-07-21 12:45:27 +0000 | [diff] [blame] | 272 | <p> </p> |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 273 | |
mwenz | b5dc2f9 | 2010-06-16 13:24:52 +0000 | [diff] [blame] | 274 | </body> |
| 275 | |
| 276 | </html> |