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

Last change on this file since 919 was 919, checked in by jts21, 10 years ago

Added license headers to all files, added full GPL3 license file, moved license header generator script to dev/bin/scripts

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