1
28 package demo.io.graphml;
29
30 import demo.view.DemoBase;
31 import demo.view.DemoDefaults;
32 import demo.view.flowchart.painters.FlowchartRealizerFactory;
33 import y.base.Edge;
34 import y.base.EdgeCursor;
35 import y.base.Node;
36 import y.base.NodeCursor;
37 import y.io.GraphMLIOHandler;
38 import y.io.graphml.output.GraphElementIdProvider;
39 import y.io.graphml.output.GraphMLWriteException;
40 import y.io.graphml.output.WriteEvent;
41 import y.io.graphml.output.WriteEventListenerAdapter;
42 import y.util.D;
43 import y.view.BevelNodePainter;
44 import y.view.EditMode;
45 import y.view.GenericNodeRealizer;
46 import y.view.Graph2D;
47 import y.view.Graph2DEvent;
48 import y.view.Graph2DListener;
49 import y.view.Graph2DUndoManager;
50 import y.view.Selections;
51 import y.view.Selections.SelectionStateObserver;
52 import y.view.ViewMode;
53 import y.view.hierarchy.HierarchyManager;
54
55 import javax.swing.BorderFactory;
56 import javax.swing.JButton;
57 import javax.swing.JLabel;
58 import javax.swing.JPanel;
59 import javax.swing.JScrollPane;
60 import javax.swing.JSplitPane;
61 import javax.swing.JTextArea;
62 import javax.swing.Timer;
63 import javax.swing.text.BadLocationException;
64 import javax.swing.text.DefaultHighlighter;
65 import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
66 import java.awt.BorderLayout;
67 import java.awt.Dimension;
68 import java.awt.EventQueue;
69 import java.awt.Font;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.beans.PropertyChangeEvent;
73 import java.beans.PropertyChangeListener;
74 import java.io.ByteArrayInputStream;
75 import java.io.IOException;
76 import java.io.StringWriter;
77 import java.util.HashMap;
78 import java.util.Iterator;
79 import java.util.Locale;
80 import java.util.Map;
81 import java.util.regex.Matcher;
82 import java.util.regex.Pattern;
83
84
85
96 public class GraphMLDemo extends DemoBase {
97 private static final String BEVEL_NODE_CONFIGURATION = "BevelNodeConfig";
98
99 protected GraphMLPane graphMLPane;
100 private Graph2DUndoManager undoManager;
101
102
105 public GraphMLDemo() {
106
107 graphMLPane = new GraphMLPane();
108 graphMLPane.setPreferredSize(new Dimension(600, 350));
109 graphMLPane.setMinimumSize(new Dimension(0, 100));
110
111
113 JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, view, graphMLPane);
114 splitPane.setBorder(BorderFactory.createEmptyBorder());
115 view.setPreferredSize(new Dimension(600, 350));
116 view.setMinimumSize(new Dimension(0, 200));
117 loadInitialGraph();
118 view.fitContent();
119 contentPane.add(splitPane, BorderLayout.CENTER);
120 }
121
122 protected void initialize() {
123 final Graph2D graph = view.getGraph2D();
124
125 new HierarchyManager(graph);
127 }
128
129 protected void configureDefaultRealizers() {
130 super.configureDefaultRealizers();
131
132 final GenericNodeRealizer.Factory f = GenericNodeRealizer.getFactory();
133 if (!f.getAvailableConfigurations().contains(BEVEL_NODE_CONFIGURATION)) {
134 BevelNodePainter bevelNodePainter = new BevelNodePainter();
135 bevelNodePainter.setDrawShadow(true);
136 Map impls = f.createDefaultConfigurationMap();
137 impls.put(GenericNodeRealizer.Painter.class, bevelNodePainter);
138 impls.put(GenericNodeRealizer.ContainsTest.class, bevelNodePainter);
139 f.addConfiguration(BEVEL_NODE_CONFIGURATION, impls);
140 }
141
142 FlowchartRealizerFactory.createData();
144 }
145
146 protected void loadInitialGraph() {
147 loadGraph("resources/ygraph/visual_features.graphml");
148 }
149
150
153 protected Graph2DUndoManager getUndoManager() {
154 if (undoManager == null) {
155 final Graph2D graph = view.getGraph2D();
156 undoManager = new Graph2DUndoManager(graph) {
157
163 public void backupRealizers(Graph2D graph, EdgeCursor ec) {
164 super.backupRealizers(graph, ec);
165 graphMLPane.firePotentialChange();
166 }
167
168
174 public void backupRealizers(Graph2D graph, NodeCursor nc) {
175 super.backupRealizers(graph, nc);
176 graphMLPane.firePotentialChange();
177 }
178 };
179 undoManager.setViewContainer(view);
180
181 graph.setBackupRealizersHandler(undoManager);
182 }
183
184 return undoManager;
185 }
186
187
190 protected String[] getExampleResources() {
191 return new String[]{
192 "resources/ygraph/visual_features.graphml",
193 "resources/ygraph/problemsolving.graphml",
194 "resources/ygraph/simple.graphml",
195 "resources/ygraph/grouping.graphml",
196 };
197 }
198
199 protected void loadGraph(Class aClass, String resourceString) {
200 try {
201 graphMLPane.setUpdating(true);
202 super.loadGraph(aClass, resourceString);
203 graphMLPane.setUpdating(false);
204 graphMLPane.showGraphMLText(view.getGraph2D());
205 }
206 finally {
207 graphMLPane.setUpdating(false);
208 }
209 }
210
211
214 public static void main(String[] args) {
215 EventQueue.invokeLater(new Runnable() {
216 public void run() {
217 Locale.setDefault(Locale.ENGLISH);
218 initLnF();
219 new GraphMLDemo().start();
220 }
221 });
222 }
223
224 class GraphMLPane extends JPanel {
225
226
229 protected boolean updating;
230 private boolean editable;
231
232 private final JButton applyButton;
233 private Map elementIdMap;
234 private final JTextArea graphMLTextPane;
235 private int lastStartIndex;
236 Timer timer;
237
238 GraphMLPane() {
239 editable = true;
240
241 JPanel graphMLHeader = new JPanel();
242 JLabel graphMLLabel = new JLabel("GraphML representation");
243 graphMLLabel.setFont(graphMLLabel.getFont().deriveFont(Font.BOLD));
244 graphMLLabel.setFont(graphMLLabel.getFont().deriveFont(12.0f));
245 graphMLLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
246 setLayout(new BorderLayout());
247
248 graphMLTextPane = new JTextArea();
249
250 JScrollPane scrollPane = new JScrollPane(graphMLTextPane);
251 scrollPane.setPreferredSize(new Dimension(0, 350));
252
253 graphMLHeader.setLayout(new BorderLayout());
254 graphMLHeader.add(graphMLLabel, BorderLayout.WEST);
255 applyButton = new JButton("Apply GraphML");
256
257 applyButton.addActionListener(new ActionListener() {
258 public void actionPerformed(ActionEvent e) {
259 applyGraphMLText(view.getGraph2D());
260 }
261 });
262
263 graphMLHeader.add(applyButton, BorderLayout.EAST);
264
265 add(graphMLHeader, BorderLayout.NORTH);
266 add(scrollPane, BorderLayout.CENTER);
267 setEditable(editable);
268 registerView();
269 }
270
271
272 public boolean isEditable() {
273 return editable;
274 }
275
276 public void setEditable(boolean editable) {
277 this.editable = editable;
278 graphMLTextPane.setEditable(editable);
279 applyButton.setVisible(editable);
280 }
281
282 void registerView() {
283
284 for(Iterator iter = view.getViewModes(); iter.hasNext();) {
285 ViewMode mode = (ViewMode) iter.next();
286 if(mode instanceof EditMode) {
287 EditMode editMode = (EditMode) mode;
288 PropertyChangeListener pcl = new PropertyChangeListener() {
289 public void propertyChange(PropertyChangeEvent evt) {
290 if (evt.getPropertyName().equals(ViewMode.EDITING_PROPERTY) && evt.getNewValue().equals(Boolean.FALSE)) {
291 firePotentialChange();
292 }
293 }
294 };
295 editMode.addPropertyChangeListener(pcl);
296 editMode.getHotSpotMode().addPropertyChangeListener(pcl);
297 editMode.getMovePortMode().addPropertyChangeListener(pcl);
298 editMode.getMoveLabelMode().addPropertyChangeListener(pcl);
299 editMode.getMoveSelectionMode().addPropertyChangeListener(pcl);
300 editMode.getMoveSelectionMode().addPropertyChangeListener(pcl);
301 break;
302 }
303 }
304
305 SelectionStateObserver sto = new SelectionStateObserver() {
306 protected void updateSelectionState(Graph2D graph) {
307 firePotentialChange();
308 }
309 };
310 view.getGraph2D().addGraphListener(sto);
311 view.getGraph2D().addGraph2DSelectionListener(sto);
312
313 view.getGraph2D().addGraph2DListener(new Graph2DListener() {
314 public void onGraph2DEvent(Graph2DEvent e) {
315 firePotentialChange();
316 }
317 });
318 }
319
320
321 public void firePotentialChange() {
322 if(!isUpdating()) {
323 if(timer == null) {
324 timer = new Timer(100, new ActionListener() {
325
326 public void actionPerformed(ActionEvent e) {
327 updateGraphMLText(view.getGraph2D());
328 }
329 });
330 timer.setRepeats(false);
331 }
332 timer.restart();
333 }
334 }
335
336 private void setUpdating(boolean updating) {
337 this.updating = updating;
338 }
339
340 private boolean isUpdating() {
341 return updating;
342 }
343
344 public void updateGraphMLText(Graph2D graph) {
345 showGraphMLText(view.getGraph2D());
347
348 if (!Selections.isNodeSelectionEmpty(graph)) {
350 scrollGraphMLTextTo(view.getGraph2D().selectedNodes().node());
351 } else if (!Selections.isEdgeSelectionEmpty(graph)) {
352 scrollGraphMLTextTo(view.getGraph2D().selectedEdges().edge());
353 }
354 }
355
356 private void scrollGraphMLTextTo(Node node) {
357 if (elementIdMap != null && elementIdMap.get(node) instanceof String) {
358 scrollGraphMLTextTo("node", elementIdMap.get(node).toString());
359 }
360 }
361
362 private void scrollGraphMLTextTo(Edge edge) {
363 if (elementIdMap != null && elementIdMap.get(edge) instanceof String) {
364 scrollGraphMLTextTo("edge", elementIdMap.get(edge).toString());
365 }
366 }
367
368 private void scrollGraphMLTextTo(String tag, String elementId) {
369 String text = graphMLTextPane.getText();
370 Pattern pattern = Pattern.compile("<" + tag + " .*id=\"" + elementId + "\"");
371 int startIndex = 0;
372 Matcher matcher = pattern.matcher(text);
373 if (matcher.find()) {
374 startIndex = matcher.start();
375 }
376 int endIndex = text.indexOf("</" + tag + ">", startIndex) + (tag.length() + 3);
377
378 DefaultHighlighter highlighter = new DefaultHighlighter();
379 DefaultHighlightPainter painter = new DefaultHighlightPainter(DemoDefaults.DEFAULT_CONTRAST_COLOR);
380 graphMLTextPane.setHighlighter(highlighter);
381 try {
382 highlighter.addHighlight(startIndex, endIndex, painter);
383 lastStartIndex = startIndex;
384 } catch (BadLocationException e1) {
385 lastStartIndex = 0;
386 e1.printStackTrace();
387 }
388
389 graphMLTextPane.requestFocus();
390 graphMLTextPane.setCaretPosition(startIndex);
391 graphMLTextPane.moveCaretPosition(endIndex);
392 view.getCanvasComponent().requestFocus();
393
394 try {
395 graphMLTextPane.scrollRectToVisible(graphMLTextPane.modelToView(startIndex));
396 } catch (BadLocationException e) {
397 e.printStackTrace();
398 }
399
400 }
401
402 private String createGraphMLTextAndUpdateGraphElementIdMap(final Graph2D graph) {
403 StringWriter buffer = new StringWriter();
404 if (graph != null) {
405 GraphMLIOHandler ioh = createGraphMLIOHandler();
406 ioh.getGraphMLHandler().addWriteEventListener(
407 new WriteEventListenerAdapter() {
408 public void onDocumentWritten(WriteEvent event)
409 throws GraphMLWriteException {
410 GraphElementIdProvider idProvider = (GraphElementIdProvider) event
411 .getContext().lookup(GraphElementIdProvider.class);
412 elementIdMap = new HashMap();
413 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
414 Node n = nc.node();
415 elementIdMap.put(n, idProvider.getNodeId(n, event
416 .getContext()));
417 }
418 for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
419 Edge e = ec.edge();
420 elementIdMap.put(e, idProvider.getEdgeId(e, event
421 .getContext()));
422 }
423 }
424 });
425 try {
426 ioh.write(graph, buffer);
427 }catch(IOException ex) {
428 ex.printStackTrace();
429 return "";
430 }
431 }
432 buffer.flush();
433 return buffer.toString();
434 }
435
436
439 protected void showGraphMLText(final Graph2D graph) {
440 if (!isUpdating()) {
441 setUpdating(true);
442 try {
443 graphMLTextPane.setText(createGraphMLTextAndUpdateGraphElementIdMap(graph));
444 graphMLTextPane.setCaretPosition(Math.min(lastStartIndex, graphMLTextPane.getText().length()));
445 }finally {
446 setUpdating(false);
447 }
448 }
449 }
450
451
454 protected void applyGraphMLText(final Graph2D graph) {
455 if (graph != null) {
456
457 Graph2D testGraph = (Graph2D) graph.createGraph();
458 new HierarchyManager(testGraph);
459 try {
460 byte[] input = graphMLTextPane.getText().getBytes("UTF-8");
461
462 {
463 ByteArrayInputStream byteStream = new ByteArrayInputStream(input);
464 createGraphMLIOHandler().read(testGraph, byteStream);
465 }
466
467 {
469 setUpdating(true);
470 ByteArrayInputStream byteStream = new ByteArrayInputStream(input);
471 GraphMLIOHandler ioh = createGraphMLIOHandler();
472 ioh.read(graph, byteStream);
473
474 createGraphMLTextAndUpdateGraphElementIdMap(graph);
475
476 setUpdating(false);
477
478 }
479 } catch (Exception e) {
480 D.show(e);
481 }
482 finally {
483 graph.updateViews();
484 }
485 }
486 }
487
488 }
489 }
490