| StateNodeRealizer.java |
1 /****************************************************************************
2 **
3 ** This file is part of yFiles-2.9.
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-2011 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 import y.io.graphml.graph2d.ShapeNodeRealizerSerializer;
30 import y.io.graphml.input.GraphMLParseContext;
31 import y.io.graphml.input.GraphMLParseException;
32 import y.io.graphml.output.XmlWriter;
33 import y.io.graphml.output.GraphMLWriteContext;
34 import org.w3c.dom.Node;
35 import org.w3c.dom.Element;
36
37 /**
38 * This class represents a custom NodeRealizer with its own paint,
39 * copy and serialisation routines.
40 * <br>
41 * This realizer will be used in the demo
42 * {@link demo.view.realizer.StateNodeRealizerDemo}.
43 * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/realizers.html#cls_ShapeNodeRealizer">Section Bringing Graph Elements to Life: The Realizer Concept</a> in the yFiles for Java Developer's Guide
44 * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/mvc_controller.html#custom_edit_mode">Section User Interaction</a> in the yFiles for Java Developer's Guide
45 */
46 public class StateNodeRealizer extends ShapeNodeRealizer
47 {
48 /**
49 * State specifier constant. A node with this state will be drawn
50 * like an ordinary ShapeNodeRealizer.
51 */
52 public static final byte INITIAL_STATE = 0;
53
54 /**
55 * State specifier constant. A node with this state will be drawn
56 * with an additional dashed line.
57 */
58 public static final byte TRANSITION_STATE = 1;
59
60 /**
61 * State specifier constant. A node with this state will be drawn
62 * with an additional solid line.
63 */
64 public static final byte FINAL_STATE = 2;
65
66
67 private byte state;
68
69 /**
70 * Instantiates a new StateNodeRealizer with the given state.
71 * @see #setState(byte)
72 */
73 public StateNodeRealizer(byte state)
74 {
75 super();
76 this.state = state;
77 this.setShapeType(ELLIPSE);
78 }
79
80 /**
81 * Instantiates a new StateNodeRealizer.
82 */
83 public StateNodeRealizer()
84 {
85 this(INITIAL_STATE);
86 }
87
88 /**
89 * Instantiates a new StateNodeRealizer as a copy of
90 * the given NodeRealizer.
91 */
92 public StateNodeRealizer(NodeRealizer r)
93 {
94 super(r);
95 if(r instanceof StateNodeRealizer)
96 {
97 StateNodeRealizer sr = (StateNodeRealizer)r;
98 state = sr.state;
99 }
100 else
101 {
102 state = INITIAL_STATE;
103 }
104 }
105
106 /**
107 * Sets the state of this realizer.
108 * @param state on of {@link #INITIAL_STATE}, {@link #TRANSITION_STATE}
109 * or {@link #FINAL_STATE}.
110 */
111 public void setState(byte state)
112 {
113 this.state = state;
114 }
115
116 /**
117 * Returns the state of this realizer.
118 * By default {@link #INITIAL_STATE} will be returned.
119 * @see #setState(byte)
120 */
121 public byte getState()
122 {
123 return this.state;
124 }
125
126
127 /**
128 * Paints the node on the given graphics context.
129 * Depending on the state of the realizer the node will be
130 * drawn differently
131 */
132 public void paintNode(Graphics2D gfx)
133 {
134 //first paint the shape node realizer
135 super.paintNode(gfx);
136
137 if(getState() != INITIAL_STATE)
138 {
139 //then draw an additional state marker
140 //on top of the node.
141 Stroke oldStroke = gfx.getStroke();
142 Color oldColor = gfx.getColor();
143 if(state == TRANSITION_STATE) {
144 gfx.setStroke(LineType.DASHED_1);
145 } else if(getState() == FINAL_STATE) {
146 gfx.setStroke(LineType.LINE_1);
147 }
148 double oldWidth = getWidth();
149 double oldHeight = getHeight();
150 if(oldWidth > 10.0 && oldHeight > 10.0)
151 {
152 setSize(oldWidth- 10.0,oldHeight- 10.0);
153 gfx.draw(shape);
154 setSize(oldWidth,oldHeight);
155 }
156
157 gfx.setColor(oldColor);
158 gfx.setStroke(oldStroke);
159 }
160 }
161
162 /**
163 * Creates a copy of the given realizer that has type
164 * StateNodeRealizer. It is important to implement this method properly
165 * if the realizer should be able to act as a template for
166 * other realizers, e.g. if it is used as default node realizer
167 * in a Graph2D.
168 * The canonical way to implement this method is to return the result
169 * of a copy constructor.
170 * @see y.view.Graph2D#setDefaultNodeRealizer(y.view.NodeRealizer)
171 * @see #StateNodeRealizer(NodeRealizer)
172 */
173 public NodeRealizer createCopy(NodeRealizer r)
174 {
175 return new StateNodeRealizer(r);
176 }
177
178 /**
179 * A custom shape type specifier.
180 */
181 public static final byte CUSTOM_SHAPE = -1;
182
183 /**
184 * Demonstrates how to define custom shapes.
185 */
186 public void setShapeType(byte type)
187 {
188 if(type == CUSTOM_SHAPE)
189 {
190 updateCustomShape();
191 }
192 super.setShapeType(type);
193 }
194
195 void updateCustomShape()
196 {
197 GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,5);
198 float x = (float)getX();
199 float y = (float)getY();
200 float w = (float)getWidth();
201 float h = (float)getHeight();
202 path.moveTo(x, y + h);
203 path.lineTo(x, y);
204 float dx = Math.min(h*0.2f,w);
205 path.lineTo(x+w-dx,y);
206 path.lineTo(x+w,y+0.5f*h);
207 path.lineTo(x+w-dx,y+h);
208 path.closePath();
209 shape = path;
210 }
211
212 /**
213 * adjust custom shape when size changes. Overrides default scaling operation.
214 */
215 public void setSize(double x, double y)
216 {
217 if(getShapeType() == CUSTOM_SHAPE)
218 {
219 shape = null;
220 super.setSize(x,y);
221 updateCustomShape();
222 }
223 else
224 {
225 super.setSize(x,y);
226 }
227 }
228
229
230 /**
231 * Writes out this realizer in a serialized form. This method
232 * will be used by YGFIOHandler to serialize this NodeRealizer.
233 * @deprecated Use {@link demo.view.realizer.StateNodeRealizer.StateNodeRealizerSerializer}
234 * for serialization to the {@link y.io.GraphMLIOHandler GraphML format}
235 * instead.
236 */
237 public void write(ObjectOutputStream out) throws IOException
238 {
239 //write out a version tag. version tags help to provide future
240 //serialization compatibility when node realizer features
241 //change.
242 out.writeByte(YVersion.VERSION_1);
243 //write out the shape node realizer features
244 super.write(out);
245 //write out the state variable
246 out.writeByte(state);
247 }
248
249 /**
250 * Reads in the serialized form of this realizer. The realizer must have been
251 * written out before by it's {@link #write(ObjectOutputStream)} method.
252 * This method will be used by YGFIOHandler to deserialize this NodeRealizer.
253 * @deprecated Use {@link demo.view.realizer.StateNodeRealizer.StateNodeRealizerSerializer}
254 * for serialization to the {@link y.io.GraphMLIOHandler GraphML format}
255 * instead.
256 */
257 public void read(ObjectInputStream in) throws IOException,
258 ClassNotFoundException
259 {
260 switch(in.readByte()) {
261 case YVersion.VERSION_1:
262 super.read(in);
263 state = in.readByte();
264 break;
265 default:
266 //trouble
267 }
268 }
269
270 /**
271 * RealizerSerializer that can be used to serialize instances of StateNodeRealizer to and from
272 * {@link y.io.GraphMLIOHandler GraphML format}.
273 */
274 static class StateNodeRealizerSerializer extends ShapeNodeRealizerSerializer {
275 public String getName() {
276 return "StateNode";
277 }
278
279 public String getNamespaceURI() {
280 return "demo.view.realizer";
281 }
282
283 public Class getRealizerClass() {
284 return StateNodeRealizer.class;
285 }
286
287 public void parse(NodeRealizer realizer, Node domNode, GraphMLParseContext context) throws GraphMLParseException {
288 super.parse(realizer, domNode, context);
289 StateNodeRealizer snr = (StateNodeRealizer) realizer;
290 String state = ((Element) domNode).getAttribute("state");
291
292 if("initial".equals(state)) {
293 snr.setState(INITIAL_STATE);
294 }
295 else if("transition".equals(state)) {
296 snr.setState(TRANSITION_STATE);
297 }
298 else if("final".equals(state)) {
299 snr.setState(FINAL_STATE);
300 }
301 }
302
303
304 protected byte decodeShapeType(String s, GraphMLParseContext context) {
305 if("custom".equals(s)) {
306 return CUSTOM_SHAPE;
307 }
308 return super.decodeShapeType(s, context);
309 }
310
311 protected String encodeShapeType(ShapeNodeRealizer snr, GraphMLWriteContext context) {
312 if(snr.getShapeType() == CUSTOM_SHAPE) {
313 return "custom";
314 }
315 return super.encodeShapeType(snr, context);
316 }
317
318 public void writeAttributes(NodeRealizer nr, XmlWriter writer, GraphMLWriteContext context) {
319 super.writeAttributes(nr, writer, context);
320 StateNodeRealizer snr = (StateNodeRealizer) nr;
321 switch(snr.getState()) {
322 case INITIAL_STATE:
323 writer.writeAttribute("state", "initial");
324 break;
325 case TRANSITION_STATE:
326 writer.writeAttribute("state", "transition");
327 break;
328 case FINAL_STATE:
329 writer.writeAttribute("state", "final");
330 break;
331 }
332 }
333 }
334 }
335
336