1
28 package demo.layout.hierarchic;
29
30 import demo.view.DemoBase;
31
32 import y.base.Node;
33 import y.base.NodeCursor;
34 import y.layout.hierarchic.IncrementalHierarchicLayouter;
35 import y.layout.hierarchic.incremental.SequenceConstraintFactory;
36 import y.util.Comparators;
37 import y.view.Graph2D;
38 import y.view.Graph2DView;
39
40 import javax.swing.AbstractAction;
41 import javax.swing.Action;
42 import javax.swing.JToolBar;
43 import java.awt.event.ActionEvent;
44 import java.awt.EventQueue;
45 import java.util.ArrayList;
46 import java.util.Comparator;
47 import java.util.HashMap;
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Map;
51 import java.util.Random;
52
53
61 public class SequenceConstraintsDemo extends DemoBase {
62
65 private static final String FIRST = "FIRST";
66
67
70 private static final String LAST = "LAST";
71
72 private final Random rndm;
73
74 public SequenceConstraintsDemo() {
75 rndm = new Random(0);
76 loadGraph("resource/SequenceConstraintsDemo.graphml");
77 }
78
79
87 private void doLayout(final Graph2DView view) {
88 final Graph2D graph = view.getGraph2D();
89
90 final List labeled = new ArrayList(graph.nodeCount());
97 final Map label2nodes = new HashMap();
98 final List firsts = new ArrayList(graph.nodeCount());
99 final List lasts = new ArrayList(graph.nodeCount());
100 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
101 final String s = graph.getRealizer(nc.node()).getLabelText().trim();
102 if (s.length() > 0) {
103 if (FIRST.equalsIgnoreCase(s)) {
104 firsts.add(nc.node());
105 } else if (LAST.equalsIgnoreCase(s)) {
106 lasts.add(nc.node());
107 } else {
108 final String text = graph.getLabelText(nc.node());
109 labeled.add(nc.node());
110 ArrayList list = (ArrayList) label2nodes.get(text);
111 if(list == null){
112 list = new ArrayList();
113 label2nodes.put(text, list);
114 }
115 list.add(nc.node());
116 }
117 }
118 }
119
120 Comparators.sort(labeled, new Comparator() {
123 public int compare(final Object o1, final Object o2) {
124 final String s1 = graph.getRealizer(((Node) o1)).getLabelText();
125 final String s2 = graph.getRealizer(((Node) o2)).getLabelText();
126 return s1.compareTo(s2);
127 }
128 });
129
130
131 final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
132 ihl.setOrthogonallyRouted(true);
133
134 final SequenceConstraintFactory scf = ihl.createSequenceConstraintFactory(graph);
136
137 String leftConstraint = null;
141 for (int i = 1; i < labeled.size(); ++i) {
142
143 String label0 = graph.getLabelText((Node) labeled.get(i - 1));
144 String label1 = graph.getLabelText((Node) labeled.get(i));
145
146 if (!(label1).equals(label0)) {
147 leftConstraint = label0;
148 }
149
150 if (leftConstraint != null) {
151 ArrayList lastNodes = (ArrayList) label2nodes.get(leftConstraint);
152 for (int j = 0; j < lastNodes.size(); j++) {
153 scf.addPlaceAfterConstraint(
154 lastNodes.get(j), labeled.get(i));
155 }
156 }
157 }
158
159 for (int i = 0, n = firsts.size(); i < n; ++i) {
162 scf.addPlaceAtHeadConstraint(firsts.get(i));
163 }
164
165 for (int i = 0, n = lasts.size(); i < n; ++i) {
168 scf.addPlaceAtTailConstraint(lasts.get(i));
169 }
170
171 view.applyLayoutAnimated(ihl);
172
173 scf.dispose();
176 }
177
178
183 private void generateRandomLabels(final Graph2D graph) {
184 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
185 final String label;
186 if (rndm.nextDouble() < 0.125) {
187 label = rndm.nextDouble() < 0.5 ? FIRST : LAST;
188 } else {
189 final char[] chars = new char[rndm.nextInt(2)];
190 for (int i = 0; i < chars.length; ++i) {
191 chars[i] = (char) (rndm.nextInt(26) + (int) 'A');
192 }
193 label = new String(chars);
194 }
195 graph.getRealizer(nc.node()).setLabelText(label);
196 }
197 }
198
199 protected JToolBar createToolBar() {
200 final JToolBar jtb = super.createToolBar();
201 jtb.addSeparator();
202 jtb.add(createActionControl(new AbstractAction(
203 "Layout", SHARED_LAYOUT_ICON) {
204 {
205 putValue(Action.SHORT_DESCRIPTION,
206 "<html><head></head><body>" +
207 "Applies a hierarchical layout." +
208 "<p>" +
209 "Nodes will be sequenced according to the lexicographical" +
210 " order of their labels." +
211 "<br>" +
212 "Nodes with empty labels will be sequenced as the layout" +
213 " algorithm deems appropriate." +
214 "<br>" +
215 "Finally, nodes labeled <code>FIRST</code> or" +
216 " <code>LAST</code> are sequenced at layer start or layer" +
217 " end respectively." +
218 "</p>" +
219 "</body></html>");
220 }
221
222 public void actionPerformed(final ActionEvent e) {
223 doLayout(view);
224 view.fitContent();
225 view.updateView();
226 }
227 }));
228
229 jtb.addSeparator();
230 jtb.add(new AbstractAction("Random Labels") {
231 {
232 putValue(Action.SHORT_DESCRIPTION,
233 "<html><head></head><body>" +
234 "Generates random node labels." +
235 "<p>" +
236 " Roughly 1/8 of the nodes will be marked either as a" +
237 " <code>FIRST</code> or as a <code>LAST</code> node." +
238 "</p>" +
239 "</body></html>");
240 }
241
242 public void actionPerformed(final ActionEvent e) {
243 generateRandomLabels(view.getGraph2D());
244 view.fitContent();
245 view.updateView();
246 }
247 });
248 return jtb;
249 }
250
251 public static void main(String[] args) {
252 EventQueue.invokeLater(new Runnable() {
253 public void run() {
254 Locale.setDefault(Locale.ENGLISH);
255 initLnF();
256 (new SequenceConstraintsDemo()).start();
257 }
258 });
259 }
260 }
261