source: trunk/src/org/expeditee/agents/GraphFramesetLinks.java@ 1102

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

File size: 9.5 KB
Line 
1/**
2 * GraphFramesetLinks.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.agents;
20
21import java.util.List;
22
23import org.expeditee.actions.Misc;
24import org.expeditee.core.Colour;
25import org.expeditee.core.Font;
26import org.expeditee.gio.gesture.StandardGestureActions;
27import org.expeditee.gui.DisplayController;
28import org.expeditee.gui.Frame;
29import org.expeditee.gui.FrameIO;
30import org.expeditee.gui.FrameUtils;
31import org.expeditee.items.Item;
32import org.expeditee.items.Line;
33import org.expeditee.items.Text;
34
35import com.mxgraph.layout.mxCircleLayout;
36import com.mxgraph.layout.mxCompactTreeLayout;
37import com.mxgraph.layout.mxFastOrganicLayout;
38import com.mxgraph.layout.mxGraphLayout;
39import com.mxgraph.layout.mxOrganicLayout;
40import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
41import com.mxgraph.model.mxCell;
42import com.mxgraph.model.mxGeometry;
43import com.mxgraph.model.mxGraphModel;
44import com.mxgraph.view.mxGraph;
45
46/**
47 * Generates a graph/visualization of the current frameset in terms of how frames are linked to each other
48 * The layout type used (tree, organic, circle, hierarchical, or the default, fastorganic) can be specified
49 * when calling the action (e.g. 'GraphFramesetLinks circle').
50 * <br >
51 * Uses JGraphX to compute the graph layout
52 * @author ngw8
53 *
54 */
55public class GraphFramesetLinks extends DefaultAgent {
56
57 private String layoutMethod;
58
59 public GraphFramesetLinks(String layoutMethod) {
60 this.layoutMethod = layoutMethod;
61 }
62
63 public GraphFramesetLinks() {
64 this.layoutMethod = "";
65 }
66
67 @Override
68 protected Frame process(Frame frame) {
69 String toProcessFramesetName = frame.getFramesetName();
70
71 Frame toProccess = FrameUtils.getFrame(toProcessFramesetName + 0);
72
73 Frame resultsFrame;
74
75 String resultsFramesetName = "LinksGraphResults";
76
77 Colour vertColor = Colour.FromRGB255(51,145,148);
78 Colour unlinkedVertColor = Colour.FromRGB255(251,107,65);
79 Colour outgoingVertColor = Colour.FromRGB255(246,216,107);
80 Colour lineColor = Colour.FromRGBA255(0,0,0, 20);
81
82 try {
83 // Creating frameset that is used to hold any generated link graphs
84 FrameIO.CreateNewFrameset(resultsFramesetName);
85 } catch (Exception e2) {
86 // frameset already exists
87 }
88
89 resultsFrame = FrameIO.CreateFrame(resultsFramesetName, toProcessFramesetName, null);
90 resultsFrame.removeAllItems(resultsFrame.getAllItems());
91
92 mxGraph graph = new mxGraph();
93 mxGraphModel model = (mxGraphModel) graph.getModel();
94 mxGraphLayout layout;
95
96 // Deciding which layout method to use
97 if(this.layoutMethod.equalsIgnoreCase("organic")) {
98 layout = new mxOrganicLayout(graph);
99 } else if (this.layoutMethod.equalsIgnoreCase("circle")) {
100 layout = new mxCircleLayout(graph);
101 } else if (this.layoutMethod.equalsIgnoreCase("tree")) {
102 layout = new mxCompactTreeLayout(graph);
103 ((mxCompactTreeLayout)layout).setLevelDistance(30);
104 } else if(this.layoutMethod.equalsIgnoreCase("hierarchical")) {
105 layout = new mxHierarchicalLayout(graph);
106 } else {
107 layout = new mxFastOrganicLayout(graph);
108 }
109
110 model.beginUpdate();
111
112 try {
113 while ((toProccess = FrameIO.LoadNext(toProccess)) != null) {
114
115 Object sourceVert = model.getCell(toProccess.getName());
116
117 if (sourceVert == null) {
118 sourceVert = graph.insertVertex(graph.getDefaultParent(), toProccess.getName(), toProccess.getName(), 0, 0, 10, 10);
119 }
120
121 List<Item> items = toProccess.getItems();
122
123 for (Item item : items) {
124 if (item.getLink() != null) {
125
126 Object destinationVert = model.getCell(item.getAbsoluteLink());
127
128 if (destinationVert == null) {
129 destinationVert = graph.insertVertex(graph.getDefaultParent(), item.getAbsoluteLink(), item.getAbsoluteLink(), 0, 0, 10, 10);
130 }
131
132 // Scaling the vertex based on the number of incoming links
133 mxGeometry destGeo = ((mxCell)(destinationVert)).getGeometry();
134 destGeo.setHeight(destGeo.getHeight() + 1);
135 destGeo.setWidth(destGeo.getHeight());
136
137 graph.insertEdge(graph.getDefaultParent(), null, null, sourceVert, destinationVert);
138 }
139 }
140 }
141
142 layout.execute(graph.getDefaultParent());
143
144 } finally {
145 graph.getModel().endUpdate();
146 }
147
148 Object[] verts = graph.getChildVertices(graph.getDefaultParent());
149
150 for (Object v : verts) {
151 mxGeometry geo = graph.getCellGeometry(v);
152
153 Item circleCenter = resultsFrame.addDot((int) geo.getCenterX(),(int) geo.getCenterY());
154
155 Text circleEdge = (Text) resultsFrame.addText((int) geo.getX(), (int) geo.getCenterY(), "@c", null, ((mxCell) v).getId());
156
157 Line circle = new Line(circleCenter, circleEdge, resultsFrame.getNextItemID());
158
159 circleCenter.setLink(((mxCell) v).getId());
160 circleCenter.setTooltip("text: " + ((mxCell) v).getId());
161 circleCenter.setTooltip("text: In: " + mxGraphModel.getDirectedEdgeCount(model, v, false));
162 circleCenter.setTooltip("text: Out: " + mxGraphModel.getDirectedEdgeCount(model, v, true));
163
164 circleCenter.setThickness(0);
165 circleCenter.setFillColor(vertColor);
166
167 // If the vert is not in the current frameset, style it differently to denote this
168 if (!((String) model.getValue(v)).replaceAll("\\d+$", "").equals(toProcessFramesetName)) {
169 circleCenter.setFillColor(outgoingVertColor);
170 }
171
172 // If there are no incoming edges (i.e. no frames link to the frame the vert represents), style it differently to denote this
173 if (mxGraphModel.getDirectedEdgeCount(model, v, false) <= 0) {
174 circleCenter.setFillColor(unlinkedVertColor);
175 }
176
177 resultsFrame.addItem(circle);
178 }
179
180 Object[] edges = graph.getChildEdges(graph.getDefaultParent());
181
182 for (Object e : edges) {
183 mxGeometry sourceGeo = graph.getCellGeometry(((mxCell) e).getTerminal(true));
184 mxGeometry destGeo = graph.getCellGeometry(((mxCell) e).getTerminal(false));
185
186 // create the endpoints of the edge/line
187 Item lineEnd = resultsFrame.createDot();
188 Item lineStart = resultsFrame.createDot();
189
190 lineStart.setPosition((int) sourceGeo.getCenterX(), (int) sourceGeo.getCenterY());
191 lineEnd.setPosition((int) destGeo.getCenterX(), (int) destGeo.getCenterY());
192
193 lineStart.anchor();
194 lineEnd.anchor();
195
196 lineEnd.setArrowheadLength(10);
197
198 // create the edge/line
199 Line line = new Line(lineStart, lineEnd, resultsFrame.getNextItemID());
200
201 line.setColor(lineColor);
202 line.setThickness(1);
203
204 // The edge/line currently has its endpoints at the vert centers, which doesn't look nice, so this shifts them out to the edge of the verts/circles
205 float ratio = (float) (destGeo.getWidth() / (2 * line.getLength()));
206 int x3 = Math.round(ratio* ((line.getStartItem().getX() - line.getEndItem().getX())));
207 int y3 = Math.round(ratio * ((line.getStartItem().getY() - line.getEndItem().getY())));
208
209 line.getEndItem().setX(line.getEndItem().getX() + x3);
210 line.getEndItem().setY(line.getEndItem().getY() + y3);
211
212 // Have to redo the calculation for the source vert, as it could have a different size
213 ratio = (float) (sourceGeo.getWidth() / (2 * line.getLength()));
214 x3 = Math.round(ratio* ((line.getEndItem().getX() - line.getStartItem().getX())));
215 y3 = Math.round(ratio * ((line.getEndItem().getY() - line.getStartItem().getY())));
216
217 line.getStartItem().setX(line.getStartItem().getX() + x3);
218 line.getStartItem().setY(line.getStartItem().getY() + y3);
219
220 resultsFrame.addItem(line);
221 }
222
223 Font keyFont = new Font("SansSerif");
224 keyFont.setSize(14);
225
226 Text keyLink = resultsFrame.addText(0, 0, "\u2192 = Link", null);
227 Text keyFrame = resultsFrame.addText(0, 0, "\u25CF = Frame", null);
228 Text keyFrameUnlinked = resultsFrame.addText(0, 0, "\u25CF = Frame with no incoming links", null);
229 Text keyFrameOutgoing = resultsFrame.addText(0, 0, "\u25CF = Frame in a different frameset", null);
230
231 keyLink.setFont(keyFont);
232 keyLink.setColor(Colour.DARK_GREY);
233
234 keyFrame.setFont(keyFont);;
235 keyFrame.setColor(vertColor);
236
237 keyFrameUnlinked.setFont(keyFont);
238 keyFrameUnlinked.setColor(unlinkedVertColor);
239
240 keyFrameOutgoing.setFont(keyFont);
241 keyFrameOutgoing.setColor(outgoingVertColor);
242
243 keyFrameOutgoing.setAnchorBottom(10);
244 keyFrameUnlinked.setAnchorBottom(30);
245 keyFrame.setAnchorBottom(50);
246 keyLink.setAnchorBottom(70);
247
248 keyFrameOutgoing.setAnchorLeft(10);
249 keyFrameUnlinked.setAnchorLeft(10);
250 keyFrame.setAnchorLeft(10);
251 keyLink.setAnchorLeft(10);
252
253 // Moving to the area of the frame that contains the graph
254 Misc.pan(resultsFrame, - (int) graph.getGraphBounds().getX(), - (int) graph.getGraphBounds().getY());
255
256 FrameIO.SaveFrame(resultsFrame);
257
258 Text link = new Text(toProcessFramesetName + " graph");
259 link.setLink(resultsFrame.getName());
260 link.setPosition(DisplayController.getMousePosition());
261 StandardGestureActions.pickup(link);
262 return null;
263 }
264}
Note: See TracBrowser for help on using the repository browser.