1
14 package demo.layout.hierarchic;
15
16 import y.base.DataProvider;
17 import y.base.Node;
18 import y.base.NodeCursor;
19 import y.layout.LayoutOrientation;
20 import y.layout.NodeLayout;
21 import y.layout.hierarchic.IncrementalHierarchicLayouter;
22 import y.layout.hierarchic.incremental.SwimLaneDescriptor;
23 import y.view.Drawable;
24 import y.view.Graph2D;
25 import y.view.Graph2DView;
26
27 import java.awt.BasicStroke;
28 import java.awt.Color;
29 import java.awt.Graphics2D;
30 import java.awt.Rectangle;
31 import java.awt.Stroke;
32 import java.awt.geom.Line2D;
33 import java.util.ArrayList;
34 import java.util.List;
35
36
39 final class SwimlaneDrawable implements Drawable {
40 private static final int X = 0;
41 private static final int Y = 1;
42
43
44 private final Line2D.Double line;
45 private final Stroke stroke;
46
47 private List lanes;
48 private Rectangle bounds;
49 private double spacing;
50 private Color[] colors;
51 private byte orientation;
52 private boolean lastUpdateWasVertical;
53
54 private Graph2D graph;
55 private Graph2DView view;
56 private boolean accessGraph;
57
58 SwimlaneDrawable( final Graph2D graph ) {
59 this(graph, null, true);
60 }
61
62 SwimlaneDrawable( final Graph2DView view ) {
63 this(null, view, false);
64 }
65
66 SwimlaneDrawable(
67 final Graph2D graph, final DataProvider swimLaneDescriptors
68 ) {
69 this(graph, null, true);
70 }
71
72 private SwimlaneDrawable(
73 final Graph2D graph, final Graph2DView view, final boolean accessGraph
74 ) {
75 this.graph = graph;
76 this.view = view;
77 this.accessGraph = accessGraph;
78
79 this.line = new Line2D.Double();
80 this.stroke = new BasicStroke(1.25f);
81 this.spacing = 20.0d;
82 this.bounds = new Rectangle(20,20,200,200);
83 this.lanes = new ArrayList(20);
84 this.colors = new Color[]{new Color(150, 150, 255), new Color(0 , 0, 150)};
85 this.orientation = LayoutOrientation.TOP_TO_BOTTOM;
86 this.lastUpdateWasVertical = true;
87 }
88
89 public void setEvenLaneColor( final Color color ) {
90 colors[0] = color;
91 }
92
93 public void setOddLaneColor( final Color color ) {
94 colors[1] = color;
95 }
96
97 public byte getOrientation() {
98 return orientation;
99 }
100
101 public void setOrientation( final byte orientation ) {
102 this.orientation = orientation;
103 }
104
105 public Rectangle getBounds() {
106 return bounds;
107 }
108
109 public void updateLanes() {
110 lanes.clear();
111
112 final Graph2D g = getGraph();
113
114 if (g.N() < 1) {
115 return;
116 }
117
118 final DataProvider slds = getSwimLaneDescriptors(g);
119 if (slds == null) {
120 return;
121 }
122
123 double minY;
124 double maxY;
125 double minX;
126 double maxX;
127 if (LayoutOrientation.TOP_TO_BOTTOM == orientation ||
128 LayoutOrientation.BOTTOM_TO_TOP == orientation) {
129 minY = Double.MAX_VALUE;
130 maxY = -Double.MAX_VALUE;
131 for (NodeCursor nc = g.nodes(); nc.ok(); nc.next()){
132 final Node node = nc.node();
133 final NodeLayout nl = g.getNodeLayout(node);
134 minY = Math.min(minY, nl.getY());
135 maxY = Math.max(maxY, nl.getY() + nl.getHeight());
136
137 final SwimLaneDescriptor sld = (SwimLaneDescriptor) slds.get(node);
138 if (sld == null) {
139 continue;
140 }
141 while (lanes.size() - 1 < sld.getComputedLaneIndex()){
142 lanes.add(new double[][]{{0, 0, 0, 0}, {0, 0}});
143 }
144 double[][] laneData = (double[][]) lanes.get(sld.getComputedLaneIndex());
145 laneData[X][0] = sld.getComputedLanePosition();
146 laneData[X][1] = laneData[X][0] + sld.getLeftLaneInset();
147 laneData[X][3] = laneData[X][0] + sld.getComputedLaneWidth();
148 laneData[X][2] = laneData[X][3] - sld.getRightLaneInset();
149 }
150
151 minX = Double.MAX_VALUE;
152 maxX = -Double.MAX_VALUE;
153 for (int i = 0; i < lanes.size(); i++){
154 double[][] laneData = (double[][]) lanes.get(i);
155 laneData[Y][0] = minY - spacing;
156 laneData[Y][1] = maxY + spacing;
157 minX = Math.min(laneData[X][0], minX);
158 maxX = Math.max(laneData[X][3], maxX);
159 }
160
161 lastUpdateWasVertical = true;
162 } else {
163 minX = Double.MAX_VALUE;
164 maxX = -Double.MAX_VALUE;
165 for (NodeCursor nc = g.nodes(); nc.ok(); nc.next()){
166 final Node node = nc.node();
167 final NodeLayout nl = g.getNodeLayout(node);
168 minX = Math.min(minX, nl.getX());
169 maxX = Math.max(maxX, nl.getX() + nl.getWidth());
170
171 final SwimLaneDescriptor sld = (SwimLaneDescriptor) slds.get(node);
172 if (sld == null) {
173 continue;
174 }
175 while (lanes.size() - 1 < sld.getComputedLaneIndex()){
176 lanes.add(new double[][]{{0, 0, 0, 0}, {0, 0}});
177 }
178 double[][] laneData = (double[][]) lanes.get(sld.getComputedLaneIndex());
179 final double sign = LayoutOrientation.LEFT_TO_RIGHT == orientation ? -1 : 1;
180 laneData[X][0] = sign * sld.getComputedLanePosition();
181 laneData[X][1] = laneData[X][0] + sign * sld.getLeftLaneInset();
182 laneData[X][3] = laneData[X][0] + sign * sld.getComputedLaneWidth();
183 laneData[X][2] = laneData[X][3] - sign * sld.getRightLaneInset();
184 }
185
186 minY = Double.MAX_VALUE;
187 maxY = -Double.MAX_VALUE;
188 for (int i = 0; i < lanes.size(); i++){
189 double[][] laneData = (double[][]) lanes.get(i);
190 laneData[Y][0] = minX - spacing;
191 laneData[Y][1] = maxX + spacing;
192 minY = Math.min(laneData[X][0], minY);
193 maxY = Math.max(laneData[X][3], maxY);
194 }
195
196 lastUpdateWasVertical = false;
197 }
198
199 bounds.setFrame(minX, minY, maxX - minX, maxY - minY);
200 g.updateViews();
201 }
202
203 public void paint( final Graphics2D g ) {
204 if (lanes.isEmpty()) {
205 return;
206 }
207
208 final Color oldColor = g.getColor();
209 final Stroke oldStroke = g.getStroke();
210 g.setStroke(stroke);
211 if (lastUpdateWasVertical) {
212 for (int i = 0; i < lanes.size(); i++) {
213 double[][] lane = (double[][]) lanes.get(i);
214
215 line.y1 = lane[Y][0];
216 line.y2 = lane[Y][1];
217
218 g.setColor(colors[i % colors.length]);
219 line.x1 = line.x2 = lane[X][1];
220 g.draw(line);
221 line.x1 = line.x2 = lane[X][2];
222 g.draw(line);
223 }
224 } else {
225 for (int i = 0; i < lanes.size(); i++) {
226 double[][] lane = (double[][]) lanes.get(i);
227
228 line.x1 = lane[Y][0];
229 line.x2 = lane[Y][1];
230
231 g.setColor(colors[i % colors.length]);
232 line.y1 = line.y2 = lane[X][1];
233 g.draw(line);
234 line.y1 = line.y2 = lane[X][2];
235 g.draw(line);
236 }
237 }
238 g.setStroke(oldStroke);
239 g.setColor(oldColor);
240 }
241
242 private DataProvider getSwimLaneDescriptors( final Graph2D graph ) {
243 return graph.getDataProvider(IncrementalHierarchicLayouter.SWIMLANE_DESCRIPTOR_DPKEY);
244 }
245
246 private Graph2D getGraph() {
247 if (accessGraph) {
248 return graph;
249 } else {
250 return view.getGraph2D();
251 }
252 }
253 }
254