KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > nightlabs > editor2d > viewer > awt > DisplayPanel


1 /* *****************************************************************************
2  * NightLabs Editor2D - Graphical editor framework *
3  * Copyright (C) 2004-2005 NightLabs - http://NightLabs.org *
4  * *
5  * This library is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or (at your option) any later version. *
9  * *
10  * This library 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 GNU *
13  * Lesser General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Lesser General Public *
16  * License along with this library; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 51 Franklin St, Fifth Floor, *
19  * Boston, MA 02110-1301 USA *
20  * *
21  * Or get it online : *
22  * http://www.gnu.org/copyleft/lesser.html *
23  * *
24  * *
25  ******************************************************************************/

26
27 package org.nightlabs.editor2d.viewer.awt;
28
29 import java.awt.BasicStroke JavaDoc;
30 import java.awt.Color JavaDoc;
31 import java.awt.Component JavaDoc;
32 import java.awt.Graphics JavaDoc;
33 import java.awt.Graphics2D JavaDoc;
34 import java.awt.Rectangle JavaDoc;
35 import java.awt.event.ComponentAdapter JavaDoc;
36 import java.awt.event.ComponentEvent JavaDoc;
37 import java.awt.event.ComponentListener JavaDoc;
38 import java.awt.geom.Point2D JavaDoc;
39 import java.awt.image.BufferedImage JavaDoc;
40 import java.util.Iterator JavaDoc;
41
42 import javax.swing.JPanel JavaDoc;
43 import javax.swing.JToolTip JavaDoc;
44
45 import org.apache.log4j.Logger;
46
47 import org.nightlabs.base.util.GeomUtil;
48 import org.nightlabs.editor2d.DrawComponent;
49 import org.nightlabs.editor2d.render.Renderer;
50 import org.nightlabs.editor2d.viewer.BufferManager;
51 import org.nightlabs.editor2d.viewer.DrawComponentPaintable;
52 import org.nightlabs.editor2d.viewer.IBufferedCanvas;
53 import org.nightlabs.editor2d.viewer.IBufferedViewport;
54 import org.nightlabs.editor2d.viewer.ICanvas;
55 import org.nightlabs.editor2d.viewer.ITempContentManager;
56 import org.nightlabs.editor2d.viewer.IViewport;
57 import org.nightlabs.editor2d.viewer.RenderingHintsManager;
58 import org.nightlabs.editor2d.viewer.TempContentManager;
59
60 public class DisplayPanel
61 extends JPanel JavaDoc
62 //implements ICanvas, IBufferedCanvas, IViewport
63
implements IBufferedViewport
64 {
65     public static final Logger LOGGER = Logger.getLogger(DisplayPanel.class);
66         
67     public DisplayPanel(DrawComponent dc)
68     {
69         super();
70         this.dc = dc;
71         Rectangle JavaDoc dcBounds = GeomUtil.translateRectToOrigin(dc.getBounds());
72         setBackground(bgColor);
73         renderingHintsManager.setRenderMode(RenderingHintsManager.RENDER_MODE_QUALITY);
74         init(dcBounds);
75 // setDebug(true, true);
76
}
77         
78     public DrawComponent getDrawComponent() {
79         return dc;
80     }
81     
82     private boolean debugBounds = false;
83     private boolean debugPaint = false;
84     
85     private void setDebug(boolean paint, boolean bounds)
86     {
87         debugPaint = paint;
88         debugBounds = bounds;
89     }
90     
91     protected int imageType = BufferedImage.TYPE_INT_RGB;
92     protected Rectangle JavaDoc bufferBounds;
93     protected DrawComponent dc;
94     protected BufferedImage JavaDoc bufferedImage;
95     protected BufferedImage JavaDoc viewImage;
96 // protected double bufferScaleFactor = 2.0d;
97
protected int initSize = 100;
98 // protected RenderingHintsManager renderingHintsManager = new RenderingHintsManager();
99
protected RenderingHintsManager renderingHintsManager = RenderingHintsManager.sharedInstance();
100     
101     /**
102      * paints the drawComponent, if no notifyChange has been called a BitBlockTransfer
103      * from the BufferedImage is performed
104      */

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

169     protected void calcBufferedViewImage()
170     {
171         int offsetX = getBufferOffsetX();
172         int offsetY = getBufferOffsetY();
173                             
174         if (viewImage != null)
175             viewImage.flush();
176         
177         long startTime = 0;
178         if (debugPaint) {
179             startTime = System.currentTimeMillis();
180         }
181
182 // viewImage = bufferedImage.getSubimage(offsetX, offsetY,
183
// viewBounds.width, viewBounds.height);
184

185         if ((bufferedImage.getWidth() >= viewBounds.width + offsetX) &&
186                 (bufferedImage.getHeight() >= viewBounds.height + offsetY))
187         {
188             viewImage =
189                 bufferedImage.getSubimage(offsetX, offsetY,
190                                                                     viewBounds.width,
191                                                                     viewBounds.height);
192         }
193                                         
194         if (debugPaint) {
195             long endTime = System.currentTimeMillis() - startTime;
196             LOGGER.debug("create viewImage took "+endTime+" ms!");
197         }
198     }
199             
200     /**
201      * sets realBounds to a new scaled Rectangle which is determined
202      * by the given scale
203      *
204      * @param scale the scaleFactor
205      */

206     protected void setZoomedRealBounds(double scale)
207     {
208         int newWidth = (int) Math.floor(initRealBounds.width * scale);
209         int newHeight = (int) Math.floor(initRealBounds.height * scale);
210         Rectangle JavaDoc newRealBounds = new Rectangle JavaDoc(0, 0, newWidth, newHeight);
211         setRealBounds(newRealBounds);
212     }
213     
214     protected double scale = 1.0d;
215     protected double oldScale = scale;
216     
217     /**
218      *
219      * @param scale the scale of the Graphics
220      */

221     public void setScale(double scale) {
222         oldScale = this.scale;
223         this.scale = scale;
224         setZoomedRealBounds(scale);
225     }
226     
227     /**
228      * @return the scale of the Graphics
229      */

230     public double getScale() {
231         return scale;
232     }
233
234     /**
235      * @see ICanvas.translateX
236      */

237     public void translateX(float translateX) {
238         setViewLocation((int)(viewBounds.x + translateX), viewBounds.y);
239     }
240     
241     /**
242      * @see ICanvas.translateY
243      */

244     public void translateY(float translateY) {
245         setViewLocation(viewBounds.x, (int)(viewBounds.y + translateY));
246     }
247     
248     protected Color JavaDoc bgColor = Color.WHITE;
249     public void setBackground(int red, int green, int blue) {
250         bgColor = new Color JavaDoc(red, green, blue);
251     }
252                             
253     protected Rectangle JavaDoc realBounds;
254     
255     /**
256      *
257      * @return the realBounds which determine the whole area which
258      * can be displayed by the DisplayPanel
259      */

260     public Rectangle JavaDoc getRealBounds() {
261         return realBounds;
262     }
263     public void setRealBounds(Rectangle JavaDoc realBounds)
264     {
265         Rectangle JavaDoc oldReal = this.realBounds;
266         checkScale(realBounds);
267         scaleToCenter();
268         firePropertyChange(REAL_CHANGE, oldReal, this.realBounds);
269         setViewBounds(getViewBounds());
270         notifyChange();
271     }
272     
273     /**
274      * sets the viewLocation so that the scale is performed into the center of the
275      * visibleArea
276      *
277      */

278     protected void scaleToCenter()
279     {
280         int newViewX = (int) ((((double)viewBounds.x) / oldScale) * scale);
281         int newViewY = (int) ((((double)viewBounds.y) / oldScale) * scale);
282 // int newViewX = (int) (((double)viewBounds.x) * scale);
283
// int newViewY = (int) (((double)viewBounds.y) * scale);
284

285         if (debugBounds) {
286             LOGGER.debug("newViewX = "+newViewX);
287             LOGGER.debug("newViewY = "+newViewY);
288         }
289         
290         setViewLocation(newViewX, newViewY);
291     }
292     
293     protected Rectangle JavaDoc viewBounds;
294     
295     /**
296      *
297      * @return the visible area of the IViewport
298      */

299     public Rectangle JavaDoc getViewBounds() {
300         return viewBounds;
301     }
302     
303     /**
304      * @see IViewport.getLocation()
305      */

306     public Point2D JavaDoc getViewLocation()
307     {
308         return getViewBounds().getLocation();
309     }
310         
311     /**
312      * sets the visible area of the IViewport
313      * @param viewBounds the new Visible Area
314      */

315     public void setViewBounds(Rectangle JavaDoc viewBounds)
316     {
317         Rectangle JavaDoc oldView = this.viewBounds;
318         
319         if (isRectangleInReal(viewBounds))
320             this.viewBounds = viewBounds;
321         else
322             this.viewBounds = GeomUtil.checkBounds(viewBounds, realBounds);
323         
324         firePropertyChange(VIEW_CHANGE, oldView, this.viewBounds);
325         checkBuffer();
326         repaint();
327                 
328         if (debugBounds) {
329             LOGGER.debug("realBounds = " + realBounds);
330             LOGGER.debug("bufferBounds = " + bufferBounds);
331             LOGGER.debug("viewBounds = "+viewBounds);
332             LOGGER.debug("");
333         }
334     }
335     
336     protected Rectangle JavaDoc initRealBounds;
337     protected Rectangle JavaDoc initViewBounds;
338     
339     protected void init(Rectangle JavaDoc realBounds)
340     {
341         initRealBounds = new Rectangle JavaDoc(realBounds);
342         initViewBounds = getVisibleRect();
343         
344         this.realBounds = realBounds;
345         viewBounds = getVisibleRect();
346         initBuffer();
347         paintDrawComponent();
348         addComponentListener(resizeListener);
349                 
350         if (debugBounds) {
351             LOGGER.debug("realBounds = "+realBounds);
352             LOGGER.debug("viewBounds = "+viewBounds);
353         }
354     }
355     
356     protected void initBuffer()
357     {
358         bufferBounds = new Rectangle JavaDoc(0, 0, initSize, initSize);
359         bufferedImage = new BufferedImage JavaDoc(bufferBounds.width, bufferBounds.height, imageType);
360     }
361     
362     protected ComponentListener JavaDoc resizeListener = new ComponentAdapter JavaDoc()
363     {
364         public void componentResized(ComponentEvent JavaDoc e)
365         {
366             Rectangle JavaDoc visibleRect = getVisibleRect();
367             initViewBounds = getVisibleRect();
368             Rectangle JavaDoc newView = new Rectangle JavaDoc(viewBounds.x, viewBounds.y,
369                     visibleRect.width, visibleRect.height);
370             
371             if (!newView.equals(viewBounds))
372             {
373                 setViewBounds(newView);
374                 if (debugBounds) {
375                     LOGGER.debug("Viewport resized!");
376                     LOGGER.debug("viewBounds = "+viewBounds);
377                 }
378             }
379         }
380     };
381     
382     protected boolean isChanged = false;
383     
384     /**
385      * notifys that a new painting has to occur, and that
386      * the buffer must be cleared
387      */

388     public void notifyChange()
389     {
390         isChanged = true;
391         repaint();
392         
393         LOGGER.debug("notifyChange!");
394     }
395     
396     /**
397      * paints the DrawComponent into the Graphics of the BufferedImage
398      */

399     protected void paintDrawComponent()
400     {
401         long startTime = 0;
402         if (debugPaint)
403             startTime = System.currentTimeMillis();
404         
405         if (bufferedImage != null)
406         {
407             Graphics2D JavaDoc g2d = (Graphics2D JavaDoc) bufferedImage.getGraphics();
408             g2d.setRenderingHints(renderingHintsManager.getRenderingHints());
409             g2d.setBackground(bgColor);
410             g2d.translate(-bufferBounds.x, -bufferBounds.y);
411             
412             g2d.setClip(bufferBounds);
413             g2d.fillRect(bufferBounds.x, bufferBounds.y, bufferBounds.width, bufferBounds.height);
414                             
415             if (debugPaint)
416             {
417                 drawRealRectangle(g2d);
418                 drawBufferRectangle(g2d);
419                 drawViewRectangle(g2d);
420             }
421             
422             g2d.scale(scale, scale);
423             DrawComponentPaintable.paintDrawComponent(dc, g2d);
424         }
425         
426         if (debugPaint)
427         {
428             long endTime = System.currentTimeMillis() - startTime;
429             LOGGER.debug("paintDrawComponent took "+endTime+" ms!");
430         }
431     }
432     
433     // for test purposes only
434
private void drawViewRectangle(Graphics2D JavaDoc g2)
435     {
436         if (viewBounds != null)
437         {
438             int distance = 10;
439             g2.setPaint(java.awt.Color.YELLOW);
440             g2.setStroke(new BasicStroke JavaDoc(2));
441             g2.drawRect(viewBounds.x+distance,
442                     viewBounds.y+distance,
443                     viewBounds.width-distance,
444                     viewBounds.height-distance);
445         }
446     }
447
448     // for test purposes only
449
private void drawBufferRectangle(Graphics2D JavaDoc g2)
450     {
451         if (bufferBounds != null)
452         {
453             int distance = 10;
454             g2.setPaint(java.awt.Color.GREEN);
455             g2.setStroke(new BasicStroke JavaDoc(4));
456             g2.drawRect(bufferBounds.x+distance,
457                     bufferBounds.y+distance,
458                     bufferBounds.width-distance,
459                     bufferBounds.height-distance);
460         }
461     }
462
463     // for test purposes only
464
private void drawRealRectangle(Graphics2D JavaDoc g2)
465     {
466         if (bufferBounds != null)
467         {
468             int distance = 10;
469             g2.setPaint(java.awt.Color.BLUE);
470             g2.setStroke(new BasicStroke JavaDoc(6));
471             g2.drawRect(realBounds.x+distance,
472                     realBounds.y+distance,
473                     realBounds.width-distance,
474                     realBounds.height-distance);
475         }
476     }
477
478     /**
479      *
480      * @return a Rectangle which determines the Size of the BufferedImage to create
481      * If it fits the size of the BufferedImage is viewBounds * bufferScaleFactor
482      */

483     protected Rectangle JavaDoc getBufferRectangle()
484     {
485         double bufferScaleFactor = BufferManager.sharedInstance().getBufferScaleFactor();
486         int bufferWidth = (int) (viewBounds.width * bufferScaleFactor);
487         int bufferHeight = (int) (viewBounds.height * bufferScaleFactor);
488         
489         Rectangle JavaDoc newBufferBounds = new Rectangle JavaDoc(viewBounds.x - ((bufferWidth - viewBounds.width)/2),
490                 viewBounds.y - ((bufferHeight-viewBounds.height)/2), bufferWidth, bufferHeight);
491         
492         if (isRectangleInReal(newBufferBounds))
493             return newBufferBounds;
494         else
495             return GeomUtil.checkBounds(newBufferBounds, realBounds);
496     }
497     
498     /**
499      * checks if the View is still in the Buffer, if not a new BufferedImage
500      * is created and paintDrawComponent is painted into the Graphics of the
501      * new BufferedImage.
502      *
503      */

504     protected void checkBuffer()
505     {
506         if (!isViewInBuffer())
507         {
508             if (bufferedImage != null)
509                 bufferedImage.flush();
510             bufferedImage = null;
511             createOffScreenImage();
512             notifyChange();
513             
514             if (debugBounds)
515                 LOGGER.debug("Buffer updated!");
516         }
517     }
518     
519     /**
520      *
521      * @return true if the viewBounds are contained in the bufferBounds, else false
522      */

523     protected boolean isViewInBuffer()
524     {
525         if (bufferBounds != null && viewBounds != null)
526             return bufferBounds.contains(viewBounds);
527         else
528             return false;
529     }
530     
531     /**
532      *
533      * @param r the Rectangle to check
534      * @return true if the given Rectangle is conatined in the realBounds, else false
535      */

536     protected boolean isRectangleInReal(Rectangle JavaDoc r)
537     {
538         if (realBounds != null && r != null)
539             return realBounds.contains(r);
540         else
541             return false;
542     }
543     
544     /**
545      * creates the Offscreen Image.
546      * The Size of the BufferedImage is the viewBounds * bufferScaleFactor
547      *
548      */

549     protected void createOffScreenImage()
550     {
551         bufferBounds = getBufferRectangle();
552         bufferedImage = new BufferedImage JavaDoc(bufferBounds.width, bufferBounds.height, imageType);
553     }
554     
555     public int getOffsetX() {
556         return viewBounds.x - realBounds.x;
557     }
558     
559     public int getOffsetY() {
560         return viewBounds.y - realBounds.y;
561     }
562     
563     protected int getBufferOffsetX() {
564         return viewBounds.x - bufferBounds.x;
565     }
566     
567     protected int getBufferOffsetY() {
568         return viewBounds.y - bufferBounds.y;
569     }
570         
571     public void setViewLocation(int x, int y) {
572         setViewBounds(new Rectangle JavaDoc(x, y, viewBounds.width, viewBounds.height));
573     }
574     
575     public void setViewLocation(Point2D JavaDoc p) {
576         setViewLocation((int)p.getX(), (int)p.getY());
577     }
578     
579     public void setViewCenter(float x, float y)
580     {
581         Rectangle JavaDoc newView = new Rectangle JavaDoc();
582         newView.setFrameFromCenter(x, y,
583                                                              x + viewBounds.getWidth() / 2,
584                                                              y + viewBounds.getHeight() / 2);
585         setViewBounds(newView);
586     }
587     
588     public Point2D JavaDoc getViewCenter()
589     {
590         double viewCenterX = viewBounds.getCenterX();
591         double viewCenterY = viewBounds.getCenterY();
592         return new Point2D.Float JavaDoc((float)viewCenterX, (float)viewCenterY);
593     }
594         
595     protected void checkScale(Rectangle JavaDoc newReal)
596     {
597         int maxRealX = (int)newReal.getMaxX();
598         int maxRealY = (int)newReal.getMaxY();
599         int maxViewX = (int)initViewBounds.getMaxX();
600         int maxViewY = (int)initViewBounds.getMaxY();
601         int maxX = Math.max(maxRealX, maxViewX);
602         int maxY = Math.max(maxRealY, maxViewY);
603         realBounds = new Rectangle JavaDoc(0, 0, maxX, maxY);
604         
605         if (debugBounds) {
606             LOGGER.debug("viewBounds = "+viewBounds);
607             LOGGER.debug("realBounds = "+realBounds);
608             LOGGER.debug("initViewBounds = "+initViewBounds);
609         }
610     }
611         
612     protected boolean drawTempContent = true;
613     public void drawTempContent(Graphics2D JavaDoc g2d)
614     {
615         for (Iterator JavaDoc it = getTempContentManager().getTempContent().iterator(); it.hasNext(); )
616         {
617             Object JavaDoc o = it.next();
618             if (o instanceof DrawComponent) {
619                 DrawComponent dc = (DrawComponent) o;
620                 Renderer r = null;
621                 if (dc.getRoot() != null) {
622                     r = dc.getRenderer();
623                 }
624                 if (r == null) {
625                     int renderMode = dc.getRenderMode();
626                     r = getDrawComponent().getRenderModeManager().getRenderer(renderMode, dc.getClass());
627                 }
628                 r.paint(dc, g2d);
629             }
630             else if (o instanceof JToolTip JavaDoc) {
631                 JToolTip JavaDoc tooltip = (JToolTip JavaDoc) o;
632                 JToolTip JavaDoc tt = createToolTip();
633                 tt.setTipText(tooltip.getTipText());
634                 tt.setLocation(tooltip.getLocation());
635             }
636             else if (o instanceof Component JavaDoc) {
637                 Component JavaDoc c = (Component JavaDoc) o;
638                 c.paint(g2d);
639             }
640         }
641     }
642         
643     protected ITempContentManager tempContentMan = new TempContentManager();
644     public ITempContentManager getTempContentManager() {
645         return tempContentMan;
646     }
647 }
648
Popular Tags