de.tuilmenau.ics.fog.eclipse.GraphViewer.java Source code

Java tutorial

Introduction

Here is the source code for de.tuilmenau.ics.fog.eclipse.GraphViewer.java

Source

/*******************************************************************************
 * Forwarding on Gates Simulator/Emulator - Eclipse
 * Copyright (c) 2012, Integrated Communication Systems Group, TU Ilmenau.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 ******************************************************************************/
package de.tuilmenau.ics.fog.eclipse;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Image;
import java.awt.Menu;
import java.awt.MenuItem;
import java.awt.Paint;
import java.awt.PopupMenu;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.UIManager;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.plugin.AbstractUIPlugin;

import de.tuilmenau.ics.fog.IController;
import de.tuilmenau.ics.fog.eclipse.ui.Activator;
import de.tuilmenau.ics.fog.eclipse.utils.SWTAWTConverter;
import de.tuilmenau.ics.fog.routing.simulated.PartialRoutingService;
import de.tuilmenau.ics.fog.routing.simulated.RemoteRoutingService;
import de.tuilmenau.ics.fog.routing.simulated.RoutingServiceAddress;
import de.tuilmenau.ics.fog.topology.Breakable;
import de.tuilmenau.ics.fog.topology.Breakable.Status;
import de.tuilmenau.ics.fog.topology.Medium;
import de.tuilmenau.ics.fog.topology.Node;
import de.tuilmenau.ics.fog.transfer.DummyForwardingElement;
import de.tuilmenau.ics.fog.transfer.Gate;
import de.tuilmenau.ics.fog.transfer.forwardingNodes.GateContainer;
import de.tuilmenau.ics.fog.transfer.gates.AbstractGate;
import de.tuilmenau.ics.fog.transfer.manager.LowerLayerObserver;
import de.tuilmenau.ics.fog.ui.Decoration;
import de.tuilmenau.ics.fog.ui.Decorator;
import de.tuilmenau.ics.fog.ui.Logging;
import de.tuilmenau.ics.fog.ui.Marker;
import de.tuilmenau.ics.fog.ui.MarkerContainer;
import de.tuilmenau.ics.fog.ui.PacketLogger;
import de.tuilmenau.ics.graph.RoutableGraph;
import de.tuilmenau.ics.graph.Transformer;
import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.ObservableGraph;
import edu.uci.ics.jung.graph.event.GraphEvent;
import edu.uci.ics.jung.graph.event.GraphEventListener;
import edu.uci.ics.jung.graph.util.Context;
import edu.uci.ics.jung.graph.util.EdgeIndexFunction;
import edu.uci.ics.jung.visualization.renderers.DefaultEdgeLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.EdgeLabelRenderer;
import edu.uci.ics.jung.visualization.FourPassImageShaper;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.AbstractEdgeShapeTransformer;
import edu.uci.ics.jung.visualization.decorators.EdgeShape.IndexedRendering;
import edu.uci.ics.jung.visualization.renderers.BasicVertexLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.renderers.Renderer.VertexLabel.Position;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;

/**
 * Class for displaying a graph in an AWT window.
 * 
 * @param <NodeObject> Class for the vertice objects of the graph 
 * @param <LinkObject> Class for the edge objects of the graph
 */
public class GraphViewer<NodeObject, LinkObject> implements Observer, Runnable {
    // scaling factor for lines: useful for enlarging lines for presentations
    private final static float SCALE_FACTOR = 1.0f;

    private final static float VERTEX_STROKE_NORMAL = 1.0f * SCALE_FACTOR;
    private final static float VERTEX_STROKE_ADD_MAX_MSG = 4.0f;

    private final static float EDGE_STROKE_NORMAL = 1.0f * SCALE_FACTOR;
    private final static float EDGE_STROKE_LOGICAL = 0.5f * SCALE_FACTOR;
    private final static float EDGE_STROKE_GATE = 1.5f * SCALE_FACTOR;

    public static final int VERTEX_RECTANGLE_HEIGHT = 20;
    public static final int VERTEX_LABEL_CHAR_WIDTH = 7;
    public static final int VERTEX_LABEL_ADD_WIDTH = 10;

    /**
     * Font sizes for text; -1=default
     */
    public static final int VERTEX_FONT_SIZE = -1;
    public static final int EDGE_FONT_SIZE = -1;

    private final static int MAX_NUMBER_MSG_GATE = 1;
    private final static float EDGE_STROKE_GATE_ADD_MAX_MSG = 1.0f;

    private static Color DEFAULT_VERTEX_COLOR = new Color(0f, 0f, 0f, 0.5f);
    private static Color DEFAULT_EDGE_COLOR = Color.BLACK;
    private static Color ERROR_EDGE_COLOR = Color.ORANGE;

    private static Color MULTIPLE_MARKING_COLOR = Color.RED;

    public GraphViewer(IController pController) {
        mController = pController;
    }

    public Component getComponent() {
        return mViewer;
    }

    public void init(RoutableGraph<NodeObject, LinkObject> pGraph) {
        mViewUpdateRunning = false;

        createGraphView(pGraph.getGraphForGUI());
        createInteraction();

        pGraph.addObserver(this);
    }

    @Override
    public void update(Observable observable, Object parameter) {
        synchronized (this) {
            // if it is already running: do not proceed
            if (mViewUpdateRunning) {
                return;
            }

            mViewUpdateRunning = true;
        }

        if (EventQueue.isDispatchThread()) {
            run();
        } else {
            // switch to AWT event queue
            EventQueue.invokeLater(this);
        }
    }

    @Override
    public void run() {
        mViewer.updateUI();

        synchronized (this) {
            mViewUpdateRunning = false;
        }
    }

    /**
     * Calculated a load value [0, 1] for an element. According to this
     * value, the GUI can highlight the element.
     * 
     * @param obj Element to calculate the load for
     * @return load value [0, 1] OR negative if no load can be calculated
     */
    protected static float getLoadLevel(Object obj) {
        PacketLogger log = PacketLogger.getLogger(obj);
        if (log != null) {
            return ((float) log.size() / (float) log.getMaxSize());
        }

        if (obj instanceof Gate) {
            return Math.min(1.0f, (float) ((Gate) obj).getNumberMessages(false) / (float) MAX_NUMBER_MSG_GATE);
        }

        return -1;
    }

    public class BentLine<V, E> extends AbstractEdgeShapeTransformer<V, E> implements IndexedRendering<V, E> {
        /**
         * singleton instance of the BentLine shape
         */
        private GeneralPath instance = new GeneralPath();

        protected EdgeIndexFunction<V, E> parallelEdgeIndexFunction;

        public void setEdgeIndexFunction(EdgeIndexFunction<V, E> parallelEdgeIndexFunction) {
            this.parallelEdgeIndexFunction = parallelEdgeIndexFunction;
            //      loop.setEdgeIndexFunction(parallelEdgeIndexFunction);
        }

        /**
         * @return the parallelEdgeIndexFunction
         */
        public EdgeIndexFunction<V, E> getEdgeIndexFunction() {
            return parallelEdgeIndexFunction;
        }

        /**
         * Get the shape for this edge, returning either the
         * shared instance or, in the case of self-loop edges, the
         * Loop shared instance.
         */
        public Shape transform(Context<Graph<V, E>, E> context) {
            E e = context.element;

            instance.reset();
            instance.moveTo(0.0f, 0.0f);

            if (e instanceof LowerLayerObserver) {
                LowerLayerObserver ni = (LowerLayerObserver) e;

                PacketLogger log = PacketLogger.getLogger(ni.getBus());

                if (log != null) {
                    int parts = log.size() + 1;
                    float dist = 1.0f / (float) parts;

                    for (int i = 0; i < parts; i++) {
                        instance.lineTo(i * dist, 0.0f);
                        instance.lineTo(i * dist, 1.0f);
                        instance.lineTo(i * dist, -1.0f);
                        instance.moveTo(i * dist, 0.0f);
                    }
                }
            }

            instance.lineTo(1.0f, 0.0f);

            return instance;
        }
    }

    public class vertexLabelRenderer extends BasicVertexLabelRenderer<NodeObject, LinkObject> {

        // the space between vertex shape and label
        final double tLabelOffset = 10;

        final Color labelBackgroundColor = new Color(255, 255, 128);

        public Component prepareRenderer(RenderContext<NodeObject, LinkObject> pRc,
                EdgeLabelRenderer pGraphLabelRenderer, Object pValue, boolean pIsSelected, NodeObject pNode) {
            return pRc.getVertexLabelRenderer().<NodeObject>getVertexLabelRendererComponent(pRc.getScreenDevice(),
                    pValue, pRc.getVertexFontTransformer().transform(pNode), pIsSelected, pNode);
        }

        public void labelVertex(RenderContext<NodeObject, LinkObject> pRc, Layout<NodeObject, LinkObject> pLayout,
                NodeObject pNode, String pLabel) {
            GraphicsDecorator tGraphicsDecorator = pRc.getGraphicsContext();
            Shape tShape = pRc.getVertexShapeTransformer().transform(pNode);
            Point2D tNodePos = pLayout.transform(pNode);
            tNodePos = pRc.getMultiLayerTransformer().transform(Layer.LAYOUT, tNodePos);

            // does the node itself contain decoration information?
            if (pNode instanceof Decorator) {
                String tAddLabel = ((Decorator) pNode).getText();
                if (tAddLabel != null) {
                    pLabel += " " + tAddLabel;
                }
            }

            // is there a decoration container with some additional information?
            if (mDecoration != null) {
                Decorator tDec = mDecoration.getDecorator(pNode);
                if (tDec != null) {
                    String tAddLabel = tDec.getText();
                    if (tAddLabel != null) {
                        pLabel += " " + tAddLabel;
                    }
                }
            }

            Component tComponent = prepareRenderer(pRc, pRc.getEdgeLabelRenderer(), (Object) pLabel,
                    pRc.getPickedVertexState().isPicked(pNode), pNode);

            Dimension tDimension = tComponent.getPreferredSize();
            tDimension.width += VERTEX_LABEL_ADD_WIDTH;

            int tPosX = (int) (tNodePos.getX() - (tDimension.width - VERTEX_LABEL_ADD_WIDTH) / 2);
            int tPosY = (int) (tNodePos.getY() - tDimension.height / 2);

            Rectangle tShapeBound = tShape.getBounds();
            if (tShapeBound.getHeight() != VERTEX_RECTANGLE_HEIGHT) {
                tPosY += tLabelOffset + tShapeBound.getHeight() / 2;

                //picture for hosts is special -> use an additional offset
                if (pNode instanceof Node)
                    tPosX += 4;
            }

            // finally draw the label component
            tGraphicsDecorator.draw(tComponent, pRc.getRendererPane(), tPosX, tPosY, tDimension.width,
                    tDimension.height, true);
        }
    }

    private Image loadImageFor(Object pObj) {
        if (pObj instanceof DummyForwardingElement) {
            pObj = ((DummyForwardingElement) pObj).getObject();
        }

        String imageName = pObj.getClass().getCanonicalName() + ".gif";

        // is there a different name given by a decorator?
        if (pObj instanceof Decorator) {
            String decorationImageName = ((Decorator) pObj).getImageName();
            if (decorationImageName != null)
                imageName = decorationImageName;
        } else {
            if (mDecoration != null) {
                Decorator decorator = mDecoration.getDecorator(pObj);
                if (decorator != null) {
                    String decorationImageName = decorator.getImageName();
                    if (decorationImageName != null) {
                        imageName = decorationImageName;
                    }
                }
            }
        }

        return loadImage(imageName);
    }

    private Image loadImage(String pFile) {
        BufferedImage tImage = mIcons.get(pFile);
        if (tImage == null) {
            if (!mIcons.containsKey(pFile)) {
                ImageDescriptor tImageDescr = AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID,
                        "icons/" + pFile);

                if (tImageDescr != null) {
                    tImage = SWTAWTConverter.convertToAWT(tImageDescr.getImageData());
                }

                // if tImage is null, store the null pointer
                // to indicate that there is no image available
                mIcons.put(pFile, tImage);
            }
            // else: already tried, but stored null pointer
        }

        return tImage;
    }

    private Icon loadIconFor(Object pObj) {
        try {
            Image tImage = loadImageFor(pObj);
            if (tImage != null) {
                return new ImageIcon(tImage);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Creates the objects needed for the view. Most of them bases on the
     * JUNG lib.
     * 
     * @param pX Width of the window
     * @param pY Hight of the window
     * @param pGraph Graph, which should be displayed
     */
    private void createGraphView(Graph<NodeObject, LinkObject> pGraph) {
        ObservableGraph<NodeObject, LinkObject> tObsGraph = new ObservableGraph<NodeObject, LinkObject>(pGraph);

        tObsGraph.addGraphEventListener(new GraphEventListener<NodeObject, LinkObject>() {
            public void handleGraphEvent(GraphEvent<NodeObject, LinkObject> pEvent) {
                updateVisualization();
            }
        });

        // create layout
        mLayout = new edu.uci.ics.jung.algorithms.layout.FRLayout2<NodeObject, LinkObject>(tObsGraph);

        Shell activeShell = Display.getDefault().getActiveShell();
        org.eclipse.swt.graphics.Rectangle tRectangle;
        if (activeShell != null) {
            tRectangle = activeShell.getBounds();
        } else {
            tRectangle = new org.eclipse.swt.graphics.Rectangle(0, 0, 300, 300);
        }

        double tWidth = tRectangle.width * 0.4;
        double tHeight = tRectangle.height * 0.4;
        Logging.log(this, "Old size was " + tRectangle.width + "x" + tRectangle.height + " while new size will be "
                + tWidth + "x" + tHeight);

        mLayout.setSize(new Dimension((int) tWidth, (int) tHeight));

        // create viewer
        mViewer = new VisualizationViewer<NodeObject, LinkObject>(mLayout);
        mViewer.setDoubleBuffered(true);
        mViewer.setPreferredSize(new Dimension(400, 400));

        // setting up view of graph itself
        // Setup up a new vertex to paint transformer...
        Transformer<NodeObject, Paint> vertexPaint = new Transformer<NodeObject, Paint>() {
            private final Color colorBlue = new Color(.1f, .3f, 1f);
            private final Color colorYellow = new Color(1f, 1f, .3f);
            private final Color colorGreen = new Color(.1f, .9f, .3f);

            public Paint transform(Object i) {
                if (i instanceof DummyForwardingElement) {
                    i = ((DummyForwardingElement) i).getObject();
                }

                if (i instanceof AbstractGate)
                    return Color.LIGHT_GRAY;
                if (i instanceof GateContainer)
                    return colorGreen;
                if (i instanceof Medium)
                    return colorYellow;

                if (i instanceof PartialRoutingService)
                    return Color.ORANGE;
                if (i instanceof RemoteRoutingService)
                    return colorBlue;
                if (i instanceof RoutingServiceAddress)
                    return colorBlue;

                // does the object define its color by itself?
                if (i instanceof Decorator) {
                    Color decColor = ((Decorator) i).getColor();
                    if (decColor != null) {
                        return decColor;
                    }
                }

                // is there an external decorator for the object?
                if (mDecoration != null) {
                    Decorator decorator = mDecoration.getDecorator(i);
                    if (decorator != null) {
                        Color decColor = decorator.getColor();
                        if (decColor != null) {
                            return decColor;
                        }
                    }
                }

                return Color.WHITE;
            }
        };

        Transformer<NodeObject, Shape> vertexShapeTransformer = new Transformer<NodeObject, Shape>() {
            public Shape transform(NodeObject pObj) {
                Image tImage = loadImageFor(pObj);
                if (tImage != null) {
                    Shape tShape = FourPassImageShaper.getShape(tImage);
                    if (tShape.getBounds().getWidth() > 0 && tShape.getBounds().getHeight() > 0) {
                        AffineTransform transform = AffineTransform.getTranslateInstance(-tImage.getWidth(null) / 2,
                                -tImage.getHeight(null) / 2);
                        tShape = transform.createTransformedShape(tShape);
                        return tShape;
                    }
                }

                String tLabel = mViewer.getRenderContext().getVertexLabelTransformer().transform(pObj);
                return new Rectangle(-(tLabel.length() * VERTEX_LABEL_CHAR_WIDTH + VERTEX_LABEL_ADD_WIDTH) / 2,
                        -VERTEX_RECTANGLE_HEIGHT / 2,
                        tLabel.length() * VERTEX_LABEL_CHAR_WIDTH + VERTEX_LABEL_ADD_WIDTH,
                        VERTEX_RECTANGLE_HEIGHT);
            }
        };

        Transformer<NodeObject, Icon> vertexIconTransformer = new Transformer<NodeObject, Icon>() {
            public Icon transform(NodeObject pObj) {
                return loadIconFor(pObj);
            }
        };

        // Set up a new stroke Transformer for the edges
        Transformer<NodeObject, Stroke> vertexStrokeTransformer = new Transformer<NodeObject, Stroke>() {
            private final Stroke normalEdgeStroke = new BasicStroke(VERTEX_STROKE_NORMAL);

            public Stroke transform(Object pVertex) {
                float loadLevel = getLoadLevel(pVertex);

                if (loadLevel > 0) {
                    return new BasicStroke(VERTEX_STROKE_NORMAL + VERTEX_STROKE_ADD_MAX_MSG * loadLevel);
                } else {
                    return normalEdgeStroke;
                }
            }
        };

        Transformer<NodeObject, Paint> vertexDraw = new Transformer<NodeObject, Paint>() {
            public Paint transform(Object pVertex) {
                Boolean tBroken = false;
                if (pVertex instanceof Breakable) {
                    try {
                        tBroken = ((Breakable) pVertex).isBroken() != Status.OK;
                    } catch (RemoteException exc) {
                        tBroken = true;
                    }
                }

                if (tBroken) {
                    return Color.RED;
                } else {
                    Marker[] tMarkers = MarkerContainer.getInstance().get(pVertex);

                    if (tMarkers.length > 0) {
                        if (tMarkers.length > 1) {
                            return MULTIPLE_MARKING_COLOR;
                        } else {
                            return tMarkers[0].getColor();
                        }
                    } else {
                        return DEFAULT_VERTEX_COLOR;
                    }
                }
            }
        };

        Transformer<LinkObject, Paint> edgeDraw = new Transformer<LinkObject, Paint>() {
            @Override
            public Paint transform(LinkObject pLink) {
                Marker[] tMarkers = MarkerContainer.getInstance().get(pLink);

                if (tMarkers.length > 0) {
                    if (tMarkers.length > 1) {
                        return MULTIPLE_MARKING_COLOR;
                    } else {
                        return tMarkers[0].getColor();
                    }
                } else {
                    if (pLink instanceof Gate) {
                        if (!((Gate) pLink).isReadyToReceive()) {
                            return ERROR_EDGE_COLOR;
                        }
                    }

                    return DEFAULT_EDGE_COLOR;
                }
            }

        };

        Transformer<NodeObject, String> vertexLabeller = new Transformer<NodeObject, String>() {
            public String transform(Object s) {
                String tName = s.toString();
                if (s instanceof RemoteRoutingService) {
                    try {
                        tName = ((RemoteRoutingService) s).getName();
                    } catch (RemoteException e) {
                        // ignore it; we will stick to the previous tName
                    }
                }

                return tName;
            }
        };

        // Set up a new stroke Transformer for the edges
        Transformer<LinkObject, Stroke> edgeStrokeTransformer = new Transformer<LinkObject, Stroke>() {
            private final Stroke normalEdgeStroke = new BasicStroke(EDGE_STROKE_NORMAL);
            private final Stroke logicalEdgeStroke = new BasicStroke(EDGE_STROKE_LOGICAL, BasicStroke.CAP_BUTT,
                    BasicStroke.JOIN_MITER, 10.0f, new float[] { 10.0f }, 0.0f);
            private final Stroke gateEdgeStroke = new BasicStroke(EDGE_STROKE_GATE);

            public Stroke transform(Object s) {
                float loadLevel = getLoadLevel(s);

                if (loadLevel > 0) {
                    return new BasicStroke(EDGE_STROKE_GATE + EDGE_STROKE_GATE_ADD_MAX_MSG * loadLevel);
                } else if (s instanceof Gate) {
                    return gateEdgeStroke;
                } else if (s.toString().regionMatches(0, "routing for", 0, "routing for".length())) {
                    return logicalEdgeStroke;
                }

                return normalEdgeStroke;
            }
        };

        Transformer<LinkObject, String> edgeLabeller = new Transformer<LinkObject, String>() {
            public String transform(Object edge) {
                if (edge == null)
                    return "null";

                // use StringBuilder in order to boost performance of string creation
                StringBuilder tName = null;

                if (edge instanceof Gate) {
                    tName = new StringBuilder();
                    if (((Gate) edge).getGateID() != null) {
                        tName.append(((Gate) edge).getGateID());
                        tName.append(" ");
                    }
                    tName.append(edge.getClass().getSimpleName());
                    tName.append(" (");
                    tName.append(((Gate) edge).getNumberMessages(false));
                    tName.append(")");
                } else if (edge instanceof LowerLayerObserver) {
                    return "LL_" + ((LowerLayerObserver) edge).getAttachmentName();
                }

                if (tName == null)
                    return edge.toString();
                else
                    return tName.toString();
            }
        };

        EdgeLabelRenderer edgeLabelRenderer = new DefaultEdgeLabelRenderer(Color.BLACK) {
            private final Color colorBg = (Color) UIManager.getDefaults().get("Panel.background");
            private final Color colorEdgeBackground = new Color(colorBg.getRed(), colorBg.getGreen(),
                    colorBg.getBlue(), 128);

            @Override
            public <T> Component getEdgeLabelRendererComponent(JComponent arg0, Object arg1, Font arg2,
                    boolean arg3, T arg4) {
                Component tRes = super.getEdgeLabelRendererComponent(arg0, arg1, arg2, arg3, arg4);
                tRes.setBackground(colorEdgeBackground);
                return tRes;
            }
        };

        Transformer<LinkObject, Font> edgeFontTransformer = new Transformer<LinkObject, Font>() {
            public Font transform(LinkObject edge) {
                if (edge == null)
                    return null;

                return edgeFont;
            }

            private Font edgeFont = new Font("SansSerif", Font.PLAIN, EDGE_FONT_SIZE);
        };

        Transformer<NodeObject, Font> vertexFontTransformer = new Transformer<NodeObject, Font>() {
            public Font transform(NodeObject vertex) {
                if (vertex == null)
                    return null;

                return vertexFont;
            }

            private Font vertexFont = new Font("SansSerif", Font.PLAIN, VERTEX_FONT_SIZE);
        };

        mViewer.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
        mViewer.getRenderContext().setVertexDrawPaintTransformer(vertexDraw);
        mViewer.getRenderContext().setVertexStrokeTransformer(vertexStrokeTransformer);
        mViewer.getRenderContext().setVertexShapeTransformer(vertexShapeTransformer);
        mViewer.getRenderContext().setVertexIconTransformer(vertexIconTransformer);
        mViewer.getRenderer().setVertexLabelRenderer(new vertexLabelRenderer());
        mViewer.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.S);
        //      mViewer.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<NodeObject>());
        mViewer.getRenderContext().setVertexLabelTransformer(vertexLabeller);
        mViewer.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
        if (VERTEX_FONT_SIZE > 0) {
            mViewer.getRenderContext().setVertexFontTransformer(vertexFontTransformer);
        }

        //        mViewer.getRenderContext().setEdgeShapeTransformer(new BentLine<NodeObject,LinkObject>());
        mViewer.getRenderContext().setEdgeStrokeTransformer(edgeStrokeTransformer);
        mViewer.getRenderContext().setEdgeDrawPaintTransformer(edgeDraw);
        mViewer.getRenderContext().setArrowDrawPaintTransformer(edgeDraw);
        mViewer.getRenderContext().setArrowFillPaintTransformer(edgeDraw);
        mViewer.getRenderContext().setEdgeLabelTransformer(edgeLabeller);
        mViewer.getRenderContext().setEdgeLabelRenderer(edgeLabelRenderer);
        if (EDGE_FONT_SIZE > 0) {
            mViewer.getRenderContext().setEdgeFontTransformer(edgeFontTransformer);
        }
    }

    /**
     * Creating the objects reacting to user input.
     * In special, the handling of the mouse click events are defined here. 
     */
    private void createInteraction() {
        // Create a graph mouse and add it to the visualization component
        mMouse = new DefaultModalGraphMouse() {
            @Override
            public void mousePressed(MouseEvent pEvent) {
                super.mousePressed(pEvent);

                if (pEvent.isPopupTrigger()) {
                    Object pSelection = getSelection(pEvent);
                    PopupMenu popup = new PopupMenu();
                    mController.fillContextMenu(pSelection, popup);

                    fillStdPopup(popup);

                    // should the popup be displayed?
                    if (popup.getItemCount() > 0) {
                        if (popup.getParent() == null) {
                            pEvent.getComponent().add(popup);
                        }

                        popup.show(pEvent.getComponent(), pEvent.getX(), pEvent.getY());
                    }
                }
            }

            @Override
            public void mouseReleased(MouseEvent pEvent) {
                super.mouseReleased(pEvent);

                if (pEvent.isPopupTrigger()) {
                    Object pSelection = getSelection(pEvent);
                    PopupMenu popup = new PopupMenu();

                    mController.fillContextMenu(pSelection, popup);

                    fillStdPopup(popup);

                    // should the popup be displayed?
                    if (popup.getItemCount() > 0) {
                        if (popup.getParent() == null) {
                            pEvent.getComponent().add(popup);
                        }

                        popup.show(pEvent.getComponent(), pEvent.getX(), pEvent.getY());
                    }
                }
            }

            @Override
            public void mouseClicked(MouseEvent pEvent) {
                super.mouseClicked(pEvent);

                mController.selected(getSelection(pEvent), (pEvent.getButton() == MouseEvent.BUTTON1),
                        pEvent.getClickCount());
            }

            private Object getSelection(MouseEvent pEvent) {
                // try to get selected node or link
                GraphElementAccessor<NodeObject, LinkObject> tAccessor = mViewer.getPickSupport();
                Object tSelection = tAccessor.getVertex(mLayout, pEvent.getX(), pEvent.getY());

                if (tSelection == null) {
                    tSelection = tAccessor.getEdge(mLayout, pEvent.getX(), pEvent.getY());
                }

                if (tSelection instanceof DummyForwardingElement) {
                    tSelection = ((DummyForwardingElement) tSelection).getObject();
                }

                return tSelection;
            }
        };

        mMouse.setMode(ModalGraphMouse.Mode.PICKING);

        mViewer.setGraphMouse(mMouse);
    }

    private void fillStdPopup(PopupMenu popup) {
        MenuItem mi;

        // if already some items listed, separate them from the default 
        if (popup.getItemCount() > 0) {
            popup.addSeparator();
        }

        mi = new MenuItem("Picking");
        mi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                if (mMouse != null)
                    mMouse.setMode(ModalGraphMouse.Mode.PICKING);
            }
        });
        popup.add(mi);

        mi = new MenuItem("Transforming");
        mi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (mMouse != null)
                    mMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
            }
        });
        popup.add(mi);

        //
        // Add decorator selection menu
        //
        Menu decMenu = new Menu("Decoration types");
        popup.add(decMenu);

        mi = new MenuItem("None");
        mi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                mDecoration = null;
                update(null, null);
            }
        });
        decMenu.add(mi);

        Set<String> decorationTypes = Decoration.getTypes();
        for (String decType : decorationTypes) {
            mi = new MenuItem(decType);
            mi.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String decType = e.getActionCommand();
                    mDecoration = Decoration.getInstance(decType);
                    update(null, null);
                }
            });
            decMenu.add(mi);
        }
    }

    /**
     * Will be called by event, if graph changes
     */
    private void updateVisualization() {
        if ((mViewer != null) && (mLayout != null)) {
            if (mViewer.getModel().getRelaxer() != null)
                mViewer.getModel().getRelaxer().pause();
            mLayout.initialize();
            if (mViewer.getModel().getRelaxer() != null)
                mViewer.getModel().getRelaxer().resume();
            mViewer.repaint();
        }
    }

    private Layout<NodeObject, LinkObject> mLayout;
    private VisualizationViewer<NodeObject, LinkObject> mViewer;
    private boolean mViewUpdateRunning = false;
    private IController mController;
    private Decoration mDecoration = null;
    private DefaultModalGraphMouse mMouse;
    private HashMap<String, BufferedImage> mIcons = new HashMap<String, BufferedImage>();
}