cz/vutbr/fit/dudka/SGVis/Visual/GraphView.java

Go to the documentation of this file.
00001 package cz.vutbr.fit.dudka.SGVis.Visual;
00002 
00011 import java.net.URL;
00012 import java.util.HashSet;
00013 import java.util.Iterator;
00014 
00015 import javax.swing.event.ChangeListener;
00016 
00017 import prefuse.Constants;
00018 import prefuse.Visualization;
00019 import prefuse.action.ActionList;
00020 import prefuse.action.GroupAction;
00021 import prefuse.action.ItemAction;
00022 import prefuse.action.RepaintAction;
00023 import prefuse.action.animate.ColorAnimator;
00024 import prefuse.action.animate.PolarLocationAnimator;
00025 import prefuse.action.animate.QualityControlAnimator;
00026 import prefuse.action.animate.VisibilityAnimator;
00027 import prefuse.action.assignment.ColorAction;
00028 import prefuse.action.assignment.FontAction;
00029 import prefuse.action.layout.CollapsedSubtreeLayout;
00030 import prefuse.action.layout.graph.NodeLinkTreeLayout;
00031 import prefuse.activity.SlowInSlowOutPacer;
00032 import prefuse.data.Graph;
00033 import prefuse.data.Node;
00034 import prefuse.data.Table;
00035 import prefuse.data.expression.ColumnExpression;
00036 import prefuse.data.tuple.TupleSet;
00037 import prefuse.render.AbstractShapeRenderer;
00038 import prefuse.render.DefaultRendererFactory;
00039 import prefuse.render.EdgeRenderer;
00040 import prefuse.render.LabelRenderer;
00041 import prefuse.util.ColorLib;
00042 import prefuse.util.FontLib;
00043 import prefuse.util.collections.IntIterator;
00044 import prefuse.visual.VisualItem;
00045 import prefuse.visual.expression.InGroupPredicate;
00046 import cz.vutbr.fit.dudka.SGVis.Config;
00047 import cz.vutbr.fit.dudka.SGVis.Data.Relation;
00048 import cz.vutbr.fit.dudka.SGVis.Data.RelationStorage;
00049 
00058 public class GraphView {
00059 
00060   private RelationStorage storage;
00061   private Table table;
00062   private Graph graph;
00063   private NodeTable nodeTable;
00064   private Visualization vis;
00065   private StatusManager status;
00066   private HashSet<String> expandedHosts;
00067 
00068   public GraphView() {
00069     vis = new Visualization();
00070     status = new StatusManager(this);
00071     storage = new RelationStorage();
00072     nodeTable = new NodeTable();
00073     expandedHosts = new HashSet<String>();
00074 
00075     table = new Table();
00076     table.addColumn("text", String.class);
00077     table.addColumn("type", String.class);
00078     graph = new Graph(table,true);
00079 
00080     // -- set up visualization --
00081     vis.add("tree", graph);
00082     vis.setInteractive("tree.edges", null, false);
00083 
00084     // -- set up renderers --
00085     LabelRenderer nodeRenderer = new LabelRenderer("text");
00086     nodeRenderer.setRenderType(AbstractShapeRenderer.RENDER_TYPE_FILL);
00087     nodeRenderer.setHorizontalAlignment(Constants.CENTER);
00088     nodeRenderer.setRoundedCorner(8,8);
00089     EdgeRenderer edgeRenderer = new EdgeRenderer(
00090         Constants.EDGE_TYPE_LINE,
00091         Constants.EDGE_ARROW_FORWARD
00092     );
00093     edgeRenderer.setArrowHeadSize(6, 10);
00094     DefaultRendererFactory rf = new DefaultRendererFactory(nodeRenderer);
00095     rf.add(new InGroupPredicate("tree.edges"), edgeRenderer);
00096     vis.setRendererFactory(rf);
00097 
00098     // -- set up processing actions --
00099 
00100     // colors
00101     ItemAction nodeColor = new NodeColorAction("tree.nodes");
00102     ItemAction textColor = new TextColorAction("tree.nodes");
00103     vis.putAction("textColor", textColor);
00104 
00105     ColorAction edgeColor = new ColorAction("tree.edges",
00106         VisualItem.STROKECOLOR, ColorLib.rgb(200,200,200));
00107 
00108     ColorAction arrowColor = new ColorAction("tree.edges",
00109         VisualItem.FILLCOLOR, ColorLib.rgb(100,100,100));
00110 
00111 
00112     FontAction fonts = new FontAction("tree.nodes", 
00113         FontLib.getFont("Tahoma", 10));
00114     //fonts.add(new InGroupPredicate("_focus_"), FontLib.getFont("Tahoma", 11));
00115 
00116     // recolor
00117     ActionList recolor = new ActionList();
00118     recolor.add(nodeColor);
00119     recolor.add(textColor);
00120     vis.putAction("recolor", recolor);
00121 
00122     // repaint
00123     ActionList repaint = new ActionList();
00124     repaint.add(recolor);
00125     repaint.add(new RepaintAction());
00126     vis.putAction("repaint", repaint);
00127 
00128     // animate paint change
00129     ActionList animatePaint = new ActionList(400);
00130     animatePaint.add(new ColorAnimator("tree.nodes"));
00131     animatePaint.add(new RepaintAction());
00132     vis.putAction("animatePaint", animatePaint);
00133 
00134     // create the tree layout action
00135     NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout("tree");
00136     vis.putAction("treeLayout", treeLayout);
00137     CollapsedSubtreeLayout subLayout = new CollapsedSubtreeLayout("tree");
00138     vis.putAction("subLayout", subLayout);
00139 
00140     // create the filtering and layout
00141     ActionList filter = new ActionList();
00142     filter.add(new TreeRootAction("tree"));
00143     filter.add(fonts);
00144     filter.add(treeLayout);
00145     filter.add(subLayout);
00146     filter.add(textColor);
00147     filter.add(nodeColor);
00148     filter.add(edgeColor);
00149     filter.add(arrowColor);
00150     vis.putAction("filter", filter);
00151 
00152     // animated transition
00153     ActionList animate = new ActionList(1250);
00154     animate.setPacingFunction(new SlowInSlowOutPacer());
00155     animate.add(new QualityControlAnimator());
00156     animate.add(new VisibilityAnimator("tree"));
00157     animate.add(new PolarLocationAnimator("tree.nodes", "linear"));
00158     animate.add(new ColorAnimator("tree.nodes"));
00159     animate.add(new RepaintAction());
00160     vis.putAction("animate", animate);
00161     vis.alwaysRunAfter("filter", "animate");
00162   }
00163 
00168   public Visualization getVisualization() {
00169     return vis;
00170   }
00171 
00176   public IntIterator edgeRows(int row) {
00177     return graph.edgeRows(row);
00178   }
00179 
00184   public RelationStorage getStorage() {
00185     return storage;
00186   }
00187   
00191   public int getNodeCount() {
00192     return graph.getNodeCount();
00193   }
00194   
00198   public int getEdgeCount() {
00199     return graph.getEdgeCount();
00200   }
00201   
00206   public void clear() {
00207     LookupWorker.killAll();
00208     vis.cancel("animatePaint");
00209     graph.clear();
00210     table.clear();
00211     storage = new RelationStorage();
00212     nodeTable.clear();
00213     expandedHosts.clear();
00214     vis.run("repaint");
00215   }
00216 
00217   private void updateVisual() {
00218     vis.cancel("animatePaint");
00219     final String errText = "Too many nodes opened. Try to collapse some hosts, if you experience long latency."; 
00220     if (graph.getNodeCount()>Config.getNodeCountWarn())
00221       status.showErrror(errText);
00222     else if (status.getStatus().equals(errText))
00223       status.showStatus(" ");
00224     vis.run("filter");
00225   }
00226 
00232   public void removeNode(int node) {
00233     removeNodePrivate(node);
00234     vis.run("repaint");
00235   }
00236 
00237   private void removeNodePrivate(int node) {
00238     nodeTable.remove(node);
00239     graph.removeNode(node);
00240   }
00241 
00242   private void removeGroup(String host) {
00243     if (nodeTable.contains(host)) {
00244       this.removeNodePrivate(nodeTable.getId(host));
00245     } else {
00246       for (URL url: storage.getUrls(host)) {
00247         String urlString = url.toString();
00248         if (nodeTable.contains(urlString)) {
00249           this.removeNodePrivate(nodeTable.getId(urlString));
00250         }
00251       }
00252     }
00253     this.expandedHosts.remove(host);
00254   }
00255 
00256 
00257   private void addGroup(String host, boolean collapsed) {
00258     if (collapsed) {
00259       if (nodeTable.contains(host))
00260         return;
00261 
00262       int row = table.addRow();
00263       table.setString(row, 0, host);
00264       table.setString(row, 1, "G");
00265       nodeTable.add(host, row);
00266 
00267       for (URL url: storage.getUrls(host)) {
00268         this.addNodeEdges(url);
00269       }
00270     } else {
00271       for (URL url: storage.getUrls(host)) {
00272         String urlString = url.toString();
00273         if (nodeTable.contains(urlString))
00274           continue;
00275 
00276         int row = table.addRow();
00277         table.setString(row, 0, urlString);
00278         table.setString(row, 1, "U");
00279         nodeTable.add(urlString, row);
00280 
00281         this.addNodeEdges(url);
00282       }
00283       this.expandedHosts.add(host);
00284     }
00285   }
00286 
00287   private void addNodeEdges(URL url) {
00288     for (Relation rel: storage.getAllIncidents(url)) {
00289       // Obtain host-only and full url strings
00290       String fromUrl = rel.from.toString();
00291       String fromHost = RelationStorage.urlToHost(rel.from);
00292       String toUrl = rel.to.toString();
00293       String toHost = RelationStorage.urlToHost(rel.to);
00294 
00295       // check source node
00296       int s;
00297       if (nodeTable.contains(fromUrl))
00298         s = nodeTable.getId(fromUrl);
00299       else if (nodeTable.contains(fromHost))
00300         s = nodeTable.getId(fromHost);
00301       else
00302         continue;
00303 
00304       // check target node
00305       int t;
00306       if (nodeTable.contains(toUrl))
00307         t = nodeTable.getId(toUrl);
00308       else if (nodeTable.contains(toHost))
00309         t = nodeTable.getId(toHost);
00310       else
00311         continue;
00312 
00313       if (s!=t) {
00314         graph.addEdge(s,t);
00315       }
00316     }
00317   }
00318 
00323   public void collapseHost(String host) {
00324     vis.cancel("animatePaint");
00325     this.removeGroup(host);
00326     this.addGroup(host, true);
00327     updateVisual();
00328   }
00329 
00334   public void expandHost(String host) {
00335     vis.cancel("animatePaint");
00336     this.removeGroup(host);
00337     this.addGroup(host, false);
00338     updateVisual();
00339   }
00340 
00344   public void zoomToFit() {
00345     vis.cancel("animatePaint");
00346     vis.run("zoomToFit");
00347   }
00348 
00353   public void lookup(URL url) {
00354     status.setStatus("Looking for " + url.toString());
00355     LookupWorker.run(url, this);
00356   }
00357 
00363   void handleResponse(RelationStorage current, URL url) {
00364     //setStatus("--- LookupWorker succesfully finished");
00365     storage.add(current);
00366     //setStatus("--- Response added to global storage");
00367     int count = graph.getNodeCount();
00368     boolean bEmpty = true;
00369     for(String host: current.getHosts()) {
00370       //setStatus("--- Adding group: " + host);
00371       this.addGroup(host, !expandedHosts.contains(host));
00372       bEmpty = false;
00373     }
00374     
00375     if (bEmpty)
00376       status.showStatus("Empty lookup for "+url.toString());
00377     else
00378       status.showStatus("Lookup complete for "+url.toString());
00379 
00380     if (count != graph.getNodeCount())
00381       this.updateVisual();
00382   }
00383 
00388   public void addStatusListener(ChangeListener listener) {
00389     status.addListener(listener);
00390   }
00391   
00396   public void showStatus(String text) {
00397     status.showStatus(text);
00398   }
00399   
00403   public String getStatus() {
00404     return status.getStatus();
00405   }
00406   
00410   public boolean isStatusError() {
00411     return status.isStatusError();
00412   }
00413   
00418   void lookupError(URL url) {
00419     status.showErrror("Lookup failed for "+url.toString());
00420   }
00421   
00422   
00423   // ------------------------------------------------------------------------
00424 
00429   private class TreeRootAction extends GroupAction {
00430     public TreeRootAction(String graphGroup) {
00431       super(graphGroup);
00432     }
00433     public void run(double frac) {
00434       TupleSet focus = m_vis.getGroup(Visualization.FOCUS_ITEMS);
00435       if ( focus==null || focus.getTupleCount() == 0 )
00436         return;
00437       Graph g = (Graph)m_vis.getGroup(m_group);
00438       Node f = null;
00439       Iterator tuples = focus.tuples();
00440       while (tuples.hasNext() && !g.containsTuple(f=(Node)tuples.next()))
00441         f = null;
00442       if ( f == null )
00443         return;
00444       g.getSpanningTree(f);
00445     }
00446   }
00447 
00451   private class NodeColorAction extends ColorAction {
00452     public NodeColorAction(String group) {
00453       super(group, VisualItem.FILLCOLOR, ColorLib.rgba(255,255,255,0));
00454       add(new ColumnExpression("_hover"), ColorLib.rgb(210,210,210));
00455       add(new ColumnExpression("_highlight"), ColorLib.rgb(210,210,210));
00456     }
00457 
00458   } // end of inner class NodeColorAction
00459 
00463   private class TextColorAction extends ColorAction {
00464     public TextColorAction(String group) {
00465       super(group, VisualItem.TEXTCOLOR, ColorLib.gray(0));
00466       add(new ColumnExpression("_hover"), ColorLib.rgb(255,0,0));
00467     }
00468   } // end of inner class TextColorAction
00469 
00470 } // end of class RadialGraphView

Generated on Sat May 3 22:56:09 2008 for SGVis by  doxygen 1.5.4