KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > nightlabs > editor2d > viewer > AbstractBufferedCanvas


1 package org.nightlabs.editor2d.viewer;
2
3 import java.awt.Color JavaDoc;
4 import java.awt.Graphics JavaDoc;
5 import java.awt.Graphics2D JavaDoc;
6 import java.awt.Rectangle JavaDoc;
7 import java.awt.geom.Point2D JavaDoc;
8 import java.awt.image.BufferedImage JavaDoc;
9 import java.beans.PropertyChangeListener JavaDoc;
10 import java.beans.PropertyChangeSupport JavaDoc;
11 import java.util.Iterator JavaDoc;
12
13 import javax.swing.JPanel JavaDoc;
14
15 import org.apache.log4j.Logger;
16 import org.nightlabs.base.util.GeomUtil;
17 import org.nightlabs.editor2d.DrawComponent;
18 import org.nightlabs.editor2d.render.Renderer;
19
20 public abstract class AbstractBufferedCanvas
21 extends JPanel JavaDoc
22 implements IBufferedCanvas, IViewport
23 {
24     public static final Logger LOGGER = Logger.getLogger(AbstractBufferedCanvas.class);
25     
26     protected ITempContentManager tempContentManager = null;
27     public ITempContentManager getTempContentManager()
28     {
29         if (tempContentManager == null)
30             tempContentManager = new TempContentManager();
31                 
32         return tempContentManager;
33     }
34
35     protected PropertyChangeSupport JavaDoc pcs = null;
36     protected PropertyChangeSupport JavaDoc getPropertyChangeSupport()
37     {
38         if (pcs == null) {
39             pcs = new PropertyChangeSupport JavaDoc(this);
40         }
41         return pcs;
42     }
43     
44     public void addPropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
45         getPropertyChangeSupport().addPropertyChangeListener(pcl);
46     }
47
48     public void removePropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
49         getPropertyChangeSupport().removePropertyChangeListener(pcl);
50     }
51
52     public void firePropertyChange(String JavaDoc propertyName, Object JavaDoc newVal, Object JavaDoc oldVal) {
53         getPropertyChangeSupport().firePropertyChange(propertyName, oldVal, newVal);
54     }
55     
56     public AbstractBufferedCanvas(DrawComponent dc)
57     {
58         super();
59         this.dc = dc;
60         Rectangle JavaDoc dcBounds = GeomUtil.translateRectToOrigin(dc.getBounds());
61 // setBackground(bgColor.get);
62
renderingHintsManager.setRenderMode(RenderingHintsManager.RENDER_MODE_QUALITY);
63         init(dcBounds);
64 // setDebug(true, true);
65
}
66         
67     public DrawComponent getDrawComponent() {
68         return dc;
69     }
70     
71     private boolean debugBounds = false;
72     private boolean debugPaint = false;
73     
74     private void setDebug(boolean paint, boolean bounds)
75     {
76         debugPaint = paint;
77         debugBounds = bounds;
78     }
79     
80     protected int imageType = BufferedImage.TYPE_INT_RGB;
81     protected Rectangle JavaDoc bufferBounds;
82     protected DrawComponent dc;
83     protected BufferedImage JavaDoc bufferedImage;
84     protected BufferedImage JavaDoc viewImage;
85     protected int initSize = 100;
86     protected RenderingHintsManager renderingHintsManager = RenderingHintsManager.sharedInstance();
87     
88     /**
89      * paints the drawComponent, if no notifyChange has been called a BitBlockTransfer
90      * from the BufferedImage is performed
91      */

92     public void paint(Graphics JavaDoc g)
93     {
94         Graphics2D JavaDoc g2d = (Graphics2D JavaDoc) g;
95         
96         long startPaintTime = 0;
97         if (debugPaint) {
98             startPaintTime = System.currentTimeMillis();
99         }
100                 
101         if (isChanged)
102         {
103             if (debugPaint)
104                 LOGGER.debug("buffer cleared!");
105                             
106             paintDrawComponent();
107             isChanged = false;
108         }
109         
110         // fill the Background
111
g2d.setPaint(bgColor);
112         Rectangle JavaDoc bgRect = initRealBounds;
113         g2d.setClip(0, 0, bgRect.width, bgRect.height);
114         g2d.fillRect(0, 0, bgRect.width, bgRect.height);
115         
116         if (debugBounds)
117             LOGGER.debug("bgRect = "+bgRect);
118                     
119         if (bufferedImage != null)
120         {
121             long startTime = 0;
122             if (debugPaint)
123                 startTime = System.currentTimeMillis();
124                                     
125             // Do a BitBlock Transfer
126
calcBufferedViewImage();
127             g2d.drawImage(viewImage, 0, 0, null);
128                         
129             if (debugPaint)
130                 LOGGER.debug("BitBlockTransfer took "+(System.currentTimeMillis()-startTime)+" ms!");
131             
132             if (debugBounds) {
133                 LOGGER.debug("viewImage width = "+viewImage.getWidth());
134                 LOGGER.debug("viewImage height = "+viewImage.getHeight());
135             }
136         }
137         
138         // Draw Temporary Content above Buffer (e.g. SelectionRectangle etc.)
139
if (drawTempContent == true) {
140             g2d.translate(-getOffsetX(), -getOffsetY());
141             g2d.scale(getScale(), getScale());
142             drawTempContent(g2d);
143         }
144                 
145         if (debugPaint) {
146             LOGGER.debug("Total Paint took "+(System.currentTimeMillis()-startPaintTime)+" ms");
147             LOGGER.debug("");
148         }
149     }
150                 
151     /**
152      * calculates the viewImage, which is a subImage (equivalent to the viewBounds)
153      * of the BufferedImage
154      *
155      */

156     protected void calcBufferedViewImage()
157     {
158         int offsetX = getBufferOffsetX();
159         int offsetY = getBufferOffsetY();
160                             
161         if (viewImage != null)
162             viewImage.flush();
163         
164         long startTime = 0;
165         if (debugPaint) {
166             startTime = System.currentTimeMillis();
167         }
168                 
169         if ((bufferedImage.getWidth() >= viewBounds.width + offsetX) &&
170                 (bufferedImage.getHeight() >= viewBounds.height + offsetY))
171         {
172             viewImage =
173                 bufferedImage.getSubimage(offsetX, offsetY,
174                                                                     viewBounds.width,
175                                                                     viewBounds.height);
176         }
177                                         
178         if (debugPaint) {
179             long endTime = System.currentTimeMillis() - startTime;
180             LOGGER.debug("create viewImage took "+endTime+" ms!");
181         }
182     }
183             
184     /**
185      * sets realBounds to a new scaled Rectangle which is determined
186      * by the given scale
187      *
188      * @param scale the scaleFactor
189      */

190     protected void setZoomedRealBounds(double scale)
191     {
192         int newWidth = (int) Math.floor(initRealBounds.width * scale);
193         int newHeight = (int) Math.floor(initRealBounds.height * scale);
194         Rectangle JavaDoc newRealBounds = new Rectangle JavaDoc(0, 0, newWidth, newHeight);
195         setRealBounds(newRealBounds);
196     }
197     
198     protected double scale = 1.0d;
199     protected double oldScale = scale;
200     
201     /**
202      *
203      * @param scale the scale of the Graphics
204      */

205     public void setScale(double scale) {
206         oldScale = this.scale;
207         this.scale = scale;
208         setZoomedRealBounds(scale);
209     }
210     
211     /**
212      * @return the scale of the Graphics
213      */

214     public double getScale() {
215         return scale;
216     }
217
218     /**
219      * @see ICanvas.translateX
220      */

221     public void translateX(float translateX) {
222         setViewLocation((int)(viewBounds.x + translateX), viewBounds.y);
223     }
224     
225     /**
226      * @see ICanvas.translateY
227      */

228     public void translateY(float translateY) {
229         setViewLocation(viewBounds.x, (int)(viewBounds.y + translateY));
230     }
231     
232     protected Color JavaDoc bgColor = Color.WHITE;
233     public void setBackground(int red, int green, int blue, int alpha) {
234         bgColor = new Color JavaDoc(red, green, blue, alpha);
235     }
236                             
237     protected Rectangle JavaDoc realBounds;
238     
239     /**
240      *
241      * @return the realBounds which determine the whole area which
242      * can be displayed by the DisplayPanel
243      */

244     public Rectangle JavaDoc getRealBounds() {
245         return realBounds;
246     }
247     public void setRealBounds(Rectangle JavaDoc realBounds)
248     {
249         Rectangle JavaDoc oldReal = this.realBounds;
250         checkScale(realBounds);
251         scaleToCenter();
252         firePropertyChange(REAL_CHANGE, oldReal, this.realBounds);
253         setViewBounds(getViewBounds());
254         notifyChange();
255     }
256     
257     /**
258      * sets the viewLocation so that the scale is performed into the center of the
259      * visibleArea
260      *
261      */

262     protected void scaleToCenter()
263     {
264         int newViewX = (int) ((((double)viewBounds.x) / oldScale) * scale);
265         int newViewY = (int) ((((double)viewBounds.y) / oldScale) * scale);
266 // int newViewX = (int) (((double)viewBounds.x) * scale);
267
// int newViewY = (int) (((double)viewBounds.y) * scale);
268

269         if (debugBounds) {
270             LOGGER.debug("newViewX = "+newViewX);
271             LOGGER.debug("newViewY = "+newViewY);
272         }
273         
274         setViewLocation(newViewX, newViewY);
275     }
276     
277     protected Rectangle JavaDoc viewBounds;
278     
279     /**
280      *
281      * @return the visible area of the IViewport
282      */

283     public Rectangle JavaDoc getViewBounds() {
284         return viewBounds;
285     }
286     
287     /**
288      * @see IViewport.getLocation()
289      */

290     public Point2D JavaDoc getViewLocation()
291     {
292         return getViewBounds().getLocation();
293     }
294         
295     /**
296      * sets the visible area of the IViewport
297      * @param viewBounds the new Visible Area
298      */

299     public void setViewBounds(Rectangle JavaDoc viewBounds)
300     {
301         Rectangle JavaDoc oldView = this.viewBounds;
302         
303         if (isRectangleInReal(viewBounds))
304             this.viewBounds = viewBounds;
305         else
306             this.viewBounds = GeomUtil.checkBounds(viewBounds, realBounds);
307         
308         firePropertyChange(VIEW_CHANGE, oldView, this.viewBounds);
309         checkBuffer();
310         repaint();
311                 
312         if (debugBounds) {
313             LOGGER.debug("realBounds = " + realBounds);
314             LOGGER.debug("bufferBounds = " + bufferBounds);
315             LOGGER.debug("viewBounds = "+viewBounds);
316             LOGGER.debug("");
317         }
318     }
319     
320     protected Rectangle JavaDoc initRealBounds;
321     protected Rectangle JavaDoc initViewBounds;
322     
323     protected void init(Rectangle JavaDoc realBounds)
324     {
325         initRealBounds = new Rectangle JavaDoc(realBounds);
326         initViewBounds = getVisibleRect();
327         
328         this.realBounds = realBounds;
329         viewBounds = getVisibleRect();
330         initBuffer();
331         paintDrawComponent();
332 // addComponentListener(resizeListener);
333

334         if (debugBounds) {
335             LOGGER.debug("realBounds = "+realBounds);
336             LOGGER.debug("viewBounds = "+viewBounds);
337         }
338     }
339     
340     protected void initBuffer()
341     {
342         bufferBounds = new Rectangle JavaDoc(0, 0, initSize, initSize);
343         bufferedImage = new BufferedImage JavaDoc(bufferBounds.width, bufferBounds.height, imageType);
344     }
345         
346     protected boolean isChanged = false;
347     
348     /**
349      * notifys that a new painting has to occur, and that
350      * the buffer must be cleared
351      */

352     public void notifyChange()
353     {
354         isChanged = true;
355         repaint();
356         
357         LOGGER.debug("notifyChange!");
358     }
359     
360     /**
361      * paints the DrawComponent into the Graphics of the BufferedImage
362      */

363     protected void paintDrawComponent()
364     {
365         long startTime = 0;
366         if (debugPaint)
367             startTime = System.currentTimeMillis();
368         
369         if (bufferedImage != null)
370         {
371             Graphics2D JavaDoc g2d = (Graphics2D JavaDoc) bufferedImage.getGraphics();
372             g2d.setRenderingHints(renderingHintsManager.getRenderingHints());
373             g2d.setBackground(bgColor);
374             g2d.translate(-bufferBounds.x, -bufferBounds.y);
375             
376             g2d.setClip(bufferBounds);
377             g2d.fillRect(bufferBounds.x, bufferBounds.y, bufferBounds.width, bufferBounds.height);
378                                         
379             g2d.scale(scale, scale);
380             DrawComponentPaintable.paintDrawComponent(dc, g2d);
381         }
382         
383         if (debugPaint)
384         {
385             long endTime = System.currentTimeMillis() - startTime;
386             LOGGER.debug("paintDrawComponent took "+endTime+" ms!");
387         }
388     }
389     
390     /**
391      *
392      * @return a Rectangle which determines the Size of the BufferedImage to create
393      * If it fits the size of the BufferedImage is viewBounds * bufferScaleFactor
394      */

395     protected Rectangle JavaDoc getBufferRectangle()
396     {
397         double bufferScaleFactor = BufferManager.sharedInstance().getBufferScaleFactor();
398         int bufferWidth = (int) (viewBounds.width * bufferScaleFactor);
399         int bufferHeight = (int) (viewBounds.height * bufferScaleFactor);
400         
401         Rectangle JavaDoc newBufferBounds = new Rectangle JavaDoc(viewBounds.x - ((bufferWidth - viewBounds.width)/2),
402                 viewBounds.y - ((bufferHeight-viewBounds.height)/2), bufferWidth, bufferHeight);
403         
404         if (isRectangleInReal(newBufferBounds))
405             return newBufferBounds;
406         else
407             return GeomUtil.checkBounds(newBufferBounds, realBounds);
408     }
409     
410     /**
411      * checks if the View is still in the Buffer, if not a new BufferedImage
412      * is created and paintDrawComponent is painted into the Graphics of the
413      * new BufferedImage.
414      *
415      */

416     protected void checkBuffer()
417     {
418         if (!isViewInBuffer())
419         {
420             if (bufferedImage != null)
421                 bufferedImage.flush();
422             bufferedImage = null;
423             createOffScreenImage();
424             notifyChange();
425             
426             if (debugBounds)
427                 LOGGER.debug("Buffer updated!");
428         }
429     }
430     
431     /**
432      *
433      * @return true if the viewBounds are contained in the bufferBounds, else false
434      */

435     protected boolean isViewInBuffer()
436     {
437         if (bufferBounds != null && viewBounds != null)
438             return bufferBounds.contains(viewBounds);
439         else
440             return false;
441     }
442     
443     /**
444      *
445      * @param r the Rectangle to check
446      * @return true if the given Rectangle is conatined in the realBounds, else false
447      */

448     protected boolean isRectangleInReal(Rectangle JavaDoc r)
449     {
450         if (realBounds != null && r != null)
451             return realBounds.contains(r);
452         else
453             return false;
454     }
455     
456     /**
457      * creates the Offscreen Image.
458      * The Size of the BufferedImage is the viewBounds * bufferScaleFactor
459      *
460      */

461     protected void createOffScreenImage()
462     {
463         bufferBounds = getBufferRectangle();
464         bufferedImage = new BufferedImage JavaDoc(bufferBounds.width, bufferBounds.height, imageType);
465     }
466     
467     public int getOffsetX() {
468         return viewBounds.x - realBounds.x;
469     }
470     
471     public int getOffsetY() {
472         return viewBounds.y - realBounds.y;
473     }
474     
475     protected int getBufferOffsetX() {
476         return viewBounds.x - bufferBounds.x;
477     }
478     
479     protected int getBufferOffsetY() {
480         return viewBounds.y - bufferBounds.y;
481     }
482         
483     public void setViewLocation(int x, int y) {
484         setViewBounds(new Rectangle JavaDoc(x, y, viewBounds.width, viewBounds.height));
485     }
486     
487     public void setViewLocation(Point2D JavaDoc p) {
488         setViewLocation((int)p.getX(), (int)p.getY());
489     }
490     
491     public void setViewCenter(float x, float y)
492     {
493         Rectangle JavaDoc newView = new Rectangle JavaDoc();
494         newView.setFrameFromCenter(x, y,
495                                                              x + viewBounds.getWidth() / 2,
496                                                              y + viewBounds.getHeight() / 2);
497         setViewBounds(newView);
498     }
499     
500     public Point2D JavaDoc getViewCenter()
501     {
502         double viewCenterX = viewBounds.getCenterX();
503         double viewCenterY = viewBounds.getCenterY();
504         return new Point2D.Float JavaDoc((float)viewCenterX, (float)viewCenterY);
505     }
506         
507     protected void checkScale(Rectangle JavaDoc newReal)
508     {
509         int maxRealX = (int)newReal.getMaxX();
510         int maxRealY = (int)newReal.getMaxY();
511         int maxViewX = (int)initViewBounds.getMaxX();
512         int maxViewY = (int)initViewBounds.getMaxY();
513         int maxX = Math.max(maxRealX, maxViewX);
514         int maxY = Math.max(maxRealY, maxViewY);
515         realBounds = new Rectangle JavaDoc(0, 0, maxX, maxY);
516         
517         if (debugBounds) {
518             LOGGER.debug("viewBounds = "+viewBounds);
519             LOGGER.debug("realBounds = "+realBounds);
520             LOGGER.debug("initViewBounds = "+initViewBounds);
521         }
522     }
523     
524     protected boolean drawTempContent = true;
525     public void drawTempContent(Graphics2D JavaDoc g2d)
526     {
527         for (Iterator JavaDoc it = getTempContentManager().getTempContent().iterator(); it.hasNext(); )
528         {
529             Object JavaDoc o = it.next();
530             if (o instanceof DrawComponent) {
531                 DrawComponent dc = (DrawComponent) o;
532                 Renderer r = null;
533                 if (dc.getRoot() != null) {
534                     r = dc.getRenderer();
535                 }
536                 if (r == null) {
537                     int renderMode = dc.getRenderMode();
538                     r = getDrawComponent().getRenderModeManager().getRenderer(renderMode, dc.getClass());
539                 }
540                 r.paint(dc, g2d);
541             }
542         }
543     }
544         
545     public abstract Rectangle JavaDoc getVisibleRect();
546     
547     protected void componentResized()
548     {
549         Rectangle JavaDoc visibleRect = getVisibleRect();
550         initViewBounds = getVisibleRect();
551         Rectangle JavaDoc newView = new Rectangle JavaDoc(viewBounds.x, viewBounds.y,
552                 visibleRect.width, visibleRect.height);
553             
554         if (!newView.equals(viewBounds))
555         {
556             setViewBounds(newView);
557             if (debugBounds) {
558                 LOGGER.debug("Viewport resized!");
559                 LOGGER.debug("viewBounds = "+viewBounds);
560             }
561         }
562     }
563     
564 }
565
Popular Tags