001 // GraphLab Project: http://graphlab.sharif.edu 002 // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology 003 // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/ 004 package graphlab.graph.graph; 005 006 import graphlab.graph.atributeset.GraphNotifiableAttrSet; 007 import graphlab.graph.event.GraphModelListener; 008 import graphlab.platform.attribute.AttributeListener; 009 import graphlab.platform.core.BlackBoard; 010 011 import javax.swing.*; 012 import java.awt.*; 013 import java.awt.image.BufferedImage; 014 import java.util.HashSet; 015 016 /** 017 * The basic renderer interface 018 */ 019 public abstract class AbstractGraphRenderer extends JPanel implements GraphModelListener, AttributeListener { 020 public static final String EVENT_KEY = "Graph View"; 021 HashSet<PaintHandler> postPaintHandlers = new HashSet<PaintHandler>(); 022 private GraphModel graph; 023 boolean ignoreRapaints; 024 int minx, miny; 025 boolean isGraphChanged = true; 026 private HashSet<PaintHandler<AbstractGraphRenderer>> prePaintHandlers = new HashSet<PaintHandler<AbstractGraphRenderer>>(); 027 028 public static AbstractGraphRenderer getCurrentGraphRenderer(BlackBoard b) { 029 return b.getData(EVENT_KEY); 030 } 031 032 protected AbstractGraphRenderer() { 033 super(); 034 } 035 036 public void setGraph(GraphModel g) { 037 this.graph = g; 038 g.addGraphListener(this); 039 new GraphNotifiableAttrSet(g).addAttributeListener(this); 040 } 041 042 public GraphModel getGraph() { 043 return graph; 044 } 045 046 /** 047 * adds ph to Post Paint Handlers which means that ph.paint will be called after each rendering of graph 048 * 049 * @param ph 050 */ 051 public void addPostPaintHandler(PaintHandler<AbstractGraphRenderer> ph) { 052 postPaintHandlers.add(ph); 053 } 054 055 /** 056 * adds ph to Pre Paint Handlers which means that ph.paint will be called before each rendering of graph 057 * 058 * @param ph 059 */ 060 public void addPrePaintHandler(PaintHandler<AbstractGraphRenderer> ph) { 061 prePaintHandlers.add(ph); 062 } 063 064 /** 065 * removes ph from both pre and post paint handlers and then repaints the graph 066 * 067 * @param ph 068 */ 069 public void removePaintHandler(PaintHandler ph) { 070 postPaintHandlers.remove(ph); 071 prePaintHandlers.remove(ph); 072 repaint(); 073 } 074 075 public abstract void render(Graphics2D gg, Boolean drawExtras); 076 077 public void repaint() { 078 if (!ignoreRapaints) { 079 super.repaint(); 080 } 081 } 082 083 BufferedImage bi; 084 int lastWidth = 0, lastHeight = 0; 085 boolean xtrans = false, ytrans = false; 086 087 final public void paint(Graphics gg) { 088 paint(gg, true); 089 } 090 091 /** 092 * paint the graph on gg 093 * 094 * @param mainG 095 * @param e 096 * @param graph 097 * @param y 098 * @param labelx 099 * @param drawExtras specifies wheter to draw extra things such as Curved Edges Control Points, on graph or not, 100 */ 101 final public void paint(Graphics mainG, Boolean drawExtras) { 102 int w = getWidth(); 103 int h = getHeight(); 104 if (w * h > 1000 * 1500) { //the limit which creating a bufferimage and double buffering consumes too much memory 105 doRender(mainG, w, h, mainG, drawExtras); 106 isGraphChanged = false; 107 bi = null; 108 } else { 109 if (w != lastWidth || h != lastHeight) 110 isGraphChanged = true; 111 // showTime(0); 112 if (isGraphChanged || bi == null) { 113 // showTime(20); 114 if (w != lastWidth || h != lastHeight) { 115 bi = this.getGraphicsConfiguration().createCompatibleImage(getWidth(), getHeight()); 116 lastWidth = w; 117 lastHeight = h; 118 } 119 120 // showTime(21); 121 Graphics bufferedG = bi.getGraphics(); 122 doRender(bufferedG, w, h, mainG, drawExtras); 123 124 } else { 125 // showTime(10); 126 //painting the buffered graph 127 128 doTranslate(mainG); 129 for (PaintHandler p : prePaintHandlers) 130 p.paint(mainG, this, drawExtras); 131 translateBack(mainG); 132 133 134 mainG.drawImage(bi, 0, 0, this); 135 // showTime(11); 136 doTranslate(mainG); 137 for (PaintHandler p : postPaintHandlers) 138 p.paint(mainG, this, drawExtras); 139 translateBack(mainG); 140 // showTime(12); 141 return; 142 } 143 isGraphChanged = false; 144 } 145 146 } 147 148 private void translateBack(Graphics mainG) { 149 if (xtrans) { 150 mainG.translate(minx, 0); 151 } 152 if (ytrans) { 153 mainG.translate(0, miny); 154 } 155 } 156 157 private void doTranslate(Graphics mainG) { 158 xtrans = false; 159 ytrans = false; 160 if (minx < 0) { 161 mainG.translate(-minx, 0); 162 xtrans = true; 163 } 164 if (miny < 0) { 165 mainG.translate(0, -miny); 166 ytrans = true; 167 } 168 } 169 170 private void doRender(Graphics bufferedG, int w, int h, Graphics mainG, Boolean drawExtras) { 171 boolean xtrans = false, ytrans = false; 172 if (!ignoreRapaints) { 173 if (minx < 0) { 174 bufferedG.translate(-minx, 0); 175 // mainG.translate(-minx, 0); 176 xtrans = true; 177 } 178 if (miny < 0) { 179 bufferedG.translate(0, -miny); 180 // mainG.translate(0, -miny); 181 ytrans = true; 182 } 183 // showTime(3); 184 bufferedG.setColor(Color.white); 185 186 // g.setClip(minx, miny, w, h); 187 bufferedG.fillRect(minx, miny, w + Math.abs(minx), h + Math.abs(miny)); 188 // showTime(4); 189 // g.clearRect(0,0, getWidth(), getHeight()); 190 191 for (PaintHandler p : prePaintHandlers) 192 p.paint(mainG, this, drawExtras); 193 render((Graphics2D) bufferedG, drawExtras); 194 // showTime(5); 195 196 mainG.drawImage(bi, 0, 0, this); 197 // showTime(6); 198 for (PaintHandler p : postPaintHandlers) 199 p.paint(mainG, this, drawExtras); 200 } 201 if (!ignoreRapaints) { 202 if (xtrans) { 203 bufferedG.translate(minx, 0); 204 // mainG.translate(minx, 0); 205 } 206 if (ytrans) { 207 bufferedG.translate(0, miny); 208 // mainG.translate(0, miny); 209 } 210 } 211 } 212 213 long lastTime; 214 215 void showTime(int i) { 216 if (i == 0) { 217 lastTime = System.currentTimeMillis(); 218 } 219 // System.out.println(i + ":" + (System.currentTimeMillis() - lastTime)); 220 lastTime = System.currentTimeMillis(); 221 } 222 223 /** 224 * ignores every repaint event on running the run 225 * <p/> 226 * This method is useful when you want to do a great 227 * change on graph structure 228 * <p/> 229 * It is equal to call ignoreRepaints(run, true) 230 * 231 * @param run 232 */ 233 public void ignoreRepaints(Runnable run) { 234 ignoreRepaints(run, true); 235 } 236 237 /** 238 * Runs run.run() and ignore all repaints until Its execution finishes 239 * 240 * @param run 241 * @param repaintAfter 242 */ 243 public void ignoreRepaints(Runnable run, boolean repaintAfter) { 244 this.ignoreRapaints = true; 245 run.run(); 246 this.ignoreRapaints = false; 247 isGraphChanged = true; 248 if (repaintAfter) 249 repaint(); 250 } 251 252 //currently listenin to graph attributes 253 public void attributeUpdated(String name, Object oldVal, Object newVal) { 254 isGraphChanged = true; 255 } 256 257 public void repaintGraph() { 258 isGraphChanged = true; 259 repaint(); 260 } 261 262 263 public int getMinx() { 264 return minx; 265 } 266 267 public int getMiny() { 268 return miny; 269 } 270 }