1
14 package demo.view.layout.tree;
15
16 import demo.view.DemoBase;
17 import y.anim.AnimationFactory;
18 import y.anim.AnimationPlayer;
19 import y.base.Edge;
20 import y.base.EdgeMap;
21 import y.base.Node;
22 import y.base.NodeCursor;
23 import y.base.NodeMap;
24 import y.geom.YPoint;
25 import y.layout.BufferedLayouter;
26 import y.layout.GraphLayout;
27 import y.layout.PortConstraint;
28 import y.layout.PortConstraintKeys;
29 import y.layout.tree.AbstractRotatableNodePlacer;
30 import y.layout.tree.AbstractRotatableNodePlacer.RootAlignment;
31 import y.layout.tree.DefaultNodePlacer;
32 import y.layout.tree.GenericTreeLayouter;
33 import y.layout.tree.NodePlacer;
34 import y.layout.tree.SimpleNodePlacer;
35 import y.util.DataProviderAdapter;
36 import y.view.CreateChildEdgeMode;
37 import y.view.EdgeRealizer;
38 import y.view.EditMode;
39 import y.view.Graph2D;
40 import y.view.HotSpotMode;
41 import y.view.LayoutMorpher;
42 import y.view.NodeRealizer;
43 import y.view.PopupMode;
44 import y.view.PortAssignmentMoveSelectionMode;
45
46 import javax.swing.AbstractAction;
47 import java.awt.Color;
48 import java.awt.Cursor;
49 import java.awt.event.ActionEvent;
50 import java.lang.reflect.Method;
51
52
56 public abstract class AbstractTreeDemo extends DemoBase {
57 protected GenericTreeLayouter treeLayouter = new GenericTreeLayouter();
58
59 private AnimationPlayer animationPlayer;
60
61 protected EdgeMap sourcePortMap;
62 protected EdgeMap targetPortMap;
63 protected NodeMap portAssignmentMap;
64 protected NodeMap nodePlacerMap;
65 protected PortAssignmentMoveSelectionMode portAssignmentMoveMode = new TreePortAssignmentMode();
66 protected Color[] layerColors = new Color[]{ Color.red, Color.orange, Color.yellow, Color.blue, Color.cyan, Color.green };
67
68
71 protected AbstractTreeDemo() {
72 view.addViewMode( new TreeCreateEditMode() );
73
74 animationPlayer = new AnimationPlayer();
75 animationPlayer.addAnimationListener( view );
76
77 Graph2D graph = view.getGraph2D();
78
79 sourcePortMap = graph.createEdgeMap();
80 targetPortMap = graph.createEdgeMap();
81 portAssignmentMap = graph.createNodeMap();
82 nodePlacerMap = graph.createNodeMap();
83 graph.addDataProvider( GenericTreeLayouter.NODE_PLACER_DPKEY, nodePlacerMap );
84 graph.addDataProvider( GenericTreeLayouter.PORT_ASSIGNMENT_DPKEY, portAssignmentMap );
85 graph.addDataProvider( GenericTreeLayouter.CHILD_COMPARATOR_DPKEY, new ChildEdgeComparatorProvider() );
86 graph.addDataProvider( PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, sourcePortMap );
87 graph.addDataProvider( PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, targetPortMap );
88
89 portAssignmentMoveMode.setSpc( sourcePortMap );
90 portAssignmentMoveMode.setTpc( targetPortMap );
91 }
92
93
98 public void setNodePlacer( Node node, NodePlacer placer ) {
99 nodePlacerMap.set( node, placer );
100 }
101
102
105 public void calcLayout() {
106 if ( !view.getGraph2D().isEmpty() ) {
107 Cursor oldCursor = view.getCanvasComponent().getCursor();
108 try {
109 view.getCanvasComponent().setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
110 GraphLayout result = new BufferedLayouter( treeLayouter ).calcLayout( view.getGraph2D() );
111
112 LayoutMorpher morpher = new LayoutMorpher( view, result );
113 morpher.setPreferredDuration( 800 );
114 animationPlayer.animate( AnimationFactory.createEasedAnimation( morpher ) );
115 } finally {
116 view.getCanvasComponent().setCursor( oldCursor );
117 }
118 }
119 }
120
121
124 protected PopupMode createTreePopupMode() {
125 return null;
126 }
127
128
131 protected void registerViewModes() {
132 }
133
134 protected NodePlacer createDefaultNodePlacer() {
135 return new SimpleNodePlacer();
136 }
137
138 protected final class ChildEdgeComparatorProvider extends DataProviderAdapter {
139 public Object get( Object dataHolder ) {
140 NodePlacer placer = ( NodePlacer ) nodePlacerMap.get( dataHolder );
141 if ( placer instanceof AbstractRotatableNodePlacer ) {
142 return ( ( AbstractRotatableNodePlacer ) placer ).createComparator();
143 }
144 if ( placer instanceof DefaultNodePlacer ) {
145 return ( ( DefaultNodePlacer ) placer ).createComparator();
146 }
147 return null;
148 }
149 }
150
151 private final class TreeHotSpotMode extends HotSpotMode {
152 public void mouseReleasedLeft( double x, double y ) {
153 super.mouseReleasedLeft( x, y );
154 calcLayout();
155 }
156 }
157
158 protected final class TreeCreateEditMode extends EditMode {
159 TreeCreateEditMode() {
160 if ( portAssignmentMoveMode == null ) throw new IllegalStateException( "portAssignmentMoveMode is null" );
161 setMoveSelectionMode( portAssignmentMoveMode );
162 setCreateEdgeMode( new TreeCreateChildEdgeMode() );
163 setHotSpotMode( new TreeHotSpotMode() );
164 setPopupMode( AbstractTreeDemo.this.createTreePopupMode() );
165 }
166
167 public boolean doAllowNodeCreation() {
168 return getGraph2D().N() == 0;
169 }
170
171 protected void nodeCreated( Node v ) {
172 super.nodeCreated( v );
173 setNodePlacer( v, createDefaultNodePlacer() );
174 }
175 }
176
177 private final class TreeCreateChildEdgeMode extends CreateChildEdgeMode {
178 protected void edgeCreated( Edge edge ) {
179 int depth = 1;
180 for ( Node node = edge.source(); node.inDegree() > 0; node = node.firstInEdge().source() ) {
181 depth++;
182 }
183 Graph2D g = getGraph2D();
184 g.getRealizer( edge.target() ).setFillColor( layerColors[ depth % layerColors.length ] );
185 EdgeRealizer er = g.getRealizer( edge );
186 if ( nodePlacerMap.get( edge.source() ) == null ) {
187 parseNodePlaceMent( g, edge, er );
188 }
189
190 nodePlacerMap.set( edge.target(), new SimpleNodePlacer() );
191 parseTargetPort( g, edge, er );
192 g.unselectAll();
193 calcLayout();
194 g.setSelected( edge.target(), true );
195 }
196
197 private void parseNodePlaceMent( Graph2D g, Edge e, EdgeRealizer er ) {
198 YPoint firstPoint = er.bendCount() > 0 ? new YPoint( er.firstBend().getX(), er.firstBend().getY() ) : g.getTargetPointAbs( e );
199 NodeRealizer source = g.getRealizer( e.source() );
200 double dx = firstPoint.x - source.getCenterX();
201 double dy = firstPoint.y - source.getCenterY();
202 nodePlacerMap.set( e.source(), new SimpleNodePlacer() );
203 }
204
205 private void parseTargetPort( Graph2D g, Edge e, EdgeRealizer er ) {
206 if ( er.bendCount() > 0 ) {
207 YPoint lastPoint = new YPoint( er.lastBend().getX(), er.lastBend().getY() );
208 NodeRealizer target = g.getRealizer( e.target() );
209 double dx = lastPoint.x - target.getCenterX();
210 double dy = lastPoint.y - target.getCenterY();
211 byte side;
212 if ( Math.abs( dx ) > Math.abs( dy ) ) {
213 if ( dx > 0 ) {
214 side = PortConstraint.EAST;
215 } else {
216 side = PortConstraint.WEST;
217 }
218 } else {
219 if ( dy > 0 ) {
220 side = PortConstraint.SOUTH;
221 } else {
222 side = PortConstraint.NORTH;
223 }
224 }
225 targetPortMap.set( e, PortConstraint.create( side ) );
226 }
227 }
228
229 protected NodeRealizer createChildNodeRealizer() {
230 NodeRealizer retValue = super.createChildNodeRealizer();
231 retValue.setLabelText( "" );
232 return retValue;
233 }
234
235 }
236
237 protected class SetHorizontalAlignmentAction extends AbstractAction {
238 private RootAlignment alignment;
239
240 protected SetHorizontalAlignmentAction( String name, RootAlignment alignment ) {
241 super( name );
242 this.alignment = alignment;
243 }
244
245 public void actionPerformed( ActionEvent e ) {
246 for ( NodeCursor nodeCursor = view.getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next() ) {
247 Node node = nodeCursor.node();
248 NodePlacer nodePlacer = ( NodePlacer ) nodePlacerMap.get( node );
249
250 try {
251 Method method = nodePlacer.getClass().getMethod( "setRootAlignment", new Class[]{ RootAlignment.class } );
252 method.invoke( nodePlacer, new Object[]{ alignment } );
253 } catch ( Exception ex ) {
254 }
255 }
256 calcLayout();
257 }
258 }
259
260 abstract class SetNodePlacerAction extends AbstractAction {
261 protected SetNodePlacerAction( String name ) {
262 super( name );
263 }
264
265 public void actionPerformed( ActionEvent e ) {
266 for ( NodeCursor nodeCursor = view.getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next() ) {
267 Node node = nodeCursor.node();
268 nodePlacerMap.set( node, createNodePlacer() );
269 }
270 calcLayout();
271 }
272
273 protected abstract NodePlacer createNodePlacer();
274 }
275
276 private final class TreePortAssignmentMode extends PortAssignmentMoveSelectionMode {
277 TreePortAssignmentMode() {
278 super( null, null );
279 }
280
281 protected boolean isPortReassignmentAllowed( Edge edge, boolean source ) {
282 return !source;
283 }
284
285 protected void selectionMovedAction( double dx, double dy, double x, double y ) {
286 super.selectionMovedAction( dx, dy, x, y );
287 calcLayout();
288 }
289
290 }
291 }
292