1 /***
2 * GraphView.java
3 *
4 * Project: Dependency Tool
5 *
6 * WHEN WHO WHAT
7 * 06.06.2003 pko initial public release
8 * 22.07.2002 ctr modification
9 * 18.04.2002 ctr modification
10 * 22.01.2002 ctr modification
11 * 08.01.2002 ctr creation
12 *
13 * Copyright 2003 ELCA Informatique SA
14 * Av. de la Harpe 22-24, 1000 Lausanne 13, Switzerland
15 * www.elca.ch
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public License
19 * as published by the Free Software Foundation; either version 2.1 of
20 * the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 * USA
31 */
32
33 package ch.elca.dependency.view;
34
35 import att.grappa.Edge;
36 import att.grappa.Element;
37 import att.grappa.Graph;
38 import att.grappa.Grappa;
39 import att.grappa.GrappaPoint;
40 import att.grappa.GrappaConstants;
41 import att.grappa.GrappaPanel;
42 import att.grappa.Node;
43 import ch.elca.dependency.adapter.grappa.GrappaSupport;
44 import ch.elca.dependency.core.DependencyContext;
45 import ch.elca.dependency.core.DependencyModel;
46 import ch.elca.dependency.graph.Perspective;
47 import ch.elca.dependency.gui.*;
48 import ch.elca.dependency.util.IOManager;
49 import ch.elca.dependency.util.IconGrabber;
50 import info.clearthought.layout.TableLayout;
51 import java.awt.*;
52 import java.awt.event.*;
53 import java.awt.event.InputEvent;
54 import java.io.File;
55 import java.io.FileOutputStream;
56 import java.net.URL;
57 import java.net.URLConnection;
58 import java.util.*;
59 import javax.swing.*;
60 import org.apache.log4j.Logger;
61 import sun.misc.BASE64Encoder;
62
63 /***
64 * This view is responsible for visualizing the graph representation of the
65 * analyzed data. A graph containing all the packages of the project as vertices
66 * and the dependencies of these packages as edges is displayed.
67 * The user can change the layout of this graph by dragging and dropping the
68 * vertices contained by the graph. The classes belonging to this
69 * <code>GraphView</code> class are reponsible that such changes can be
70 * performed properly.
71 *
72 * The display method of the <code>View</code> class is implemented here. It
73 * gets the needed data from the model and displays it in order to this view.
74 * For enabling this several listener classes are used.
75 *
76 * @see ch.elca.dependency.view.View
77 *
78 * @author Christoph Trutmann
79 * @author Pawel Kowalski
80 * @version 1.0-beta
81 */
82 public final class GraphView extends View implements GrappaConstants, ActionListener {
83
84 //****************************************************************************************/
85 // singleton part
86 //****************************************************************************************/
87
88 private static GraphView m_instance = null;
89
90 /***
91 * Returns the last created instance of the GraphView or null if
92 * none has been created yet.
93 *
94 * @return a <code>GraphView</code> value
95 */
96 public static GraphView singleton() {
97 return m_instance;
98 }
99
100 //****************************************************************************************/
101 // static fields
102 //****************************************************************************************/
103
104 /***
105 * Log4j Logger.
106 */
107 private final static Logger LOG = Logger.getLogger(GraphView.class);
108
109 /***
110 * Title used for this Frame.
111 */
112 private final static String FRAME_TITLE = "Graph View";
113
114 /***
115 * Zoomfactor for zooming in.
116 */
117 private final static double s_positiveZoomFact = 0.5d;
118
119 /***
120 * Zoomfactor for zooming out.
121 */
122 private final static double s_negativeZoomFact = (s_positiveZoomFact * 2) / 3;
123
124 /***
125 * Available formats for saving a graph. The current version of
126 * dot.exe can't save graphs as postscripts correctly, it only
127 * saves the firs page of a graph. Therefore the functionality to
128 * save the graph as ps has been abandoned.
129 */
130 // private static final String[] s_formats = new String[] { "dot", "gif", "jpg", "ps", "svg" };
131 private static final String[] s_formats = new String[] { "dot", "gif", "jpg", "svg" };
132
133 //****************************************************************************************/
134 // instance fields
135 //****************************************************************************************/
136
137 /***
138 * Instance of the <code>Graph</code> object to visualize.
139 */
140 private Graph m_graph = null;
141
142 /***
143 * Scrollpane wrapping the graph canvas.
144 */
145 private JScrollPane m_scrollPane = null;
146
147 /***
148 * Enables some features on the graph.
149 */
150 private MyGrappaAdapter m_adapter = null;
151
152 /***
153 * Pointer to the GrappaPanel.
154 */
155 private GrappaPanel m_gPanel = null;
156
157 /***
158 * Dialog for showing the dependency information on the edges.
159 */
160 private DependencyDetails m_depDetails = null;
161
162 /***
163 * Temporary list storing the current selection in the graph. This list is
164 * needed when the layout is changed by the user.
165 */
166 private ArrayList m_selectListTmp = new ArrayList();
167
168 /***
169 * Proxy used for layouting over the web.
170 */
171 private String m_proxy = null;
172
173 /***
174 * Os is windows?
175 */
176 private boolean m_noWin = false;
177
178 private Perspective m_perspective = Perspective.DEFAULT_PERSPECTIVE;
179
180 //****************************************************************************************/
181 // create a GraphView
182 //****************************************************************************************/
183
184 /***
185 * Creates a new <code>GraphView</code> instance.
186 *
187 * @param dependencyModel a <code>DependencyModel</code> value
188 */
189 public GraphView(DependencyModel dependencyModel) {
190 super(dependencyModel, FRAME_TITLE);
191 setDefaultBounds(new Rectangle(4, 3, 657, 553));
192 recallConfig();
193
194 m_instance = this;
195 }
196
197 protected void internalInitData() {
198
199 // get data from the dependency context
200 //
201 DependencyContext dependencyCtx = m_dependencyModel.getDependencyContext();
202 m_noWin = ((Boolean)dependencyCtx.get(DependencyContext.NOWIN_KEY)).booleanValue();
203 m_proxy = ((String)dependencyCtx.get(DependencyContext.PROXY_KEY));
204 }
205
206 protected void initView() {
207
208 // create the MenuBar
209 //
210 final JMenuBar menuBar = new JMenuBar();
211 setJMenuBar(menuBar);
212
213 // ============================= Zoom Menu BEGIN
214 //
215 JMenu zoomMenu = new JMenu("Zoom");
216 zoomMenu.setMnemonic(KeyEvent.VK_Z);
217 menuBar.add(zoomMenu);
218
219 // menu item for zoom in
220 //
221 JMenuItem zoomInItem = new JMenuItem(new ZoomInAction());
222 zoomMenu.add(zoomInItem);
223
224 // menu item for zoom out
225 //
226 JMenuItem zoomOutItem = new JMenuItem(new ZoomOutAction());
227 zoomMenu.add(zoomOutItem);
228
229 // menu item for rectangle zoom
230 //
231 JMenuItem zoomSweepItem = new JMenuItem(new RectangleZoomAction());
232 zoomMenu.add(zoomSweepItem);
233
234 // menu item for resetting zoom
235 //
236 JMenuItem zoomOutlineItem = new JMenuItem(new ResetZoomAction());
237 zoomOutlineItem.setMargin(new Insets(100, 116, 100, 100));
238 zoomMenu.add(zoomOutlineItem);
239 //
240 // ============================= Zoom Menu END
241
242 // ============================= Perspectives Menu BEGIN
243 //
244 JMenu perspectivesMenu = new JMenu("Perspectives");
245 perspectivesMenu.setMnemonic(KeyEvent.VK_P);
246 menuBar.add(perspectivesMenu);
247
248 // button group for the checkboxes
249 //
250 ButtonGroup perspectivesButtonGroup = new ButtonGroup();
251 JRadioButtonMenuItem perspectiveMenuItem = null;
252 Perspective[] perspectives = m_dependencyModel.getPerspectives();
253 for (int i = 0; i < perspectives.length; i++) {
254 perspectiveMenuItem = new JRadioButtonMenuItem(new PerspectiveAction(perspectives[i]));
255 perspectivesButtonGroup.add(perspectiveMenuItem);
256 perspectivesMenu.add(perspectiveMenuItem);
257
258 // select the default perspective which exists in any case
259 //
260 if (i == 0) {
261 perspectiveMenuItem.setSelected(true);
262 }
263 }
264 //
265 // ============================= Perspectives Menu END
266
267 // ============================= Output Menu BEGIN
268 //
269 JMenu outputMenu = new JMenu("Output");
270 outputMenu.setMnemonic(KeyEvent.VK_O);
271
272 JMenuItem saveAsFormatItem = null;
273 for (int i = 0; i < s_formats.length; i++) {
274 saveAsFormatItem = new JMenuItem(new SaveGraphAction(s_formats[i]));
275 outputMenu.add(saveAsFormatItem);
276 }
277
278 menuBar.add(outputMenu);
279 //
280 // ============================= Output Menu END
281
282 // configure TableLayout
283 //
284 double border = 10;
285 double fill = TableLayout.FILL;
286 double pref = TableLayout.PREFERRED;
287 double size[][] =
288 {{border, fill, border}, // Columns
289 {border, fill, border}}; // Rows
290
291
292 getContentPane().setLayout(new TableLayout(size));
293
294 // scroll pane with the graph
295 //
296 m_scrollPane = new JScrollPane();
297 m_scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
298
299 // add the scroll pane to the frame
300 //
301 getContentPane().add(m_scrollPane, "1, 1, F, F");
302
303 // set the parameters of the internal frame
304 //
305 setBackground(menuBar.getBackground());
306
307 Frame mainFrame = (Frame)m_dependencyModel.get(DependencyModel.MAIN_FRAME_KEY);
308 m_depDetails = new DependencyDialog(mainFrame, m_dependencyModel);
309
310 setVisible(true);
311 validate();
312 }
313
314 //****************************************************************************************/
315 // work with a GraphView
316 //****************************************************************************************/
317
318 /***
319 * Implementation of the abstract display method declared in
320 * the <code>View</code> class. Gets the changed data from the
321 * model and displays it.
322 *
323 * @tbd remove hack with background color
324 */
325 public void display() {
326
327 LOG.debug("Displaying GraphView");
328
329 super.setCursor(new Cursor(Cursor.WAIT_CURSOR));
330
331 // get the filtered model
332 //
333 if (m_perspective != null) {
334 m_graph = m_perspective.process(m_dependencyModel.getFilteredGraph());
335 } else {
336 m_graph = m_dependencyModel.getFilteredGraph();
337 }
338
339 // figure out to do this differently
340 //
341 m_graph.setGrappaAttribute(GRAPPA_BACKGROUND_COLOR_ATTR,"white");
342
343 // panel with the graph
344 //
345 m_gPanel = new GrappaPanel(m_graph);
346
347 // create and reference adapter add the listeners to the panel
348 //
349 m_adapter = new MyGrappaAdapter();
350 m_adapter.setZoomFactor(s_positiveZoomFact, s_negativeZoomFact);
351 m_adapter.reference(m_dependencyModel, m_depDetails);
352 m_gPanel.addGrappaListener(m_adapter);
353
354 // by default the tool tips are enabled
355 //
356 String tip = m_graph.getToolTipText();
357 if (tip == null) {
358 tip = Grappa.getToolTipText();
359 }
360 m_gPanel.setToolTipText(tip);
361
362 // viewport is the panel
363 //
364 m_scrollPane.setViewportView(m_gPanel);
365
366 // do layout with dot
367 //
368 if ( ! m_noWin ) {
369 doLayoutWithDot();
370 select(m_selectListTmp);
371 } else {
372 doLayoutOverWeb();
373 select(m_selectListTmp);
374 }
375
376 validate();
377 super.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
378 }
379
380 /***
381 * Selects all the packages in the specified list for all the views
382 * implementing the <code>Observer</code> interface.
383 *
384 * @param selectList List containing all the selected packages.
385 */
386 public void select(ArrayList selectList) {
387
388 if (LOG.isDebugEnabled()) {
389 StringBuffer buf = new StringBuffer();
390 for (Iterator iter = selectList.iterator(); iter.hasNext();) {
391 Object obj = iter.next();
392 buf.append(obj.getClass().getName() + ":" + obj.toString());
393 }
394 LOG.debug("Select called with: " + buf.toString());
395 }
396
397 // doesn't work either
398 //
399 // if (selectList.size() > 0) {
400 // for (Enumeration enum = m_graph.nodeElements(); enum.hasMoreElements(); ) {
401 // Node node = (Node)enum.nextElement();
402 // if (node.getName().indexOf(selectList.get(selectList.size()-1).toString()) != -1) {
403 // LOG.debug("grappa click simulation: " + node.getName());
404 // m_adapter.grappaClicked(m_graph, node, new GrappaPoint(),
405 // InputEvent.BUTTON1_MASK, 1, m_gPanel);
406 // break;
407 // }
408 // }
409 // }
410
411 // m_selectListTmp = selectList;
412 // for (Enumeration enum = m_graph.elements(); enum.hasMoreElements(); ) {
413 // Element elem = (att.grappa.Element)enum.nextElement();
414 // LOG.debug("unhighlighted element: " + elem.toString());
415 // GrappaSupport.setHighlight(elem, 0, HIGHLIGHT_OFF);
416 // }
417 // m_graph.getGraph().repaint();
418 // m_graph.repaint();
419 // m_gPanel.repaint();
420 // m_graph.currentSelection = null;
421
422 // clear the old selection
423 //
424 // Iterator lastIter = m_dependencyModel.getLastSelection().iterator();
425 // while ( lastIter.hasNext() ) {
426 // String tmp = (String)lastIter.next();
427 // Node nodeTmp = m_graph.findNodeByName(tmp);
428 // // clear selection of the node
429 // //
430 // if ( nodeTmp != null ) {
431 // GrappaSupport.setHighlight(nodeTmp, 0, HIGHLIGHT_OFF);
432 // // clear selection of all the outgoing edges
433 // //
434 // Enumeration outEnum = nodeTmp.outEdgeElements();
435 // while ( outEnum.hasMoreElements() ) {
436 // Edge edgeTmp = (Edge)outEnum.nextElement();
437 // if ( edgeTmp != null ) {
438 // GrappaSupport.setHighlight(edgeTmp, 0, HIGHLIGHT_OFF);
439 // }
440 // }
441 // }
442 // }
443
444 // add the new selection
445 //
446 // ListIterator selectIter = m_selectListTmp.listIterator();
447 // int count = 0;
448 // Vector sel = new Vector();
449 // Node nodeTmp = null;
450 // while (selectIter.hasNext() ) {
451 // count++;
452 // String name = (String)selectIter.next();
453 // nodeTmp = m_graph.findNodeByName(name);
454 // if ( nodeTmp != null ) {
455 // nodeTmp.highlight |= SELECTION_MASK;
456 // sel.add(nodeTmp);
457 // // select all the outgoing edges
458 // //
459 // Enumeration outEdgeEnum = nodeTmp.outEdgeElements();
460 // while ( outEdgeEnum.hasMoreElements() ) {
461 // Edge edgeTmp = (Edge)outEdgeEnum.nextElement();
462 // edgeTmp.highlight |= SELECTION_MASK;
463 // }
464 // }
465 // }
466 // if ( count == 1 ) {
467 // m_graph.currentSelection = nodeTmp;
468 // }
469 // else if ( count > 1 ) {
470 // m_graph.currentSelection = sel;
471 // }
472
473 m_graph.repaint();
474 m_scrollPane.repaint();
475 }
476
477 /***
478 * Clears all the selections in all the views.
479 */
480 public void clearSelection(){
481 m_selectListTmp.clear();
482 m_adapter.clearSelection(m_gPanel, m_graph);
483 }
484
485 /***
486 * Return the currently used Perspective.
487 *
488 * @return a <code>Perspective</code> value
489 */
490 public Perspective getCurrentPerspective() {
491 return m_perspective;
492 }
493
494 /***
495 * Set the Perspective to be used.
496 *
497 * @param perspective a <code>Perspective</code> value
498 */
499 private void setPerspective(Perspective perspective) {
500 m_perspective = perspective;
501 update(m_dependencyModel);
502 }
503
504 /***
505 * Uses the dot.exe local.
506 * @tbd error message in case the user chooses: nowindows, or if
507 * the dot layout doesn't work for some reason.
508 */
509 private void doLayoutWithDot() {
510 LOG.debug("Layouting graph with dot.exe");
511 String message = "";
512 String errorMessage = "dot.exe not available, could not layout graph!";
513 m_statusListenerSupport.postMessage("layouting graph...");
514
515 try {
516 Process connector = (Process)Runtime.getRuntime().exec(IOManager.getDotExe());
517 if( !GrappaSupport.filterGraph(m_graph, connector) ) {
518 LOG.error("Can't layout the graph with dot.exe!");
519 message = errorMessage;
520 }
521 m_graph.repaint();
522 } catch (Exception ex) {
523 ex.printStackTrace();
524 message = errorMessage;
525 }
526 m_statusListenerSupport.postMessage(message);
527 }
528
529 /***
530 * Layout provided from the at&t over the web.
531 */
532 private void doLayoutOverWeb() {
533 LOG.info("Start doing the graph layout over the web...");
534
535 m_statusListenerSupport.postMessage("layouting graph over web...");
536
537 String proxyMachineName = null, port = null, user = null,
538 password = null, auth = null;
539
540 if ( ! m_proxy.equals("") ) {
541 StringTokenizer tokenizer
542 = new StringTokenizer(m_proxy, ":,", false);
543
544 int i = 0;
545 while ( tokenizer.hasMoreTokens() ) {
546 String tmp = tokenizer.nextToken();
547
548 switch ( i ) {
549 // proxy machine name
550 case 0:
551 proxyMachineName = tmp;
552 break;
553 // port
554 case 1:
555 port = tmp;
556 break;
557 // user name
558 case 2:
559 user = tmp;
560 break;
561 // password
562 case 3:
563 password = tmp;
564 break;
565 }
566 i++;
567 }
568
569 // set system properties
570 //
571 System.getProperties().put("proxySet", "true");
572 System.getProperties().put("proxyHost", proxyMachineName);
573 System.getProperties().put("proxyPort", port);
574
575 if ( ! (user == null) && ! (password == null) ) {
576 String authStr = user.concat(":" + password);
577 auth = "Basic " + new BASE64Encoder().encode(authStr.getBytes());
578 }
579 }
580
581 Object connector = null;
582 try {
583 connector = (new URL("http://www.research.att.com/~john/cgi-bin/format-graph")).openConnection();
584 URLConnection urlConn = (URLConnection)connector;
585 urlConn.setDoInput(true);
586 urlConn.setDoOutput(true);
587 urlConn.setUseCaches(false);
588
589 // do the autorisaton for the proxy
590 //
591 if ( (! m_proxy.equals(""))
592 && (! (user == null) && ! (password == null)) ) {
593
594 urlConn.setRequestProperty("Proxy-Authorisation", auth);
595 }
596 urlConn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
597
598 } catch ( Exception ex ) {
599 System.err.println("Exception while setting up URLConnection: " + ex.getMessage() + "\nLayout not performed.");
600 connector = null;
601 }
602
603 String message = "";
604 String errorMessage = "could not layout the graph remotely!";
605 m_statusListenerSupport.postMessage("layouting graph...");
606
607 if ( connector != null ) {
608 if( ! GrappaSupport.filterGraph(m_graph, connector) ) {
609 LOG.error(errorMessage);
610 message = errorMessage;
611 }
612 connector = null;
613 }
614 m_graph = m_perspective.process(m_graph);
615 m_graph.repaint();
616
617 m_statusListenerSupport.postMessage(message);
618 }
619
620 /***
621 * Handles the action events generated from the menus.
622 *
623 * @param e Action event generated from a menu.
624 */
625 public void actionPerformed(ActionEvent e) {
626 }
627
628 //****************************************************************************************/
629 // Actions
630 //****************************************************************************************/
631
632 class ZoomInAction extends AbstractAction {
633 public ZoomInAction() {
634 super("Zoom In", IconGrabber.getIcon("zoomIn.gif"));
635 putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_MASK));
636 putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_I));
637 }
638 public void actionPerformed(ActionEvent event) {
639
640 LOG.debug("PRE ZoomInAction");
641
642 m_gPanel.multiplyScaleFactor(1d + s_positiveZoomFact);
643 m_gPanel.clearOutline();
644 m_gPanel.repaint();
645
646 LOG.debug("POST ZoomInAction");
647
648 }
649 }
650
651 class ZoomOutAction extends AbstractAction {
652 public ZoomOutAction() {
653 super("Zoom Out", IconGrabber.getIcon("zoomOut.gif"));
654 putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
655 putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
656 }
657 public void actionPerformed(ActionEvent event) {
658
659 LOG.debug("PRE ZoomOutAction");
660
661 m_gPanel.multiplyScaleFactor(1d - s_negativeZoomFact);
662 m_gPanel.clearOutline();
663 m_gPanel.repaint();
664
665 LOG.debug("POST ZoomOutAction");
666
667 }
668 }
669
670 class RectangleZoomAction extends AbstractAction {
671 public RectangleZoomAction() {
672 super("Zoom to sweep", IconGrabber.getIcon("zoom.gif"));
673 putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_E));
674 }
675 public void actionPerformed(ActionEvent event) {
676 m_gPanel.zoomToOutline();
677 m_gPanel.clearOutline();
678 }
679 }
680
681 class ResetZoomAction extends AbstractAction {
682 public ResetZoomAction() {
683 super("Reset Zoom", IconGrabber.getIcon("null.png"));
684 putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R));
685 }
686 public void actionPerformed(ActionEvent event) {
687 m_gPanel.resetZoom();
688 m_gPanel.clearOutline();
689 }
690 }
691
692 class PerspectiveAction extends AbstractAction {
693 private Perspective m_perspective = null;
694 public PerspectiveAction(Perspective perspective) {
695 super(perspective.getName(), IconGrabber.getIcon("perspective.gif"));
696 m_perspective = perspective;
697 }
698 public void actionPerformed(ActionEvent event) {
699 GraphView.this.setPerspective(m_perspective);
700 }
701 }
702
703 class SaveGraphAction extends AbstractAction {
704
705 private final JFileChooser m_fileChooser = new JFileChooser(".");
706 private final String m_dotSuffix = "dot";
707 private String m_formatSuffix = null;
708
709 public SaveGraphAction(String formatSuffix) {
710 super("Save Graph in " + formatSuffix + " format", IconGrabber.getIcon("save.gif"));
711 m_formatSuffix = formatSuffix;
712 m_fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
713 m_fileChooser.setFileFilter(MyFileFilter.getFileFilter(m_formatSuffix));
714 }
715
716 public void actionPerformed(ActionEvent event) {
717
718 File saveFile = null;
719 String fileName = null;
720 int dialogResult = 0;
721
722 // ask user for the file, where to save the graph
723 // if this file exists already, ask whether to overwrite.
724 //
725 while (true) {
726 dialogResult = m_fileChooser.showSaveDialog(GraphView.this);
727 if (dialogResult == JFileChooser.CANCEL_OPTION) {
728 return;
729 }
730 saveFile = m_fileChooser.getSelectedFile();
731 m_fileChooser.setCurrentDirectory(saveFile);
732
733 if ((saveFile.exists() && saveFile.getName().endsWith(m_formatSuffix))
734 || new File(saveFile.getAbsolutePath() + "." + m_formatSuffix).exists()) {
735 dialogResult = JOptionPane.showConfirmDialog(GraphView.this, "Overwrite existing file?");
736 if (dialogResult == JOptionPane.CANCEL_OPTION) {
737 return;
738 } else if (dialogResult == JOptionPane.YES_OPTION) {
739 break;
740 } else if (dialogResult == JOptionPane.NO_OPTION) {
741 continue;
742 }
743 } else {
744 break;
745 }
746 }
747
748 // append m_filesuffix if its not there already
749 //
750 fileName = saveFile.toString();
751 if (!fileName.endsWith("." + m_formatSuffix)) {
752 fileName = fileName + "." + m_formatSuffix;
753 }
754
755 try {
756 saveGraph(fileName);
757 LOG.info("Graph saved successfully: " + fileName);
758 } catch (Exception e) {
759 LOG.error("Could not save graph: " + e.getClass().getName() + ": " + e.getMessage());
760 }
761 }
762
763 private void saveGraph(String fileName) throws Exception {
764
765 String tempFile = null;
766
767 if (m_formatSuffix.equals(m_dotSuffix)) {
768 printGraph(fileName);
769 } else {
770 tempFile = printGraph(fileName + "." + m_dotSuffix);
771 reformatGraph(fileName, tempFile);
772 }
773 }
774
775 private void reformatGraph(String outputFile, final String dotFile) throws Exception {
776 String dotExePath = IOManager.getDotExe();
777 String commandString = dotExePath + " -T" + m_formatSuffix + " "
778 + "\"" + dotFile + "\"" + " -o " + "\"" + outputFile + "\"";
779
780 final Process reformatter = Runtime.getRuntime().exec(commandString);
781
782 // this Thread allows to delete a temporary file we don't need
783 // without making the gui wait for termination of the reformatter process
784 //
785 new Thread() {
786 public void run() {
787 try {
788 reformatter.waitFor();
789 new File(dotFile).delete();
790 } catch (InterruptedException e) {
791 LOG.error("Could not delete temporary File: " + dotFile);
792 }
793 }
794 }.start();
795 }
796
797 private String printGraph(String fileName) throws Exception {
798
799 File tempFile = new File(fileName);
800 if (tempFile.exists()) {
801 tempFile.delete();
802 }
803
804 FileOutputStream fos = new FileOutputStream(tempFile);
805 m_graph.printGraph(fos);
806 fos.close();
807 return fileName;
808 }
809 }
810 }
This page was automatically generated by Maven