KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > nightlabs > editor2d > figures > OversizedBufferFreeformLayer


1 /**
2  * <p> Project: com.nightlabs.editor2d </p>
3  * <p> Copyright: Copyright (c) 2004 </p>
4  * <p> Company: NightLabs GmbH (Germany) </p>
5  * <p> Creation Date: 14.12.2004 </p>
6  * <p> Author: Daniel Mazurek </p>
7  *
8  **/

9 package com.nightlabs.editor2d.figures;
10
11 import java.awt.Color JavaDoc;
12 import java.awt.Graphics2D JavaDoc;
13 import java.awt.image.BufferedImage JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.LinkedList JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.apache.log4j.Logger;
19 import org.eclipse.draw2d.Figure;
20 import org.eclipse.draw2d.FreeformFigure;
21 import org.eclipse.draw2d.FreeformListener;
22 import org.eclipse.draw2d.Graphics;
23 import org.eclipse.draw2d.IFigure;
24 import org.eclipse.draw2d.J2DGraphics;
25 import org.eclipse.draw2d.Layer;
26 import org.eclipse.draw2d.geometry.Point;
27 import org.eclipse.draw2d.geometry.Rectangle;
28 import org.eclipse.gef.EditPart;
29 import org.eclipse.gef.EditPartViewer;
30 import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
31 import org.eclipse.swt.widgets.Control;
32 import org.holongate.j2d.J2DRegistry;
33
34 import com.nightlabs.editor2d.util.EditorUtil;
35
36 /**
37  * Buffers its contents for optimized painting.
38  *
39  * @author Daniel Mazurek
40  * @author Alexander Bieber <alex[AT]nightlabs[DOT]de>
41  */

42 public class OversizedBufferFreeformLayer
43 extends Layer
44 implements FreeformFigure, BufferedFreeformLayer
45 {
46     public static final Logger LOGGER = Logger.getLogger(OversizedBufferFreeformLayer.class);
47     
48     // private FreeformHelper helper = new FreeformHelper(this);
49
private LayerFreeformHelper helper = new LayerFreeformHelper(this);
50     
51     /**
52      * The offscreen buffer
53      */

54     private BufferedImage JavaDoc bufferedImage;
55     /**
56      * The control is needed to know the buffers needed size
57      */

58     private Control viewerControl;
59     /**
60      * The editpart is needed for EditorUtil methods and
61      * to retrieve the control. It is passed to the constructor
62      */

63     private EditPart editPart;
64     /**
65      * Current zoom, buffer will be cleared if the
66      * editPart's zoom differes from that
67      */

68     private double currentZoom = 1.0;
69     /**
70      * The scroll offset at the time when the buffer was (re)created
71      */

72     private Point bufferedScrollOffset;
73     /**
74      * The current size of the associated Control
75      */

76     private Point currentSize = new Point(0,0);
77     /**
78      * The current size of the buffer
79      */

80     private Point bufferSize = new Point(0,0);
81     /**
82      * The translation within the buffer caused by its size
83      * given in coordinatates of the controls
84      * system so not scaled with the current zoom
85      */

86     private Point bufferTranslation = new Point(0,0);
87     /**
88      * The origin within the buffer for the copy operation used in paint
89      */

90     private Point bufferOrigin = new Point(0,0);
91     /**
92      * To be able to paint children even if not an instance of DrawComponentFigure
93      */

94     private List JavaDoc nonDCFChildren = new LinkedList JavaDoc();
95     
96     
97     protected Point calculateBufferFactors() {
98         Point result = new Point(1,1);
99         Point realSizeBounds = EditorUtil.toAbsolute(editPart, currentSize.x, currentSize.y);
100         Point so = EditorUtil.getScrollOffset(editPart);
101 // Point realSO = EditorUtil.toAbsolute(editPart, so.x, so.y);
102
Rectangle childBound = getChildBounds();
103         if (childBounds == null)
104             return result;
105         if (realSizeBounds.x >= childBound.width && realSizeBounds.y >= childBound.height) {
106             // all children fit in the control
107
// do not overdimension buffer
108
return result;
109         }
110         else {
111             int addX = 1;
112             int addY = 1;
113             if (so.x > 0)
114                 addX = 2;
115             if (so.y > 0)
116                 addY = 2;
117             result.setLocation(
118                     Math.min(4, (childBound.width / realSizeBounds.x)+addX),
119                     Math.min(4, (childBound.height / realSizeBounds.y)+addY)
120                 );
121         }
122         LOGGER.debug("Calculated buffer factors: "+result);
123         return result;
124     }
125     
126     /**
127      * Returns the offscreen buffer (recrates if neccassary) and sets
128      * {@link #bufferOrigin} to the correct value concerning the
129      * current scroll offset.
130      *
131      * @return The offscreen buffer
132      */

133     protected BufferedImage JavaDoc getBufferedImage() {
134         
135         double tmpZoom = EditorUtil.getZoom(editPart);
136         if (tmpZoom != currentZoom) {
137             // clear buffer if zoom changed
138
currentZoom = EditorUtil.getZoom(editPart);
139             clearBuffer();
140         }
141         if (bufferedScrollOffset == null) {
142             clearBuffer();
143         }
144         if (bufferedImage == null) {
145             long time = System.currentTimeMillis();
146             currentSize.setLocation(viewerControl.getSize().x, viewerControl.getSize().x);
147             Point factors = calculateBufferFactors();
148             bufferSize.setLocation(currentSize.x * factors.x, currentSize.y*factors.y);
149             if (bufferedImage == null) {
150                 bufferedImage = new BufferedImage JavaDoc(bufferSize.x, bufferSize.y, BufferedImage.TYPE_INT_ARGB);
151             }
152             Graphics2D JavaDoc bufferedGraphics = bufferedImage.createGraphics();
153 // bufferedGraphics.copyArea()
154
try {
155                 bufferedGraphics.setClip(null);
156                 bufferedGraphics.scale(currentZoom, currentZoom);
157                 bufferedScrollOffset = EditorUtil.getScrollOffset(editPart);
158                 Point offsetTranslation = EditorUtil.toAbsolute(
159                         editPart,
160                         bufferedScrollOffset.x,
161                         bufferedScrollOffset.y
162                 );
163                 bufferTranslation.setLocation((bufferSize.x - currentSize.x) / 2, (bufferSize.y - currentSize.y) / 2);
164                 Point absoluteBufferTranslation = EditorUtil.toAbsolute(
165                         editPart,
166                         bufferTranslation.x,
167                         bufferTranslation.y
168                         
169                 );
170                 bufferedGraphics.translate(
171                         absoluteBufferTranslation.x-offsetTranslation.x,
172                         absoluteBufferTranslation.y-offsetTranslation.y
173                 );
174                 J2DRegistry.initGraphics(bufferedGraphics);
175                 nonDCFChildren.clear();
176                 for (Iterator JavaDoc iter = getChildren().iterator(); iter.hasNext();) {
177                     Figure figure = (Figure) iter.next();
178                     if (figure instanceof DrawComponentFigure) {
179                         // let all children draw on the buffer
180
((DrawComponentFigure)figure).paint(bufferedGraphics);
181                     }
182                     else {
183                         // Figure can not draw on a Graphics2D
184
// will be painted unbuffered
185
nonDCFChildren.add(figure);
186                     }
187                 }
188                 LOGGER.debug("buffer created in "+(System.currentTimeMillis()-time)+" ms");
189             }
190             finally {
191                 if (bufferedGraphics != null)
192                 bufferedGraphics.dispose();
193             }
194             
195         }
196         Point scrollOffset = EditorUtil.getScrollOffset(editPart);
197         bufferOrigin.setLocation(0,0);
198         bufferOrigin.translate(
199             (scrollOffset.x-bufferedScrollOffset.x)+bufferTranslation.x,
200             (scrollOffset.y-bufferedScrollOffset.y)+bufferTranslation.y
201         );
202         if (
203                 (bufferOrigin.x < 0 || bufferOrigin.y < 0) ||
204                 (bufferOrigin.x > (bufferSize.x - currentSize.x) || bufferOrigin.y > (bufferSize.y - currentSize.y))
205             ) {
206             // clear buffer if region to copy is outside
207
// of the buffer
208
clearBuffer();
209             return getBufferedImage();
210         }
211         return bufferedImage;
212     }
213     
214     public void paint(Graphics graphics) {
215 // super.paint(graphics);
216
// if (true)
217
// return;
218
long time = System.currentTimeMillis();
219         if (graphics instanceof J2DGraphics) {
220             J2DGraphics j2dGraphics = (J2DGraphics)graphics;
221 // j2dGraphics.setClip((Rectangle)null);
222
j2dGraphics.clipRect(null);
223             
224             // get / create the buffer
225
BufferedImage JavaDoc buffer = getBufferedImage();
226             
227             // create the Graphics where the buffer is drawn on
228
Graphics2D JavaDoc g2d = j2dGraphics.createGraphics2D();
229             // scale it invers of the current zoom ...
230
g2d.scale(1/currentZoom, 1/currentZoom);
231             // and translate it with the current scroll offset
232
// so 0,0 will be drawn on top left of the control
233
Point scrollOffset = EditorUtil.getScrollOffset(editPart);
234             g2d.translate(scrollOffset.x, scrollOffset.y);
235             
236             // now copy the buffer region
237
// LOGGER.debug("painting to bufferOrigin "+bufferOrigin+" ms");
238
// g2d.setPaint(new Color(0,0,0,0));
239
g2d.setPaint(Color.WHITE);
240             g2d.fillRect(-2, -2, currentSize.x+2, currentSize.y+2);
241             g2d.drawImage(
242                 buffer,
243                 0, 0, currentSize.x, currentSize.y,
244                 bufferOrigin.x, bufferOrigin.y, bufferOrigin.x+currentSize.x, bufferOrigin.y+currentSize.y,
245                 null
246             );
247             g2d.dispose();
248             // Paint all children that are not an instance of DrawComponentFigure
249
for (Iterator JavaDoc iter = nonDCFChildren.iterator(); iter.hasNext();) {
250                 Figure figure = (Figure) iter.next();
251                 figure.paint(graphics);
252             }
253         }
254         else {
255             super.paint(graphics);
256         }
257 // LOGGER.debug("painted in "+(System.currentTimeMillis()-time));
258
}
259     
260     
261     protected void clearBuffer() {
262         // TODO: make sure this is called when editor is closed
263
if (bufferedImage != null) {
264             bufferedImage.flush();
265             long time = System.currentTimeMillis();
266             System.gc();
267             LOGGER.debug("gc() took "+(System.currentTimeMillis()-time)+" ms");
268         }
269         bufferedImage = null;
270         childBounds = null;
271 // LOGGER.debug("buffer cleared()");
272
}
273     
274     
275     /**
276      * @see BufferedFreeformLayer#refresh()
277      */

278     public void refresh() {
279         clearBuffer();
280     }
281
282     /**
283      * @see BufferedFreeformLayer#refresh(Figure)
284      */

285     public void refresh(Figure figure) {
286         clearBuffer();
287     }
288     
289 // public void refresh(List figures) {
290
// clearBuffer();
291
// }
292

293     private Rectangle childBounds;
294     
295     protected Rectangle getChildBounds() {
296         if (childBounds == null) {
297             for (Iterator JavaDoc iter = getChildren().iterator(); iter.hasNext();) {
298                 Figure figure = (Figure) iter.next();
299                 Rectangle figureBounds = figure.getBounds();
300                 if (childBounds == null)
301                     childBounds = new Rectangle(figureBounds);
302                 else
303                     childBounds.union(figureBounds);
304             }
305         }
306         return childBounds;
307     }
308     
309     /**
310      * Constructs a new OversizedBufferFreeformLayer. The
311      * root of the given editPart is consulted to
312      * retrieve the parent Graphical viewer and
313      * its Control.
314      *
315      * @param editPart The editPart.
316      */

317     public OversizedBufferFreeformLayer()
318     {
319         //TODO remove this workaround, and instead try to catch the Layer-selection in the outline
320
// I think this is ok now (Alex)
321
super.setBounds(new Rectangle(-Integer.MAX_VALUE / 2, -Integer.MAX_VALUE / 2, Integer.MAX_VALUE, Integer.MAX_VALUE));
322     }
323     
324     public void init(EditPart editPart) {
325         this.editPart = editPart;
326         EditPartViewer viewer = editPart.getRoot().getViewer();
327         if (viewer instanceof ScrollingGraphicalViewer) {
328             ScrollingGraphicalViewer graphicalViewer = (ScrollingGraphicalViewer) viewer;
329             Control control = graphicalViewer.getControl();
330             this.viewerControl = control;
331         }
332     }
333     
334     /**
335      * @see IFigure#add(IFigure, Object, int)
336      */

337     public void add(IFigure child, Object JavaDoc constraint, int index) {
338         super.add(child, constraint, index);
339         helper.hookChild(child);
340         clearBuffer();
341     }
342     
343     /**
344      * @see FreeformFigure#addFreeformListener(FreeformListener)
345      */

346     public void addFreeformListener(FreeformListener listener) {
347         addListener(FreeformListener.class, listener);
348     }
349     
350     /**
351      * @see FreeformFigure#fireExtentChanged()
352      */

353     public void fireExtentChanged() {
354         Iterator JavaDoc iter = getListeners(FreeformListener.class);
355         while (iter.hasNext())
356             ((FreeformListener)iter.next())
357             .notifyFreeformExtentChanged();
358     }
359     
360     /**
361      * Overrides to do nothing.
362      * @see Figure#fireMoved()
363      */

364     protected void fireMoved() { }
365     
366     /**
367      * @see FreeformFigure#getFreeformExtent()
368      */

369     public Rectangle getFreeformExtent() {
370         return helper.getFreeformExtent();
371     }
372     
373     /**
374      * @see Figure#primTranslate(int, int)
375      */

376     public void primTranslate(int dx, int dy) {
377         bounds.x += dx;
378         bounds.y += dy;
379     }
380     
381     /**
382      * @see IFigure#remove(IFigure)
383      */

384     public void remove(IFigure child) {
385         helper.unhookChild(child);
386         super.remove(child);
387         clearBuffer();
388     }
389     
390     /**
391      * @see FreeformFigure#removeFreeformListener(FreeformListener)
392      */

393     public void removeFreeformListener(FreeformListener listener) {
394         removeListener(FreeformListener.class, listener);
395     }
396     
397     /**
398      * @see FreeformFigure#setFreeformBounds(Rectangle)
399      */

400     public void setFreeformBounds(Rectangle bounds) {
401         // clearBuffer();
402
// LOGGER.debug("setFreeformBounds("+bounds+")");
403
// helper.setFreeformBounds(bounds);
404
}
405     
406     public void setBounds(Rectangle rect) {
407         // clearBuffer();
408
// LOGGER.debug("setBounds("+rect+")");
409
// super.setBounds(rect);
410
}
411     
412     
413 }
414
Popular Tags