Skip to content

Commit b9a9255

Browse files
committed
added #HierarchicalGraphView api and unit tests
1 parent edea848 commit b9a9255

14 files changed

+2576
-142
lines changed

store/src/main/java/org/gephi/graph/api/GraphModel.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
*/
1616
package org.gephi.graph.api;
1717

18+
import org.gephi.graph.impl.GraphModelImpl;
19+
import org.joda.time.DateTimeZone;
20+
1821
import java.io.DataInput;
1922
import java.io.DataOutput;
2023
import java.io.IOException;
21-
import org.gephi.graph.impl.GraphModelImpl;
22-
import org.joda.time.DateTimeZone;
2324

2425
/**
2526
* Graph API's entry point.
@@ -351,6 +352,13 @@ public static void write(DataOutput output, GraphModel graphModel) throws IOExce
351352
*/
352353
public GraphView createView(boolean node, boolean edge);
353354

355+
/**
356+
* Creates a new hierarchical graph view.
357+
*
358+
* @return newly created hierarchical graph view
359+
*/
360+
public HierarchicalGraphView createHierarchicalView();
361+
354362
/**
355363
* Creates a new graph view based on an existing view.
356364
*
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.gephi.graph.api;
2+
3+
/**
4+
* A hierarchical graph view which allows for collapsible sub-groups. Each node,
5+
* whether it is collapsed or extended, should be in core in view. If a node is
6+
* node is hidden by collapsed parent, it will omitted within
7+
* directed/undirected graph queries.
8+
*/
9+
public interface HierarchicalGraphView extends GraphView {
10+
/**
11+
* @return Return iterator for each hierarchical node group.
12+
*/
13+
Iterable<HierarchicalNodeGroup> getGroups();
14+
15+
/**
16+
* @return Return root node which first-tier nodes should be attached.
17+
*/
18+
HierarchicalNodeGroup getRoot();
19+
20+
/**
21+
* @param node node within graph graph
22+
* @return Return existing hierarchical group if available; else null.
23+
*/
24+
HierarchicalNodeGroup getGroup(Node node);
25+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.gephi.graph.api;
2+
3+
/**
4+
* A group of nodes within a hierarchical graph view.
5+
*/
6+
public interface HierarchicalNodeGroup {
7+
/**
8+
* @return Returns true if the group is collapsed, which means the children
9+
* are hidden from visible graph.
10+
*/
11+
boolean isCollapsed();
12+
13+
/**
14+
* @return Returns true if the group is expanded, which means the children
15+
* are visible within visible graph.
16+
*/
17+
boolean isExpanded();
18+
19+
/**
20+
* Expand node, displaying children.
21+
*/
22+
void expand();
23+
24+
/**
25+
* Collapse node, hiding children.
26+
*/
27+
void collapse();
28+
29+
/**
30+
* @return Return iterator containing children nodes (not recursive).
31+
*/
32+
Iterable<Node> getNodes();
33+
34+
/**
35+
* @return Return iterator containing children nodes.
36+
*/
37+
Iterable<Node> getNodes(boolean recursive);
38+
39+
/**
40+
* Add node to this group.
41+
*
42+
* @param node child node
43+
* @return Returns child hierarchical group, if created; else null.
44+
*/
45+
HierarchicalNodeGroup addNode(Node node);
46+
47+
/**
48+
* Remove node from group.
49+
*
50+
* @param node child node
51+
* @return Returns true if child hierarchical group was remoce; else false.
52+
*/
53+
boolean removeNode(Node node);
54+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.gephi.graph.impl;
2+
3+
import org.gephi.graph.api.DirectedSubgraph;
4+
import org.gephi.graph.api.Graph;
5+
import org.gephi.graph.api.GraphObserver;
6+
import org.gephi.graph.api.GraphView;
7+
import org.gephi.graph.api.Interval;
8+
import org.gephi.graph.api.UndirectedSubgraph;
9+
10+
abstract public class AbstractGraphView implements GraphView {
11+
protected final GraphStore graphStore;
12+
13+
protected final GraphAttributesImpl attributes;
14+
15+
protected final boolean nodeView;
16+
17+
protected final boolean edgeView;
18+
19+
private Interval interval;
20+
21+
private int storeId = GraphViewStore.NULL_VIEW;
22+
23+
public AbstractGraphView(final GraphStore store, boolean nodes, boolean edges) {
24+
this.graphStore = store;
25+
this.nodeView = nodes;
26+
this.edgeView = edges;
27+
this.interval = Interval.INFINITY_INTERVAL;
28+
this.attributes = new GraphAttributesImpl();
29+
}
30+
31+
public AbstractGraphView(final AbstractGraphView view, boolean nodes, boolean edges) {
32+
this.graphStore = view.graphStore;
33+
this.nodeView = nodes;
34+
this.edgeView = edges;
35+
this.interval = view.interval;
36+
this.attributes = new GraphAttributesImpl();
37+
}
38+
39+
public int getStoreId() {
40+
return this.storeId;
41+
}
42+
43+
protected void setStoreId(final int id) {
44+
this.storeId = id;
45+
}
46+
47+
@Override
48+
public boolean isDestroyed() {
49+
return GraphViewStore.NULL_VIEW == this.storeId;
50+
}
51+
52+
@Override
53+
public GraphModelImpl getGraphModel() {
54+
return this.graphStore.graphModel;
55+
}
56+
57+
@Override
58+
public boolean isMainView() {
59+
return false;
60+
}
61+
62+
@Override
63+
public boolean isNodeView() {
64+
return this.nodeView;
65+
}
66+
67+
@Override
68+
public boolean isEdgeView() {
69+
return this.edgeView;
70+
}
71+
72+
public void setTimeInterval(Interval interval) {
73+
if (interval == null) {
74+
interval = Interval.INFINITY_INTERVAL;
75+
}
76+
this.interval = interval;
77+
}
78+
79+
@Override
80+
public Interval getTimeInterval() {
81+
return this.interval;
82+
}
83+
84+
abstract public DirectedSubgraph getDirectedGraph();
85+
86+
abstract public UndirectedSubgraph getUndirectedGraph();
87+
88+
abstract public boolean deepEquals(AbstractGraphView view);
89+
90+
abstract public int deepHashCode();
91+
92+
abstract protected void viewDestroyed();
93+
94+
abstract protected void nodeAdded(NodeImpl node);
95+
96+
abstract protected void nodeRemoved(NodeImpl node);
97+
98+
abstract protected void edgeAdded(EdgeImpl edge);
99+
100+
abstract protected void edgeRemoved(EdgeImpl edge);
101+
102+
abstract protected GraphObserverImpl createGraphObserver(Graph graph, boolean withDiff);
103+
104+
abstract protected void destroyGraphObserver(GraphObserver graphObserver);
105+
}

store/src/main/java/org/gephi/graph/impl/GraphModelImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.gephi.graph.impl;
1717

1818
import org.gephi.graph.api.Configuration;
19+
import org.gephi.graph.api.HierarchicalGraphView;
1920
import org.gephi.graph.api.Index;
2021
import org.gephi.graph.api.Table;
2122
import org.gephi.graph.api.TimeFormat;
@@ -238,6 +239,11 @@ public GraphView createView(boolean node, boolean edge) {
238239
return store.viewStore.createView(node, edge);
239240
}
240241

242+
@Override
243+
public HierarchicalGraphView createHierarchicalView() {
244+
return store.viewStore.createHierarchicalView();
245+
}
246+
241247
@Override
242248
public GraphView copyView(GraphView view) {
243249
return store.viewStore.createView(view);

store/src/main/java/org/gephi/graph/impl/GraphStore.java

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,56 +15,74 @@
1515
*/
1616
package org.gephi.graph.impl;
1717

18-
import java.util.ArrayList;
19-
import java.util.Collection;
20-
import java.util.Iterator;
21-
import java.util.List;
22-
import java.util.Set;
2318
import org.gephi.graph.api.Configuration;
24-
import org.gephi.graph.api.Origin;
25-
import org.gephi.graph.api.TimeFormat;
26-
import org.gephi.graph.api.Interval;
27-
import org.gephi.graph.api.types.TimestampSet;
2819
import org.gephi.graph.api.DirectedGraph;
2920
import org.gephi.graph.api.DirectedSubgraph;
3021
import org.gephi.graph.api.Edge;
3122
import org.gephi.graph.api.EdgeIterable;
3223
import org.gephi.graph.api.Graph;
3324
import org.gephi.graph.api.GraphModel;
3425
import org.gephi.graph.api.GraphView;
26+
import org.gephi.graph.api.Interval;
3527
import org.gephi.graph.api.Node;
3628
import org.gephi.graph.api.NodeIterable;
29+
import org.gephi.graph.api.Origin;
3730
import org.gephi.graph.api.Subgraph;
38-
import org.joda.time.DateTimeZone;
31+
import org.gephi.graph.api.TimeFormat;
3932
import org.gephi.graph.api.TimeRepresentation;
4033
import org.gephi.graph.api.types.IntervalSet;
34+
import org.gephi.graph.api.types.TimestampSet;
35+
import org.joda.time.DateTimeZone;
36+
37+
import java.util.ArrayList;
38+
import java.util.Collection;
39+
import java.util.Iterator;
40+
import java.util.List;
41+
import java.util.Set;
4142

4243
public class GraphStore implements DirectedGraph, DirectedSubgraph {
4344

4445
protected final GraphModelImpl graphModel;
46+
4547
protected final Configuration configuration;
48+
4649
// Stores
4750
protected final NodeStore nodeStore;
51+
4852
protected final EdgeStore edgeStore;
53+
4954
protected final EdgeTypeStore edgeTypeStore;
55+
5056
protected final TableImpl<Node> nodeTable;
57+
5158
protected final TableImpl<Edge> edgeTable;
59+
5260
protected final GraphViewStore viewStore;
61+
5362
protected final TimeStore timeStore;
63+
5464
protected final GraphAttributesImpl attributes;
65+
5566
// Factory
5667
protected final GraphFactoryImpl factory;
68+
5769
// Lock
5870
protected final GraphLock lock;
71+
5972
// Version
6073
protected final GraphVersion version;
74+
6175
protected final List<GraphObserverImpl> observers;
76+
6277
// Undirected
6378
protected final UndirectedDecorator undirectedDecorator;
79+
6480
// Main Graph view
6581
protected final GraphView mainGraphView;
82+
6683
// TimeFormat
6784
protected TimeFormat timeFormat;
85+
6886
// Time zone
6987
protected DateTimeZone timeZone;
7088

@@ -822,6 +840,7 @@ public boolean deepEquals(GraphStore obj) {
822840
protected class NodeIterableWrapper implements NodeIterable {
823841

824842
protected final Iterator<Node> iterator;
843+
825844
protected final boolean blocking;
826845

827846
public NodeIterableWrapper(Iterator<Node> iterator) {
@@ -842,7 +861,10 @@ public Iterator<Node> iterator() {
842861
public Node[] toArray() {
843862
List<Node> list = new ArrayList<Node>();
844863
for (; iterator.hasNext();) {
845-
list.add(iterator.next());
864+
Node node = iterator.next();
865+
if (node != null) {
866+
list.add(node);
867+
}
846868
}
847869
return list.toArray(new Node[0]);
848870
}
@@ -851,7 +873,10 @@ public Node[] toArray() {
851873
public Collection<Node> toCollection() {
852874
List<Node> list = new ArrayList<Node>();
853875
for (; iterator.hasNext();) {
854-
list.add(iterator.next());
876+
Node node = iterator.next();
877+
if (node != null) {
878+
list.add(node);
879+
}
855880
}
856881
return list;
857882
}
@@ -867,6 +892,7 @@ public void doBreak() {
867892
protected class EdgeIterableWrapper implements EdgeIterable {
868893

869894
protected final Iterator<Edge> iterator;
895+
870896
protected final boolean blocking;
871897

872898
public EdgeIterableWrapper(Iterator<Edge> iterator) {

store/src/main/java/org/gephi/graph/impl/GraphViewDecorator.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
*/
1616
package org.gephi.graph.impl;
1717

18-
import java.util.Collection;
19-
import java.util.Iterator;
20-
import java.util.Set;
2118
import org.gephi.graph.api.DirectedSubgraph;
2219
import org.gephi.graph.api.Edge;
2320
import org.gephi.graph.api.EdgeIterable;
@@ -30,6 +27,10 @@
3027
import org.gephi.graph.api.Subgraph;
3128
import org.gephi.graph.api.UndirectedSubgraph;
3229

30+
import java.util.Collection;
31+
import java.util.Iterator;
32+
import java.util.Set;
33+
3334
public class GraphViewDecorator implements DirectedSubgraph, UndirectedSubgraph {
3435

3536
protected final boolean undirected;
@@ -736,10 +737,10 @@ void checkValidViewObject(final GraphView view) {
736737
if (view == null) {
737738
throw new NullPointerException();
738739
}
739-
if (!(view instanceof GraphViewImpl)) {
740-
throw new ClassCastException("Object must be a GraphViewImpl object");
740+
if (!(view instanceof AbstractGraphView)) {
741+
throw new ClassCastException("Object must be a AbstractGraphView object");
741742
}
742-
if (((GraphViewImpl) view).graphStore != graphStore) {
743+
if (((AbstractGraphView) view).graphStore != graphStore) {
743744
throw new RuntimeException("The view doesn't belong to this store");
744745
}
745746
}

0 commit comments

Comments
 (0)