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