jgraphmodeladapter.java

来自「JAVA图论的算法包。用过觉得还不错」· Java 代码 · 共 1,149 行 · 第 1/3 页

JAVA
1,149
字号
/* ==========================================
 * JGraphT : a free Java graph-theory library
 * ==========================================
 *
 * Project Info:  http://jgrapht.sourceforge.net/
 * Project Creator:  Barak Naveh (http://sourceforge.net/users/barak_naveh)
 *
 * (C) Copyright 2003-2007, by Barak Naveh and Contributors.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */
/* -----------------------
 * JGraphModelAdapter.java
 * -----------------------
 * (C) Copyright 2003-2007, by Barak Naveh and Contributors.
 *
 * Original Author:  Barak Naveh
 * Contributor(s):   Erik Postma
 *
 * $Id: JGraphModelAdapter.java 586 2008-01-27 23:30:50Z perfecthash $
 *
 * Changes
 * -------
 * 02-Aug-2003 : Initial revision (BN);
 * 10-Aug-2003 : Adaptation to new event model (BN);
 * 06-Nov-2003 : Allowed non-listenable underlying JGraphT graph (BN);
 * 12-Dec-2003 : Added CellFactory support (BN);
 * 27-Jan-2004 : Added support for JGraph->JGraphT change propagation (EP);
 * 29-Jan-2005 : Added support for JGraph dangling edges (BN);
 * 07-May-2006 : Changed from List<Edge> to Set<Edge> (JVS);
 * 28-May-2006 : Moved connectivity info from edge to graph (JVS);
 *
 */
package org.jgrapht.ext;

import java.awt.Color;
import java.awt.Font;
import java.awt.geom.*;

import java.io.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.*;

import org.jgraph.event.*;
import org.jgraph.event.GraphModelEvent.*;
import org.jgraph.graph.*;

import org.jgrapht.*;
import org.jgrapht.event.*;


/**
 * An adapter that reflects a JGraphT graph as a JGraph graph. This adapter is
 * useful when using JGraph in order to visualize JGraphT graphs. For more about
 * JGraph see <a href="http://jgraph.sourceforge.net">
 * http://jgraph.sourceforge.net</a>
 *
 * <p>Modifications made to the underlying JGraphT graph are reflected to this
 * JGraph model if and only if the underlying JGraphT graph is a {@link
 * org.jgrapht.ListenableGraph}. If the underlying JGraphT graph is <i>not</i>
 * ListenableGraph, then this JGraph model represent a snapshot if the graph at
 * the time of its creation.</p>
 *
 * <p>Changes made to this JGraph model are also reflected back to the
 * underlying JGraphT graph. To avoid confusion, variables are prefixed
 * according to the JGraph/JGraphT object(s) they are referring to.</p>
 *
 * <p><b>KNOWN BUGS:</b> There is a small issue to be aware of. JGraph allows
 * 'dangling edges' incident with just one vertex; JGraphT doesn't. Such a
 * configuration can arise when adding an edge or removing a vertex. The code
 * handles this by removing the newly-added dangling edge or removing all edges
 * incident with the vertex before actually removing the vertex, respectively.
 * This works very well, only it doesn't play all that nicely with the
 * undo-manager in the JGraph: for the second situation where you remove a
 * vertex incident with some edges, if you undo the removal, the vertex is
 * 'unremoved' but the edges aren't.</p>
 *
 * @author Barak Naveh
 * @since Aug 2, 2003
 */

/*
 * FUTURE WORK: Now that the adapter supports JGraph dangling edges, it is
 * possible, with a little effort, to eliminate the "known bugs" above. Some
 * todo and fixme marks in the code indicate where the possible improvements
 * could be made to realize that.
 */
public class JGraphModelAdapter<V, E>
    extends DefaultGraphModel
{
    //~ Static fields/initializers ---------------------------------------------

    private static final long serialVersionUID = 3256722883706302515L;

    //~ Instance fields --------------------------------------------------------

    /**
     * The following (jCells|jtElement)Being(Added|Removed) sets are used to
     * prevent bouncing of events between the JGraph and JGraphT listeners. They
     * ensure that their respective add/remove operations are done exactly once.
     * Here is an example of how jCellsBeingAdded is used when an edge is added
     * to a JGraph graph:
     *
     * <pre>
        1. First, we add the desired edge to jCellsBeingAdded to indicate
        that the edge is being inserted internally.
        2.    Then we invoke the JGraph 'insert' operation.
        3.    The JGraph listener will detect the newly inserted edge.
        4.    It checks if the edge is contained in jCellsBeingAdded.
        5.    If yes,
        it just removes it and does nothing else.
        if no,
        it knows that the edge was inserted externally and performs
        the insertion.
        6. Lastly, we remove the edge from the jCellsBeingAdded.
     * </pre>
     *
     * <p>Step 6 is not always required but we do it anyway as a safeguard
     * against the rare case where the edge to be added is already contained in
     * the graph and thus NO event will be fired. If 6 is not done, a junk edge
     * will remain in the jCellsBeingAdded set.</p>
     *
     * <p>The other sets are used in a similar manner to the above. Apparently,
     * All that complication could be eliminated if JGraph and JGraphT had both
     * allowed operations that do not inform listeners...</p>
     */
    final Set<GraphCell> jCellsBeingAdded = new HashSet<GraphCell>();
    final Set<GraphCell> jCellsBeingRemoved = new HashSet<GraphCell>();
    final Set<Object> jtElementsBeingAdded = new HashSet<Object>();
    final Set<Object> jtElementsBeingRemoved = new HashSet<Object>();
    private final CellFactory<V, E> cellFactory;

    /**
     * Maps JGraph edges to JGraphT edges
     */
    private final Map<org.jgraph.graph.Edge, E> cellToEdge =
        new HashMap<org.jgraph.graph.Edge, E>();

    /**
     * Maps JGraph vertices to JGraphT vertices
     */
    private final Map<GraphCell, V> cellToVertex = new HashMap<GraphCell, V>();
    private AttributeMap defaultEdgeAttributes;
    private AttributeMap defaultVertexAttributes;

    /**
     * Maps JGraphT edges to JGraph edges
     */
    private final Map<E, org.jgraph.graph.Edge> edgeToCell =
        new HashMap<E, org.jgraph.graph.Edge>();

    /**
     * Maps JGraphT vertices to JGraph vertices
     */
    private final Map<V, GraphCell> vertexToCell = new HashMap<V, GraphCell>();
    private final ShieldedGraph jtGraph;

    //~ Constructors -----------------------------------------------------------

    /**
     * Constructs a new JGraph model adapter for the specified JGraphT graph.
     *
     * @param jGraphTGraph the JGraphT graph for which JGraph model adapter to
     * be created. <code>null</code> is NOT permitted.
     */
    public JGraphModelAdapter(Graph<V, E> jGraphTGraph)
    {
        this(
            jGraphTGraph,
            createDefaultVertexAttributes(),
            createDefaultEdgeAttributes(jGraphTGraph));
    }

    /**
     * Constructs a new JGraph model adapter for the specified JGraphT graph.
     *
     * @param jGraphTGraph the JGraphT graph for which JGraph model adapter to
     * be created. <code>null</code> is NOT permitted.
     * @param defaultVertexAttributes a default map of JGraph attributes to
     * format vertices. <code>null</code> is NOT permitted.
     * @param defaultEdgeAttributes a default map of JGraph attributes to format
     * edges. <code>null</code> is NOT permitted.
     */
    public JGraphModelAdapter(
        Graph<V, E> jGraphTGraph,
        AttributeMap defaultVertexAttributes,
        AttributeMap defaultEdgeAttributes)
    {
        this(
            jGraphTGraph,
            defaultVertexAttributes,
            defaultEdgeAttributes,
            new DefaultCellFactory<V, E>());
    }

    /**
     * Constructs a new JGraph model adapter for the specified JGraphT graph.
     *
     * @param jGraphTGraph the JGraphT graph for which JGraph model adapter to
     * be created. <code>null</code> is NOT permitted.
     * @param defaultVertexAttributes a default map of JGraph attributes to
     * format vertices. <code>null</code> is NOT permitted.
     * @param defaultEdgeAttributes a default map of JGraph attributes to format
     * edges. <code>null</code> is NOT permitted.
     * @param cellFactory a {@link CellFactory} to be used to create the JGraph
     * cells. <code>null</code> is NOT permitted.
     *
     * @throws IllegalArgumentException
     */
    public JGraphModelAdapter(
        Graph<V, E> jGraphTGraph,
        AttributeMap defaultVertexAttributes,
        AttributeMap defaultEdgeAttributes,
        CellFactory<V, E> cellFactory)
    {
        super();

        if ((jGraphTGraph == null)
            || (defaultVertexAttributes == null)
            || (defaultEdgeAttributes == null)
            || (cellFactory == null))
        {
            throw new IllegalArgumentException("null is NOT permitted");
        }

        jtGraph = new ShieldedGraph(jGraphTGraph);
        setDefaultVertexAttributes(defaultVertexAttributes);
        setDefaultEdgeAttributes(defaultEdgeAttributes);
        this.cellFactory = cellFactory;

        if (jGraphTGraph instanceof ListenableGraph) {
            ListenableGraph<V, E> g = (ListenableGraph<V, E>) jGraphTGraph;
            g.addGraphListener(new JGraphTListener());
        }

        for (
            Iterator<V> i = jGraphTGraph.vertexSet().iterator();
            i.hasNext();)
        {
            handleJGraphTAddedVertex(i.next());
        }

        for (Iterator<E> i = jGraphTGraph.edgeSet().iterator(); i.hasNext();) {
            handleJGraphTAddedEdge(i.next());
        }

        this.addGraphModelListener(new JGraphListener());
    }

    //~ Methods ----------------------------------------------------------------

    /**
     * Creates and returns a map of attributes to be used as defaults for edge
     * attributes, depending on the specified graph.
     *
     * @param jGraphTGraph the graph for which default edge attributes to be
     * created.
     *
     * @return a map of attributes to be used as default for edge attributes.
     */
    public static <V, E> AttributeMap createDefaultEdgeAttributes(
        Graph<V, E> jGraphTGraph)
    {
        AttributeMap map = new AttributeMap();

        if (jGraphTGraph instanceof DirectedGraph) {
            GraphConstants.setLineEnd(map, GraphConstants.ARROW_TECHNICAL);
            GraphConstants.setEndFill(map, true);
            GraphConstants.setEndSize(map, 10);
        }

        GraphConstants.setForeground(map, Color.decode("#25507C"));
        GraphConstants.setFont(
            map,
            GraphConstants.DEFAULTFONT.deriveFont(Font.BOLD, 12));
        GraphConstants.setLineColor(map, Color.decode("#7AA1E6"));

        return map;
    }

    /**
     * Creates and returns a map of attributes to be used as defaults for vertex
     * attributes.
     *
     * @return a map of attributes to be used as defaults for vertex attributes.
     */
    public static AttributeMap createDefaultVertexAttributes()
    {
        AttributeMap map = new AttributeMap();
        Color c = Color.decode("#FF9900");

        GraphConstants.setBounds(map, new Rectangle2D.Double(50, 50, 90, 30));
        GraphConstants.setBorder(map, BorderFactory.createRaisedBevelBorder());
        GraphConstants.setBackground(map, c);
        GraphConstants.setForeground(map, Color.white);
        GraphConstants.setFont(
            map,
            GraphConstants.DEFAULTFONT.deriveFont(Font.BOLD, 12));
        GraphConstants.setOpaque(map, true);

        return map;
    }

    /**
     * Returns the cell factory used to create the JGraph cells.
     *
     * @return the cell factory used to create the JGraph cells.
     */
    public CellFactory<V, E> getCellFactory()
    {
        return cellFactory;
    }

    /**
     * Sets the default edge attributes used for creating new JGraph edges.
     *
     * @param defaultEdgeAttributes the default edge attributes to set.
     */
    public void setDefaultEdgeAttributes(AttributeMap defaultEdgeAttributes)
    {
        this.defaultEdgeAttributes = defaultEdgeAttributes;
    }

    /**
     * Returns the default edge attributes used for creating new JGraph edges.
     *
     * @return the default edge attributes used for creating new JGraph edges.
     */
    public AttributeMap getDefaultEdgeAttributes()
    {
        return defaultEdgeAttributes;
    }

    /**
     * Sets the default vertex attributes used for creating new JGraph vertices.
     *
     * @param defaultVertexAttributes the default vertex attributes to set.
     */
    public void setDefaultVertexAttributes(
        AttributeMap defaultVertexAttributes)
    {
        this.defaultVertexAttributes = defaultVertexAttributes;
    }

    /**
     * Returns the default vertex attributes used for creating new JGraph
     * vertices.
     *
     * @return the default vertex attributes used for creating new JGraph
     * vertices.
     */
    public AttributeMap getDefaultVertexAttributes()
    {
        return defaultVertexAttributes;
    }

    /**
     * Returns the JGraph edge cell that corresponds to the specified JGraphT
     * edge. If no corresponding cell found, returns <code>null</code>.
     *
     * @param jGraphTEdge a JGraphT edge of the JGraphT graph.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?