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