| UMLClassNodeRealizer.java |
1 /****************************************************************************
2 * This demo file is part of yFiles for Java 2.14.
3 * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4 * 72070 Tuebingen, Germany. All rights reserved.
5 *
6 * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7 * of demo files in source code or binary form, with or without
8 * modification, is not permitted.
9 *
10 * Owners of a valid software license for a yFiles for Java version that this
11 * demo is shipped with are allowed to use the demo source code as basis
12 * for their own yFiles for Java powered applications. Use of such programs is
13 * governed by the rights and conditions as set out in the yFiles for Java
14 * license agreement.
15 *
16 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19 * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 ***************************************************************************/
28 package demo.view.realizer;
29
30 import java.awt.Color;
31 import java.awt.EventQueue;
32 import java.awt.Font;
33 import java.awt.Graphics2D;
34 import java.awt.Shape;
35 import java.io.IOException;
36 import java.io.ObjectInputStream;
37 import java.io.ObjectOutputStream;
38
39 import javax.swing.JFrame;
40 import javax.swing.JRootPane;
41
42 import demo.view.DemoDefaults;
43 import y.util.D;
44 import y.util.YVersion;
45 import y.view.EditMode;
46 import y.view.Graph2DView;
47 import y.view.NodeLabel;
48 import y.view.NodeRealizer;
49 import y.view.ShapeNodeRealizer;
50 import y.view.SmartNodeLabelModel;
51 import y.view.YLabel;
52
53 /**
54 * NodeRealizer implementation that represents a UML Class Node.
55 * This node realizer displays the following properties of a class
56 * in UML notation:
57 * <ul>
58 * <li>class name</li>
59 * <li>stereotype property</li>
60 * <li>constraint property</li>
61 * <li>attribute list</li>
62 * <li>method list</li>
63 * </ul>
64 * Executing this class will display a sample instance of this realizer.
65 * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/realizers#cls_ShapeNodeRealizer" target="_blank">Section Bringing Graph Elements to Life: The Realizer Concept</a> in the yFiles for Java Developer's Guide
66 */
67 public class UMLClassNodeRealizer extends ShapeNodeRealizer
68 {
69 private NodeLabel aLabel; //attributeLabel
70 private NodeLabel mLabel; //methodLabel
71 private boolean clipContent;
72 private boolean omitDetails;
73 private String stereotype = "";
74 private String constraint = "";
75
76 /**
77 * Instantiates a new UMLNodeRealizer.
78 */
79 public UMLClassNodeRealizer()
80 {
81 init();
82 }
83
84 void init()
85 {
86 setShapeType(RECT_3D);
87
88 SmartNodeLabelModel model = new SmartNodeLabelModel();
89 getLabel().setLabelModel(model,
90 model.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_TOP));
91
92 getLabel().setFontSize(13);
93 getLabel().setFontStyle(Font.BOLD);
94
95 aLabel = new NodeLabel();
96 aLabel.bindRealizer(this);
97 aLabel.setAlignment(YLabel.ALIGN_LEFT);
98 aLabel.setLabelModel(model, model.getDefaultParameter());
99
100 mLabel = new NodeLabel();
101 mLabel.bindRealizer(this);
102 mLabel.setAlignment(YLabel.ALIGN_LEFT);
103 mLabel.setLabelModel(model, model.getDefaultParameter());
104
105 clipContent = true;
106 omitDetails = false;
107 }
108
109 /**
110 * Instantiates a new UMLNodeRealizer as a copy of a given
111 * realizer.
112 */
113 public UMLClassNodeRealizer(NodeRealizer r)
114 {
115 super(r);
116 if(r instanceof UMLClassNodeRealizer)
117 {
118 UMLClassNodeRealizer cnr = (UMLClassNodeRealizer)r;
119 aLabel = (NodeLabel)cnr.aLabel.clone();
120 aLabel.bindRealizer(this);
121 mLabel = (NodeLabel)cnr.mLabel.clone();
122 mLabel.bindRealizer(this);
123 constraint = cnr.constraint;
124 stereotype = cnr.stereotype;
125 clipContent = cnr.clipContent;
126 omitDetails = cnr.omitDetails;
127 }
128 else {
129 init();
130 }
131 }
132
133 /**
134 * Returns a UMLNodERealizer that is a copy of the given
135 * realizer.
136 */
137 public NodeRealizer createCopy(NodeRealizer r)
138 {
139 return new UMLClassNodeRealizer(r);
140 }
141
142
143 //////////////////////////////////////////////////////////////////////////////
144 // SETTER & GETTER ///////////////////////////////////////////////////////////
145 //////////////////////////////////////////////////////////////////////////////
146
147
148 /**
149 * Set the class name to be displayed by this realizer.
150 */
151 public void setClassName(String name)
152 {
153 setLabelText(name);
154 }
155
156 /**
157 * Returns the class name to be displayed by this realizer.
158 */
159 public String getClassName()
160 {
161 return getLabelText();
162 }
163
164
165 /**
166 * Sets the constraint property of this realizer.
167 */
168 public void setConstraint(String constraint)
169 {
170 this.constraint = constraint;
171 }
172
173
174 /**
175 * Sets the stereotype property of this realizer.
176 */
177 public void setStereotype(String stereotype)
178 {
179 this.stereotype = stereotype;
180 }
181
182
183 /**
184 * Returns the constraint property of this realizer.
185 */
186 public String getConstraint()
187 {
188 return constraint;
189 }
190
191 /**
192 * Returns the stereotype property of this realizer.
193 */
194 public String getStereotype()
195 {
196 return stereotype;
197 }
198
199
200 /**
201 * Returns the node label that represents all added
202 * method strings.
203 */
204 public NodeLabel getMethodLabel()
205 {
206 return mLabel;
207 }
208
209 /**
210 * Returns the node label that represents all added
211 * attribute strings.
212 */
213 public NodeLabel getAttributeLabel()
214 {
215 return aLabel;
216 }
217
218 /**
219 * Returns whether or not the display of the labels should be
220 * clipped with the bounding box of the realizer.
221 */
222 public boolean getClipContent()
223 {
224 return clipContent;
225 }
226
227 /**
228 * Sets whether or not the display of the labels should be
229 * clipped with the bounding box of the realizer.
230 */
231 public void setClipContent(boolean clipping)
232 {
233 clipContent = clipping;
234 }
235
236
237 /**
238 * Set whether or not this realizer should omit details when being displayed.
239 */
240 public void setOmitDetails(boolean b)
241 {
242 omitDetails = b;
243 }
244
245
246 /**
247 * Returns whether or not this realizer should omit details when being displayed.
248 */
249 public boolean getOmitDetails()
250 {
251 return omitDetails;
252 }
253
254 private void addToLabel(NodeLabel l, String s)
255 {
256 if(l.getText().length() > 0) {
257 l.setText(l.getText() + '\n' + s);
258 } else {
259 l.setText(s);
260 }
261 }
262
263
264 /**
265 * Adds a class method label to this realizer.
266 */
267 public void addMethod(String method)
268 {
269 addToLabel(mLabel,method);
270 }
271
272 /**
273 * Adds a class attribute label to this realizer.
274 */
275 public void addAttribute(String attr)
276 {
277 addToLabel(aLabel,attr);
278 }
279
280 /**
281 * Set the size of this realizer automatically. This method will adapt the size
282 * of this realizer so that the labels defined for it will fit within its
283 * bounding box.
284 */
285 public void fitContent()
286 {
287 double height = 3.0;
288 double width = getLabel().getWidth() + 10.0;
289
290 if(stereotype.length() > 0)
291 {
292 NodeLabel l = new NodeLabel();
293 l.setText("<<" + getStereotype() + ">>");
294 height += l.getHeight() + 5.0;
295 width = Math.max(l.getWidth()+ 10.0, width);
296 }
297
298 height += getLabel().getHeight() + 3.0;
299
300 if(constraint.length() > 0)
301 {
302 NodeLabel l = new NodeLabel();
303 l.setText("{" + getConstraint() + "}");
304 height += l.getHeight() + 5.0;
305 width = Math.max(l.getWidth() + 10.0, width);
306 }
307
308 if(!omitDetails && !(aLabel.getText().length() == 0 && mLabel.getText().length() == 0))
309 {
310 height += 3.0;
311 height += aLabel.getHeight() + 3.0;
312 width = Math.max(aLabel.getWidth() + 10.0,width);
313 height += 3.0;
314 height += mLabel.getHeight() + 3.0;
315 width = Math.max(mLabel.getWidth() + 10.0,width);
316 }
317
318 setSize(width, height);
319 }
320
321
322 //////////////////////////////////////////////////////////////////////////////
323 // GRAPHICS /////////////////////////////////////////////////////////////////
324 //////////////////////////////////////////////////////////////////////////////
325
326 /**
327 * Paint the labels associated with this realizer.
328 */
329 public void paintText(Graphics2D gfx)
330 {
331 Shape oldClip = null;
332 if(clipContent)
333 {
334 oldClip = gfx.getClip();
335 gfx.clip(getBoundingBox());//Rect((int)x,(int)y,(int)width,(int)height);
336 }
337
338 double yoff = 3.0;
339
340 final SmartNodeLabelModel model = new SmartNodeLabelModel();
341
342 if(stereotype.length() > 0)
343 {
344 NodeLabel l = new NodeLabel();
345 l.bindRealizer( this );
346 l.setText("<<" + getStereotype() + ">>");
347 // Create a specific model parameter which aligns the node's and the label's centers horizontally
348 // (nodeRatioX and labelRatioX are 0) and the upper sides of node and label vertically. (nodeRatioY
349 // and labelRatioY are -0.5). In y-direction an offset is added (yoff) to to move the label to a
350 // position with some distance to the border of the node.
351 l.setLabelModel(model, model.createSpecificModelParameter(0, -0.5, 0, -0.5, 0, yoff, 0, -1));
352 l.paint(gfx);
353 yoff += l.getHeight() + 5.0;
354 }
355
356 NodeLabel label = getLabel();
357 // Create a specific model parameter which aligns the node's and the label's centers horizontally
358 // (nodeRatioX and labelRatioX are 0) and the upper sides of node and label vertically. (nodeRatioY
359 // and labelRatioY are -0.5). In y-direction an offset is added (yoff) to to move the label to a
360 // position with some distance to the border of the node or to the previous label respectively.
361 label.setModelParameter(model.createSpecificModelParameter(0, -0.5, 0, -0.5, 0, yoff, 0, -1));
362 label.paint(gfx);
363 yoff += label.getHeight() + 3.0;
364
365 if(constraint.length() > 0)
366 {
367 NodeLabel l = new NodeLabel();
368 l.bindRealizer( this );
369 l.setText("{" + getConstraint() + "}");
370 // Create a specific model parameter which aligns the node's and the label's right sides horizontally
371 // (nodeRatioX and labelRatioX are 0.5) and the upper sides of node and label vertically. (nodeRatioY
372 // and labelRatioY are -0.5). In y-direction an offset is added (yoff) to to move the label to a
373 // position with some distance to the border of the node or to the previous label respectively. In
374 // x-direction the offset (-0.5) is set so keep a distance to the border of the node.
375 l.setLabelModel(model, model.createSpecificModelParameter(0.5, -0.5, 0.5, -0.5, -5.0, yoff, 0, -1));
376 l.paint(gfx);
377 yoff += l.getHeight() + 5.0;
378 }
379
380 if(!omitDetails && !(aLabel.getText().length() == 0 && mLabel.getText().length() == 0))
381 {
382 gfx.setColor(getLineColor());
383 gfx.drawLine((int)x+1,(int)(y+yoff),(int)(x+width-1.0),(int)(y+yoff));
384 yoff += 3.0;
385 // Create a specific model parameter which aligns the node's and the label's left sides horizontally
386 // (nodeRatioX and labelRatioX are -0.5) and the upper sides of node and label vertically. (nodeRatioY
387 // and labelRatioY are -0.5). In y-direction an offset is added (yoff) to to move the label to a
388 // position with some distance to the border of the node or to the previous label respectively. In
389 // x-direction the offset (3.0) is set so keep a distance to the border of the node.
390 aLabel.setModelParameter(model.createSpecificModelParameter(-0.5, -0.5, -0.5, -0.5, 3.0, yoff, 0, -1));
391 aLabel.paint(gfx);
392 yoff += aLabel.getHeight() + 3.0;
393 gfx.drawLine((int)x+1,(int)(y+yoff),(int)(x+width-1.0),(int)(y+yoff));
394 yoff += 3.0;
395 mLabel.setModelParameter(model.createSpecificModelParameter(-0.5, -0.5, -0.5, -0.5, 3.0, yoff, 0, -1));
396 mLabel.paint(gfx);
397 }
398
399 if(clipContent)
400 {
401 gfx.setClip(oldClip);
402 }
403 }
404
405 //////////////////////////////////////////////////////////////////////////////
406 // SERIALIZATION /////////////////////////////////////////////////////////////
407 //////////////////////////////////////////////////////////////////////////////
408
409 /**
410 * Serialization routine that allows this realizer to be written out
411 * in YGF graph format.
412 * @deprecated Use a custom {@link y.io.graphml.graph2d.NodeRealizerSerializer}
413 * for serialization to the {@link y.io.GraphMLIOHandler GraphML format}
414 * instead.
415 */
416 public void write(ObjectOutputStream out) throws IOException
417 {
418 out.writeByte(YVersion.VERSION_1);
419 super.write(out);
420 aLabel.write( out );
421 mLabel.write( out );
422 out.writeBoolean(clipContent);
423 out.writeBoolean(omitDetails);
424 out.writeObject(getStereotype());
425 out.writeObject(getConstraint());
426 }
427
428
429 /**
430 * Deserialization routine that allows this realizer to be read in
431 * from YGF graph format.
432 * @deprecated Use a custom {@link y.io.graphml.graph2d.NodeRealizerSerializer}
433 * for serialization to the {@link y.io.GraphMLIOHandler GraphML format}
434 * instead.
435 */
436 public void read(ObjectInputStream in) throws IOException, ClassNotFoundException
437 {
438 switch(in.readByte()) {
439 case YVersion.VERSION_1:
440 super.read(in);
441 init();
442 aLabel.read(in);
443 mLabel.read(in);
444 clipContent = in.readBoolean();
445 omitDetails = in.readBoolean();
446 stereotype = (String)in.readObject();
447 constraint = (String)in.readObject();
448 break;
449 default:
450 D.fatal("Unsupported Format");
451 }
452 }
453
454
455
456 public static void addContentTo( final JRootPane rootPane )
457 {
458 final UMLClassNodeRealizer r = new UMLClassNodeRealizer();
459 r.setClassName("com.mycompany.MyClass");
460 r.setConstraint("abstract");
461 r.setStereotype("factory");
462 r.addAttribute("-graph");
463 r.addAttribute("-id");
464 r.addMethod("+setGraph(Graph)");
465 r.addMethod("+getGraph():Graph");
466 r.addMethod("+setID(int)");
467 r.addMethod("+getID():int");
468 r.fitContent();
469 r.setFillColor(new Color(255, 153, 0));
470 final Graph2DView view = new Graph2DView();
471 view.setFitContentOnResize(true);
472 view.getGraph2D().setDefaultNodeRealizer(r.createCopy());
473 view.getGraph2D().createNode();
474 view.addViewMode(new EditMode());
475
476 rootPane.setContentPane(view);
477 }
478
479 /**
480 * Launcher method. Execute this class to see a sample instantiation of
481 * this node realizer in action.
482 */
483 public static void main(String[] args)
484 {
485 EventQueue.invokeLater(new Runnable() {
486 public void run() {
487 DemoDefaults.initLnF();
488 final JFrame frame = new JFrame();
489 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
490 addContentTo(frame.getRootPane());
491 frame.pack();
492 frame.setLocationRelativeTo(null);
493 frame.setVisible(true);
494 }
495 });
496 }
497 }
498
499