1
14 package demo.view.layout.hierarchic;
15
16 import demo.view.DemoBase;
17
18 import y.base.NodeCursor;
19 import y.base.Node;
20 import y.view.Graph2D;
21 import y.layout.hierarchic.IncrementalHierarchicLayouter;
22 import y.layout.hierarchic.incremental.SequenceConstraintFactory;
23 import y.layout.BufferedLayouter;
24 import y.io.GMLIOHandler;
25
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.List;
30 import java.util.Random;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.net.URL;
34 import java.awt.event.ActionEvent;
35 import javax.swing.JToolBar;
36 import javax.swing.AbstractAction;
37
38
45 public class SequenceConstraintsDemo extends DemoBase {
46
50 private static final String HEAD = "HEAD";
51
55 private static final String TAIL = "TAIL";
56
57 private final Random rndm;
58
59 public SequenceConstraintsDemo() {
60 rndm = new Random(666);
61 loadInitialGraph(view.getGraph2D());
62 generateRandomLabels(view.getGraph2D());
63 view.fitContent();
64 view.updateView();
65 }
66
67
75 private void doLayout( final Graph2D graph ) {
76 final List labeled = new ArrayList(graph.nodeCount());
83 final List heads = new ArrayList(graph.nodeCount());
84 final List tails = new ArrayList(graph.nodeCount());
85 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
86 final String s = graph.getRealizer(nc.node()).getLabelText().trim();
87 if (s.length() > 0) {
88 if (HEAD.equalsIgnoreCase(s)) {
89 heads.add(nc.node());
90 } else if (TAIL.equalsIgnoreCase(s)) {
91 tails.add(nc.node());
92 } else {
93 labeled.add(nc.node());
94 }
95 }
96 }
97
98 Collections.sort(labeled, new Comparator() {
101 public int compare( final Object o1, final Object o2 ) {
102 final String s1 = graph.getRealizer(((Node) o1)).getLabelText();
103 final String s2 = graph.getRealizer(((Node) o2)).getLabelText();
104 return s1.compareTo(s2);
105 }
106 });
107
108
109 final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
110
111
112 final SequenceConstraintFactory scf = ihl.createSequenceConstraintFactory(graph);
114
115 for (int i = 1, n = labeled.size(); i < n; ++i) {
119 scf.addPlaceNodeAfterConstraint(
120 (Node) labeled.get(i - 1), (Node) labeled.get(i));
121 }
122
123 for (int i = 0, n = heads.size(); i < n; ++i) {
126 scf.addPlaceNodeAtHeadConstraint((Node) heads.get(i));
127 }
128
129 for (int i = 0, n = tails.size(); i < n; ++i) {
132 scf.addPlaceNodeAtTailConstraint((Node) tails.get(i));
133 }
134
135 (new BufferedLayouter(ihl)).doLayout(graph);
136
137 scf.dispose();
140 }
141
142
147 private void generateRandomLabels( final Graph2D graph ) {
148 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
149 final String label;
150 if (rndm.nextDouble() < 0.125) {
151 label = rndm.nextDouble() < 0.5 ? HEAD : TAIL;
152 } else {
153 final char[] chars = new char[rndm.nextInt(3)];
154 for (int i = 0; i < chars.length; ++i) {
155 chars[i] = (char)(rndm.nextInt(26) + (int)'A');
156 }
157 label = new String(chars);
158 }
159 graph.getRealizer(nc.node()).setLabelText(label);
160 }
161 }
162
163
166 private void loadInitialGraph( final Graph2D graph ) {
167 final String resource = "resource/small_ihl_sample.gml";
168 final URL url = getClass().getResource(resource);
169 if (url != null) {
170 try {
171 InputStream is = null;
172 try {
173 is = url.openStream();
174 (new GMLIOHandler()).read(graph, is);
175 } finally {
176 if (is != null) {
177 is.close();
178 }
179 }
180 } catch (IOException ioe) {
181 System.err.println("Could not read file \"" + resource + "\".");
182 }
183 } else {
184 System.err.println("Could not find file \"" + resource + "\".");
185 }
186 }
187
188 protected JToolBar createToolBar() {
189 final JToolBar jtb = super.createToolBar();
190 jtb.addSeparator();
191 jtb.add(new AbstractAction("Layout") {
192 {
193 putValue(AbstractAction.SHORT_DESCRIPTION,
194 "<html><head></head><body>" +
195 "Applies a hierarchical layout." +
196 "<p>" +
197 "Nodes will be sequenced according to the lexicographical" +
198 " order of their labels." +
199 "<br>" +
200 "Nodes with empty labels will be sequenced as the layout" +
201 " algorithm deems appropriate." +
202 "<br>" +
203 "Finally, nodes labeled <code>HEAD</code> or" +
204 " <code>TAIL</code> are sequenced at layer start or layer" +
205 " end respectively." +
206 "</p>" +
207 "</body></html>");
208 }
209
210 public void actionPerformed( final ActionEvent e ) {
211 doLayout(view.getGraph2D());
212 view.fitContent();
213 view.updateView();
214 }
215 });
216 jtb.add(new AbstractAction("New Labels") {
217 {
218 putValue(AbstractAction.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>HEAD</code> or as a <code>TAIL</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 initLnF();
239 (new SequenceConstraintsDemo()).start();
240 }
241 }
242