Samples.Advanced.GraphEditorDemo.java Source code

Java tutorial

Introduction

Here is the source code for Samples.Advanced.GraphEditorDemo.java

Source

/*
 * Copyright (c) 2003, the JUNG Project and the Regents of the University of
 * California All rights reserved.
 * 
 * This software is open-source under the BSD license; see either "license.txt"
 * or http://jung.sourceforge.net/license.txt for a description.
 * 
 */
package Samples.Advanced;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;

import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.functors.MapTransformer;
import org.apache.commons.collections15.map.LazyMap;

import control.Vem;

import edu.uci.ics.jung.algorithms.layout.AbstractLayout;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.annotations.AnnotationControls;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.EditingModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

/**
 * Shows how  to create a graph editor with JUNG.
 * Mouse modes and actions are explained in the help text.
 * The application version of GraphEditorDemo provides a
 * File menu with an option to save the visible graph as
 * a jpeg file.
 * 
 * @author Tom Nelson
 * 
 */
public class GraphEditorDemo extends JApplet implements Printable, ClipboardOwner {

    /**
    * 
    */
    private static final long serialVersionUID = -2023243689258876709L;

    /**
      * the graph
      */
    static Graph<Number, Number> graph;

    AbstractLayout<Number, Number> layout;

    /**
     * the visual component and renderer for the graph
     */
    VisualizationViewer<Number, Number> vv;

    String instructions = "<html>" + "<h3>All Modes:</h3>" + "<ul>"
            + "<li>Right-click an empty area for <b>Create Vertex</b> popup"
            + "<li>Right-click on a Vertex for <b>Delete Vertex</b> popup"
            + "<li>Right-click on a Vertex for <b>Add Edge</b> menus <br>(if there are selected Vertices)"
            + "<li>Right-click on an Edge for <b>Delete Edge</b> popup"
            + "<li>Mousewheel scales with a crossover value of 1.0.<p>"
            + "     - scales the graph layout when the combined scale is greater than 1<p>"
            + "     - scales the graph view when the combined scale is less than 1" +

            "</ul>" + "<h3>Editing Mode:</h3>" + "<ul>" + "<li>Left-click an empty area to create a new Vertex"
            + "<li>Left-click on a Vertex and drag to another Vertex to create an Undirected Edge"
            + "<li>Shift+Left-click on a Vertex and drag to another Vertex to create a Directed Edge" + "</ul>"
            + "<h3>Picking Mode:</h3>" + "<ul>" + "<li>Mouse1 on a Vertex selects the vertex"
            + "<li>Mouse1 elsewhere unselects all Vertices"
            + "<li>Mouse1+Shift on a Vertex adds/removes Vertex selection"
            + "<li>Mouse1+drag on a Vertex moves all selected Vertices"
            + "<li>Mouse1+drag elsewhere selects Vertices in a region"
            + "<li>Mouse1+Shift+drag adds selection of Vertices in a new region"
            + "<li>Mouse1+CTRL on a Vertex selects the vertex and centers the display on it"
            + "<li>Mouse1 double-click on a vertex or edge allows you to edit the label" + "</ul>"
            + "<h3>Transforming Mode:</h3>" + "<ul>" + "<li>Mouse1+drag pans the graph"
            + "<li>Mouse1+Shift+drag rotates the graph" + "<li>Mouse1+CTRL(or Command)+drag shears the graph"
            + "<li>Mouse1 double-click on a vertex or edge allows you to edit the label" + "</ul>"
            + "<h3>Annotation Mode:</h3>" + "<ul>" + "<li>Mouse1 begins drawing of a Rectangle"
            + "<li>Mouse1+drag defines the Rectangle shape"
            + "<li>Mouse1 release adds the Rectangle as an annotation"
            + "<li>Mouse1+Shift begins drawing of an Ellipse" + "<li>Mouse1+Shift+drag defines the Ellipse shape"
            + "<li>Mouse1+Shift release adds the Ellipse as an annotation"
            + "<li>Mouse3 shows a popup to input text, which will become"
            + "<li>a text annotation on the graph at the mouse location" + "</ul>" + "</html>";

    /**
     * create an instance of a simple graph with popup controls to
     * create a graph.
     * 
     */
    public GraphEditorDemo() {

        // create a simple graph for the demo
        graph = new SparseMultigraph<Number, Number>();

        this.layout = new StaticLayout<Number, Number>(graph, new Dimension(600, 600));

        vv = new VisualizationViewer<Number, Number>(layout);
        vv.setBackground(Color.white);

        vv.getRenderContext().setVertexLabelTransformer(MapTransformer.<Number, String>getInstance(
                LazyMap.<Number, String>decorate(new HashMap<Number, String>(), new ToStringLabeller<Number>())));

        vv.getRenderContext().setEdgeLabelTransformer(MapTransformer.<Number, String>getInstance(
                LazyMap.<Number, String>decorate(new HashMap<Number, String>(), new ToStringLabeller<Number>())));

        vv.setVertexToolTipTransformer(vv.getRenderContext().getVertexLabelTransformer());

        Container content = getContentPane();
        final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
        content.add(panel);
        Factory<Number> vertexFactory = new VertexFactory();
        Factory<Number> edgeFactory = new EdgeFactory();

        final EditingModalGraphMouse<Number, Number> graphMouse = new EditingModalGraphMouse<Number, Number>(
                vv.getRenderContext(), vertexFactory, edgeFactory);

        // the EditingGraphMouse will pass mouse event coordinates to the
        // vertexLocations function to set the locations of the vertices as
        // they are created
        //        graphMouse.setVertexLocations(vertexLocations);
        vv.setGraphMouse(graphMouse);
        vv.addKeyListener(graphMouse.getModeKeyListener());

        graphMouse.setMode(ModalGraphMouse.Mode.EDITING);

        final ScalingControl scaler = new CrossoverScalingControl();
        JButton plus = new JButton("+");
        plus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1.1f, vv.getCenter());
            }
        });
        JButton minus = new JButton("-");
        minus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1 / 1.1f, vv.getCenter());
            }
        });

        JButton help = new JButton("Help");
        help.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(vv, instructions);
            }
        });

        AnnotationControls<Number, Number> annotationControls = new AnnotationControls<Number, Number>(
                graphMouse.getAnnotatingPlugin());
        JPanel controls = new JPanel();
        controls.add(plus);
        controls.add(minus);
        JComboBox modeBox = graphMouse.getModeComboBox();
        controls.add(modeBox);
        controls.add(annotationControls.getAnnotationsToolBar());
        controls.add(help);
        content.add(controls, BorderLayout.SOUTH);
    }

    /**
     * copy the visible part of the graph to a file as a jpeg image
     * @param file
     */
    public void writeJPEGImage(File file) {
        int width = vv.getWidth();
        int height = vv.getHeight();

        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = bi.createGraphics();
        vv.paint(graphics);
        graphics.dispose();

        try {
            ImageIO.write(bi, "jpeg", file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public int print(java.awt.Graphics graphics, java.awt.print.PageFormat pageFormat, int pageIndex)
            throws java.awt.print.PrinterException {
        if (pageIndex > 0) {
            return (Printable.NO_SUCH_PAGE);
        } else {
            java.awt.Graphics2D g2d = (java.awt.Graphics2D) graphics;
            vv.setDoubleBuffered(false);
            g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());

            vv.paint(g2d);
            vv.setDoubleBuffered(true);

            return (Printable.PAGE_EXISTS);
        }
    }

    class VertexFactory implements Factory<Number> {

        int i = 0;

        public Number create() {
            return i++;
        }
    }

    class EdgeFactory implements Factory<Number> {

        int i = 0;

        public Number create() {
            return i++;
        }
    }

    /**
     * a driver for this demo
     */
    @SuppressWarnings("serial")
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final GraphEditorDemo demo = new GraphEditorDemo();

        JMenu menu = new JMenu("File");
        menu.add(new AbstractAction("Make Image") {
            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser();
                int option = chooser.showSaveDialog(demo);
                if (option == JFileChooser.APPROVE_OPTION) {
                    File file = chooser.getSelectedFile();
                    demo.writeJPEGImage(file);
                }
            }
        });
        menu.add(new AbstractAction("Print") {
            public void actionPerformed(ActionEvent e) {
                PrinterJob printJob = PrinterJob.getPrinterJob();
                printJob.setPrintable(demo);
                if (printJob.printDialog()) {
                    try {
                        printJob.print();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });
        JPopupMenu.setDefaultLightWeightPopupEnabled(false);
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(menu);
        JMenu matrixMenu = new JMenu();
        matrixMenu.setText("Matrix");
        matrixMenu.setIcon(null);
        matrixMenu.setPreferredSize(new Dimension(80, 20));
        menuBar.add(matrixMenu);
        JMenuItem copyMatrix = new JMenuItem("Copy Matrix to clipboard", KeyEvent.VK_C);
        copyMatrix.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
        menuBar.add(copyMatrix);
        frame.setJMenuBar(menuBar);
        frame.getContentPane().add(demo);
        copyMatrix.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                Vem textTransfer = new Vem();

                //Set up Matrix
                List<Integer[]> graphMatrix = new ArrayList<Integer[]>();
                int MatrixSize = graph.getVertexCount();

                Integer[] activeV = new Integer[MatrixSize];
                int count = 0;
                int activeVPos = 0;

                while (activeVPos < MatrixSize) {
                    if (graph.containsVertex(count)) {
                        activeV[activeVPos] = count;
                        activeVPos++;
                    }
                    count++;
                }

                // sgv.g.getVertices().toArray()  ((Integer[])(sgv.g.getVertices().toArray()))
                for (int i = 0; i < MatrixSize; i++) {
                    Integer[] tempArray = new Integer[MatrixSize];
                    for (int j = 0; j < MatrixSize; j++) {
                        if (graph.findEdge(activeV[i], activeV[j]) != null) {
                            tempArray[j] = 1;
                        } else {
                            tempArray[j] = 0;
                        }
                    }
                    graphMatrix.add(tempArray);
                }
                //graphMatrix.add(new Integer[]{1, 2, 3});
                //graphMatrix.add(new Integer[]{4, 5 , 6, 7});

                //System.out.println(matrixToString(graphMatrix));
                //System.out.println(matrixToMathematica(graphMatrix));

                textTransfer.setClipboardContents("" + matrixToMathematica(graphMatrix));
                System.out.println("Clipboard contains:" + textTransfer.getClipboardContents());
            }
        });

        frame.pack();
        frame.setVisible(true);
    }

    @SuppressWarnings("unused")
    private static String matrixToString(List<Integer[]> graphMatrix) {
        String mString = "";
        for (int i = 0; i < graphMatrix.size(); i++) {
            for (int t = 0; t < graphMatrix.get(i).length; t++) {
                mString += (graphMatrix.get(i))[t] + " ";
            }
            mString += "\n";
        }
        return mString;
    }

    private static String matrixToMathematica(List<Integer[]> graphMatrix) {
        String mString = "MatrixForm[{";
        for (int i = 0; i < graphMatrix.size(); i++) {
            mString += "{";
            for (int t = 0; t < graphMatrix.get(i).length; t++) {
                if (t == graphMatrix.get(i).length - 1) {
                    mString += (graphMatrix.get(i))[t];
                } else {
                    mString += (graphMatrix.get(i))[t] + ",";
                }
            }
            if (i == graphMatrix.size() - 1) {
                mString += "}\n";
            } else {
                mString += "},\n";
            }

        }
        mString += "}]";
        return mString;
    }

    /**
      * Empty implementation of the ClipboardOwner interface.
      */
    public void lostOwnership(Clipboard aClipboard, Transferable aContents) {
        //do nothing
    }

    /**
    * Place a String on the clipboard, and make this class the
    * owner of the Clipboard's contents.
    */
    public void setClipboardContents(String aString) {
        StringSelection stringSelection = new StringSelection(aString);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(stringSelection, this);
    }

    /**
    * Get the String residing on the clipboard.
    *
    * @return any text found on the Clipboard; if none found, return an
    * empty String.
    */
    public String getClipboardContents() {
        String result = "";
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        //odd: the Object param of getContents is not currently used
        Transferable contents = clipboard.getContents(null);
        boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
        if (hasTransferableText) {
            try {
                result = (String) contents.getTransferData(DataFlavor.stringFlavor);
            } catch (UnsupportedFlavorException ex) {
                //highly unlikely since we are using a standard DataFlavor
                System.out.println(ex);
                ex.printStackTrace();
            } catch (IOException ex) {
                System.out.println(ex);
                ex.printStackTrace();
            }
        }
        return result;
    }
}