1
14 package demo.layout.hierarchic;
15
16 import demo.view.DemoBase;
17
18 import y.base.Node;
19 import y.base.NodeCursor;
20 import y.layout.hierarchic.IncrementalHierarchicLayouter;
21 import y.layout.hierarchic.incremental.SequenceConstraintFactory;
22 import y.util.Comparators;
23 import y.view.Graph2D;
24 import y.view.Graph2DView;
25
26 import javax.swing.AbstractAction;
27 import javax.swing.Action;
28 import javax.swing.JToolBar;
29 import java.awt.event.ActionEvent;
30 import java.awt.EventQueue;
31 import java.util.ArrayList;
32 import java.util.Comparator;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Random;
38
39
47 public class SequenceConstraintsDemo extends DemoBase {
48
51 private static final String FIRST = "FIRST";
52
53
56 private static final String LAST = "LAST";
57
58 private final Random rndm;
59
60 public SequenceConstraintsDemo() {
61 rndm = new Random(0);
62 loadGraph("resource/SequenceConstraintsDemo.graphml");
63 }
64
65
73 private void doLayout(final Graph2DView view) {
74 final Graph2D graph = view.getGraph2D();
75
76 final List labeled = new ArrayList(graph.nodeCount());
83 final Map label2nodes = new HashMap();
84 final List firsts = new ArrayList(graph.nodeCount());
85 final List lasts = new ArrayList(graph.nodeCount());
86 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
87 final String s = graph.getRealizer(nc.node()).getLabelText().trim();
88 if (s.length() > 0) {
89 if (FIRST.equalsIgnoreCase(s)) {
90 firsts.add(nc.node());
91 } else if (LAST.equalsIgnoreCase(s)) {
92 lasts.add(nc.node());
93 } else {
94 final String text = graph.getLabelText(nc.node());
95 labeled.add(nc.node());
96 ArrayList list = (ArrayList) label2nodes.get(text);
97 if(list == null){
98 list = new ArrayList();
99 label2nodes.put(text, list);
100 }
101 list.add(nc.node());
102 }
103 }
104 }
105
106 Comparators.sort(labeled, new Comparator() {
109 public int compare(final Object o1, final Object o2) {
110 final String s1 = graph.getRealizer(((Node) o1)).getLabelText();
111 final String s2 = graph.getRealizer(((Node) o2)).getLabelText();
112 return s1.compareTo(s2);
113 }
114 });
115
116
117 final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
118 ihl.setOrthogonallyRouted(true);
119
120 final SequenceConstraintFactory scf = ihl.createSequenceConstraintFactory(graph);
122
123 String leftConstraint = null;
127 for (int i = 1; i < labeled.size(); ++i) {
128
129 String label0 = graph.getLabelText((Node) labeled.get(i - 1));
130 String label1 = graph.getLabelText((Node) labeled.get(i));
131
132 if (!(label1).equals(label0)) {
133 leftConstraint = label0;
134 }
135
136 if (leftConstraint != null) {
137 ArrayList lastNodes = (ArrayList) label2nodes.get(leftConstraint);
138 for (int j = 0; j < lastNodes.size(); j++) {
139 scf.addPlaceNodeAfterConstraint(
140 lastNodes.get(j), labeled.get(i));
141 }
142 }
143 }
144
145 for (int i = 0, n = firsts.size(); i < n; ++i) {
148 scf.addPlaceNodeAtHeadConstraint(firsts.get(i));
149 }
150
151 for (int i = 0, n = lasts.size(); i < n; ++i) {
154 scf.addPlaceNodeAtTailConstraint(lasts.get(i));
155 }
156
157 view.applyLayoutAnimated(ihl);
158
159 scf.dispose();
162 }
163
164
169 private void generateRandomLabels(final Graph2D graph) {
170 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
171 final String label;
172 if (rndm.nextDouble() < 0.125) {
173 label = rndm.nextDouble() < 0.5 ? FIRST : LAST;
174 } else {
175 final char[] chars = new char[rndm.nextInt(2)];
176 for (int i = 0; i < chars.length; ++i) {
177 chars[i] = (char) (rndm.nextInt(26) + (int) 'A');
178 }
179 label = new String(chars);
180 }
181 graph.getRealizer(nc.node()).setLabelText(label);
182 }
183 }
184
185 protected JToolBar createToolBar() {
186 final JToolBar jtb = super.createToolBar();
187 jtb.addSeparator();
188 jtb.add(createActionControl(new AbstractAction(
189 "Layout", SHARED_LAYOUT_ICON) {
190 {
191 putValue(Action.SHORT_DESCRIPTION,
192 "<html><head></head><body>" +
193 "Applies a hierarchical layout." +
194 "<p>" +
195 "Nodes will be sequenced according to the lexicographical" +
196 " order of their labels." +
197 "<br>" +
198 "Nodes with empty labels will be sequenced as the layout" +
199 " algorithm deems appropriate." +
200 "<br>" +
201 "Finally, nodes labeled <code>FIRST</code> or" +
202 " <code>LAST</code> are sequenced at layer start or layer" +
203 " end respectively." +
204 "</p>" +
205 "</body></html>");
206 }
207
208 public void actionPerformed(final ActionEvent e) {
209 doLayout(view);
210 view.fitContent();
211 view.updateView();
212 }
213 }));
214
215 jtb.addSeparator();
216 jtb.add(new AbstractAction("Random Labels") {
217 {
218 putValue(Action.SHORT_DESCRIPTION,
219 "<html><head></head><body>" +
220 "Generates random node labels." +
221 "<p>" +
222 " Roughly 1/8 of the nodes will be marked either as a" +
223 " <code>FIRST</code> or as a <code>LAST</code> node." +
224 "</p>" +
225 "</body></html>");
226 }
227
228 public void actionPerformed(final ActionEvent e) {
229 generateRandomLabels(view.getGraph2D());
230 view.fitContent();
231 view.updateView();
232 }
233 });
234 return jtb;
235 }
236
237 public static void main(String[] args) {
238 EventQueue.invokeLater(new Runnable() {
239 public void run() {
240 Locale.setDefault(Locale.ENGLISH);
241 initLnF();
242 (new SequenceConstraintsDemo()).start();
243 }
244 });
245 }
246 }
247