unikl.disco.calculator.gui.NetworkVisualizationPanel.java Source code

Java tutorial

Introduction

Here is the source code for unikl.disco.calculator.gui.NetworkVisualizationPanel.java

Source

/*
 *  (c) 2017 Michael A. Beck, Sebastian Henningsen
 *        disco | Distributed Computer Systems Lab
 *        University of Kaiserslautern, Germany
 *  All Rights Reserved.
 *
 * This software is work in progress and is released in the hope that it will
 * be useful to the scientific community. It is provided "as is" without
 * express or implied warranty, including but not limited to the correctness
 * of the code or its suitability for any particular purpose.
 *
 * This software is provided under the MIT License, however, we would 
 * appreciate it if you contacted the respective authors prior to commercial use.
 *
 * If you find our software useful, we would appreciate if you mentioned it
 * in any publication arising from the use of this software or acknowledge
 * our work otherwise. We would also like to hear of any fixes or useful
 */
package unikl.disco.calculator.gui;

import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.graph.util.Context;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.visualization.BasicVisualizationServer;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractModalGraphMouse;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import java.awt.Dimension;
import java.awt.ScrollPane;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.apache.commons.collections15.Transformer;
import unikl.disco.calculator.SNC;
import unikl.disco.calculator.network.Flow;
import unikl.disco.calculator.network.Network;
import unikl.disco.calculator.network.NetworkListener;
import unikl.disco.calculator.network.Vertex;

/**
 * A panel which uses a graph library to display a network.
 *
 * @author Sebastian Henningsen
 */
public class NetworkVisualizationPanel {

    //private final JScrollPane visualizationPanel;
    private GraphZoomScrollPane visualizationPanel;
    private Graph<GraphItem, GraphItem> graph;
    private Layout<GraphItem, GraphItem> layout;
    VisualizationViewer<GraphItem, GraphItem> bvs;
    private Dimension size;
    private List<GraphItem> vertices;
    private List<GraphItem> flows;
    private final double attractionMultiplier = 0.5;
    private final double repulsionMultiplier = 1;

    /**
     * Creates the panel.
     *
     * @param size
     */
    public NetworkVisualizationPanel(Dimension size) {
        vertices = new LinkedList<>();
        flows = new LinkedList<>();
        this.size = size;
        graph = new SparseMultigraph();

        layout = new FRLayout<>(graph);
        ((FRLayout) layout).setAttractionMultiplier(attractionMultiplier);
        ((FRLayout) layout).setRepulsionMultiplier(repulsionMultiplier);
        layout.setSize(size);
        bvs = new VisualizationViewer<>(layout);
        bvs.setPreferredSize(size);
        bvs.getRenderContext().setVertexLabelTransformer(new Transformer<GraphItem, String>() {
            @Override
            public String transform(GraphItem i) {
                return i.toString();
            }
        });
        bvs.getRenderContext().setEdgeLabelTransformer(new Transformer<GraphItem, String>() {
            @Override
            public String transform(GraphItem i) {
                return i.toString();
            }
        });
        bvs.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.CNTR);
        visualizationPanel = new GraphZoomScrollPane(bvs);
        visualizationPanel.setPreferredSize(size);

        final AbstractModalGraphMouse graphMouse = new DefaultModalGraphMouse();
        bvs.setGraphMouse(graphMouse);

        //visualizationPanel.add(bvs);
        SNC.getInstance().registerNetworkListener(new NetworkChangeListener());
    }

    /**
     * Returns the Panel on which everything is displayed.
     *
     * @return
     */
    public JPanel getPanel() {
        return visualizationPanel;
    }

    private class NetworkChangeListener implements NetworkListener {

        private void updateLayout() {
            bvs.getGraphLayout().setGraph(graph);
            //layout = new FRLayout<>(graph);
            //bvs.setGraphLayout(layout);
            bvs.repaint();
        }

        @Override
        public void vertexAdded(Vertex newVertex) {
            GraphItem gi = new GraphItem(newVertex.getID(), newVertex.getAlias());
            graph.addVertex(gi);
            vertices.add(gi);
            updateLayout();
        }

        @Override
        public void vertexRemoved(Vertex removedVertex) {
            GraphItem gi = new GraphItem(removedVertex.getID(), removedVertex.getAlias());
            vertices.remove(gi);
            graph.removeVertex(gi);
            // TODO: Handle flows. Is this already covered by flowChanged()?
            updateLayout();
        }

        @Override
        public void flowAdded(Flow newFlow) {
            List<Integer> route = newFlow.getVerticeIDs();
            Iterator<Integer> it = route.iterator();
            int oldId = it.next();
            if (route.size() > 1) {
                int newID = 0;
                int i = 0;
                while (it.hasNext()) {
                    newID = it.next();
                    System.out.println(oldId + " " + newID);
                    GraphItem gi = new GraphItem(newFlow.getID() + i, newFlow.getAlias());
                    flows.add(gi);
                    graph.addEdge(gi, getVertexbyID(oldId), getVertexbyID(newID), EdgeType.DIRECTED);
                    oldId = newID;
                    i++;
                }
            } else {
                GraphItem gi = new GraphItem(newFlow.getID(), newFlow.getAlias());
                flows.add(gi);
                graph.addEdge(gi, getVertexbyID(oldId), getVertexbyID(oldId), EdgeType.DIRECTED);
            }
            updateLayout();
        }

        @Override
        public void flowRemoved(Flow removedFlow) {
            List<Integer> route = removedFlow.getVerticeIDs();
            for (int i = 0; i < route.size(); i++) {
                GraphItem gi = getFlowbyID(removedFlow.getID() + i);
                graph.removeEdge(gi);
                flows.remove(gi);
            }
            updateLayout();

        }

        @Override
        public void flowChanged(Flow changedFlow) {
            // Only the route is relevant for us
            // Remove the old one and add new ones
            for (GraphItem gi : getFlowbyAlias(changedFlow.getAlias())) {
                graph.removeEdge(gi);
                flows.remove(gi);
            }
            flowAdded(changedFlow);

        }

        @Override
        public void vertexChanged(Vertex changedVertex) {
            // Ignore for now
        }

        @Override
        public void clear() {
            graph = new SparseMultigraph<>();
            updateLayout();
        }

        private GraphItem getVertexbyID(int id) {
            GraphItem result = null;
            for (GraphItem gi : vertices) {
                if (gi.getID() == id) {
                    result = gi;
                }
            }
            return result;
        }

        private GraphItem getFlowbyID(int id) {
            GraphItem result = null;
            for (GraphItem gi : flows) {
                if (gi.getID() == id) {
                    result = gi;
                }
            }
            return result;
        }

        private List<GraphItem> getFlowbyAlias(String alias) {
            List<GraphItem> result = new LinkedList<>();
            for (GraphItem gi : flows) {
                if (gi.getAlias().equals(alias)) {
                    result.add(gi);
                }
            }
            return result;
        }

    }
}

class GraphItem {

    private final int id;
    private final String alias;

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 79 * hash + this.id;
        hash = 79 * hash + Objects.hashCode(this.alias);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final GraphItem other = (GraphItem) obj;
        if (this.id != other.id) {
            return false;
        }
        if (!Objects.equals(this.alias, other.alias)) {
            return false;
        }
        return true;
    }

    public GraphItem(int id, String alias) {
        this.id = id;
        this.alias = alias;
    }

    @Override
    public String toString() {
        return alias;
    }

    public int getID() {
        return id;
    }

    public String getAlias() {
        return alias;
    }

}

/*class VisibilityPredicate<V extends GraphItem, E extends GraphItem> implements Predicate<Context<Graph<V, E>, V>> {
    
@Override
public boolean evaluate(Context<Graph<V, E>, V> context) {
    Graph<V, E> g = context.graph;
    V v = context.element;
    return v.isVisible();
}
}*/