1
14 package demo.layout.module;
15
16 import y.module.LayoutModule;
17 import y.module.YModule;
18
19 import y.base.DataProvider;
20 import y.base.Edge;
21 import y.base.EdgeCursor;
22 import y.base.EdgeMap;
23 import y.base.Node;
24 import y.base.NodeCursor;
25 import y.layout.router.BusDescriptor;
26 import y.layout.router.BusRouter;
27 import y.option.ConstraintManager;
28 import y.option.DoubleOptionItem;
29 import y.option.IntOptionItem;
30 import y.option.OptionGroup;
31 import y.option.OptionHandler;
32 import y.option.OptionItem;
33 import y.util.DataProviderAdapter;
34 import y.util.Maps;
35 import y.view.Graph2D;
36
37 import java.awt.Color;
38 import java.util.HashSet;
39 import java.util.Set;
40
41
62 public class BusRouterModule extends LayoutModule {
63
64 private static final String NAME = "BUS_ROUTER";
65 private static final String GROUP_LAYOUT = "GROUP_LAYOUT";
66 private static final String GROUP_SELECTION = "GROUP_SELECTION";
67 private static final String GROUP_ROUTING = "GROUP_ROUTING";
68
69 private static final String ALL = "ALL";
70 private static final String BUSES = "BUSES";
71 private static final String COLOR = "COLOR";
72 private static final String CROSSING_COST = "CROSSING_COST";
73 private static final String CROSSING_REROUTING = "CROSSING_REROUTING";
74 private static final String GRID_ENABLED = "GRID_ENABLED";
75 private static final String GRID_SPACING = "GRID_SPACING";
76 private static final String MINIMUM_CONNECTIONS_COUNT = "MINIMUM_CONNECTIONS_COUNT";
77 private static final String MINIMUM_BACKBONE_LENGTH = "MINIMUM_BACKBONE_LENGTH";
78 private static final String MIN_DISTANCE_TO_EDGES = "MIN_DISTANCE_TO_EDGES";
79 private static final String MIN_DISTANCE_TO_NODES = "MIN_DISTANCE_TO_NODES";
80 private static final String PREFERRED_BACKBONE_COUNT = "PREFERRED_BACKBONE_COUNT";
81 private static final String PARTIAL = "PARTIAL";
82 private static final String SCOPE = "SCOPE";
83 private static final String SINGLE = "SINGLE";
84 private static final String SUBSET = "SUBSET";
85 private static final String SUBSET_BUS = "SUBSET_BUS";
86
87 private final BusRouter busRouter;
88
89
92 protected boolean optionsLayout;
93
96 protected boolean optionsSelection;
97
100 protected boolean optionsRouting;
101
102
105 public BusRouterModule() {
106 super(NAME, "yFiles Layout Team", "Routes edges in bus-style");
107 busRouter = new BusRouter();
108 optionsLayout = true;
109 optionsSelection = true;
110 optionsRouting = true;
111 }
112
113
116 protected OptionHandler createOptionHandler() {
117 final OptionHandler oh = new OptionHandler(NAME);
118 addOptionItems(oh);
119 return oh;
120 }
121
122
126 protected void addOptionItems(OptionHandler oh) {
127 ConstraintManager cm = new ConstraintManager(oh);
128
129 BusRouter localRouter = new BusRouter();
130
131 if (optionsLayout) {
132 OptionItem item;
133 oh.addEnum(SCOPE, new String[]{ALL, SUBSET, SUBSET_BUS, PARTIAL}, (int) localRouter.getScope());
134 oh.addEnum(BUSES, new String[]{SINGLE, COLOR}, 0);
135 oh.addBool(GRID_ENABLED, localRouter.isGridRoutingEnabled());
136 item = oh.addInt(GRID_SPACING, localRouter.getGridSpacing());
137 item.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(1));
138 item = oh.addInt(MIN_DISTANCE_TO_NODES, localRouter.getMinimumDistanceToNode());
139 item.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(1));
140 item = oh.addInt(MIN_DISTANCE_TO_EDGES, localRouter.getMinimumDistanceToEdge());
141 item.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(1));
142
143 cm.setEnabledOnValueEquals(GRID_ENABLED, Boolean.TRUE, GRID_SPACING);
144
145 OptionGroup og = new OptionGroup();
146 og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, GROUP_LAYOUT);
147 og.addItem(oh.getItem(SCOPE));
148 og.addItem(oh.getItem(BUSES));
149 og.addItem(oh.getItem(GRID_ENABLED));
150 og.addItem(oh.getItem(GRID_SPACING));
151 og.addItem(oh.getItem(MIN_DISTANCE_TO_NODES));
152 og.addItem(oh.getItem(MIN_DISTANCE_TO_EDGES));
153 }
154
155 if (optionsSelection) {
156 OptionItem item;
157 item = oh.addInt(PREFERRED_BACKBONE_COUNT, localRouter.getPreferredBackboneSegmentCount());
158 item.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(1));
159 item = oh.addDouble(MINIMUM_BACKBONE_LENGTH, localRouter.getMinimumBackboneSegmentLength());
160 item.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(1.0));
161
162 OptionGroup og = new OptionGroup();
163 og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, GROUP_SELECTION);
164 og.addItem(oh.getItem(PREFERRED_BACKBONE_COUNT));
165 og.addItem(oh.getItem(MINIMUM_BACKBONE_LENGTH));
166 }
167
168 if (optionsRouting) {
169 OptionItem item;
170 item = oh.addDouble(CROSSING_COST, localRouter.getCrossingCost());
171 item.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(0.0));
172 oh.addBool(CROSSING_REROUTING, localRouter.isReroutingEnabled());
173 item.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(0.0));
174 item = oh.addInt(MINIMUM_CONNECTIONS_COUNT, localRouter.getMinimumBusConnectionsCount());
175 item.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(1));
176
177 OptionGroup og = new OptionGroup();
178 og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, GROUP_ROUTING);
179 og.addItem(oh.getItem(CROSSING_COST));
180 og.addItem(oh.getItem(CROSSING_REROUTING));
181 og.addItem(oh.getItem(MINIMUM_CONNECTIONS_COUNT));
182 }
183
184 initOptionHandler(oh, busRouter);
185 }
186
187
192 protected void initOptionHandler(OptionHandler oh, BusRouter busRouter) {
193 if (optionsLayout) {
194 oh.set(SCOPE, toScopeName(busRouter.getScope()));
195 oh.set(GRID_ENABLED, Boolean.valueOf(busRouter.isGridRoutingEnabled()));
196 oh.set(GRID_SPACING, new Integer(busRouter.getGridSpacing()));
197 oh.set(MIN_DISTANCE_TO_NODES, new Integer(busRouter.getMinimumDistanceToNode()));
198 oh.set(MIN_DISTANCE_TO_EDGES, new Integer(busRouter.getMinimumDistanceToEdge()));
199 }
200
201 if (optionsSelection) {
202 oh.set(CROSSING_COST, new Double(busRouter.getCrossingCost()));
203 oh.set(CROSSING_REROUTING, Boolean.valueOf(busRouter.isReroutingEnabled()));
204 }
205
206 if (optionsRouting) {
207 oh.set(PREFERRED_BACKBONE_COUNT, new Integer(busRouter.getPreferredBackboneSegmentCount()));
208 oh.set(MINIMUM_CONNECTIONS_COUNT, new Integer(busRouter.getMinimumBusConnectionsCount()));
209 oh.set(MINIMUM_BACKBONE_LENGTH, new Double(busRouter.getMinimumBackboneSegmentLength()));
210 }
211 }
212
213
218 public void configure(BusRouter busRouter) {
219 final OptionHandler oh = getOptionHandler();
220
221 if (optionsLayout) {
222 busRouter.setScope(toBusRouterScope(oh.get(SCOPE)));
223 busRouter.setGridRoutingEnabled(oh.getBool(GRID_ENABLED));
224 busRouter.setGridSpacing(oh.getInt(GRID_SPACING));
225 busRouter.setMinimumDistanceToNode(oh.getInt(MIN_DISTANCE_TO_NODES));
226 busRouter.setMinimumDistanceToEdge(oh.getInt(MIN_DISTANCE_TO_EDGES));
227 }
228
229 if (optionsSelection) {
230 busRouter.setCrossingCost(oh.getDouble(CROSSING_COST));
231 busRouter.setReroutingEnabled(oh.getBool(CROSSING_REROUTING));
232 }
233
234 if (optionsRouting) {
235 busRouter.setPreferredBackboneSegmentCount(oh.getInt(PREFERRED_BACKBONE_COUNT));
236 busRouter.setMinimumBusConnectionsCount(oh.getInt(MINIMUM_CONNECTIONS_COUNT));
237 busRouter.setMinimumBackboneSegmentLength(oh.getDouble(MINIMUM_BACKBONE_LENGTH));
238 }
239 }
240
241
245 protected BusRouter getBusRouter() {
246 return busRouter;
247 }
248
249
253 protected void mainrun() {
254 launchLayouter(busRouter);
255 }
256
257
260 protected void init() {
261 super.init();
262 configure(busRouter);
263
264 if (!optionsLayout) {
265 return;
266 }
267
268 final Graph2D graph = getGraph2D();
269 final OptionHandler oh = getOptionHandler();
270
271 final boolean busByColor = COLOR.equals(oh.get(BUSES));
273 final boolean scopePartial = PARTIAL.equals(oh.get(SCOPE));
274
275
279 final EdgeMap descriptorMap = Maps.createHashedEdgeMap();
280 graph.addDataProvider(BusRouter.EDGE_DESCRIPTOR_DPKEY, descriptorMap);
281 for (EdgeCursor ec = SUBSET.equals(oh.get(SCOPE)) ? graph.selectedEdges() : graph.edges(); ec.ok(); ec.next()) {
284 final Edge edge = ec.edge();
285 final boolean fixed = scopePartial && !graph.isSelected(edge.source()) && !graph.isSelected(edge.target());
287 final Color id = busByColor ? graph.getRealizer(edge).getLineColor() : Color.BLACK;
288 descriptorMap.set(edge, new BusDescriptor(id, fixed));
289 }
290
291
294 final DataProvider descriptorDP = graph.getDataProvider(BusRouter.EDGE_DESCRIPTOR_DPKEY);
295 if (SUBSET.equals(oh.get(SCOPE))) {
296 graph.addDataProvider(busRouter.getSelectedEdgesDpKey(), new DataProviderAdapter() {
298 public boolean getBool(Object dataHolder) {
299 return dataHolder instanceof Edge && graph.isSelected((Edge) dataHolder);
300 }
301 });
302 } else if (SUBSET_BUS.equals(oh.get(SCOPE))) {
303 final Set selectedIDs = new HashSet();
305 for (EdgeCursor ec = graph.selectedEdges(); ec.ok(); ec.next()) {
306 selectedIDs.add(((BusDescriptor) descriptorDP.get(ec.edge())).getID());
307 }
308 graph.addDataProvider(busRouter.getSelectedEdgesDpKey(), new DataProviderAdapter() {
309 public boolean getBool(Object dataHolder) {
310 return selectedIDs.contains(((BusDescriptor) descriptorDP.get(dataHolder)).getID());
311 }
312 });
313 } else if (PARTIAL.equals(oh.get(SCOPE))) {
314 final Set selectedIDs = new HashSet();
317 for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next()) {
318 final Node node = nc.node();
319 for (EdgeCursor ec = node.edges(); ec.ok(); ec.next()) {
320 selectedIDs.add(((BusDescriptor) descriptorDP.get(ec.edge())).getID());
321 }
322 }
323 graph.addDataProvider(busRouter.getSelectedEdgesDpKey(), new DataProviderAdapter() {
324 public boolean getBool(Object dataHolder) {
325 return selectedIDs.contains(((BusDescriptor) descriptorDP.get(dataHolder)).getID());
326 }
327 });
328 }
329
330 }
331
332
335 protected void dispose() {
336 if (optionsLayout) {
337 getGraph2D().removeDataProvider(BusRouter.EDGE_DESCRIPTOR_DPKEY);
339
340 if (!ALL.equals(getOptionHandler().get(SCOPE))) {
341 getGraph2D().removeDataProvider(busRouter.getSelectedEdgesDpKey());
342 }
343 }
344
345 super.dispose();
346 }
347
348 private static byte toBusRouterScope(Object scopeName) {
349 if (ALL.equals(scopeName)) {
350 return BusRouter.SCOPE_ALL;
351 } else if (SUBSET.equals(scopeName) || SUBSET_BUS.equals(scopeName) || PARTIAL.equals(scopeName)) {
352 return BusRouter.SCOPE_SUBSET;
353 } else {
354 return BusRouter.SCOPE_ALL;
355 }
356 }
357
358 private static String toScopeName(byte busRouterScope) {
359 if (BusRouter.SCOPE_ALL == busRouterScope) {
360 return ALL;
361 } else if (BusRouter.SCOPE_SUBSET == busRouterScope) {
362 return SUBSET;
363 } else {
364 throw new IllegalArgumentException("Unknown scope: " + busRouterScope);
365 }
366 }
367 }
368