diff --git a/mastfrog-graph-adapter/src/main/java/com/mastfrog/graph/jung/adapter/GraphAdapter.java b/mastfrog-graph-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java
similarity index 99%
rename from mastfrog-graph-adapter/src/main/java/com/mastfrog/graph/jung/adapter/GraphAdapter.java
rename to mastfrog-graph-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java
index 8c7e8be..a40d9c8 100644
--- a/mastfrog-graph-adapter/src/main/java/com/mastfrog/graph/jung/adapter/GraphAdapter.java
+++ b/mastfrog-graph-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java
@@ -23,7 +23,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-package com.mastfrog.graph.jung.adapter;
+package com.mastfrog.graph.jgrapht.adapter;
import com.mastfrog.abstractions.Wrapper;
import com.mastfrog.abstractions.list.IndexedResolvable;
diff --git a/mastfrog-graph-adapter/src/test/java/com/mastfrog/graph/jung/adapter/GraphAdapterTest.java b/mastfrog-graph-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java
similarity index 99%
rename from mastfrog-graph-adapter/src/test/java/com/mastfrog/graph/jung/adapter/GraphAdapterTest.java
rename to mastfrog-graph-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java
index e2a7ff3..fcb000b 100644
--- a/mastfrog-graph-adapter/src/test/java/com/mastfrog/graph/jung/adapter/GraphAdapterTest.java
+++ b/mastfrog-graph-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java
@@ -23,7 +23,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-package com.mastfrog.graph.jung.adapter;
+package com.mastfrog.graph.jgrapht.adapter;
import com.mastfrog.abstractions.list.IndexedResolvable;
import com.mastfrog.graph.IntGraph;
diff --git a/mastfrog-jgrapht-adapter/pom.xml b/mastfrog-jgrapht-adapter/pom.xml
new file mode 100644
index 0000000..b69beea
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+ com.mastfrog
+ visual-library-jung
+ 2.3
+
+ mastfrog-jgrapht-adapter
+ Adapters to wrapper com.mastfrog:graph bit-set based graphs as JUNG graphs
+ https://github.com:timboudreau/vl-jung
+ Visual Library + Mastfrog Graph Adapters
+
+ git@github.com:timboudreau/vl-jung.git
+ scm:git:https://github.com:timboudreau/vl-jung.git
+ git@github.com:timboudreau/vl-jung.git
+
+
+ Github
+ https://github.com/timboudreau/vl-jung/issues
+
+
+ Mastfrog Technologies
+ https://mastfrog.com
+
+
+
+ BSD-2-Clause
+ https://opensource.org/licenses/BSD-2-Clause
+ repo
+
+
+
+
+ timboudreau
+ Tim Boudreau
+ https://timboudreau.com
+ tim+github@timboudreau.com
+
+
+
+
+ com.mastfrog
+ abstractions
+
+
+ com.mastfrog
+ graph
+
+
+ org.jgrapht
+ jgrapht-core
+
+
+ junit
+ junit
+ test
+
+
+ ${project.groupId}
+ vl-jungrapht-demo
+ test
+
+
+ org.hamcrest
+ hamcrest-core
+ test
+
+
+
diff --git a/mastfrog-jgrapht-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java b/mastfrog-jgrapht-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java
new file mode 100644
index 0000000..3556316
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2020, Mastfrog Technologies
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.mastfrog.graph.jgrapht.adapter;
+
+import com.mastfrog.abstractions.Wrapper;
+import com.mastfrog.abstractions.list.IndexedResolvable;
+import com.mastfrog.graph.IntGraph;
+import com.mastfrog.graph.ObjectGraph;
+import com.mastfrog.graph.ObjectGraphVisitor;
+import org.jgrapht.Graph;
+import org.jgrapht.GraphType;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+
+/**
+ * Adapts com.mastfrog:graph's super-lightweight bit-set based graphs as JGraphT
+ * graphs.
+ *
+ * @author Tim Boudreau
+ */
+public final class GraphAdapter {
+
+ /**
+ * Create a JGraphT graph for a Mastfrog graph.
+ *
+ * @param The vertex type
+ * @param The edge type
+ * @param graph The original graph
+ * @param edgeFactory The factory for edge objects
+ * @return A graph
+ */
+ public static Graph wrap(ObjectGraph graph, EdgeFactory edgeFactory) {
+ return new WrappedObjectGraph<>(graph, edgeFactory);
+ }
+
+ /**
+ * Create a JGraphT graph for a Mastfrog graph, using the built-in edge type,
+ * which unwraps the underlying IntGraph and represents edges internally as
+ * a pair of ints, for the most lightweight possible edge objects.
+ *
+ * @param The vertex type
+ * @param graph The original graph
+ * @param directed Whether or not to return a graph that represents itself
+ * to JGraphT as being a directed graph (be very sure!)
+ * @return A graph
+ */
+ public static Graph> wrap(ObjectGraph graph,
+ boolean directed) {
+ DefaultEdgeFactory def = new DefaultEdgeFactory(graph, directed);
+ return new WrappedObjectGraph<>(graph, def);
+ }
+
+ /**
+ * Create a JGraphT graph for a Mastfrog graph, using the built-in edge type,
+ * which unwraps the underlying IntGraph and represents edges internally as
+ * a pair of ints, for the most lightweight possible edge objects.
+ *
+ * This method will probe the graph to determine if it is directed or
+ * undirected; if the graph is very large and has very few cycles, this may
+ * be expensive - if you know for sure the graph can or cannot be directed,
+ * you should use one of the other methods that lets you pass that
+ * information.
+ *
+ *
+ * @param The vertex type
+ * @param graph The original graph
+ * @return A graph
+ */
+ public static Graph> wrap(ObjectGraph graph) {
+ DefaultEdgeFactory def = new DefaultEdgeFactory(graph, null);
+ return new WrappedObjectGraph<>(graph, def);
+ }
+
+ private GraphAdapter() {
+ throw new AssertionError();
+ }
+
+ /**
+ * A factory for edges which can provide information JGraphT graphs need.
+ * Resulting edge objects must have the following characteristics:
+ *
+ *
equals() must return true for identical edges (same
+ * source, same destination)
+ *
hashCode() must return the same value for identical
+ * edges
+ *
If the graph is undirected, equals() must return true
+ * for identical edges (same source, same destination)
+ * and for mirror-image edges (source=dest, dest=source)
+ *
If the graph is undirected hashCode() must return the
+ * same value for identical edges
+ * and for mirror-image edges (hint, before hashing, sort on
+ * hashCode() or some similar means of achieving consistency)
+ *
+ *
+ *
+ * @param The vertex type
+ * @param The edge type
+ */
+ public interface EdgeFactory extends BiFunction {
+
+ V sourceOf(E e);
+
+ V destOf(E e);
+ }
+
+ private static final class DefaultEdgeFactory implements
+ EdgeFactory.Edg> {
+
+ private final ObjectGraph graph;
+ private final IntGraph ig;
+ private final IndexedResolvable extends V> contents;
+ private boolean undirected;
+
+ DefaultEdgeFactory(ObjectGraph graph, Boolean directed) {
+ this.graph = graph;
+ Object[] stuff = dissect(graph);
+ contents = (IndexedResolvable extends V>) stuff[0];
+ ig = (IntGraph) stuff[1];
+ if (directed == null) {
+ ig.connectors().forEachSetBitAscending(id -> {
+ if (ig.isRecursive(id)) {
+ undirected = true;
+ return false;
+ }
+ return true;
+ });
+ } else {
+ undirected = !directed.booleanValue();
+ }
+ }
+
+ private static Object[] dissect(ObjectGraph graph) {
+ Object[] result = new Object[2];
+ graph.toIntGraph((contents, intGraph) -> {
+ result[0] = contents;
+ result[1] = intGraph;
+ });
+ return result;
+ }
+
+ @Override
+ public V sourceOf(Edg e) {
+ return e.source();
+ }
+
+ @Override
+ public V destOf(Edg e) {
+ return e.dest();
+ }
+
+ @Override
+ public Edg apply(V t, V u) {
+ return new Edg(contents.indexOf(t), contents.indexOf(u));
+ }
+
+ class Edg extends Edge {
+
+ private final int src;
+ private final int dest;
+
+ public Edg(int src, int dest) {
+ this.src = src;
+ this.dest = dest;
+ }
+
+ @Override
+ public V source() {
+ return contents.forIndex(src);
+ }
+
+ @Override
+ public V dest() {
+ return contents.forIndex(dest);
+ }
+
+ @Override
+ public boolean equalsDirected(Edge> other) {
+ if (!(other.getClass() == Edg.class)) {
+ return false;
+ }
+ Edg o = (Edg) other;
+ return o.src == src && o.dest == dest;
+ }
+
+ @Override
+ public boolean equalsUndirected(Edge> other) {
+ if (!(other.getClass() == Edg.class)) {
+ return false;
+ }
+ Edg o = (Edg) other;
+ return (o.src == src && o.dest == dest)
+ || (o.src == dest && o.dest == src);
+ }
+
+ public String toString() {
+ return source() + ":" + dest();
+ }
+
+ @Override
+ public int hashCode() {
+ if (undirected && dest < src) {
+ return (7 * dest) + (41131 * src);
+ }
+ return (7 * src) + (41131 * dest);
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o == null || o.getClass() != Edg.class) {
+ return false;
+ }
+ Edg other = (Edg) o;
+ if (undirected) {
+ return equalsUndirected(other);
+ } else {
+ return equalsDirected(other);
+ }
+ }
+ }
+ }
+
+ public static Edge create(V a, V b, boolean directed) {
+ return new DefaultEdge(a, b, directed);
+ }
+
+ public static abstract class Edge {
+
+ public abstract V source();
+
+ public abstract V dest();
+
+ public boolean equalsDirected(Edge> other) {
+ return source().equals(other.source()) && dest().equals(other.dest());
+ }
+
+ public boolean equalsUndirected(Edge> other) {
+ return equalsDirected(other)
+ || (source().equals(other.dest()) && dest().equals(other.source()));
+ }
+ }
+
+ private static final class DefaultEdge extends Edge {
+
+ private final V source;
+ private final V dest;
+ private final boolean directed;
+
+ public DefaultEdge(V source, V dest, boolean directed) {
+ this.source = source;
+ this.dest = dest;
+ this.directed = directed;
+ }
+
+ public V source() {
+ return source;
+ }
+
+ public V dest() {
+ return dest;
+ }
+
+ @Override
+ public String toString() {
+ if (directed) {
+ return source + ":" + dest;
+ } else {
+ if (source.hashCode() > dest.hashCode()) {
+ return dest + ":" + source;
+ } else {
+ return source + ":" + dest;
+ }
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ if (directed || source.hashCode() < dest.hashCode()) {
+ return source.hashCode() + (24133 * dest.hashCode());
+ }
+ return dest.hashCode() + (24133 * source.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o == null || o.getClass() != DefaultEdge.class) {
+ return false;
+ }
+ DefaultEdge other = (DefaultEdge) o;
+ boolean dir = directed || other.directed;
+ if (dir) {
+ return equalsDirected(other);
+ } else {
+ return equalsUndirected(other);
+ }
+ }
+ }
+
+ static class WrappedObjectGraph implements Graph, Wrapper> {
+
+ private final ObjectGraph graph;
+ private final EdgeFactory edgeFactory;
+
+ public WrappedObjectGraph(ObjectGraph graph, EdgeFactory edgeFactory) {
+ this.graph = graph;
+ this.edgeFactory = edgeFactory;
+ }
+
+ @Override
+ public ObjectGraph> wrapped() {
+ return graph;
+ }
+
+ @Override
+ public F find(Class super F> what) {
+ if (IntGraph.class == what) {
+ IntGraph[] ig = new IntGraph[1];
+ graph.toIntGraph((ir, g) -> ig[0] = g);
+ return (F) what.cast(ig[0]);
+ }
+ return Wrapper.super.find(what);
+ }
+
+ @Override
+ public boolean has(Class super F> what) {
+ if (IntGraph.class == what) {
+ return true;
+ }
+ return Wrapper.super.has(what);
+ }
+
+ @Override
+ public ObjectGraph> root() {
+ return graph;
+ }
+
+ private Set edges;
+
+ private Set allVertices;
+
+
+ @Override
+ public boolean containsVertex(V vertex) {
+ return vertexSet().contains(vertex);
+ }
+
+ @Override
+ public Set edgeSet() {
+ if (edges != null) {
+ return edges;
+ }
+ Set result = new HashSet<>();
+ graph.walk(new ObjectGraphVisitor() {
+ LinkedList stack = new LinkedList<>();
+
+ @Override
+ public void enterNode(V node, int depth) {
+ if (stack.size() > 0) {
+ V curr = stack.peek();
+ result.add(edgeFactory.apply(curr, node));
+ }
+ stack.push(node);
+ }
+
+ @Override
+ public void exitNode(V node, int depth) {
+ stack.pop();
+ }
+ });
+ return edges = Collections.unmodifiableSet(result);
+ }
+
+ @Override
+ public int degreeOf(V vertex) {
+ return inDegreeOf(vertex) + outDegreeOf(vertex);
+ }
+
+ @Override
+ public Set edgesOf(V vertex) {
+ return null;
+ }
+
+ @Override
+ public int inDegreeOf(V vertex) {
+ return graph.inboundReferenceCount(vertex);
+ }
+
+ @Override
+ public Set incomingEdgesOf(V vertex) {
+ Set result = new HashSet<>();
+ graph.parents(vertex).forEach(o -> result.add(edgeFactory.apply(vertex, o)));
+ return result;
+ }
+
+ @Override
+ public int outDegreeOf(V vertex) {
+ return graph.outboundReferenceCount(vertex);
+ }
+
+ @Override
+ public Set outgoingEdgesOf(V vertex) {
+ Set result = new HashSet<>();
+ graph.children(vertex).forEach(o -> result.add(edgeFactory.apply(vertex, o)));
+ return result;
+ }
+
+ @Override
+ public boolean removeAllEdges(Collection extends E> edges) {
+ throw new UnsupportedOperationException("immutable"); }
+
+ @Override
+ public Set removeAllEdges(V sourceVertex, V targetVertex) {
+ throw new UnsupportedOperationException("immutable"); }
+
+ @Override
+ public boolean removeAllVertices(Collection extends V> vertices) {
+ throw new UnsupportedOperationException("immutable"); }
+
+ @Override
+ public E removeEdge(V sourceVertex, V targetVertex) {
+ throw new UnsupportedOperationException("immutable"); }
+
+ @Override
+ public boolean containsEdge(E edge) {
+ V src = edgeFactory.sourceOf(edge);
+ V dest = edgeFactory.destOf(edge);
+ return graph.children(src).contains(dest);
+ }
+
+ @Override
+ public Set getAllEdges(V v1, V v2) {
+ Set edges = new HashSet<>();
+ if (graph.parents(v2).contains(v1)) {
+ edges.add(edgeFactory.apply(v1, v2));
+ }
+ if (graph.parents(v2).contains(v1)) {
+ edges.add(edgeFactory.apply(v2, v1));
+ }
+ return edges;
+ }
+
+ @Override
+ public E getEdge(V v1, V v2) {
+ if (graph.parents(v2).contains(v1)) {
+ return edgeFactory.apply(v1, v2);
+ } else if (graph.parents(v2).contains(v1)) {
+ return edgeFactory.apply(v2, v1);
+ }
+ return null;
+ }
+
+ @Override
+ public Supplier getVertexSupplier() {
+ return null;
+ }
+
+ @Override
+ public Supplier getEdgeSupplier() {
+ return null;
+ }
+
+ @Override
+ public E addEdge(V sourceVertex, V targetVertex) {
+ throw new UnsupportedOperationException("Immutable."); }
+
+ @Override
+ public boolean addEdge(V sourceVertex, V targetVertex, E e) {
+ throw new UnsupportedOperationException("Immutable."); }
+
+ @Override
+ public V addVertex() {
+ throw new UnsupportedOperationException("Immutable."); }
+
+ @Override
+ public boolean addVertex(V vertex) {
+ throw new UnsupportedOperationException("Immutable.");
+ }
+
+ @Override
+ public boolean containsEdge(V sourceVertex, V targetVertex) {
+ return false;
+ }
+
+ @Override
+ public boolean removeVertex(V vertex) {
+ throw new UnsupportedOperationException("immutable");
+ }
+
+ @Override
+ public Set vertexSet() {
+ if (allVertices != null) {
+ return allVertices;
+ }
+ Set items = new HashSet<>();
+ for (int i = 0; i < graph.size(); i++) {
+ items.add(graph.toNode(i));
+ }
+ return allVertices = Collections.unmodifiableSet(items);
+ }
+
+ @Override
+ public V getEdgeSource(E e) {
+ return null;
+ }
+
+ @Override
+ public V getEdgeTarget(E e) {
+ return null;
+ }
+
+ @Override
+ public GraphType getType() {
+ return null;
+ }
+
+ @Override
+ public double getEdgeWeight(E e) {
+ return 0;
+ }
+
+ @Override
+ public void setEdgeWeight(E e, double weight) {
+
+ }
+
+ @Override
+ public boolean removeEdge(E edge) {
+ throw new UnsupportedOperationException("immutable");
+ }
+
+ }
+}
diff --git a/mastfrog-jgrapht-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java b/mastfrog-jgrapht-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java
new file mode 100644
index 0000000..f1c734d
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java
@@ -0,0 +1,1923 @@
+/*
+ * Copyright (c) 2020, Mastfrog Technologies
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.mastfrog.graph.jgrapht.adapter;
+
+import com.mastfrog.abstractions.list.IndexedResolvable;
+import com.mastfrog.graph.IntGraph;
+import com.mastfrog.graph.ObjectGraph;
+import java.awt.EventQueue;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+import com.timboudreau.vl.jungrapht.demo.App;
+import org.jgrapht.Graph;
+import org.junit.Test;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Tim Boudreau
+ */
+public class GraphAdapterTest {
+
+ @Test
+ public void testSomeMethod() throws IOException, InterruptedException, InvocationTargetException {
+ if (true) {
+ // for manual testing
+ return;
+ }
+ IntGraph ig = sensorConfigLanguageRules();
+ IXA ixa = new IXA(ig.size());
+ List ixs = new ArrayList<>();
+ for (int i = 0; i < ixa.size; i++) {
+ ixs.add(i);
+ }
+ ObjectGraph og = ig.toObjectGraph(ixs);
+ Graph> g = GraphAdapter.wrap(og, true);
+
+ EventQueue.invokeAndWait(() -> {
+ try {
+ App.showDemo(g);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+// System.exit(1);
+ }
+ });
+ Thread.currentThread().join();
+ }
+
+ static class IXA implements IndexedResolvable {
+
+ private final int size;
+
+ public IXA(int size) {
+ this.size = size;
+ }
+
+ @Override
+ public Integer forIndex(int index) {
+ return index;
+ }
+
+ @Override
+ public int size() {
+ return size;
+ }
+
+ @Override
+ public int indexOf(Object obj) {
+ return (Integer) obj;
+ }
+
+ }
+
+ static IntGraph sensorConfigLanguageRules() {
+ BitSet[] parents = new BitSet[67];
+ BitSet[] children = new BitSet[67];
+ parents[0] = new BitSet();
+ parents[0].set(54);
+ parents[0].set(66);
+ children[0] = new BitSet();
+ parents[1] = new BitSet();
+ children[1] = new BitSet();
+ children[1].set(30);
+ parents[2] = new BitSet();
+ parents[2].set(38);
+ children[2] = new BitSet();
+ parents[3] = new BitSet();
+ parents[3].set(4);
+ parents[3].set(7);
+ children[3] = new BitSet();
+ parents[4] = new BitSet();
+ parents[4].set(36);
+ children[4] = new BitSet();
+ children[4].set(3);
+ parents[5] = new BitSet();
+ parents[5].set(24);
+ children[5] = new BitSet();
+ parents[6] = new BitSet();
+ parents[6].set(25);
+ children[6] = new BitSet();
+ parents[7] = new BitSet();
+ parents[7].set(38);
+ children[7] = new BitSet();
+ children[7].set(3);
+ children[7].set(8);
+ parents[8] = new BitSet();
+ parents[8].set(7);
+ children[8] = new BitSet();
+ parents[9] = new BitSet();
+ parents[9].set(49);
+ children[9] = new BitSet();
+ parents[10] = new BitSet();
+ parents[10].set(57);
+ children[10] = new BitSet();
+ parents[11] = new BitSet();
+ parents[11].set(41);
+ children[11] = new BitSet();
+ parents[12] = new BitSet();
+ parents[12].set(43);
+ children[12] = new BitSet();
+ parents[13] = new BitSet();
+ parents[13].set(49);
+ children[13] = new BitSet();
+ parents[14] = new BitSet();
+ parents[14].set(45);
+ children[14] = new BitSet();
+ parents[15] = new BitSet();
+ parents[15].set(47);
+ children[15] = new BitSet();
+ parents[16] = new BitSet();
+ parents[16].set(48);
+ children[16] = new BitSet();
+ parents[17] = new BitSet();
+ parents[17].set(52);
+ children[17] = new BitSet();
+ parents[18] = new BitSet();
+ parents[18].set(53);
+ children[18] = new BitSet();
+ parents[19] = new BitSet();
+ parents[19].set(57);
+ children[19] = new BitSet();
+ parents[20] = new BitSet();
+ parents[20].set(58);
+ children[20] = new BitSet();
+ parents[21] = new BitSet();
+ parents[21].set(59);
+ children[21] = new BitSet();
+ parents[22] = new BitSet();
+ parents[22].set(65);
+ children[22] = new BitSet();
+ parents[23] = new BitSet();
+ parents[23].set(60);
+ parents[23].set(66);
+ children[23] = new BitSet();
+ children[23].set(24);
+ children[23].set(25);
+ parents[24] = new BitSet();
+ parents[24].set(23);
+ children[24] = new BitSet();
+ children[24].set(5);
+ parents[25] = new BitSet();
+ parents[25].set(23);
+ children[25] = new BitSet();
+ children[25].set(6);
+ parents[26] = new BitSet();
+ parents[26].set(52);
+ children[26] = new BitSet();
+ parents[27] = new BitSet();
+ parents[27].set(50);
+ children[27] = new BitSet();
+ parents[28] = new BitSet();
+ parents[28].set(52);
+ parents[28].set(58);
+ parents[28].set(62);
+ children[28] = new BitSet();
+ parents[29] = new BitSet();
+ parents[29].set(56);
+ children[29] = new BitSet();
+ parents[30] = new BitSet();
+ parents[30].set(1);
+ children[30] = new BitSet();
+ parents[31] = new BitSet();
+ parents[31].set(52);
+ children[31] = new BitSet();
+ parents[32] = new BitSet();
+ parents[32].set(39);
+ parents[32].set(43);
+ parents[32].set(53);
+ parents[32].set(59);
+ children[32] = new BitSet();
+ parents[33] = new BitSet();
+ parents[33].set(50);
+ children[33] = new BitSet();
+ parents[34] = new BitSet();
+ children[34] = new BitSet();
+ parents[35] = new BitSet();
+ children[35] = new BitSet();
+ parents[36] = new BitSet();
+ parents[36].set(43);
+ parents[36].set(46);
+ parents[36].set(47);
+ parents[36].set(50);
+ parents[36].set(56);
+ parents[36].set(57);
+ parents[36].set(59);
+ parents[36].set(66);
+ children[36] = new BitSet();
+ children[36].set(4);
+ parents[37] = new BitSet();
+ parents[37].set(64);
+ parents[37].set(66);
+ children[37] = new BitSet();
+ parents[38] = new BitSet();
+ children[38] = new BitSet();
+ children[38].set(2);
+ children[38].set(7);
+ parents[39] = new BitSet();
+ parents[39].set(40);
+ children[39] = new BitSet();
+ children[39].set(32);
+ children[39].set(45);
+ children[39].set(57);
+ children[39].set(58);
+ parents[40] = new BitSet();
+ parents[40].set(42);
+ children[40] = new BitSet();
+ children[40].set(39);
+ parents[41] = new BitSet();
+ parents[41].set(61);
+ children[41] = new BitSet();
+ children[41].set(11);
+ children[41].set(63);
+ parents[42] = new BitSet();
+ children[42] = new BitSet();
+ children[42].set(40);
+ children[42].set(44);
+ children[42].set(52);
+ children[42].set(55);
+ children[42].set(59);
+ parents[43] = new BitSet();
+ parents[43].set(44);
+ children[43] = new BitSet();
+ children[43].set(12);
+ children[43].set(32);
+ children[43].set(36);
+ children[43].set(49);
+ children[43].set(64);
+ parents[44] = new BitSet();
+ parents[44].set(42);
+ children[44] = new BitSet();
+ children[44].set(43);
+ parents[45] = new BitSet();
+ parents[45].set(39);
+ children[45] = new BitSet();
+ children[45].set(14);
+ children[45].set(60);
+ parents[46] = new BitSet();
+ parents[46].set(63);
+ children[46] = new BitSet();
+ children[46].set(36);
+ parents[47] = new BitSet();
+ parents[47].set(51);
+ children[47] = new BitSet();
+ children[47].set(15);
+ children[47].set(36);
+ parents[48] = new BitSet();
+ parents[48].set(61);
+ children[48] = new BitSet();
+ children[48].set(16);
+ children[48].set(63);
+ parents[49] = new BitSet();
+ parents[49].set(43);
+ children[49] = new BitSet();
+ children[49].set(9);
+ children[49].set(13);
+ parents[50] = new BitSet();
+ parents[50].set(52);
+ children[50] = new BitSet();
+ children[50].set(27);
+ children[50].set(33);
+ children[50].set(36);
+ children[50].set(63);
+ parents[51] = new BitSet();
+ parents[51].set(58);
+ children[51] = new BitSet();
+ children[51].set(47);
+ children[51].set(54);
+ parents[52] = new BitSet();
+ parents[52].set(42);
+ children[52] = new BitSet();
+ children[52].set(17);
+ children[52].set(26);
+ children[52].set(28);
+ children[52].set(31);
+ children[52].set(50);
+ children[52].set(64);
+ parents[53] = new BitSet();
+ parents[53].set(55);
+ children[53] = new BitSet();
+ children[53].set(18);
+ children[53].set(32);
+ children[53].set(54);
+ children[53].set(62);
+ parents[54] = new BitSet();
+ parents[54].set(51);
+ parents[54].set(53);
+ parents[54].set(57);
+ children[54] = new BitSet();
+ children[54].set(0);
+ parents[55] = new BitSet();
+ parents[55].set(42);
+ children[55] = new BitSet();
+ children[55].set(53);
+ parents[56] = new BitSet();
+ parents[56].set(63);
+ children[56] = new BitSet();
+ children[56].set(29);
+ children[56].set(36);
+ parents[57] = new BitSet();
+ parents[57].set(39);
+ children[57] = new BitSet();
+ children[57].set(10);
+ children[57].set(19);
+ children[57].set(36);
+ children[57].set(54);
+ children[57].set(63);
+ parents[58] = new BitSet();
+ parents[58].set(39);
+ children[58] = new BitSet();
+ children[58].set(20);
+ children[58].set(28);
+ children[58].set(51);
+ children[58].set(64);
+ parents[59] = new BitSet();
+ parents[59].set(42);
+ children[59] = new BitSet();
+ children[59].set(21);
+ children[59].set(32);
+ children[59].set(36);
+ parents[60] = new BitSet();
+ parents[60].set(45);
+ children[60] = new BitSet();
+ children[60].set(23);
+ parents[61] = new BitSet();
+ parents[61].set(62);
+ children[61] = new BitSet();
+ children[61].set(41);
+ children[61].set(48);
+ children[61].set(65);
+ parents[62] = new BitSet();
+ parents[62].set(53);
+ children[62] = new BitSet();
+ children[62].set(28);
+ children[62].set(61);
+ parents[63] = new BitSet();
+ parents[63].set(41);
+ parents[63].set(48);
+ parents[63].set(50);
+ parents[63].set(57);
+ parents[63].set(65);
+ children[63] = new BitSet();
+ children[63].set(46);
+ children[63].set(56);
+ children[63].set(64);
+ parents[64] = new BitSet();
+ parents[64].set(43);
+ parents[64].set(52);
+ parents[64].set(58);
+ parents[64].set(63);
+ children[64] = new BitSet();
+ children[64].set(37);
+ parents[65] = new BitSet();
+ parents[65].set(61);
+ children[65] = new BitSet();
+ children[65].set(22);
+ children[65].set(63);
+ parents[66] = new BitSet();
+ children[66] = new BitSet();
+ children[66].set(0);
+ children[66].set(23);
+ children[66].set(36);
+ children[66].set(37);
+ return IntGraph.create(parents, children);
+ }
+
+ static IntGraph rustGrammarRules() {
+ // Rule graph of Rust.g4
+ BitSet[] parents = new BitSet[252];
+ BitSet[] children = new BitSet[252];
+ parents[0] = new BitSet();
+ parents[0].set(166);
+ parents[0].set(213);
+ parents[0].set(214);
+ parents[0].set(215);
+ parents[0].set(242);
+ children[0] = new BitSet();
+ parents[1] = new BitSet();
+ parents[1].set(220);
+ children[1] = new BitSet();
+ parents[2] = new BitSet();
+ parents[2].set(185);
+ parents[2].set(196);
+ parents[2].set(231);
+ parents[2].set(238);
+ parents[2].set(241);
+ children[2] = new BitSet();
+ parents[3] = new BitSet();
+ parents[3].set(168);
+ children[3] = new BitSet();
+ parents[4] = new BitSet();
+ parents[4].set(168);
+ children[4] = new BitSet();
+ parents[5] = new BitSet();
+ parents[5].set(168);
+ children[5] = new BitSet();
+ parents[6] = new BitSet();
+ parents[6].set(168);
+ children[6] = new BitSet();
+ parents[7] = new BitSet();
+ parents[7].set(168);
+ children[7] = new BitSet();
+ parents[8] = new BitSet();
+ parents[8].set(168);
+ children[8] = new BitSet();
+ parents[9] = new BitSet();
+ parents[9].set(168);
+ children[9] = new BitSet();
+ parents[10] = new BitSet();
+ parents[10].set(168);
+ children[10] = new BitSet();
+ parents[11] = new BitSet();
+ parents[11].set(168);
+ children[11] = new BitSet();
+ parents[12] = new BitSet();
+ children[12] = new BitSet();
+ parents[13] = new BitSet();
+ parents[13].set(23);
+ parents[13].set(164);
+ parents[13].set(207);
+ parents[13].set(242);
+ children[13] = new BitSet();
+ parents[14] = new BitSet();
+ children[14] = new BitSet();
+ parents[15] = new BitSet();
+ parents[15].set(212);
+ children[15] = new BitSet();
+ parents[16] = new BitSet();
+ children[16] = new BitSet();
+ parents[17] = new BitSet();
+ parents[17].set(18);
+ parents[17].set(29);
+ children[17] = new BitSet();
+ children[17].set(20);
+ children[17].set(37);
+ children[17].set(126);
+ children[17].set(128);
+ children[17].set(139);
+ parents[18] = new BitSet();
+ parents[18].set(31);
+ children[18] = new BitSet();
+ children[18].set(17);
+ children[18].set(107);
+ parents[19] = new BitSet();
+ parents[19].set(107);
+ parents[19].set(128);
+ children[19] = new BitSet();
+ parents[20] = new BitSet();
+ parents[20].set(17);
+ parents[20].set(171);
+ parents[20].set(179);
+ parents[20].set(206);
+ children[20] = new BitSet();
+ parents[21] = new BitSet();
+ parents[21].set(179);
+ parents[21].set(197);
+ children[21] = new BitSet();
+ children[21].set(43);
+ parents[22] = new BitSet();
+ parents[22].set(72);
+ children[22] = new BitSet();
+ parents[23] = new BitSet();
+ parents[23].set(23);
+ children[23] = new BitSet();
+ children[23].set(13);
+ children[23].set(23);
+ children[23].set(24);
+ children[23].set(138);
+ parents[24] = new BitSet();
+ parents[24].set(23);
+ children[24] = new BitSet();
+ parents[25] = new BitSet();
+ parents[25].set(198);
+ children[25] = new BitSet();
+ parents[26] = new BitSet();
+ parents[26].set(165);
+ parents[26].set(171);
+ parents[26].set(203);
+ children[26] = new BitSet();
+ children[26].set(67);
+ children[26].set(147);
+ parents[27] = new BitSet();
+ children[27] = new BitSet();
+ parents[28] = new BitSet();
+ children[28] = new BitSet();
+ parents[29] = new BitSet();
+ parents[29].set(165);
+ parents[29].set(203);
+ children[29] = new BitSet();
+ children[29].set(17);
+ children[29].set(30);
+ children[29].set(114);
+ children[29].set(137);
+ parents[30] = new BitSet();
+ parents[30].set(29);
+ children[30] = new BitSet();
+ parents[31] = new BitSet();
+ children[31] = new BitSet();
+ children[31].set(18);
+ children[31].set(32);
+ children[31].set(114);
+ children[31].set(115);
+ parents[32] = new BitSet();
+ parents[32].set(31);
+ children[32] = new BitSet();
+ parents[33] = new BitSet();
+ parents[33].set(36);
+ parents[33].set(129);
+ children[33] = new BitSet();
+ children[33].set(125);
+ children[33].set(128);
+ parents[34] = new BitSet();
+ parents[34].set(107);
+ children[34] = new BitSet();
+ parents[35] = new BitSet();
+ parents[35].set(198);
+ children[35] = new BitSet();
+ parents[36] = new BitSet();
+ children[36] = new BitSet();
+ children[36].set(33);
+ children[36].set(114);
+ children[36].set(137);
+ parents[37] = new BitSet();
+ parents[37].set(17);
+ parents[37].set(204);
+ children[37] = new BitSet();
+ parents[38] = new BitSet();
+ parents[38].set(215);
+ parents[38].set(228);
+ parents[38].set(229);
+ parents[38].set(248);
+ children[38] = new BitSet();
+ parents[39] = new BitSet();
+ parents[39].set(165);
+ parents[39].set(175);
+ parents[39].set(180);
+ parents[39].set(181);
+ parents[39].set(199);
+ parents[39].set(202);
+ parents[39].set(208);
+ parents[39].set(210);
+ parents[39].set(214);
+ parents[39].set(226);
+ parents[39].set(227);
+ parents[39].set(230);
+ parents[39].set(232);
+ parents[39].set(238);
+ parents[39].set(244);
+ parents[39].set(245);
+ children[39] = new BitSet();
+ parents[40] = new BitSet();
+ children[40] = new BitSet();
+ parents[41] = new BitSet();
+ children[41] = new BitSet();
+ parents[42] = new BitSet();
+ parents[42].set(183);
+ parents[42].set(250);
+ children[42] = new BitSet();
+ parents[43] = new BitSet();
+ parents[43].set(21);
+ parents[43].set(69);
+ parents[43].set(72);
+ parents[43].set(100);
+ parents[43].set(118);
+ parents[43].set(119);
+ children[43] = new BitSet();
+ parents[44] = new BitSet();
+ children[44] = new BitSet();
+ parents[45] = new BitSet();
+ parents[45].set(176);
+ children[45] = new BitSet();
+ children[45].set(46);
+ parents[46] = new BitSet();
+ parents[46].set(45);
+ children[46] = new BitSet();
+ parents[47] = new BitSet();
+ children[47] = new BitSet();
+ parents[48] = new BitSet();
+ parents[48].set(69);
+ parents[48].set(179);
+ parents[48].set(247);
+ children[48] = new BitSet();
+ parents[49] = new BitSet();
+ parents[49].set(118);
+ parents[49].set(228);
+ children[49] = new BitSet();
+ parents[50] = new BitSet();
+ parents[50].set(119);
+ children[50] = new BitSet();
+ parents[51] = new BitSet();
+ parents[51].set(204);
+ children[51] = new BitSet();
+ parents[52] = new BitSet();
+ children[52] = new BitSet();
+ parents[53] = new BitSet();
+ parents[53].set(190);
+ parents[53].set(217);
+ parents[53].set(218);
+ children[53] = new BitSet();
+ parents[54] = new BitSet();
+ parents[54].set(173);
+ children[54] = new BitSet();
+ parents[55] = new BitSet();
+ parents[55].set(172);
+ parents[55].set(204);
+ children[55] = new BitSet();
+ parents[56] = new BitSet();
+ parents[56].set(213);
+ children[56] = new BitSet();
+ parents[57] = new BitSet();
+ parents[57].set(69);
+ children[57] = new BitSet();
+ children[57].set(155);
+ parents[58] = new BitSet();
+ parents[58].set(194);
+ children[58] = new BitSet();
+ parents[59] = new BitSet();
+ parents[59].set(177);
+ children[59] = new BitSet();
+ children[59].set(60);
+ parents[60] = new BitSet();
+ parents[60].set(59);
+ children[60] = new BitSet();
+ parents[61] = new BitSet();
+ children[61] = new BitSet();
+ parents[62] = new BitSet();
+ parents[62].set(168);
+ parents[62].set(193);
+ parents[62].set(210);
+ parents[62].set(240);
+ children[62] = new BitSet();
+ parents[63] = new BitSet();
+ parents[63].set(181);
+ parents[63].set(183);
+ children[63] = new BitSet();
+ parents[64] = new BitSet();
+ parents[64].set(66);
+ parents[64].set(187);
+ parents[64].set(198);
+ children[64] = new BitSet();
+ parents[65] = new BitSet();
+ parents[65].set(66);
+ parents[65].set(187);
+ parents[65].set(198);
+ children[65] = new BitSet();
+ parents[66] = new BitSet();
+ children[66] = new BitSet();
+ children[66].set(64);
+ children[66].set(65);
+ parents[67] = new BitSet();
+ parents[67].set(26);
+ children[67] = new BitSet();
+ parents[68] = new BitSet();
+ parents[68].set(175);
+ parents[68].set(209);
+ children[68] = new BitSet();
+ parents[69] = new BitSet();
+ parents[69].set(186);
+ children[69] = new BitSet();
+ children[69].set(43);
+ children[69].set(48);
+ children[69].set(57);
+ parents[70] = new BitSet();
+ parents[70].set(192);
+ children[70] = new BitSet();
+ parents[71] = new BitSet();
+ parents[71].set(188);
+ children[71] = new BitSet();
+ parents[72] = new BitSet();
+ parents[72].set(197);
+ children[72] = new BitSet();
+ children[72].set(22);
+ children[72].set(43);
+ children[72].set(75);
+ children[72].set(82);
+ children[72].set(108);
+ children[72].set(155);
+ parents[73] = new BitSet();
+ parents[73].set(173);
+ children[73] = new BitSet();
+ parents[74] = new BitSet();
+ parents[74].set(115);
+ parents[74].set(117);
+ children[74] = new BitSet();
+ parents[75] = new BitSet();
+ parents[75].set(72);
+ children[75] = new BitSet();
+ parents[76] = new BitSet();
+ parents[76].set(198);
+ parents[76].set(222);
+ children[76] = new BitSet();
+ parents[77] = new BitSet();
+ parents[77].set(198);
+ parents[77].set(222);
+ children[77] = new BitSet();
+ parents[78] = new BitSet();
+ parents[78].set(198);
+ parents[78].set(222);
+ children[78] = new BitSet();
+ parents[79] = new BitSet();
+ parents[79].set(198);
+ parents[79].set(222);
+ children[79] = new BitSet();
+ parents[80] = new BitSet();
+ parents[80].set(198);
+ parents[80].set(222);
+ children[80] = new BitSet();
+ parents[81] = new BitSet();
+ parents[81].set(84);
+ parents[81].set(95);
+ children[81] = new BitSet();
+ children[81].set(162);
+ children[81].set(163);
+ parents[82] = new BitSet();
+ parents[82].set(72);
+ children[82] = new BitSet();
+ parents[83] = new BitSet();
+ parents[83].set(198);
+ parents[83].set(222);
+ children[83] = new BitSet();
+ parents[84] = new BitSet();
+ parents[84].set(178);
+ parents[84].set(183);
+ parents[84].set(190);
+ parents[84].set(191);
+ parents[84].set(206);
+ parents[84].set(210);
+ parents[84].set(211);
+ parents[84].set(217);
+ parents[84].set(218);
+ parents[84].set(226);
+ parents[84].set(228);
+ parents[84].set(229);
+ parents[84].set(233);
+ parents[84].set(238);
+ parents[84].set(243);
+ parents[84].set(250);
+ children[84] = new BitSet();
+ children[84].set(81);
+ parents[85] = new BitSet();
+ parents[85].set(193);
+ parents[85].set(194);
+ parents[85].set(209);
+ children[85] = new BitSet();
+ parents[86] = new BitSet();
+ children[86] = new BitSet();
+ parents[87] = new BitSet();
+ parents[87].set(188);
+ parents[87].set(250);
+ children[87] = new BitSet();
+ parents[88] = new BitSet();
+ parents[88].set(195);
+ children[88] = new BitSet();
+ parents[89] = new BitSet();
+ parents[89].set(173);
+ parents[89].set(202);
+ parents[89].set(231);
+ children[89] = new BitSet();
+ parents[90] = new BitSet();
+ parents[90].set(169);
+ parents[90].set(181);
+ parents[90].set(208);
+ parents[90].set(211);
+ parents[90].set(226);
+ parents[90].set(227);
+ parents[90].set(235);
+ parents[90].set(238);
+ children[90] = new BitSet();
+ parents[91] = new BitSet();
+ parents[91].set(165);
+ parents[91].set(242);
+ children[91] = new BitSet();
+ parents[92] = new BitSet();
+ parents[92].set(171);
+ parents[92].set(179);
+ parents[92].set(180);
+ parents[92].set(190);
+ parents[92].set(192);
+ parents[92].set(206);
+ parents[92].set(210);
+ parents[92].set(226);
+ parents[92].set(230);
+ parents[92].set(232);
+ parents[92].set(233);
+ parents[92].set(244);
+ parents[92].set(245);
+ parents[92].set(250);
+ children[92] = new BitSet();
+ parents[93] = new BitSet();
+ parents[93].set(173);
+ children[93] = new BitSet();
+ parents[94] = new BitSet();
+ parents[94].set(193);
+ parents[94].set(240);
+ children[94] = new BitSet();
+ parents[95] = new BitSet();
+ parents[95].set(201);
+ children[95] = new BitSet();
+ children[95].set(81);
+ children[95].set(137);
+ children[95].set(140);
+ parents[96] = new BitSet();
+ children[96] = new BitSet();
+ children[96].set(97);
+ parents[97] = new BitSet();
+ parents[97].set(96);
+ children[97] = new BitSet();
+ parents[98] = new BitSet();
+ parents[98].set(205);
+ children[98] = new BitSet();
+ parents[99] = new BitSet();
+ parents[99].set(207);
+ children[99] = new BitSet();
+ parents[100] = new BitSet();
+ parents[100].set(209);
+ children[100] = new BitSet();
+ children[100].set(43);
+ children[100].set(146);
+ parents[101] = new BitSet();
+ parents[101].set(164);
+ parents[101].set(179);
+ parents[101].set(197);
+ children[101] = new BitSet();
+ parents[102] = new BitSet();
+ parents[102].set(211);
+ children[102] = new BitSet();
+ parents[103] = new BitSet();
+ parents[103].set(172);
+ children[103] = new BitSet();
+ parents[104] = new BitSet();
+ parents[104].set(166);
+ parents[104].set(213);
+ parents[104].set(246);
+ children[104] = new BitSet();
+ parents[105] = new BitSet();
+ parents[105].set(107);
+ children[105] = new BitSet();
+ parents[106] = new BitSet();
+ parents[106].set(173);
+ children[106] = new BitSet();
+ parents[107] = new BitSet();
+ parents[107].set(18);
+ parents[107].set(129);
+ children[107] = new BitSet();
+ children[107].set(19);
+ children[107].set(34);
+ children[107].set(105);
+ children[107].set(137);
+ parents[108] = new BitSet();
+ parents[108].set(72);
+ children[108] = new BitSet();
+ parents[109] = new BitSet();
+ parents[109].set(164);
+ children[109] = new BitSet();
+ parents[110] = new BitSet();
+ parents[110].set(172);
+ parents[110].set(209);
+ children[110] = new BitSet();
+ parents[111] = new BitSet();
+ parents[111].set(164);
+ children[111] = new BitSet();
+ parents[112] = new BitSet();
+ parents[112].set(211);
+ parents[112].set(239);
+ parents[112].set(249);
+ children[112] = new BitSet();
+ parents[113] = new BitSet();
+ children[113] = new BitSet();
+ parents[114] = new BitSet();
+ parents[114].set(29);
+ parents[114].set(31);
+ parents[114].set(36);
+ parents[114].set(115);
+ parents[114].set(117);
+ parents[114].set(141);
+ children[114] = new BitSet();
+ parents[115] = new BitSet();
+ parents[115].set(31);
+ parents[115].set(115);
+ children[115] = new BitSet();
+ children[115].set(74);
+ children[115].set(114);
+ children[115].set(115);
+ parents[116] = new BitSet();
+ parents[116].set(117);
+ children[116] = new BitSet();
+ parents[117] = new BitSet();
+ parents[117].set(117);
+ parents[117].set(141);
+ children[117] = new BitSet();
+ children[117].set(74);
+ children[117].set(114);
+ children[117].set(116);
+ children[117].set(117);
+ parents[118] = new BitSet();
+ parents[118].set(188);
+ parents[118].set(209);
+ children[118] = new BitSet();
+ children[118].set(43);
+ children[118].set(49);
+ parents[119] = new BitSet();
+ parents[119].set(188);
+ children[119] = new BitSet();
+ children[119].set(43);
+ children[119].set(50);
+ parents[120] = new BitSet();
+ parents[120].set(241);
+ children[120] = new BitSet();
+ parents[121] = new BitSet();
+ parents[121].set(241);
+ children[121] = new BitSet();
+ parents[122] = new BitSet();
+ parents[122].set(246);
+ children[122] = new BitSet();
+ parents[123] = new BitSet();
+ parents[123].set(219);
+ children[123] = new BitSet();
+ parents[124] = new BitSet();
+ parents[124].set(173);
+ parents[124].set(202);
+ parents[124].set(231);
+ children[124] = new BitSet();
+ parents[125] = new BitSet();
+ parents[125].set(33);
+ parents[125].set(169);
+ parents[125].set(208);
+ parents[125].set(211);
+ parents[125].set(226);
+ parents[125].set(227);
+ parents[125].set(235);
+ parents[125].set(238);
+ children[125] = new BitSet();
+ parents[126] = new BitSet();
+ parents[126].set(17);
+ parents[126].set(165);
+ parents[126].set(195);
+ parents[126].set(212);
+ parents[126].set(242);
+ children[126] = new BitSet();
+ parents[127] = new BitSet();
+ parents[127].set(171);
+ parents[127].set(179);
+ parents[127].set(180);
+ parents[127].set(190);
+ parents[127].set(192);
+ parents[127].set(206);
+ parents[127].set(210);
+ parents[127].set(226);
+ parents[127].set(230);
+ parents[127].set(232);
+ parents[127].set(233);
+ parents[127].set(244);
+ parents[127].set(245);
+ parents[127].set(250);
+ children[127] = new BitSet();
+ parents[128] = new BitSet();
+ parents[128].set(17);
+ parents[128].set(33);
+ children[128] = new BitSet();
+ children[128].set(19);
+ parents[129] = new BitSet();
+ parents[129].set(141);
+ children[129] = new BitSet();
+ children[129].set(33);
+ children[129].set(107);
+ parents[130] = new BitSet();
+ children[130] = new BitSet();
+ parents[131] = new BitSet();
+ children[131] = new BitSet();
+ parents[132] = new BitSet();
+ parents[132].set(218);
+ children[132] = new BitSet();
+ parents[133] = new BitSet();
+ parents[133].set(214);
+ children[133] = new BitSet();
+ parents[134] = new BitSet();
+ parents[134].set(182);
+ parents[134].set(184);
+ parents[134].set(223);
+ parents[134].set(226);
+ parents[134].set(239);
+ children[134] = new BitSet();
+ parents[135] = new BitSet();
+ parents[135].set(221);
+ children[135] = new BitSet();
+ parents[136] = new BitSet();
+ parents[136].set(221);
+ children[136] = new BitSet();
+ parents[137] = new BitSet();
+ parents[137].set(29);
+ parents[137].set(36);
+ parents[137].set(95);
+ parents[137].set(107);
+ children[137] = new BitSet();
+ parents[138] = new BitSet();
+ parents[138].set(23);
+ parents[138].set(164);
+ children[138] = new BitSet();
+ parents[139] = new BitSet();
+ parents[139].set(17);
+ children[139] = new BitSet();
+ parents[140] = new BitSet();
+ parents[140].set(95);
+ children[140] = new BitSet();
+ parents[141] = new BitSet();
+ parents[141].set(165);
+ parents[141].set(203);
+ children[141] = new BitSet();
+ children[141].set(114);
+ children[141].set(117);
+ children[141].set(129);
+ parents[142] = new BitSet();
+ parents[142].set(226);
+ children[142] = new BitSet();
+ parents[143] = new BitSet();
+ parents[143].set(250);
+ children[143] = new BitSet();
+ parents[144] = new BitSet();
+ parents[144].set(218);
+ children[144] = new BitSet();
+ parents[145] = new BitSet();
+ children[145] = new BitSet();
+ parents[146] = new BitSet();
+ parents[146].set(100);
+ children[146] = new BitSet();
+ parents[147] = new BitSet();
+ parents[147].set(26);
+ children[147] = new BitSet();
+ parents[148] = new BitSet();
+ children[148] = new BitSet();
+ parents[149] = new BitSet();
+ parents[149].set(198);
+ parents[149].set(236);
+ children[149] = new BitSet();
+ parents[150] = new BitSet();
+ parents[150].set(198);
+ parents[150].set(236);
+ children[150] = new BitSet();
+ parents[151] = new BitSet();
+ parents[151].set(198);
+ parents[151].set(236);
+ children[151] = new BitSet();
+ parents[152] = new BitSet();
+ parents[152].set(198);
+ parents[152].set(236);
+ children[152] = new BitSet();
+ parents[153] = new BitSet();
+ parents[153].set(198);
+ parents[153].set(236);
+ children[153] = new BitSet();
+ parents[154] = new BitSet();
+ parents[154].set(198);
+ parents[154].set(236);
+ children[154] = new BitSet();
+ parents[155] = new BitSet();
+ parents[155].set(57);
+ parents[155].set(72);
+ parents[155].set(175);
+ parents[155].set(244);
+ parents[155].set(248);
+ children[155] = new BitSet();
+ parents[156] = new BitSet();
+ children[156] = new BitSet();
+ parents[157] = new BitSet();
+ parents[157].set(234);
+ parents[157].set(235);
+ children[157] = new BitSet();
+ parents[158] = new BitSet();
+ parents[158].set(239);
+ children[158] = new BitSet();
+ parents[159] = new BitSet();
+ children[159] = new BitSet();
+ parents[160] = new BitSet();
+ parents[160].set(251);
+ children[160] = new BitSet();
+ parents[161] = new BitSet();
+ children[161] = new BitSet();
+ parents[162] = new BitSet();
+ parents[162].set(81);
+ children[162] = new BitSet();
+ parents[163] = new BitSet();
+ parents[163].set(81);
+ children[163] = new BitSet();
+ parents[164] = new BitSet();
+ parents[164].set(179);
+ children[164] = new BitSet();
+ children[164].set(13);
+ children[164].set(101);
+ children[164].set(109);
+ children[164].set(111);
+ children[164].set(138);
+ parents[165] = new BitSet();
+ parents[165].set(203);
+ children[165] = new BitSet();
+ children[165].set(26);
+ children[165].set(29);
+ children[165].set(39);
+ children[165].set(91);
+ children[165].set(126);
+ children[165].set(141);
+ children[165].set(179);
+ children[165].set(186);
+ children[165].set(197);
+ parents[166] = new BitSet();
+ parents[166].set(240);
+ children[166] = new BitSet();
+ children[166].set(0);
+ children[166].set(104);
+ parents[167] = new BitSet();
+ parents[167].set(179);
+ parents[167].set(225);
+ children[167] = new BitSet();
+ children[167].set(168);
+ children[167].set(179);
+ children[167].set(242);
+ parents[168] = new BitSet();
+ parents[168].set(167);
+ children[168] = new BitSet();
+ children[168].set(3);
+ children[168].set(4);
+ children[168].set(5);
+ children[168].set(6);
+ children[168].set(7);
+ children[168].set(8);
+ children[168].set(9);
+ children[168].set(10);
+ children[168].set(11);
+ children[168].set(62);
+ parents[169] = new BitSet();
+ parents[169].set(170);
+ parents[169].set(172);
+ parents[169].set(175);
+ parents[169].set(188);
+ parents[169].set(189);
+ parents[169].set(193);
+ parents[169].set(194);
+ parents[169].set(205);
+ parents[169].set(209);
+ parents[169].set(224);
+ parents[169].set(234);
+ parents[169].set(251);
+ children[169] = new BitSet();
+ children[169].set(90);
+ children[169].set(125);
+ children[169].set(177);
+ children[169].set(179);
+ children[169].set(180);
+ children[169].set(195);
+ children[169].set(224);
+ parents[170] = new BitSet();
+ parents[170].set(172);
+ children[170] = new BitSet();
+ children[170].set(169);
+ children[170].set(179);
+ parents[171] = new BitSet();
+ parents[171].set(171);
+ parents[171].set(194);
+ parents[171].set(209);
+ parents[171].set(251);
+ children[171] = new BitSet();
+ children[171].set(20);
+ children[171].set(26);
+ children[171].set(92);
+ children[171].set(127);
+ children[171].set(171);
+ children[171].set(173);
+ children[171].set(179);
+ parents[172] = new BitSet();
+ parents[172].set(179);
+ children[172] = new BitSet();
+ children[172].set(55);
+ children[172].set(103);
+ children[172].set(110);
+ children[172].set(169);
+ children[172].set(170);
+ children[172].set(179);
+ children[172].set(202);
+ children[172].set(212);
+ children[172].set(214);
+ children[172].set(220);
+ parents[173] = new BitSet();
+ parents[173].set(171);
+ parents[173].set(179);
+ children[173] = new BitSet();
+ children[173].set(54);
+ children[173].set(73);
+ children[173].set(89);
+ children[173].set(93);
+ children[173].set(106);
+ children[173].set(124);
+ parents[174] = new BitSet();
+ children[174] = new BitSet();
+ children[174].set(200);
+ parents[175] = new BitSet();
+ parents[175].set(208);
+ children[175] = new BitSet();
+ children[175].set(39);
+ children[175].set(68);
+ children[175].set(155);
+ children[175].set(169);
+ children[175].set(179);
+ children[175].set(225);
+ parents[176] = new BitSet();
+ parents[176].set(192);
+ parents[176].set(211);
+ parents[176].set(226);
+ parents[176].set(229);
+ children[176] = new BitSet();
+ children[176].set(45);
+ parents[177] = new BitSet();
+ parents[177].set(169);
+ children[177] = new BitSet();
+ children[177].set(59);
+ parents[178] = new BitSet();
+ children[178] = new BitSet();
+ children[178].set(84);
+ children[178].set(216);
+ parents[179] = new BitSet();
+ parents[179].set(165);
+ parents[179].set(167);
+ parents[179].set(169);
+ parents[179].set(170);
+ parents[179].set(171);
+ parents[179].set(172);
+ parents[179].set(175);
+ parents[179].set(179);
+ parents[179].set(180);
+ parents[179].set(188);
+ parents[179].set(193);
+ parents[179].set(199);
+ parents[179].set(207);
+ parents[179].set(209);
+ parents[179].set(219);
+ parents[179].set(228);
+ parents[179].set(230);
+ parents[179].set(235);
+ parents[179].set(240);
+ parents[179].set(242);
+ children[179] = new BitSet();
+ children[179].set(20);
+ children[179].set(21);
+ children[179].set(48);
+ children[179].set(92);
+ children[179].set(101);
+ children[179].set(127);
+ children[179].set(164);
+ children[179].set(167);
+ children[179].set(172);
+ children[179].set(173);
+ children[179].set(179);
+ children[179].set(190);
+ children[179].set(203);
+ children[179].set(207);
+ children[179].set(221);
+ children[179].set(227);
+ children[179].set(230);
+ children[179].set(234);
+ children[179].set(235);
+ children[179].set(241);
+ children[179].set(242);
+ parents[180] = new BitSet();
+ parents[180].set(169);
+ parents[180].set(240);
+ children[180] = new BitSet();
+ children[180].set(39);
+ children[180].set(92);
+ children[180].set(127);
+ children[180].set(179);
+ parents[181] = new BitSet();
+ parents[181].set(200);
+ children[181] = new BitSet();
+ children[181].set(39);
+ children[181].set(63);
+ children[181].set(90);
+ children[181].set(182);
+ children[181].set(212);
+ parents[182] = new BitSet();
+ parents[182].set(181);
+ children[182] = new BitSet();
+ children[182].set(134);
+ children[182].set(192);
+ children[182].set(195);
+ children[182].set(212);
+ parents[183] = new BitSet();
+ parents[183].set(184);
+ children[183] = new BitSet();
+ children[183].set(42);
+ children[183].set(63);
+ children[183].set(84);
+ parents[184] = new BitSet();
+ parents[184].set(200);
+ children[184] = new BitSet();
+ children[184].set(134);
+ children[184].set(183);
+ parents[185] = new BitSet();
+ parents[185].set(186);
+ children[185] = new BitSet();
+ children[185].set(2);
+ children[185].set(187);
+ parents[186] = new BitSet();
+ parents[186].set(165);
+ parents[186].set(203);
+ children[186] = new BitSet();
+ children[186].set(69);
+ children[186].set(185);
+ children[186].set(187);
+ parents[187] = new BitSet();
+ parents[187].set(185);
+ parents[187].set(186);
+ children[187] = new BitSet();
+ children[187].set(64);
+ children[187].set(65);
+ parents[188] = new BitSet();
+ parents[188].set(224);
+ children[188] = new BitSet();
+ children[188].set(71);
+ children[188].set(87);
+ children[188].set(118);
+ children[188].set(119);
+ children[188].set(169);
+ children[188].set(179);
+ children[188].set(224);
+ children[188].set(243);
+ parents[189] = new BitSet();
+ parents[189].set(200);
+ parents[189].set(211);
+ parents[189].set(224);
+ children[189] = new BitSet();
+ children[189].set(169);
+ children[189].set(192);
+ parents[190] = new BitSet();
+ parents[190].set(179);
+ parents[190].set(225);
+ children[190] = new BitSet();
+ children[190].set(53);
+ children[190].set(84);
+ children[190].set(92);
+ children[190].set(127);
+ children[190].set(199);
+ children[190].set(216);
+ children[190].set(231);
+ parents[191] = new BitSet();
+ parents[191].set(192);
+ children[191] = new BitSet();
+ children[191].set(84);
+ parents[192] = new BitSet();
+ parents[192].set(182);
+ parents[192].set(189);
+ children[192] = new BitSet();
+ children[192].set(70);
+ children[192].set(92);
+ children[192].set(127);
+ children[192].set(176);
+ children[192].set(191);
+ children[192].set(202);
+ children[192].set(212);
+ children[192].set(214);
+ children[192].set(220);
+ children[192].set(249);
+ parents[193] = new BitSet();
+ parents[193].set(224);
+ children[193] = new BitSet();
+ children[193].set(62);
+ children[193].set(85);
+ children[193].set(94);
+ children[193].set(169);
+ children[193].set(179);
+ children[193].set(224);
+ children[193].set(243);
+ parents[194] = new BitSet();
+ parents[194].set(224);
+ children[194] = new BitSet();
+ children[194].set(58);
+ children[194].set(85);
+ children[194].set(169);
+ children[194].set(171);
+ parents[195] = new BitSet();
+ parents[195].set(169);
+ parents[195].set(182);
+ parents[195].set(200);
+ parents[195].set(229);
+ children[195] = new BitSet();
+ children[195].set(88);
+ children[195].set(126);
+ children[195].set(210);
+ parents[196] = new BitSet();
+ parents[196].set(197);
+ children[196] = new BitSet();
+ children[196].set(2);
+ children[196].set(222);
+ children[196].set(236);
+ parents[197] = new BitSet();
+ parents[197].set(165);
+ parents[197].set(203);
+ children[197] = new BitSet();
+ children[197].set(21);
+ children[197].set(72);
+ children[197].set(101);
+ children[197].set(196);
+ children[197].set(222);
+ children[197].set(236);
+ parents[198] = new BitSet();
+ parents[198].set(233);
+ children[198] = new BitSet();
+ children[198].set(25);
+ children[198].set(35);
+ children[198].set(64);
+ children[198].set(65);
+ children[198].set(76);
+ children[198].set(77);
+ children[198].set(78);
+ children[198].set(79);
+ children[198].set(80);
+ children[198].set(83);
+ children[198].set(149);
+ children[198].set(150);
+ children[198].set(151);
+ children[198].set(152);
+ children[198].set(153);
+ children[198].set(154);
+ parents[199] = new BitSet();
+ parents[199].set(190);
+ parents[199].set(206);
+ children[199] = new BitSet();
+ children[199].set(39);
+ children[199].set(179);
+ parents[200] = new BitSet();
+ parents[200].set(174);
+ children[200] = new BitSet();
+ children[200].set(181);
+ children[200].set(184);
+ children[200].set(189);
+ children[200].set(195);
+ children[200].set(211);
+ children[200].set(226);
+ children[200].set(234);
+ children[200].set(239);
+ parents[201] = new BitSet();
+ parents[201].set(202);
+ parents[201].set(213);
+ parents[201].set(215);
+ children[201] = new BitSet();
+ children[201].set(95);
+ parents[202] = new BitSet();
+ parents[202].set(172);
+ parents[202].set(192);
+ parents[202].set(226);
+ children[202] = new BitSet();
+ children[202].set(39);
+ children[202].set(89);
+ children[202].set(124);
+ children[202].set(201);
+ parents[203] = new BitSet();
+ parents[203].set(179);
+ parents[203].set(209);
+ parents[203].set(210);
+ children[203] = new BitSet();
+ children[203].set(26);
+ children[203].set(29);
+ children[203].set(141);
+ children[203].set(165);
+ children[203].set(186);
+ children[203].set(197);
+ parents[204] = new BitSet();
+ children[204] = new BitSet();
+ children[204].set(37);
+ children[204].set(51);
+ children[204].set(55);
+ parents[205] = new BitSet();
+ parents[205].set(224);
+ children[205] = new BitSet();
+ children[205].set(98);
+ children[205].set(169);
+ parents[206] = new BitSet();
+ parents[206].set(225);
+ children[206] = new BitSet();
+ children[206].set(20);
+ children[206].set(84);
+ children[206].set(92);
+ children[206].set(127);
+ children[206].set(199);
+ parents[207] = new BitSet();
+ parents[207].set(179);
+ parents[207].set(224);
+ children[207] = new BitSet();
+ children[207].set(13);
+ children[207].set(99);
+ children[207].set(179);
+ children[207].set(208);
+ parents[208] = new BitSet();
+ parents[208].set(207);
+ children[208] = new BitSet();
+ children[208].set(39);
+ children[208].set(90);
+ children[208].set(125);
+ children[208].set(175);
+ children[208].set(209);
+ parents[209] = new BitSet();
+ parents[209].set(208);
+ children[209] = new BitSet();
+ children[209].set(68);
+ children[209].set(85);
+ children[209].set(100);
+ children[209].set(110);
+ children[209].set(118);
+ children[209].set(169);
+ children[209].set(171);
+ children[209].set(179);
+ children[209].set(203);
+ children[209].set(225);
+ children[209].set(244);
+ parents[210] = new BitSet();
+ parents[210].set(195);
+ parents[210].set(210);
+ parents[210].set(212);
+ children[210] = new BitSet();
+ children[210].set(39);
+ children[210].set(62);
+ children[210].set(84);
+ children[210].set(92);
+ children[210].set(127);
+ children[210].set(203);
+ children[210].set(210);
+ parents[211] = new BitSet();
+ parents[211].set(200);
+ parents[211].set(211);
+ children[211] = new BitSet();
+ children[211].set(84);
+ children[211].set(90);
+ children[211].set(102);
+ children[211].set(112);
+ children[211].set(125);
+ children[211].set(176);
+ children[211].set(189);
+ children[211].set(211);
+ children[211].set(212);
+ children[211].set(239);
+ parents[212] = new BitSet();
+ parents[212].set(172);
+ parents[212].set(181);
+ parents[212].set(182);
+ parents[212].set(192);
+ parents[212].set(211);
+ parents[212].set(226);
+ parents[212].set(229);
+ parents[212].set(239);
+ children[212] = new BitSet();
+ children[212].set(15);
+ children[212].set(126);
+ children[212].set(210);
+ parents[213] = new BitSet();
+ parents[213].set(215);
+ parents[213].set(228);
+ parents[213].set(229);
+ children[213] = new BitSet();
+ children[213].set(0);
+ children[213].set(56);
+ children[213].set(104);
+ children[213].set(201);
+ parents[214] = new BitSet();
+ parents[214].set(172);
+ parents[214].set(192);
+ children[214] = new BitSet();
+ children[214].set(0);
+ children[214].set(39);
+ children[214].set(133);
+ children[214].set(215);
+ parents[215] = new BitSet();
+ parents[215].set(214);
+ children[215] = new BitSet();
+ children[215].set(0);
+ children[215].set(38);
+ children[215].set(201);
+ children[215].set(213);
+ children[215].set(233);
+ children[215].set(243);
+ parents[216] = new BitSet();
+ parents[216].set(178);
+ parents[216].set(190);
+ parents[216].set(233);
+ parents[216].set(237);
+ parents[216].set(242);
+ children[216] = new BitSet();
+ children[216].set(217);
+ children[216].set(218);
+ parents[217] = new BitSet();
+ parents[217].set(216);
+ children[217] = new BitSet();
+ children[217].set(53);
+ children[217].set(84);
+ parents[218] = new BitSet();
+ parents[218].set(216);
+ children[218] = new BitSet();
+ children[218].set(53);
+ children[218].set(84);
+ children[218].set(132);
+ children[218].set(144);
+ parents[219] = new BitSet();
+ parents[219].set(225);
+ children[219] = new BitSet();
+ children[219].set(123);
+ children[219].set(179);
+ parents[220] = new BitSet();
+ parents[220].set(172);
+ parents[220].set(192);
+ children[220] = new BitSet();
+ children[220].set(1);
+ children[220].set(232);
+ children[220].set(233);
+ parents[221] = new BitSet();
+ parents[221].set(179);
+ children[221] = new BitSet();
+ children[221].set(135);
+ children[221].set(136);
+ parents[222] = new BitSet();
+ parents[222].set(196);
+ parents[222].set(197);
+ children[222] = new BitSet();
+ children[222].set(76);
+ children[222].set(77);
+ children[222].set(78);
+ children[222].set(79);
+ children[222].set(80);
+ children[222].set(83);
+ parents[223] = new BitSet();
+ parents[223].set(224);
+ children[223] = new BitSet();
+ children[223].set(134);
+ children[223].set(225);
+ parents[224] = new BitSet();
+ parents[224].set(169);
+ parents[224].set(188);
+ parents[224].set(193);
+ children[224] = new BitSet();
+ children[224].set(169);
+ children[224].set(188);
+ children[224].set(189);
+ children[224].set(193);
+ children[224].set(194);
+ children[224].set(205);
+ children[224].set(207);
+ children[224].set(223);
+ children[224].set(251);
+ parents[225] = new BitSet();
+ parents[225].set(175);
+ parents[225].set(209);
+ parents[225].set(223);
+ children[225] = new BitSet();
+ children[225].set(167);
+ children[225].set(190);
+ children[225].set(206);
+ children[225].set(219);
+ children[225].set(240);
+ parents[226] = new BitSet();
+ parents[226].set(200);
+ children[226] = new BitSet();
+ children[226].set(39);
+ children[226].set(84);
+ children[226].set(90);
+ children[226].set(92);
+ children[226].set(125);
+ children[226].set(127);
+ children[226].set(134);
+ children[226].set(142);
+ children[226].set(176);
+ children[226].set(202);
+ children[226].set(212);
+ children[226].set(229);
+ children[226].set(233);
+ parents[227] = new BitSet();
+ parents[227].set(179);
+ children[227] = new BitSet();
+ children[227].set(39);
+ children[227].set(90);
+ children[227].set(125);
+ children[227].set(228);
+ children[227].set(233);
+ parents[228] = new BitSet();
+ parents[228].set(227);
+ children[228] = new BitSet();
+ children[228].set(38);
+ children[228].set(49);
+ children[228].set(84);
+ children[228].set(179);
+ children[228].set(213);
+ parents[229] = new BitSet();
+ parents[229].set(226);
+ children[229] = new BitSet();
+ children[229].set(38);
+ children[229].set(84);
+ children[229].set(176);
+ children[229].set(195);
+ children[229].set(212);
+ children[229].set(213);
+ children[229].set(233);
+ parents[230] = new BitSet();
+ parents[230].set(179);
+ children[230] = new BitSet();
+ children[230].set(39);
+ children[230].set(92);
+ children[230].set(127);
+ children[230].set(179);
+ parents[231] = new BitSet();
+ parents[231].set(190);
+ children[231] = new BitSet();
+ children[231].set(2);
+ children[231].set(89);
+ children[231].set(124);
+ children[231].set(233);
+ parents[232] = new BitSet();
+ parents[232].set(220);
+ children[232] = new BitSet();
+ children[232].set(39);
+ children[232].set(92);
+ children[232].set(127);
+ children[232].set(233);
+ parents[233] = new BitSet();
+ parents[233].set(215);
+ parents[233].set(220);
+ parents[233].set(226);
+ parents[233].set(227);
+ parents[233].set(229);
+ parents[233].set(231);
+ parents[233].set(232);
+ parents[233].set(240);
+ parents[233].set(241);
+ parents[233].set(248);
+ children[233] = new BitSet();
+ children[233].set(84);
+ children[233].set(92);
+ children[233].set(127);
+ children[233].set(198);
+ children[233].set(216);
+ parents[234] = new BitSet();
+ parents[234].set(179);
+ parents[234].set(200);
+ children[234] = new BitSet();
+ children[234].set(157);
+ children[234].set(169);
+ parents[235] = new BitSet();
+ parents[235].set(179);
+ children[235] = new BitSet();
+ children[235].set(90);
+ children[235].set(125);
+ children[235].set(157);
+ children[235].set(179);
+ parents[236] = new BitSet();
+ parents[236].set(196);
+ parents[236].set(197);
+ children[236] = new BitSet();
+ children[236].set(149);
+ children[236].set(150);
+ children[236].set(151);
+ children[236].set(152);
+ children[236].set(153);
+ children[236].set(154);
+ parents[237] = new BitSet();
+ parents[237].set(239);
+ children[237] = new BitSet();
+ children[237].set(216);
+ children[237].set(238);
+ parents[238] = new BitSet();
+ parents[238].set(237);
+ children[238] = new BitSet();
+ children[238].set(2);
+ children[238].set(39);
+ children[238].set(84);
+ children[238].set(90);
+ children[238].set(125);
+ parents[239] = new BitSet();
+ parents[239].set(200);
+ parents[239].set(211);
+ children[239] = new BitSet();
+ children[239].set(112);
+ children[239].set(134);
+ children[239].set(158);
+ children[239].set(212);
+ children[239].set(237);
+ parents[240] = new BitSet();
+ parents[240].set(225);
+ children[240] = new BitSet();
+ children[240].set(62);
+ children[240].set(94);
+ children[240].set(166);
+ children[240].set(179);
+ children[240].set(180);
+ children[240].set(233);
+ children[240].set(241);
+ children[240].set(243);
+ children[240].set(245);
+ children[240].set(246);
+ children[240].set(248);
+ parents[241] = new BitSet();
+ parents[241].set(179);
+ parents[241].set(240);
+ children[241] = new BitSet();
+ children[241].set(2);
+ children[241].set(120);
+ children[241].set(121);
+ children[241].set(233);
+ parents[242] = new BitSet();
+ parents[242].set(167);
+ parents[242].set(179);
+ children[242] = new BitSet();
+ children[242].set(0);
+ children[242].set(13);
+ children[242].set(91);
+ children[242].set(126);
+ children[242].set(179);
+ children[242].set(216);
+ children[242].set(247);
+ parents[243] = new BitSet();
+ parents[243].set(188);
+ parents[243].set(193);
+ parents[243].set(215);
+ parents[243].set(240);
+ parents[243].set(244);
+ parents[243].set(247);
+ parents[243].set(248);
+ children[243] = new BitSet();
+ children[243].set(84);
+ parents[244] = new BitSet();
+ parents[244].set(209);
+ children[244] = new BitSet();
+ children[244].set(39);
+ children[244].set(92);
+ children[244].set(127);
+ children[244].set(155);
+ children[244].set(243);
+ parents[245] = new BitSet();
+ parents[245].set(240);
+ children[245] = new BitSet();
+ children[245].set(39);
+ children[245].set(92);
+ children[245].set(127);
+ children[245].set(248);
+ parents[246] = new BitSet();
+ parents[246].set(240);
+ children[246] = new BitSet();
+ children[246].set(104);
+ children[246].set(122);
+ parents[247] = new BitSet();
+ parents[247].set(242);
+ children[247] = new BitSet();
+ children[247].set(48);
+ children[247].set(243);
+ parents[248] = new BitSet();
+ parents[248].set(240);
+ parents[248].set(245);
+ children[248] = new BitSet();
+ children[248].set(38);
+ children[248].set(155);
+ children[248].set(233);
+ children[248].set(243);
+ parents[249] = new BitSet();
+ parents[249].set(192);
+ children[249] = new BitSet();
+ children[249].set(112);
+ children[249].set(250);
+ parents[250] = new BitSet();
+ parents[250].set(249);
+ children[250] = new BitSet();
+ children[250].set(42);
+ children[250].set(84);
+ children[250].set(87);
+ children[250].set(92);
+ children[250].set(127);
+ children[250].set(143);
+ parents[251] = new BitSet();
+ parents[251].set(224);
+ children[251] = new BitSet();
+ children[251].set(160);
+ children[251].set(169);
+ children[251].set(171);
+ return IntGraph.create(parents, children);
+ }
+
+}
diff --git a/mastfrog-jgrapht-adapter/target/maven-archiver/pom.properties b/mastfrog-jgrapht-adapter/target/maven-archiver/pom.properties
new file mode 100644
index 0000000..aa5721a
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/maven-archiver/pom.properties
@@ -0,0 +1,3 @@
+artifactId=mastfrog-jgrapht-adapter
+groupId=com.mastfrog
+version=2.3
diff --git a/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
new file mode 100644
index 0000000..55c42ad
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -0,0 +1,8 @@
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$Edge.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$WrappedObjectGraph.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$DefaultEdgeFactory.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$WrappedObjectGraph$1.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$DefaultEdgeFactory$Edg.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$EdgeFactory.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapter$DefaultEdge.class
diff --git a/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
new file mode 100644
index 0000000..de8b002
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -0,0 +1 @@
+/home/tom/projects/forkvl-jung/vl-jung/mastfrog-jgrapht-adapter/src/main/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapter.java
diff --git a/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
new file mode 100644
index 0000000..107f54d
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
@@ -0,0 +1,2 @@
+com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.class
+com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest$IXA.class
diff --git a/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
new file mode 100644
index 0000000..f080dfb
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
@@ -0,0 +1 @@
+/home/tom/projects/forkvl-jung/vl-jung/mastfrog-jgrapht-adapter/src/test/java/com/mastfrog/graph/jgrapht/adapter/GraphAdapterTest.java
diff --git a/mastfrog-jgrapht-adapter/target/surefire-reports/TEST-com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest.xml b/mastfrog-jgrapht-adapter/target/surefire-reports/TEST-com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest.xml
new file mode 100644
index 0000000..fa450a6
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/surefire-reports/TEST-com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mastfrog-jgrapht-adapter/target/surefire-reports/com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest.txt b/mastfrog-jgrapht-adapter/target/surefire-reports/com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest.txt
new file mode 100644
index 0000000..e505739
--- /dev/null
+++ b/mastfrog-jgrapht-adapter/target/surefire-reports/com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest.txt
@@ -0,0 +1,4 @@
+-------------------------------------------------------------------------------
+Test set: com.mastfrog.graph.jgrapht.adapter.GraphAdapterTest
+-------------------------------------------------------------------------------
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.062 sec
diff --git a/pom.xml b/pom.xml
index 0f51489..9bf6bec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,6 +11,9 @@
https://github.com:timboudreau/vl-jung2.1.1
+ 1.7.25
+ 1.5.0
+ 1.0bsdRELEASE113UTF-8
@@ -29,6 +32,11 @@
mastfrog-graph-adapteralternate-layouts
+ vl-jungrapht
+ vl-jungrapht-extensions
+ vl-jungrapht-demo
+ vl-jungrapht-nbm
+ mastfrog-jgrapht-adaptergit@github.com:timboudreau/vl-jung.git
@@ -60,6 +68,26 @@
+
+ org.jgrapht
+ jgrapht-core
+ ${version.jgrapht}
+
+
+ com.github.tomnelson
+ jungrapht-layout
+ ${version.jungrapht}
+
+
+ com.github.tomnelson
+ jungrapht-visualization
+ ${version.jungrapht}
+
+
+ org.slf4j
+ slf4j-api
+ ${version.slf4j}
+ com.google.guavaguava
@@ -85,6 +113,11 @@
vl-jung-demo${project.version}
+
+ ${project.groupId}
+ vl-jungrapht-demo
+ ${project.version}
+ org.hamcresthamcrest-core
diff --git a/vl-jung-nbm/pom.xml b/vl-jung-nbm/pom.xml
index b38ba9f..eb412f9 100644
--- a/vl-jung-nbm/pom.xml
+++ b/vl-jung-nbm/pom.xml
@@ -1,6 +1,6 @@
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0com.mastfrog
@@ -39,7 +39,21 @@
tim+github@timboudreau.com
+
+ 1.7.25
+ 1.5.0
+
+
+ org.jgrapht
+ jgrapht-core
+ ${version.jgrapht}
+
+
+ org.slf4j
+ slf4j-api
+ ${version.slf4j}
+ org.netbeans.apiorg-openide-util-lookup
diff --git a/vl-jungrapht-demo/nbactions.xml b/vl-jungrapht-demo/nbactions.xml
new file mode 100644
index 0000000..8ba1618
--- /dev/null
+++ b/vl-jungrapht-demo/nbactions.xml
@@ -0,0 +1,17 @@
+
+
+
+ run
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:1.2.1:exec
+
+
+ -classpath %classpath com.timboudreau.vl.jungrapht.demo.App
+ java
+
+
+
diff --git a/vl-jungrapht-demo/pom.xml b/vl-jungrapht-demo/pom.xml
new file mode 100644
index 0000000..ba95532
--- /dev/null
+++ b/vl-jungrapht-demo/pom.xml
@@ -0,0 +1,73 @@
+
+
+ 4.0.0
+
+ com.mastfrog
+ visual-library-jung
+ 2.3
+
+ vl-jungrapht-demo
+ Visual Library + JunGraphT Demo
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+ com.mastfrog
+ vl-jungrapht
+ ${project.version}
+
+
+ com.mastfrog
+ vl-jungrapht-extensions
+ ${project.version}
+
+
+
+ bsd
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.5.5
+
+
+ jar-with-dependencies
+
+
+ true
+
+ true
+ true
+ true
+ simple
+ com.timboudreau.vl.jungrapht.demo.App
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+ jar-with-dependencies
+
+ vl-jungrapht-demo
+ true
+
+
+
+
+
+
+
diff --git a/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/App.java b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/App.java
new file mode 100644
index 0000000..ee61277
--- /dev/null
+++ b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/App.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2013, Tim Boudreau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.timboudreau.vl.jungrapht.demo;
+
+import com.timboudreau.vl.jungrapht.extensions.BaseJungraphtScene;
+import org.jgrapht.Graph;
+import org.jgrapht.ListenableGraph;
+import org.jgrapht.graph.DefaultListenableGraph;
+import org.jgrapht.graph.builder.GraphTypeBuilder;
+import org.jungrapht.visualization.decorators.EdgeShape;
+import org.jungrapht.visualization.layout.algorithms.BalloonLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.CircleLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.DAGLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.FRLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.ForceAtlas2LayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.GEMLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.ISOMLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.KKLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.RadialTreeLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.SpringLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.SugiyamaLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.TidierRadialTreeLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.TidierTreeLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.TreeLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFA2Repulsion;
+import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFRRepulsion;
+import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutSpringRepulsion;
+import org.jungrapht.visualization.layout.algorithms.sugiyama.Layering;
+import org.jungrapht.visualization.layout.algorithms.util.EdgeArticulationFunctionSupplier;
+import org.jungrapht.visualization.layout.model.Rectangle;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.LookupEvent;
+import org.openide.util.LookupListener;
+
+import javax.swing.*;
+import javax.swing.border.BevelBorder;
+import javax.swing.plaf.nimbus.NimbusLookAndFeel;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Insets;
+import java.awt.Shape;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class App {
+
+ private static final Pattern QUOTES = Pattern.compile("\"(.*?)\"\\s+\"(.*?)\"\\s+");
+ private static final Pattern NO_QUOTES = Pattern.compile("(.*?)\\s+(.*)");
+
+ private static class GraphAndForest {
+
+ private final ListenableGraph graph;
+ private final Graph forest;
+
+ public GraphAndForest(ListenableGraph graph, Graph forest) {
+ this.graph = graph;
+ this.forest = forest;
+ }
+ }
+
+ public static void main(String[] args) throws IOException {
+ try {
+ UIManager.setLookAndFeel(new NimbusLookAndFeel());
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ GraphAndForest gf = loadGraph(args);
+
+ showDemo(gf);
+ }
+
+ public static JFrame showDemo(GraphAndForest gf) throws IOException {
+ return showDemo(gf.graph, gf.forest);
+ }
+
+ public static JFrame showDemo(Graph graph) throws IOException {
+ return showDemo(graph, null);
+ }
+
+ public static JFrame showDemo(Graph graph, Graph forest) throws IOException {
+ final JFrame jf = new JFrame("Visual Library + Jungrapht Demo");
+ jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+// GraphAndForest gf = loadGraph(args);
+
+ LayoutAlgorithm layout;
+
+ try {
+ layout = forest == null ? new KKLayoutAlgorithm<>() : new TreeLayoutAlgorithm<>();
+ } catch (IllegalArgumentException ex) {
+ layout = new KKLayoutAlgorithm<>();
+ }
+ final BaseJungraphtScene scene = new SceneImpl((ListenableGraph)graph, layout);
+ jf.setLayout(new BorderLayout());
+ jf.add(new JScrollPane(scene.createView()), BorderLayout.CENTER);
+
+ JToolBar bar = new JToolBar();
+ bar.setMargin(new Insets(5, 5, 5, 5));
+ bar.setLayout(new FlowLayout(5));
+ DefaultComboBoxModel mdl = new DefaultComboBoxModel<>();
+ mdl.addElement(KKLayoutAlgorithm.builder()
+ .build());
+ mdl.addElement(layout);
+ // all of the tree layout algorithms will work with an arbitrary graph
+ mdl.addElement(new BalloonLayoutAlgorithm());
+ mdl.addElement(new RadialTreeLayoutAlgorithm());
+ mdl.addElement(TidierTreeLayoutAlgorithm.edgeAwareBuilder()
+ .vertexBoundsFunction(v -> Rectangle.of(-10, -10, 20, 20)).build());
+ mdl.addElement(TidierRadialTreeLayoutAlgorithm.edgeAwareBuilder()
+ .vertexBoundsFunction(v -> Rectangle.of(-10, -10, 20, 20)).build());
+ mdl.addElement(CircleLayoutAlgorithm.builder().threaded(false).build());
+ mdl.addElement(FRLayoutAlgorithm.builder().repulsionContractBuilder(BarnesHutFRRepulsion.barnesHutBuilder())
+ .build());
+ mdl.addElement(ISOMLayoutAlgorithm.builder()
+ .build());
+ mdl.addElement(SpringLayoutAlgorithm.builder().repulsionContractBuilder(BarnesHutSpringRepulsion.barnesHutBuilder())
+ .build());
+ mdl.addElement(DAGLayoutAlgorithm.builder().build()
+ );
+ mdl.addElement(GEMLayoutAlgorithm.edgeAwareBuilder()
+ .build());
+ mdl.addElement(ForceAtlas2LayoutAlgorithm.builder()
+ .repulsionContractBuilder(BarnesHutFA2Repulsion.builder().repulsionK(300))
+ .build());
+ mdl.addElement(SugiyamaLayoutAlgorithm.edgeAwareBuilder()
+ .layering(Layering.COFFMAN_GRAHAM)
+ .threaded(false)
+ .build());
+
+ mdl.setSelectedItem(layout);
+ final JCheckBox checkbox = new JCheckBox("Animate iterative layouts");
+
+ scene.setLayoutAnimationFramesPerSecond(48);
+
+ final JComboBox layouts = new JComboBox(mdl);
+ layouts.setRenderer(new DefaultListCellRenderer() {
+ @Override
+ public Component getListCellRendererComponent(JList> jlist, Object o, int i, boolean bln, boolean bln1) {
+ o = o.getClass().getSimpleName();
+ return super.getListCellRendererComponent(jlist, o, i, bln, bln1); //To change body of generated methods, choose Tools | Templates.
+ }
+ });
+ bar.add(new JLabel(" Layout Type"));
+ bar.add(layouts);
+
+ bar.add(new JLabel(" Connection Shape"));
+ DefaultComboBoxModel, String, Shape>> shapes = new DefaultComboBoxModel<>();
+ shapes.addElement(new EdgeShape.QuadCurve<>());
+ shapes.addElement(new EdgeShape.CubicCurve<>());
+ shapes.addElement(new EdgeShape.Line<>());
+ shapes.addElement(new EdgeShape.Box<>());
+
+ final JComboBox, String, Shape>> shapesBox = new JComboBox<>(shapes);
+ shapesBox.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ BiFunction, String, Shape> xform =
+ (BiFunction, String, Shape>) shapesBox.getSelectedItem();
+ scene.setConnectionEdgeShape(xform);
+ }
+ });
+ shapesBox.setRenderer(new DefaultListCellRenderer() {
+ @Override
+ public Component getListCellRendererComponent(JList> jlist, Object o, int i, boolean bln, boolean bln1) {
+ o = o.getClass().getSimpleName();
+ return super.getListCellRendererComponent(jlist, o, i, bln, bln1); //To change body of generated methods, choose Tools | Templates.
+ }
+ });
+ shapesBox.setSelectedItem(new EdgeShape.QuadCurve<>());
+ bar.add(shapesBox);
+
+
+ layouts.addActionListener(ae -> {
+ LayoutAlgorithm layout1 = (LayoutAlgorithm) layouts.getSelectedItem();
+
+ if (layout1 instanceof EdgeArticulationFunctionSupplier) {
+ BiFunction, String, Shape> edgeShapeFunction = EdgeShape.articulatedLine();
+
+ ((EdgeShape.ArticulatedLine) edgeShapeFunction)
+ .setEdgeArticulationFunction(
+ ((EdgeArticulationFunctionSupplier) layout1)
+ .getEdgeArticulationFunction());
+ }
+
+ // These two layouts implement IterativeContext, but they do
+ // not evolve toward anything, they just randomly rearrange
+ // themselves. So disable animation for these.
+ if (layout1 instanceof ISOMLayoutAlgorithm || layout1 instanceof DAGLayoutAlgorithm) {
+ checkbox.setSelected(false);
+ }
+
+ if (layout1 instanceof EdgeArticulationFunctionSupplier) {
+ EdgeArticulationFunctionSupplier edgeArticulationFunctionSupplier =
+ (EdgeArticulationFunctionSupplier) layout1;
+ EdgeShape.ArticulatedLine articulatedLineShape = EdgeShape.articulatedLine();
+ articulatedLineShape.setEdgeArticulationFunction(edgeArticulationFunctionSupplier.getEdgeArticulationFunction());
+ scene.setConnectionEdgeShape(articulatedLineShape);
+ } else {
+ scene.setConnectionEdgeShape((BiFunction) shapes.getSelectedItem());
+ }
+
+ SwingUtilities.invokeLater(() ->
+ scene.setGraphLayout(layout1, true));
+ });
+
+ jf.add(bar, BorderLayout.NORTH);
+ bar.add(new MinSizePanel(scene.createSatelliteView()));
+ bar.setFloatable(false);
+ bar.setRollover(true);
+
+ final JLabel selectionLabel = new JLabel(" ");
+ Lookup.Result selectedNodes = scene.getLookup().lookupResult(String.class);
+ selectedNodes.allInstances();
+ LookupListener listener = new LookupListener() {
+ @Override
+ public void resultChanged(LookupEvent le) {
+ Lookup.Result res = (Lookup.Result) le.getSource();
+ StringBuilder sb = new StringBuilder("");
+ List l = new ArrayList<>(res.allInstances());
+ Collections.sort(l);
+ for (String s : l) {
+ if (sb.length() != 6) {
+ sb.append(", ");
+ }
+ sb.append(s);
+ }
+ sb.append("");
+ selectionLabel.setText(sb.toString());
+ }
+ };
+ selectionLabel.putClientProperty("ll", listener); // ensure it's not garbage collected
+ selectionLabel.putClientProperty("lr", selectedNodes); // ensure it's not garbage collected
+ selectedNodes.addLookupListener(listener);
+ selectedNodes.allInstances();
+
+
+ checkbox.setSelected(true);
+ checkbox.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ scene.setAnimateIterativeLayouts(checkbox.isSelected());
+ }
+ });
+ bar.add(checkbox);
+ bar.add(selectionLabel);
+ selectionLabel.setHorizontalAlignment(SwingConstants.TRAILING);
+
+// jf.setSize(jf.getGraphicsConfiguration().getBounds().width - 120, 700);
+ jf.setSize(new Dimension(1280, 720));
+ jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ jf.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowOpened(WindowEvent we) {
+ scene.relayout(true);
+ scene.validate();
+ }
+ });
+ jf.setVisible(true);
+ return jf;
+ }
+
+ private static class MinSizePanel extends JPanel {
+
+ MinSizePanel(JComponent inner) {
+ setLayout(new BorderLayout());
+ add(inner, BorderLayout.CENTER);
+ setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ }
+
+ public Dimension getPreferredSize() {
+ Dimension result = super.getPreferredSize();
+ result.height = 40;
+ return result;
+ }
+ }
+
+ private static String[] elements(String line, String[] into) {
+ if (line.startsWith("#")) {
+ return null;
+ }
+ Matcher m = QUOTES.matcher(line);
+ if (m.find()) {
+ into[0] = m.group(1);
+ into[1] = m.group(2);
+ return into;
+ } else {
+ m = NO_QUOTES.matcher(line);
+ if (m.find()) {
+ into[0] = m.group(1);
+ into[1] = m.group(2);
+ return into;
+ }
+ }
+ return null;
+ }
+
+ private static GraphAndForest loadGraph(String[] args) throws FileNotFoundException, IOException {
+ if (args.length > 0) {
+ File f = new File(args[0]);
+ if (!f.exists() || !f.isFile() || !f.canRead()) {
+ System.err.println("File does not exist, is not readable, or is not a file: " + f);
+ System.exit(1);
+ }
+ try {
+ Graph forest = GraphTypeBuilder.directed()
+ .buildGraph();
+ String[] arr = new String[2];
+ Set pairs = new HashSet<>();
+ try (BufferedReader br = new BufferedReader(new FileReader(f))) {
+ int ix = 0;
+ for (String line; (line = br.readLine()) != null;) {
+ line = line.trim();
+ String[] items = elements(line, arr);
+ if (items != null) {
+ if (items[0].equals(items[1])) {
+ continue;
+ }
+ String[] x = new String[]{items[0], items[1]};
+ Arrays.sort(x);
+ String key = x[0] + "::" + x[1];
+ if (!pairs.contains(key)) {
+ String edge = Integer.toString(ix);
+ forest.addEdge(items[0], items[1], edge);
+ pairs.add(key);
+ } else {
+ System.out.println("DUP: " + key);
+ }
+ }
+ ix++;
+ }
+ }
+ ListenableGraph g = new DefaultListenableGraph<>(forest);
+ return new GraphAndForest(g, forest);
+ } catch (Exception e) {
+ // Graph has cycles - try undirected
+ e.printStackTrace();
+ Graph graph = GraphTypeBuilder.undirected()
+ .allowingSelfLoops(true)
+ .allowingMultipleEdges(true).buildGraph();
+
+ String[] arr = new String[2];
+ Set pairs = new HashSet<>();
+ try (BufferedReader br = new BufferedReader(new FileReader(f))) {
+ int ix = 0;
+ for (String line; (line = br.readLine()) != null;) {
+ line = line.trim();
+ String[] items = elements(line, arr);
+ if (items != null) {
+ if (items[0].equals(items[1])) {
+ continue;
+ }
+ String edge = Integer.toString(ix);
+ try {
+ String[] x = new String[]{items[0], items[1]};
+ Arrays.sort(x);
+ String key = x[0] + "::" + x[1];
+ if (!pairs.contains(key)) {
+ graph.addEdge(items[0], items[1], edge);
+ pairs.add(key);
+ } else {
+ System.out.println("DUP: " + key);
+ }
+ } catch (IllegalArgumentException ex) {
+ System.err.println(ex.getMessage());
+ }
+ }
+ ix++;
+ }
+ }
+ ListenableGraph g = (ListenableGraph)graph;
+ return new GraphAndForest(g, null);
+ }
+ } else {
+ Graph forest = GraphTypeBuilder.directed()
+ .edgeSupplier(BalloonLayoutDemo.edgeFactory).buildGraph();
+
+ ListenableGraph g = new DefaultListenableGraph(new BalloonLayoutDemo().createTree(forest));
+ return new GraphAndForest(g, forest);
+ }
+ }
+}
diff --git a/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/BalloonLayoutDemo.java b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/BalloonLayoutDemo.java
new file mode 100644
index 0000000..a80bc20
--- /dev/null
+++ b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/BalloonLayoutDemo.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013, Tim Boudreau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.timboudreau.vl.jungrapht.demo;
+
+
+import org.jgrapht.Graph;
+
+import java.util.function.Supplier;
+
+/**
+ * Demonstrates the visualization of a Tree using TreeLayout and BalloonLayout.
+ * An examiner lens performing a hyperbolic transformation of the view is also
+ * included.
+ *
+ * @author Tom Nelson
+ */
+@SuppressWarnings("serial")
+public class BalloonLayoutDemo {
+
+ // Code borrowed from JUNG's demos
+
+ public static Supplier edgeFactory = new Supplier() {
+ int i = 0;
+ public String get() {
+ return Integer.toString(i++);
+ }
+ };
+
+ Graph createTree(Graph graph) {
+ String base = "Base Node";
+ graph.addVertex(base);
+ graph.addVertex("B0");
+ graph.addEdge(base, "B0");
+ graph.addVertex("B1");
+ graph.addEdge(base, "B1");
+ graph.addVertex("B2");
+ graph.addEdge(base, "B2");
+
+ graph.addVertex("C0");
+ graph.addEdge("B0", "C0");
+ graph.addVertex("C1");
+ graph.addEdge("B0", "C1");
+ graph.addVertex("C2");
+ graph.addEdge("B0", "C2");
+ graph.addVertex("C3");
+ graph.addEdge("B0", "C3");
+
+ graph.addVertex("H0");
+ graph.addEdge("C2", "H0");
+ graph.addVertex("H1");
+ graph.addEdge("C2", "H1");
+
+ graph.addVertex("D0");
+ graph.addEdge("B1", "D0");
+ graph.addVertex("D1");
+ graph.addEdge("B1", "D1");
+ graph.addVertex("D2");
+ graph.addEdge("B1", "D2");
+
+ graph.addEdge(base, "D2");
+ graph.addEdge(base, "C3");
+
+ graph.addVertex("E0");
+ graph.addEdge("B2", "E0");
+ graph.addVertex("E1");
+ graph.addEdge("B2", "E1");
+ graph.addVertex("E2");
+ graph.addEdge("B2", "E2");
+
+ graph.addVertex("F0");
+ graph.addEdge("D0", "F0");
+ graph.addVertex("F1");
+ graph.addEdge("D0", "F1");
+ graph.addVertex("F2");
+ graph.addEdge("D0", "F2");
+
+ graph.addVertex("G0");
+ graph.addEdge("D1", "G0");
+ graph.addVertex("G1");
+ graph.addEdge("D1", "G1");
+ graph.addVertex("G2");
+ graph.addEdge("D1", "G2");
+ graph.addVertex("G3");
+ graph.addEdge("D1", "G3");
+ graph.addVertex("G4");
+ graph.addEdge("D1", "G4");
+ graph.addVertex("G5");
+ graph.addEdge("D1", "G5");
+ graph.addVertex("G6");
+ graph.addEdge("D1", "G6");
+ graph.addVertex("G7");
+ graph.addEdge("D1", "G7");
+
+ graph.addVertex("HA1");
+ graph.addEdge(base, "HA1");
+ graph.addVertex("HA2");
+ graph.addEdge(base, "HA2");
+ graph.addVertex("HA3");
+ graph.addEdge(base, "HA3");
+ graph.addVertex("I1");
+ graph.addEdge("HA3", "I1");
+ graph.addVertex("I2");
+ graph.addEdge("HA3", "I2");
+
+ graph.addVertex("J1");
+ graph.addEdge("I2", "J1");
+ graph.addVertex("K0");
+ graph.addVertex("K1");
+ graph.addEdge("K0", "K1");
+ graph.addVertex("K2");
+ graph.addEdge("K0", "K2");
+ graph.addVertex("K3");
+ graph.addEdge("K0", "K3");
+
+ graph.addVertex("J0");
+ graph.addVertex("J1");
+ graph.addEdge("J0", "J1");
+ graph.addVertex("J2");
+ graph.addEdge("J0", "J2");
+ graph.addVertex("J4");
+ graph.addEdge("J1", "J4");
+ graph.addVertex("J3");
+ graph.addEdge("J2", "J3");
+
+ graph.addEdge(base, "J4");
+
+ graph.addVertex("J5");
+ graph.addEdge("J2", "J5");
+ graph.addVertex("J6");
+ graph.addEdge("J4", "J6");
+ graph.addVertex("J7");
+ graph.addEdge("J4", "J7");
+ graph.addVertex("J8");
+ graph.addEdge("J3", "J8");
+ graph.addVertex("B9");
+ graph.addEdge("J6", "B9");
+ return graph;
+ }
+}
diff --git a/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/DemoWidget.java b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/DemoWidget.java
new file mode 100644
index 0000000..8189f51
--- /dev/null
+++ b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/DemoWidget.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2013, Tim Boudreau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.timboudreau.vl.jungrapht.demo;
+
+import com.timboudreau.vl.jungrapht.JungraphtScene;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.RoundRectangle2D;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.api.visual.action.ActionFactory;
+import org.netbeans.api.visual.action.TextFieldInplaceEditor;
+import org.netbeans.api.visual.widget.Widget;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author Tim Boudreau
+ */
+public class DemoWidget extends Widget {
+
+ private Stroke stroke = new BasicStroke(2);
+ private String label = "";
+ final String node;
+ private final Lookup lkp;
+
+ public DemoWidget(JungraphtScene scene, String node) {
+ super(scene);
+ lkp = Lookups.fixed(node);
+ this.node = node;
+ setBackground(new Color(240, 240, 255));
+ setForeground(Color.gray);
+ getActions().addAction(ActionFactory.createInplaceEditorAction(new TextFieldInplaceEditor() {
+
+ @Override
+ public boolean isEnabled(Widget widget) {
+ return true;
+ }
+
+ @Override
+ public String getText(Widget widget) {
+ return label;
+ }
+
+ @Override
+ public void setText(Widget widget, String text) {
+ label = text;
+ revalidate();
+ }
+ }));
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return lkp;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public void setStroke(Stroke stroke) {
+ this.stroke = stroke;
+ }
+
+ private JungraphtScene scene() {
+ return (JungraphtScene) getScene();
+ }
+
+ private Shape getShape() {
+ // Get the node
+ N node = (N) scene().findObject(this);
+ // Grow the shape based on the number of connections
+ int ix = scene().graph().degreeOf(node);
+ // Minimum size 18 pixels, grow by 3 for each connection
+ double w, h;
+ w = h = 18 + (ix * 3);
+
+ double labelWidth = getGraphics().getFontMetrics().stringWidth(label);
+ w = Math.max(w, labelWidth + 18);
+
+// Ellipse2D.Double e = new Ellipse2D.Double(0, 0, w, h);
+ RoundRectangle2D.Double e = new RoundRectangle2D.Double(-w / 2D, -h / 2D, w, h, 8, 8);
+ return e;
+ }
+
+ @Override
+ protected Rectangle calculateClientArea() {
+ // Stroke the shape to make sure we include the line width in our
+ // bounding box
+ return stroke.createStrokedShape(getShape()).getBounds();
+ }
+
+ private Paint getPaint() {
+ Color start = (Color) getBackground();
+ Color end = start.brighter();
+ Rectangle r = getClientArea();
+ float x = r.x;
+ float y = r.y;
+ float x1 = r.x + r.width;
+ float y1 = r.y + r.height;
+ GradientPaint result;
+ if (getScene().getSceneAnimator().isAnimatingBackgroundColor(this)) {
+ // Don't cache transient gradient paints, just ones that will
+ // be used repeatedly
+ result = new GradientPaint(x, y, start, x1, y1, end);
+ } else {
+ result = CACHE.getPaint(x, y, start, x1, y1, end);
+ }
+ return result;
+ }
+
+ @Override
+ protected void paintWidget() {
+ Graphics2D g = getGraphics();
+
+ g.setFont(getFont());
+ g.setStroke(stroke);
+ // First fill the shape
+ Shape shape = getShape();
+ // Set up our gradient
+ g.setPaint(getPaint());
+ g.fill(shape);
+
+ // Now draw the outline
+ g.setPaint(getForeground());
+ g.draw(shape);
+
+ // Now draw toString() on the node
+ float ht = g.getFontMetrics().getHeight();
+ float w = g.getFontMetrics().stringWidth(label);
+ Rectangle r = getClientArea();
+ g.setColor(getTextColor());
+ float y = (float) r.getCenterY() - (ht / 2F);
+ y += g.getFontMetrics().getMaxAscent();
+ float x = (float) r.getCenterX() - (w / 2F);
+ g.drawString(label, x, y);
+
+ // Draw a highlight shape if it is selected
+ if (scene().getSelection().isSelected(scene().findObject(this))) {
+ g.setColor(new Color(150, 150, 250));
+ AffineTransform scale = AffineTransform.getScaleInstance(0.8, 0.8);
+ double width = (shape.getBounds().getWidth() * 0.0125D);
+ scale.concatenate(AffineTransform.getTranslateInstance(width, width));
+ shape = scale.createTransformedShape(shape);
+ g.draw(shape);
+ }
+ }
+
+ private static GPCache CACHE = new GPCache();
+
+ private Color getTextColor() {
+ // Convoluted but works.
+ Color c = (Color) getBackground();
+ // Get the grascale version of the color, so that we handle perceptual
+ // differences in dark/light - a highly saturated blue is bright according
+ // to HSB a dark color is not readable against it
+ ColorSpace grayscale = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+ float[] rgb = new float[]{(float) c.getRed() / 255F,
+ (float) c.getGreen() / 255F, (float) c.getBlue() / 255F};
+// rgb = grayscale.fromRGB(rgb);
+ // Invert the grayscale version of all color components
+ for (int i = 0; i < rgb.length; i++) {
+ rgb[i] = 1F - rgb[i];
+ }
+ // Convert it back to RGB values between 0.0F and 1.0F
+ rgb = grayscale.toRGB(rgb);
+ // Convert it back to a color, doing some additional computation -
+ // we want values very close to 0.5F - neutral gray - not to be
+ // indistinguishable, so have values between 0.3 and 0.7 repel
+ // the value
+ return new Color(toByteValue(rgb[0]), toByteValue(rgb[1]), toByteValue(rgb[2]));
+ }
+
+ private int toByteValue(float f) {
+ float dist = 0.5F - f;
+ // bounce the value away from 0.5
+ if (Math.abs(dist) < 0.4) {
+ f *= 1F - dist;
+ }
+ // multiply it back into a Color value and constrain it within 0-255
+ float result = Math.min(255F, Math.max(0F, f * 255F));
+ return (int) result;
+ }
+
+ /**
+ * GradientPaint allocates a fairly large byte[] raster; since the number of
+ * these needed is finite, we use a cache to reduce memory pressure.
+ */
+ private static class GPCache {
+
+ private final Map paints = new HashMap<>();
+
+ public GradientPaint getPaint(float x, float y, Color start, float x1, float y1, Color end) {
+ // A key that will be unique by the passed parameters
+ String key = (int) x + "-" + (int) y + "-" + (int) x1 + "-" + (int) y1 + ':' + c2s(start) + ',' + c2s(end);
+ GradientPaint p = paints.get(key);
+ if (p == null) {
+ if (paints.size() > 50) {
+ // Don't let the cache get huge
+ paints.clear();
+ }
+ p = new GradientPaint(x, y, start, x1, y1, end);
+ paints.put(key, p);
+ }
+ return p;
+ }
+
+ private String c2s(Color color) {
+ return Integer.toHexString(color.getRGB());
+ }
+ }
+}
diff --git a/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/SceneImpl.java b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/SceneImpl.java
new file mode 100644
index 0000000..507bc30
--- /dev/null
+++ b/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/SceneImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, Tim Boudreau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.timboudreau.vl.jungrapht.demo;
+
+import com.timboudreau.vl.jungrapht.MultiMoveAction;
+import com.timboudreau.vl.jungrapht.ObjectSceneAdapter;
+import com.timboudreau.vl.jungrapht.extensions.BaseJungraphtScene;
+import org.jgrapht.ListenableGraph;
+import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
+import org.netbeans.api.visual.model.ObjectSceneEvent;
+import org.netbeans.api.visual.model.ObjectSceneEventType;
+import org.netbeans.api.visual.widget.LabelWidget;
+import org.netbeans.api.visual.widget.LayerWidget;
+import org.netbeans.api.visual.widget.Widget;
+import org.openide.util.RequestProcessor;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.io.IOException;
+
+/**
+ *
+ * @author Tim Boudreau
+ */
+class SceneImpl extends BaseJungraphtScene {
+
+ private final LayerWidget edgeTooltipLayer = new LayerWidget(this);
+ private final LabelWidget label = new LabelWidget(this);
+
+ public SceneImpl(ListenableGraph graph, LayoutAlgorithm layoutAlgorithm) throws IOException {
+ super(graph, layoutAlgorithm);
+ addChild(edgeTooltipLayer);
+ edgeTooltipLayer.addChild(label);
+ addObjectSceneListener(new HoverListener(), ObjectSceneEventType.OBJECT_HOVER_CHANGED);
+ }
+
+ @Override
+ protected Widget createNodeWidget(String node) {
+ DemoWidget w = new DemoWidget(this, node);
+ w.setLabel(node + "");
+ w.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ w.getActions().addAction(new MultiMoveAction(relatedProvider(), moveProvider()));
+ return w;
+ }
+
+ private class HoverListener extends ObjectSceneAdapter implements Runnable {
+
+ private final RequestProcessor.Task task = RequestProcessor.getDefault().create(this);
+ private Widget widget;
+ private String hover;
+
+ @Override
+ public void run() {
+ if (!EventQueue.isDispatchThread()) {
+ EventQueue.invokeLater(this);
+ } else if (widget != null && hover != null) {
+ Rectangle r = widget.getClientArea();
+ Point p = new Point((int) r.getCenterX(), (int) r.getCenterY());
+ label.setForeground(new Color(255, 255, 255, 0));
+ label.setPreferredLocation(p);
+ getSceneAnimator().animateForegroundColor(label, Color.black);
+ }
+ }
+
+ @Override
+ public void hoverChanged(ObjectSceneEvent event, Object previousHoveredObject, Object newHoveredObject) {
+ if (newHoveredObject instanceof String) {
+ hover = (String) newHoveredObject;
+ widget = findWidget(hover);
+ task.schedule(750);
+ } else {
+ widget = null;
+ hover = null;
+ task.cancel();
+ getSceneAnimator().animateForegroundColor(label, new Color(255, 255, 255, 0));
+ }
+ }
+ }
+}
diff --git a/vl-jungrapht-demo/target/maven-archiver/pom.properties b/vl-jungrapht-demo/target/maven-archiver/pom.properties
new file mode 100644
index 0000000..8d8c704
--- /dev/null
+++ b/vl-jungrapht-demo/target/maven-archiver/pom.properties
@@ -0,0 +1,3 @@
+artifactId=vl-jungrapht-demo
+groupId=com.mastfrog
+version=2.3
diff --git a/vl-jungrapht-demo/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/vl-jungrapht-demo/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
new file mode 100644
index 0000000..d1072f3
--- /dev/null
+++ b/vl-jungrapht-demo/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -0,0 +1,17 @@
+com/timboudreau/vl/jungrapht/demo/App$1.class
+com/timboudreau/vl/jungrapht/demo/App$MinSizePanel.class
+com/timboudreau/vl/jungrapht/demo/App$2.class
+com/timboudreau/vl/jungrapht/demo/App$6.class
+com/timboudreau/vl/jungrapht/demo/SceneImpl.class
+com/timboudreau/vl/jungrapht/demo/App$GraphAndForest.class
+com/timboudreau/vl/jungrapht/demo/App.class
+com/timboudreau/vl/jungrapht/demo/SceneImpl$HoverListener.class
+com/timboudreau/vl/jungrapht/demo/App$5.class
+com/timboudreau/vl/jungrapht/demo/App$4.class
+com/timboudreau/vl/jungrapht/demo/DemoWidget$GPCache.class
+com/timboudreau/vl/jungrapht/demo/DemoWidget.class
+com/timboudreau/vl/jungrapht/demo/BalloonLayoutDemo$1.class
+com/timboudreau/vl/jungrapht/demo/BalloonLayoutDemo.class
+com/timboudreau/vl/jungrapht/demo/SceneImpl$1.class
+com/timboudreau/vl/jungrapht/demo/App$3.class
+com/timboudreau/vl/jungrapht/demo/DemoWidget$1.class
diff --git a/vl-jungrapht-demo/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/vl-jungrapht-demo/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
new file mode 100644
index 0000000..8d88d87
--- /dev/null
+++ b/vl-jungrapht-demo/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -0,0 +1,4 @@
+/home/tom/projects/forkvl-jung/vl-jung/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/SceneImpl.java
+/home/tom/projects/forkvl-jung/vl-jung/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/DemoWidget.java
+/home/tom/projects/forkvl-jung/vl-jung/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/BalloonLayoutDemo.java
+/home/tom/projects/forkvl-jung/vl-jung/vl-jungrapht-demo/src/main/java/com/timboudreau/vl/jungrapht/demo/App.java
diff --git a/vl-jungrapht-extensions/pom.xml b/vl-jungrapht-extensions/pom.xml
new file mode 100644
index 0000000..755d6a3
--- /dev/null
+++ b/vl-jungrapht-extensions/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+
+ com.mastfrog
+ visual-library-jung
+ 2.3
+
+ com.mastfrog
+ vl-jungrapht-extensions
+ 2.3
+ Visual Library JunGraphT Base Classes
+
+
+ org.slf4j
+ slf4j-api
+ ${version.slf4j}
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+ com.mastfrog
+ vl-jungrapht
+ ${project.version}
+
+
+
diff --git a/vl-jungrapht-extensions/src/main/java/com/timboudreau/vl/jungrapht/extensions/BaseJungraphtScene.java b/vl-jungrapht-extensions/src/main/java/com/timboudreau/vl/jungrapht/extensions/BaseJungraphtScene.java
new file mode 100644
index 0000000..f899703
--- /dev/null
+++ b/vl-jungrapht-extensions/src/main/java/com/timboudreau/vl/jungrapht/extensions/BaseJungraphtScene.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2013, Tim Boudreau
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.timboudreau.vl.jungrapht.extensions;
+
+import com.timboudreau.vl.jungrapht.JungraphtConnectionWidget;
+import com.timboudreau.vl.jungrapht.JungraphtScene;
+import com.timboudreau.vl.jungrapht.ObjectSceneAdapter;
+import com.timboudreau.vl.jungrapht.RingsWidget;
+import static com.timboudreau.vl.jungrapht.extensions.States.CONNECTED_TO_SELECTION;
+import static com.timboudreau.vl.jungrapht.extensions.States.HOVERED;
+import static com.timboudreau.vl.jungrapht.extensions.States.INDIRECTLY_CONNECTED_TO_SELECTION;
+import static com.timboudreau.vl.jungrapht.extensions.States.SELECTED;
+import static com.timboudreau.vl.jungrapht.extensions.States.UNRELATED_TO_SELECTION;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import javax.swing.JComponent;
+
+import org.jgrapht.Graph;
+import org.jungrapht.visualization.layout.algorithms.BalloonLayoutAlgorithm;
+import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
+import org.netbeans.api.visual.action.ActionFactory;
+import org.netbeans.api.visual.action.WidgetAction;
+import org.netbeans.api.visual.anchor.Anchor;
+import org.netbeans.api.visual.anchor.AnchorFactory;
+import org.netbeans.api.visual.layout.LayoutFactory;
+import org.netbeans.api.visual.model.ObjectSceneEvent;
+import org.netbeans.api.visual.model.ObjectSceneEventType;
+import org.netbeans.api.visual.model.ObjectState;
+import org.netbeans.api.visual.widget.ConnectionWidget;
+import org.netbeans.api.visual.widget.LayerWidget;
+import org.netbeans.api.visual.widget.Widget;
+import org.netbeans.api.visual.widget.general.IconNodeWidget;
+
+/**
+ * A convenience base class for Jungrapht scenes which draws connections and
+ * handles layers correctly.
+ *
+ * @author Tim Boudreau
+ * @param
+ * @param
+ */
+public class BaseJungraphtScene extends JungraphtScene {
+
+ protected final LayerWidget mainLayer = new LayerWidget(this);
+ protected final LayerWidget connectionLayer = new LayerWidget(this);
+ protected final LayerWidget selectionLayer = new LayerWidget(this);
+ private final HoverAndSelectionHandler hover = new HoverAndSelectionHandler();
+ protected final Widget decorationLayer = new RingsWidget(this);
+ private final GraphTheme colors;
+ private WidgetAction scrollZoom;
+ private WidgetAction edgeClickSelect;
+ private Dimension lastSize = new Dimension();
+
+ public BaseJungraphtScene(Graph graph, LayoutAlgorithm layoutAlgorithm) throws IOException {
+ super(graph, layoutAlgorithm);
+ colors = createColors();
+ // Selection layer is behind everything
+ addChild(selectionLayer);
+ // Rings also drawn behind everything but the selection
+ addChild(decorationLayer);
+ // Connections are drawn below the node widgets
+ addChild(connectionLayer);
+ // The layer where node widgets live
+ addChild(mainLayer);
+
+
+ // Set some layouts
+ connectionLayer.setLayout(LayoutFactory.createAbsoluteLayout());
+ mainLayer.setLayout(LayoutFactory.createAbsoluteLayout());
+ // Zoom on scroll by default
+ getActions().addAction(ActionFactory.createMouseCenteredZoomAction(1.1));
+ getActions().addAction(ActionFactory.createPanAction());
+
+ // Use the built in rectangular selection action
+ getActions().addAction(ActionFactory.createRectangularSelectAction(this,
+ selectionLayer));
+
+ // Add the listener which will notice when we hover and update
+ // the node color
+ addObjectSceneListener(hover, ObjectSceneEventType.OBJECT_HOVER_CHANGED,
+ ObjectSceneEventType.OBJECT_SELECTION_CHANGED);
+ }
+
+ /**
+ * Create a color theme. The default one starts with one color and
+ * modifies it to portray different selection states.
+ * @return A theme
+ */
+ protected GraphTheme createColors() {
+ return new GraphThemeImpl();
+ }
+
+ /**
+ * Re-layout the graph
+ */
+ public void relayout(boolean animate) {
+ JComponent vw = getView();
+ if (vw != null) {
+ int preferredWidth = layoutModel().getPreferredWidth();
+ int preferredHeight = layoutModel().getPreferredHeight();
+ model.setSize(preferredWidth, preferredHeight);
+ }
+ super.performLayout(animate);
+ }
+
+ protected Widget createNodeWidget(N node) {
+ IconNodeWidget result = new IconNodeWidget(this);
+ result.setLabel(node + "");
+ return result;
+ }
+
+ protected void attachActionsToNodeWidget(Widget widget) {
+ widget.getActions().addAction(createNodeMoveAction());
+ widget.getActions().addAction(createObjectHoverAction());
+ widget.getActions().addAction(createSelectAction());
+ widget.getActions().addAction(createSelectByClickAction());
+ }
+
+ @Override
+ protected Widget attachNodeWidget(final N node) {
+ Widget widget = createNodeWidget(node);
+ // Set up the colors and actions
+ widget.setBackground(colors.getBackground());
+ widget.setForeground(colors.getForeground());
+ attachActionsToNodeWidget(widget);
+ mainLayer.addChild(widget);
+ validate();
+ return widget;
+ }
+
+ protected Widget createEdgeWidget(E edge) {
+ JungraphtConnectionWidget w = JungraphtConnectionWidget.createQuadratic(this, edge);
+ return w;
+ }
+
+ @Override
+ protected Widget attachEdgeWidget(final E edge) {
+ Widget w = createEdgeWidget(edge);
+ w.setForeground(colors.getEdgeColor());
+ w.getActions().addAction(createObjectHoverAction());
+ w.getActions().addAction(createEdgeClickSelectAction());
+ connectionLayer.addChild(w);
+ return w;
+ }
+
+ protected WidgetAction createEdgeClickSelectAction() {
+ if (edgeClickSelect == null) {
+ edgeClickSelect = new EdgeClickSelectAction();
+ }
+ return edgeClickSelect;
+ }
+
+ @Override
+ public void onMove(N n, Widget widget) {
+ connectionLayer.repaint();
+ if (layout instanceof BalloonLayoutAlgorithm) {
+ decorationLayer.revalidate();
+ }
+ }
+
+ @Override
+ protected void attachEdgeSourceAnchor(E edge, N oldSourceNode, N sourceNode) {
+ Widget w = findWidget(edge);
+ // Not the case by default, but could be overridden
+ if (w instanceof ConnectionWidget) {
+ Widget sourceNodeWidget = findWidget(sourceNode);
+ Anchor sourceAnchor = AnchorFactory.createCenterAnchor(sourceNodeWidget);
+ ConnectionWidget edgeWidget = (ConnectionWidget) w;
+ edgeWidget.setSourceAnchor(sourceAnchor);
+ }
+ }
+
+ @Override
+ protected void attachEdgeTargetAnchor(E edge, N oldTargetNode, N targetNode) {
+ Widget w = findWidget(edge);
+ // Not the case by default, but could be overridden
+ if (w instanceof ConnectionWidget) {
+ Widget targetNodeWidget = findWidget(targetNode);
+ Anchor targetAnchor = AnchorFactory.createCenterAnchor(targetNodeWidget);
+ ConnectionWidget edgeWidget = (ConnectionWidget) findWidget(edge);
+ edgeWidget.setTargetAnchor(targetAnchor);
+ }
+ }
+
+ /**
+ * Called when an edge stops being hovered
+ * @param edge The edge
+ * @param w The widget
+ */
+ protected void onEdgeUnhover(E edge, Widget w) {
+ Color c = colors.getEdgeColor();
+ getSceneAnimator().animateForegroundColor(w, c);
+ }
+
+ /**
+ * Called when an edge becomes hovered
+ * @param edge The edge
+ * @param w The widget
+ */
+ protected void onEdgeHover(E edge, Widget w) {
+ Color c = colors.getEdgeColor(HOVERED);
+ getSceneAnimator().animateForegroundColor(w, c);
+ }
+
+ /**
+ * Called when a node stops being hovered
+ * @param n The node
+ * @param w The widget
+ */
+ protected void onNodeUnhover(N n, Widget w) {
+ ObjectState state = getObjectState(n);
+ boolean hasSelection = !getSelectedObjects().isEmpty();
+ boolean connected = getSelection().isConnectedToSelection(n);
+ boolean indirect = !connected && !state.isSelected() && getSelection().isIndirectlyConnectedToSelection(n);
+ States[] states = state.isSelected() ? new States[]{SELECTED}
+ : hasSelection ? new States[]{connected ? CONNECTED_TO_SELECTION : indirect ? INDIRECTLY_CONNECTED_TO_SELECTION : UNRELATED_TO_SELECTION} : new States[0];
+ Color c = colors.getEdgeColor(states);
+ for (E edge : findNodeEdges(n, true, false)) {
+ Widget w1 = findWidget(edge);
+ getSceneAnimator().animateForegroundColor(w1, c);
+ }
+ getSceneAnimator().animateBackgroundColor(w, colors.getBackground(states));
+ }
+
+ /**
+ * Called when a node starts being hovered
+ * @param n The node
+ * @param w The widget
+ */
+ protected void onNodeHover(N n, Widget w) {
+ ObjectState state = getObjectState(n);
+ boolean hasSelection = !getSelectedObjects().isEmpty();
+ boolean connected = getSelection().isConnectedToSelection(n);
+ boolean indirect = !connected && !state.isSelected() && getSelection().isIndirectlyConnectedToSelection(n);
+ States[] states = state.isSelected()
+ ? new States[]{SELECTED, HOVERED}
+ : hasSelection
+ ? new States[]{HOVERED, connected ? CONNECTED_TO_SELECTION : indirect ? INDIRECTLY_CONNECTED_TO_SELECTION : UNRELATED_TO_SELECTION}
+ : new States[]{HOVERED};
+
+ Color c = colors.getEdgeColor(states);
+ for (E edge : findNodeEdges(n, true, false)) {
+ Widget w1 = findWidget(edge);
+ getSceneAnimator().animateForegroundColor(w1, c);
+ }
+ getSceneAnimator().animateBackgroundColor(w, colors.getBackground(states));
+ }
+
+ /**
+ * Called when the selection is cleared, once for every node widget
+ * @param w The widget
+ * @param n The node
+ */
+ protected void onSelectionCleared(Widget w, N n) {
+ getSceneAnimator().animateBackgroundColor(w, colors.getBackground(statesFor(null, n)));
+ getSceneAnimator().animateForegroundColor(w, colors.getForeground(statesFor(null, n)));
+ }
+
+ /**
+ * Called when the selection is cleared, once for every edge widget
+ * @param w The widget
+ * @param e The edge
+ */
+ protected void onEdgeSelectionCleared(Widget w, E e) {
+ getSceneAnimator().animateForegroundColor(w, colors.getEdgeColor(statesFor(null, e)));
+ }
+
+ /**
+ * Called when a node becomes selected
+ * @param w The widget
+ * @param n The node
+ */
+ protected void onNodeSelected(Widget w, N n) {
+ getSceneAnimator().animateBackgroundColor(w, colors.getBackground(statesFor(SELECTED, n)));
+ getSceneAnimator().animateForegroundColor(w, colors.getForeground(statesFor(SELECTED, n)));
+ }
+
+ /**
+ * Called when a node connected to this one was selected assuming it is not
+ * also selected
+ * @param w The widget
+ * @param n The node
+ */
+ protected void onNodeConnectedToSelection(Widget w, N n) {
+ getSceneAnimator().animateBackgroundColor(w,
+ colors.getBackground(statesFor(CONNECTED_TO_SELECTION, n)));
+ getSceneAnimator().animateForegroundColor(w,
+ colors.getForeground(statesFor(CONNECTED_TO_SELECTION, n)));
+ }
+
+ /**
+ * Called when a node connected to this one is connected to the selected node,
+ * assuming this one is not selected or directly connected to the selected node
+ * @param w The widget
+ * @param n The node
+ */
+ protected void onNodeIndirectlyConnectedToSelection(Widget w, N n) {
+ getSceneAnimator().animateBackgroundColor(w, colors.getBackground(statesFor(INDIRECTLY_CONNECTED_TO_SELECTION, n)));
+ getSceneAnimator().animateForegroundColor(w, colors.getForeground(statesFor(INDIRECTLY_CONNECTED_TO_SELECTION, n)));
+ }
+
+ /**
+ * Called when a node becomes unconnected to any selected node due to a
+ * selection change
+ * @param w The widget
+ * @param n The node
+ */
+ protected void onNodeUnrelatedToSelection(Widget w, N n) {
+ getSceneAnimator().animateBackgroundColor(w, colors.getBackground(statesFor(UNRELATED_TO_SELECTION, n)));
+ getSceneAnimator().animateForegroundColor(w, colors.getForeground(statesFor(UNRELATED_TO_SELECTION, n)));
+ }
+
+ /**
+ * Called when an edge becomes connected to the selection due to a selection
+ * change
+ * @param e The edge
+ */
+ protected void onEdgeConnectedToSelection(E e) {
+ getSceneAnimator().animateForegroundColor(findWidget(e), colors.getEdgeColor(statesFor(CONNECTED_TO_SELECTION, e)));
+ }
+
+ /**
+ * Called when an edge becomes connected to a node which is connected to the
+ * selection but not selected itself, due to a selection change
+ * @param e The edge
+ */
+ protected void onEdgeIndirectlyConnectedToSelection(E e) {
+ getSceneAnimator().animateForegroundColor(findWidget(e), colors.getEdgeColor(statesFor(INDIRECTLY_CONNECTED_TO_SELECTION, e)));
+ }
+
+ /**
+ * Get the set of states which apply to this object, in terms of an array
+ * of States.
+ * @param curr A state to include in the reuslt if non-null
+ * @param o The object - may be an edge or node
+ * @return
+ */
+ public States[] statesFor(States curr, Object o) {
+ ObjectState st = getObjectState(o);
+ if (st.isHovered()) {
+ return curr == null ? new States[]{States.HOVERED} : new States[]{curr, States.HOVERED};
+ } else {
+ return curr == null ? new States[0] : new States[]{curr};
+ }
+ }
+
+ private class HoverAndSelectionHandler extends ObjectSceneAdapter {
+
+ @Override
+ public void hoverChanged(ObjectSceneEvent event, Object previousHoveredObject, Object newHoveredObject) {
+ @SuppressWarnings("element-type-mismatch")
+ boolean wasEdge = getEdges().contains(previousHoveredObject);
+ @SuppressWarnings("element-type-mismatch")
+ boolean wasNode = getNodes().contains(previousHoveredObject);
+ @SuppressWarnings("element-type-mismatch")
+ boolean isEdge = getEdges().contains(newHoveredObject);
+ @SuppressWarnings("element-type-mismatch")
+ boolean isNode = getNodes().contains(newHoveredObject);
+ if (wasEdge) {
+ E edge = (E) previousHoveredObject;
+ onEdgeUnhover(edge, findWidget(edge));
+ } else if (wasNode) {
+ N node = (N) previousHoveredObject;
+ onNodeUnhover(node, findWidget(node));
+ }
+ if (isEdge) {
+ E edge = (E) newHoveredObject;
+ onEdgeHover(edge, findWidget(edge));
+ } else if (isNode) {
+ N node = (N) newHoveredObject;
+ onNodeHover(node, findWidget(node));
+ }
+ }
+
+ @Override
+ public void selectionChanged(ObjectSceneEvent event, Set