1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.6. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2008 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.realizer;
15  
16  
17  import java.awt.Color;
18  import java.awt.Graphics2D;
19  import java.awt.Stroke;
20  import java.awt.geom.GeneralPath;
21  import java.io.IOException;
22  import java.io.ObjectInputStream;
23  import java.io.ObjectOutputStream;
24  
25  import y.util.YVersion;
26  import y.view.LineType;
27  import y.view.NodeRealizer;
28  import y.view.ShapeNodeRealizer;
29  
30  /**
31   * This class represents a custom NodeRealizer with its own paint,
32   * copy and serialisation routines.
33   * <br>
34   * This realizer will be used in the demo
35   *  {@link demo.view.realizer.StateNodeRealizerDemo}. 
36   */
37  public class StateNodeRealizer extends ShapeNodeRealizer
38  {
39    /**
40     * State specifier constant. A node with this state will be drawn
41     * like an ordinary ShapeNodeRealizer.
42     */
43    public final static byte INITIAL_STATE     = 0;
44    
45    /**
46     * State specifier constant. A node with this state will be drawn
47     * with an additional dashed line.
48     */
49    public final static byte TRANSITION_STATE  = 1;
50  
51    /**
52     * State specifier constant. A node with this state will be drawn
53     * with an additional solid line.
54     */
55    public final static byte FINAL_STATE       = 2;
56    
57    
58    private byte state;
59    
60    /**
61     * Instantiates a new StateNodeRealizer with the given state.
62     * @see #setState(byte)
63     */
64    public StateNodeRealizer(byte state)
65    {
66      super();
67      this.state = state;
68      this.setShapeType(ELLIPSE);
69    }
70    
71    /**
72     * Instantiates a new StateNodeRealizer.
73     */
74    public StateNodeRealizer()
75    {
76      this(INITIAL_STATE);
77    }
78    
79    /**
80     * Instantiates a new StateNodeRealizer as a copy of 
81     * the given NodeRealizer.
82     */
83    public StateNodeRealizer(NodeRealizer r)
84    {
85      super(r);
86      if(r instanceof StateNodeRealizer)
87      {
88        StateNodeRealizer sr = (StateNodeRealizer)r;
89        state = sr.state;
90      }
91      else
92      {
93        state = INITIAL_STATE;
94      }
95    }
96    
97    /**
98     * Sets the state of this realizer.
99     * @param state on of {@link #INITIAL_STATE}, {@link #TRANSITION_STATE}
100    * or {@link #FINAL_STATE}.
101    */
102   public void setState(byte state)
103   {
104     this.state = state;
105   }
106   
107   /**
108    * Returns the state of this realizer.
109    * By default {@link #INITIAL_STATE} will be returned.
110    * @see #setState(byte)
111    */
112   public byte getState()
113   {
114     return this.state;
115   }
116   
117   
118   /**
119    * Paints the node on the given graphics context.
120    * Depending on the state of the realizer the node will be
121    * drawn differently
122    */
123   public void paintNode(Graphics2D gfx)
124   {
125     //first paint the shape node realzier
126     super.paintNode(gfx);
127     
128     if(getState() != INITIAL_STATE)
129     {
130       //then draw an additional state marker
131       //on top of the node.
132       Stroke oldStroke = gfx.getStroke();
133       Color oldColor   = gfx.getColor();
134       if(state == TRANSITION_STATE)
135         gfx.setStroke(LineType.DASHED_1);
136       else if(getState() == FINAL_STATE)
137         gfx.setStroke(LineType.LINE_1); 
138       double oldWidth  = getWidth();
139       double oldHeight = getHeight();
140       if(oldWidth > 10 && oldHeight > 10)
141       {
142         setSize(oldWidth-10,oldHeight-10);
143         gfx.draw(shape);
144         setSize(oldWidth,oldHeight);
145       }
146       
147       gfx.setColor(oldColor);
148       gfx.setStroke(oldStroke);
149     }
150   }
151   
152   /**
153    * Creates a copy of the given realizer that has type
154    * StateNodeRealizer. It is important to implement this method properly
155    * if the realizer should be able to act as a template for 
156    * other realizers, e.g. if it is used as default ndoe realizer
157    * in a Graph2D.
158    * The canonic way to implement this method is to return the result
159    * of a copy constructor.
160    * @see y.view.Graph2D#setDefaultNodeRealizer(y.view.NodeRealizer)
161    * @see #StateNodeRealizer(NodeRealizer) 
162    */
163   public NodeRealizer createCopy(NodeRealizer r)
164   {
165     return new StateNodeRealizer(r);
166   }
167 
168   /**
169    * A custom shape type specifier.
170    */
171   public final static byte CUSTOM_SHAPE = -1;
172 
173   /**
174    * Demonstrates how to define custom shapes.
175    */
176   public void setShapeType(byte type)
177   {
178     if(type == CUSTOM_SHAPE)
179     {
180       updateCustomShape();
181     }
182     super.setShapeType(type);
183   }
184   
185   void updateCustomShape()
186   {
187     GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,5);
188     float x = (float)getX();
189     float y = (float)getY();
190     float w = (float)getWidth();
191     float h = (float)getHeight();
192     path.moveTo(x, y + h);
193     path.lineTo(x, y);
194     float dx = Math.min(h*0.2f,w);
195     path.lineTo(x+w-dx,y);
196     path.lineTo(x+w,y+0.5f*h);
197     path.lineTo(x+w-dx,y+h);
198     path.closePath();
199     shape = path;      
200   }
201   
202   /**
203    * adjust custom shape when size changes. Overrides default scaling operation.
204    */
205   public void setSize(double x, double y)
206   {
207     if(getShapeType() == CUSTOM_SHAPE)
208     {
209       shape = null;
210       super.setSize(x,y);
211       updateCustomShape();
212     }
213     else
214     {
215       super.setSize(x,y);
216     }
217   }
218       
219   
220   /**
221    * Writes out this realizer in a serialized form. This method 
222    * will be used by YGFIOHandler to serialize this NodeRealizer.
223    */
224   public void write(ObjectOutputStream out) throws IOException 
225   {
226     //write out a version tag. version tags help to provide future
227     //serialization compatibility when node realizer features
228     //change.    
229     out.writeByte(YVersion.VERSION_1);
230     //write out the shape node realzier features
231     super.write(out);
232     //write out the state variable
233     out.writeByte(state);
234   }
235   
236   /**
237    * Reads in the serialized form of this realizer. The realizer must have been
238    * written out before by it's {@link #write(ObjectOutputStream)} method.
239    * This method will be used by YGFIOHandler to deserialize this NodeRealizer.
240    */
241   public void read(ObjectInputStream in) throws IOException, 
242     ClassNotFoundException 
243   {
244     switch(in.readByte()) {
245     case YVersion.VERSION_1:
246       super.read(in);
247       state = in.readByte();
248       break;
249     default:
250       //trouble
251     }
252   }
253 }
254 
255