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