Wiki source code of Updated Java Version Example with Connections
Last modified by Niklas Rentz on 2023/09/12 13:04
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | Here you'll find an updated version of the minimal examle: | ||
2 | |||
3 | [[attach:de.cau.cs.kieler.klighd.example.mydata.zip]] | ||
4 | |||
5 | |||
6 | |||
7 | Use the same procedure to get it to run as described on the [[parent page>>doc:KIELER.Discontinued Projects.KLighD old Minimal Example HowTo.Minimal Example (Java Model).WebHome]]. | ||
8 | |||
9 | |||
10 | |||
11 | The example runs with the following current (4.12.2014) version of KLighD: 0.6.0 ([[Pragmatics v. 2014-10>>url:http://rtsys.informatik.uni-kiel.de/%7Ekieler/updatesite/release_pragmatics_2014-10/||rel="nofollow" shape="rect" class="external-link"]]) | ||
12 | |||
13 | The visualized diagrams look like this: | ||
14 | |||
15 | [[image:attach:klighd-updated1.jpg]][[image:attach:klighd-updated2.jpg]] | ||
16 | |||
17 | Note that this diagram synthesis requests a specific layout algorithm for each case: | ||
18 | |||
19 | 1. de.cau.cs.kieler.graphviz.dot for splines, and | ||
20 | 1. de.cau.cs.kieler.klay.layered for NO splines). | ||
21 | |||
22 | == The Files == | ||
23 | |||
24 | {{code title="MyData.java" language="java"}} | ||
25 | public class MyData { | ||
26 | |||
27 | public String name; | ||
28 | public List<MyData> subData = new LinkedList<MyData>(); | ||
29 | |||
30 | public static MyData getTestData() { | ||
31 | MyData d1 = new MyData(); | ||
32 | d1.name = "all data"; | ||
33 | MyData d2 = new MyData(); | ||
34 | d2.name = "outer data"; | ||
35 | MyData d3 = new MyData(); | ||
36 | d3.name = "inner 1"; | ||
37 | MyData d4 = new MyData(); | ||
38 | d4.name = "inner 2"; | ||
39 | MyData d5 = new MyData(); | ||
40 | d5.name = "inner 5"; | ||
41 | MyData d6 = new MyData(); | ||
42 | d6.name = "most inner 6"; | ||
43 | d1.subData.add(d2); | ||
44 | d2.subData.add(d3); | ||
45 | d2.subData.add(d4); | ||
46 | d2.subData.add(d5); | ||
47 | d4.subData.add(d6); | ||
48 | return d1; | ||
49 | } | ||
50 | |||
51 | } | ||
52 | {{/code}} | ||
53 | |||
54 | {{code title="MyDataDiagrammSynthesisHandler.java" language="java"}} | ||
55 | /* | ||
56 | * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient | ||
57 | * | ||
58 | * http://www.informatik.uni-kiel.de/rtsys/kieler/ | ||
59 | * | ||
60 | * Copyright 2013 by | ||
61 | * + Christian-Albrechts-University of Kiel | ||
62 | * + Department of Computer Science | ||
63 | * + Real-Time and Embedded Systems Group | ||
64 | * | ||
65 | * This code is provided under the terms of the Eclipse Public License (EPL). | ||
66 | * See the file epl-v10.html for the license text. | ||
67 | */ | ||
68 | package de.cau.cs.kieler.klighd.example.mydata; | ||
69 | |||
70 | import org.eclipse.core.commands.ExecutionEvent; | ||
71 | import org.eclipse.core.commands.ExecutionException; | ||
72 | import org.eclipse.ui.internal.handlers.WorkbenchWindowHandlerDelegate; | ||
73 | |||
74 | import de.cau.cs.kieler.klighd.kivi.effects.KlighdUpdateDiagramEffect; | ||
75 | import de.cau.cs.kieler.klighd.krendering.SimpleUpdateStrategy; | ||
76 | import de.cau.cs.kieler.klighd.util.KlighdSynthesisProperties; | ||
77 | |||
78 | /** | ||
79 | * This is a small mininal example action that triggers a diagram synthesis of a | ||
80 | * static data example. In this example the actions is connected to a tool bar | ||
81 | * button and can be invoked by clicking on the button. | ||
82 | * | ||
83 | * UPDATED VERSION 4. DECEMBER 2014 | ||
84 | * | ||
85 | * @author Christian Motika | ||
86 | */ | ||
87 | public class MyDataDiagrammSynthesisHandler extends | ||
88 | WorkbenchWindowHandlerDelegate { //IWorkbenchWindowActionDelegate { | ||
89 | |||
90 | |||
91 | public Object execute(ExecutionEvent event) throws ExecutionException { | ||
92 | // Get some static dummy test data | ||
93 | MyData data = MyData.getTestData(); | ||
94 | |||
95 | // Prepare the diagram synthesis: Create a new klighdUpdateDiagramEffect | ||
96 | KlighdUpdateDiagramEffect klighdEffect = new KlighdUpdateDiagramEffect( | ||
97 | "de.cau.cs.kieler.klighd.example.mydata.MyDataDiagramSynthesis", | ||
98 | "KLighD MyData Diagram", data); | ||
99 | |||
100 | // FIXME: Note that the incremental update currently is under re-development | ||
101 | // for Eclipse Kepler after large API changes to EMF Compare had been made. | ||
102 | // At this time we cannot use the incremental update strategy (commented out). | ||
103 | // As soon as it is fixed, uncomment the line below and delete the | ||
104 | // SimpleUpdateStrategy line: | ||
105 | |||
106 | // klighdEffect.setProperty(LightDiagramServices.REQUESTED_UPDATE_STRATEGY, | ||
107 | // UpdateStrategy.ID); | ||
108 | |||
109 | klighdEffect.setProperty( | ||
110 | KlighdSynthesisProperties.REQUESTED_UPDATE_STRATEGY, | ||
111 | SimpleUpdateStrategy.ID); | ||
112 | |||
113 | // Do the diagram synthesis | ||
114 | klighdEffect.execute(); | ||
115 | return null; | ||
116 | } | ||
117 | |||
118 | } | ||
119 | |||
120 | |||
121 | {{/code}} | ||
122 | |||
123 | {{code title="MyDataDiagramSynthesis.xtend"}} | ||
124 | /* | ||
125 | * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient | ||
126 | * | ||
127 | * http://www.informatik.uni-kiel.de/rtsys/kieler/ | ||
128 | * | ||
129 | * Copyright 2013 by | ||
130 | * + Christian-Albrechts-University of Kiel | ||
131 | * + Department of Computer Science | ||
132 | * + Real-Time and Embedded Systems Group | ||
133 | * | ||
134 | * This code is provided under the terms of the Eclipse Public License (EPL). | ||
135 | * See the file epl-v10.html for the license text. | ||
136 | */ | ||
137 | package de.cau.cs.kieler.klighd.example.mydata | ||
138 | |||
139 | import com.google.common.collect.ImmutableList | ||
140 | import de.cau.cs.kieler.core.kgraph.KNode | ||
141 | import de.cau.cs.kieler.core.krendering.KColor | ||
142 | import de.cau.cs.kieler.core.krendering.KPolyline | ||
143 | import de.cau.cs.kieler.core.krendering.extensions.KColorExtensions | ||
144 | import de.cau.cs.kieler.core.krendering.extensions.KContainerRenderingExtensions | ||
145 | import de.cau.cs.kieler.core.krendering.extensions.KEdgeExtensions | ||
146 | import de.cau.cs.kieler.core.krendering.extensions.KNodeExtensions | ||
147 | import de.cau.cs.kieler.core.krendering.extensions.KPolylineExtensions | ||
148 | import de.cau.cs.kieler.core.krendering.extensions.KRenderingExtensions | ||
149 | import de.cau.cs.kieler.kiml.options.Direction | ||
150 | import de.cau.cs.kieler.kiml.options.EdgeRouting | ||
151 | import de.cau.cs.kieler.kiml.options.LayoutOptions | ||
152 | import de.cau.cs.kieler.klighd.SynthesisOption | ||
153 | import de.cau.cs.kieler.klighd.syntheses.AbstractDiagramSynthesis | ||
154 | import javax.inject.Inject | ||
155 | |||
156 | import static extension org.eclipse.emf.ecore.util.EcoreUtil.* | ||
157 | |||
158 | //import static de.cau.cs.kieler.klighd.example.mydata.MyDataDiagramSynthesis.* | ||
159 | /** | ||
160 | * This is a small mininal example that creates a hierarchical KLighD diagram | ||
161 | * out of very simple hierarchical data structure (MyData). | ||
162 | * | ||
163 | * @author Christian Motika | ||
164 | */ | ||
165 | class MyDataDiagramSynthesis extends AbstractDiagramSynthesis<MyData> { | ||
166 | |||
167 | @Inject extension KNodeExtensions | ||
168 | @Inject extension KEdgeExtensions | ||
169 | |||
170 | // @Inject extension KPortExtensions | ||
171 | // @Inject extension KLabelExtensions | ||
172 | @Inject extension KRenderingExtensions | ||
173 | @Inject extension KContainerRenderingExtensions | ||
174 | @Inject extension KPolylineExtensions | ||
175 | @Inject extension KColorExtensions | ||
176 | |||
177 | // Some self-defined colors | ||
178 | private static val KColor BLUE1 = RENDERING_FACTORY.createKColor() => | ||
179 | [it.red = 248; it.green = 249; it.blue = 253]; | ||
180 | private static val KColor BLUE2 = RENDERING_FACTORY.createKColor() => | ||
181 | [it.red = 205; it.green = 220; it.blue = 243]; | ||
182 | |||
183 | // Additional transformation option to hide or show a shadow | ||
184 | private static val SynthesisOption SHOW_SHADOW = SynthesisOption::createCheckOption("Shadow", true); | ||
185 | private static SynthesisOption EDGE_STYLE = SynthesisOption::createCheckOption("Spline", false); | ||
186 | |||
187 | // Add all transformation options (comma separated) | ||
188 | override getDisplayedSynthesisOptions() { | ||
189 | return ImmutableList::of( | ||
190 | SHOW_SHADOW, | ||
191 | EDGE_STYLE | ||
192 | ); | ||
193 | } | ||
194 | |||
195 | override KNode transform(MyData data) { | ||
196 | val rootNode = data.createNode() | ||
197 | |||
198 | if (EDGE_STYLE.booleanValue) { | ||
199 | rootNode.setLayoutOption(LayoutOptions::SPACING, Float::valueOf("25.0")); | ||
200 | rootNode.setLayoutOption(LayoutOptions::DIRECTION, Direction::DOWN); | ||
201 | rootNode.addLayoutParam(LayoutOptions::EDGE_ROUTING, EdgeRouting::SPLINES); | ||
202 | rootNode.addLayoutParam(LayoutOptions::ALGORITHM, "de.cau.cs.kieler.graphviz.dot"); | ||
203 | } else { | ||
204 | rootNode.setLayoutOption(LayoutOptions::SPACING, Float::valueOf("15.0")); | ||
205 | rootNode.setLayoutOption(LayoutOptions::DIRECTION, Direction::DOWN); | ||
206 | rootNode.addLayoutParam(LayoutOptions::EDGE_ROUTING, EdgeRouting::ORTHOGONAL); | ||
207 | rootNode.addLayoutParam(LayoutOptions::ALGORITHM, "de.cau.cs.kieler.klay.layered"); | ||
208 | } | ||
209 | |||
210 | buildNodes(data, rootNode) | ||
211 | buildConnections(data, rootNode) | ||
212 | |||
213 | return rootNode; | ||
214 | } | ||
215 | |||
216 | def void buildNodes(MyData parentData, KNode rootNode) { | ||
217 | val root = parentData.createNode() | ||
218 | root.putToLookUpWith(parentData) => [ | ||
219 | // Optional Layout parameters can be set | ||
220 | //it.addLayoutParam(LayoutOptions::ALGORITHM, "de.cau.cs.kieler.kiml.ogdf.planarization"); | ||
221 | //it.addLayoutParam(LayoutOptions::SPACING, 75f); | ||
222 | //it.addLayoutParam(LayoutOptions::DIRECTION, Direction::UP); | ||
223 | // A rounded rectangle is created for every MyData instance | ||
224 | it.addRoundedRectangle(5, 5) => [ | ||
225 | // Set linewith, foreground color, and a fading background color | ||
226 | it.lineWidth = 1; | ||
227 | it.setForeground("darkGray".color) | ||
228 | // We need a fresh copy of each color item, because it is contained by its element | ||
229 | it.setBackgroundGradient(BLUE1.copy, BLUE2.copy, 90) | ||
230 | // Here we see a how to use a boolean transformation/diagram option | ||
231 | if (SHOW_SHADOW.booleanValue) { | ||
232 | it.shadow = "black".color; | ||
233 | } | ||
234 | // Set a text | ||
235 | it.addText(" " + parentData.name + " ") => [ | ||
236 | it.setFontSize(9) | ||
237 | it.setForeground("black".color) | ||
238 | ] | ||
239 | // If this is a hierarchical MyData instance, then create horizontal splitter, | ||
240 | // a child area, and add its children | ||
241 | if (parentData.subData.length > 0) { | ||
242 | it.setGridPlacement(1); | ||
243 | it.addHorizontalSeperatorLine(1, 2).setForeground("darkGray".color) | ||
244 | it.addChildArea().setGridPlacementData() => [ | ||
245 | from(LEFT, 3, 0, TOP, 3, 0).to(RIGHT, 3, 0, BOTTOM, 3, 0) | ||
246 | minCellHeight = 5; | ||
247 | minCellWidth = 5; | ||
248 | ]; | ||
249 | for (subData : parentData.subData) { | ||
250 | |||
251 | // To the recursive call to transform for all children | ||
252 | val child = subData.transform | ||
253 | |||
254 | // It is important to add all children to the root! | ||
255 | root.children.add(child) | ||
256 | } | ||
257 | } | ||
258 | ] | ||
259 | ] | ||
260 | |||
261 | } | ||
262 | |||
263 | // Connect every first child to all childs (including itself!) | ||
264 | def void buildConnections(MyData parentData, KNode rootNode) { | ||
265 | |||
266 | // only if there is any child there | ||
267 | if (parentData.subData.size > 0) { | ||
268 | val firstChild = parentData.subData.get(0); | ||
269 | |||
270 | for (child : parentData.subData) { | ||
271 | |||
272 | // BE CAREFUL IF YOU CREATE A MAPPING LIKE THIS THERE WILL JUST BE CREATED ONE | ||
273 | // EDGE PER "firstchild". That's why better use the child, because we iterate | ||
274 | // over different child-objects (targets) but always habe the same firstChild- | ||
275 | // -object. | ||
276 | //val kEdge = firstChild.createEdge() // THIS IS MOST LIKELY WRONG | ||
277 | |||
278 | val kEdge = child.createEdge() | ||
279 | kEdge.source = firstChild.node; | ||
280 | kEdge.target = child.node; | ||
281 | |||
282 | System::out.println("Connect " + firstChild.name + " to " + child.name); | ||
283 | |||
284 | if (!EDGE_STYLE.booleanValue) { | ||
285 | kEdge.addPolyline(2) | ||
286 | } else { | ||
287 | kEdge.addSpline(2); | ||
288 | } | ||
289 | |||
290 | kEdge.KRendering as KPolyline => [ | ||
291 | it.addArrowDecorator() | ||
292 | it.setLineWidth(2) | ||
293 | ]; | ||
294 | |||
295 | child.buildConnections(rootNode); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | } | ||
300 | |||
301 | } | ||
302 | |||
303 | |||
304 | {{/code}} |