001    /**
002     * ========================================
003     * JFreeReport : a free Java report library
004     * ========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/
007     *
008     * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009     *
010     * This library is free software; you can redistribute it and/or modify it under the terms
011     * of the GNU Lesser General Public License as published by the Free Software Foundation;
012     * either version 2.1 of the License, or (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public License along with this
019     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020     * Boston, MA 02111-1307, USA.
021     *
022     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023     * in the United States and other countries.]
024     *
025     * ------------
026     * $Id: ComponentDrawable.java 3525 2007-10-16 11:43:48Z tmorgner $
027     * ------------
028     * (C) Copyright 2000-2005, by Object Refinery Limited.
029     * (C) Copyright 2005-2007, by Pentaho Corporation.
030     */
031    
032    package org.jfree.report.util;
033    
034    import java.awt.Component;
035    import java.awt.Dimension;
036    import java.awt.Graphics2D;
037    import java.awt.Window;
038    import java.awt.geom.Rectangle2D;
039    import javax.swing.JComponent;
040    import javax.swing.JFrame;
041    import javax.swing.JPanel;
042    import javax.swing.RepaintManager;
043    import javax.swing.SwingUtilities;
044    
045    import org.jfree.ui.ExtendedDrawable;
046    import org.jfree.util.Log;
047    
048    /**
049     * Creation-Date: 11.10.2005, 14:03:15
050     *
051     * @author Thomas Morgner
052     */
053    public class ComponentDrawable implements ExtendedDrawable
054    {
055      private class PainterRunnable implements Runnable
056      {
057        private Rectangle2D area;
058        private Graphics2D graphics;
059    
060        private PainterRunnable()
061        {
062        }
063    
064        public Graphics2D getGraphics()
065        {
066          return graphics;
067        }
068    
069        public void setGraphics(final Graphics2D graphics)
070        {
071          this.graphics = graphics;
072        }
073    
074        public Rectangle2D getArea()
075        {
076          return area;
077        }
078    
079        public void setArea(final Rectangle2D area)
080        {
081          this.area = area;
082        }
083    
084        public void run()
085        {
086          if (component instanceof Window)
087          {
088            component.addNotify();
089          }
090          else if (isOwnPeerConnected())
091          {
092            final Window w = getWindowAncestor(component);
093            w.validate();
094          }
095          else
096          {
097            peerSupply.pack();
098            contentPane.add(component);
099          }
100    
101          component.setBounds
102                  ((int) area.getX(), (int) area.getY(),
103                   (int) area.getWidth(), (int) area.getHeight());
104          component.validate();
105          component.paint(graphics);
106    
107        }
108      }
109    
110      private boolean preserveAspectRatio;
111      private Component component;
112      private JFrame peerSupply;
113      private JPanel contentPane;
114      private PainterRunnable runnable;
115      private boolean paintSynchronously;
116      private boolean allowOwnPeer;
117    
118      public ComponentDrawable()
119      {
120        peerSupply = new JFrame();
121        peerSupply.pack(); // add a peer ...
122        contentPane = new JPanel();
123        contentPane.setLayout(null);
124        peerSupply.setContentPane(contentPane);
125        runnable = new PainterRunnable();
126      }
127    
128      public boolean isAllowOwnPeer()
129      {
130        return allowOwnPeer;
131      }
132    
133      public void setAllowOwnPeer(final boolean allowOwnPeer)
134      {
135        this.allowOwnPeer = allowOwnPeer;
136      }
137    
138      public boolean isPaintSynchronously()
139      {
140        return paintSynchronously;
141      }
142    
143      public void setPaintSynchronously(final boolean paintSynchronously)
144      {
145        this.paintSynchronously = paintSynchronously;
146      }
147    
148      private void cleanUp ()
149      {
150        if (component instanceof JComponent && isOwnPeerConnected() == false)
151        {
152          final JComponent jc = (JComponent) component;
153          RepaintManager.currentManager(jc).removeInvalidComponent(jc);
154          RepaintManager.currentManager(jc).markCompletelyClean(jc);
155        }
156        contentPane.removeAll();
157        RepaintManager.currentManager(contentPane).removeInvalidComponent(contentPane);
158        RepaintManager.currentManager(contentPane).markCompletelyClean(contentPane);
159        peerSupply.dispose();
160      }
161    
162      public Component getComponent()
163      {
164        return component;
165      }
166    
167      public void setComponent(final Component component)
168      {
169        this.component = component;
170        prepareComponent(component);
171      }
172    
173      public synchronized Dimension getPreferredSize()
174      {
175        if (component == null)
176        {
177          return new Dimension(0,0);
178        }
179        if (component instanceof Window == false &&
180                isOwnPeerConnected() == false)
181        {
182          peerSupply.pack();
183          contentPane.add(component);
184          contentPane.validate();
185          component.validate();
186        }
187        else if (isOwnPeerConnected())
188        {
189          return component.getSize();
190        }
191        else
192        {
193          component.validate();
194        }
195        final Dimension retval = component.getPreferredSize();
196        cleanUp();
197        return retval;
198      }
199    
200      private boolean isOwnPeerConnected()
201      {
202        if (allowOwnPeer == false)
203        {
204          return false;
205        }
206        final Window windowAncestor = getWindowAncestor(component);
207        return (windowAncestor != null && windowAncestor != peerSupply);
208      }
209    
210      protected static Window getWindowAncestor(final Component component)
211      {
212        Component parent = component.getParent();
213        while (parent != null)
214        {
215          if (parent instanceof Window)
216          {
217            return (Window) parent;
218          }
219          parent = parent.getParent();
220        }
221        return null;
222      }
223    
224      public void setPreserveAspectRatio(final boolean preserveAspectRatio)
225      {
226        this.preserveAspectRatio = preserveAspectRatio;
227      }
228    
229      public boolean isPreserveAspectRatio()
230      {
231        return preserveAspectRatio;
232      }
233    
234      public synchronized void draw(final Graphics2D g2, final Rectangle2D area)
235      {
236        if (component == null)
237        {
238          return;
239        }
240    
241        runnable.setArea(area);
242        runnable.setGraphics(g2);
243    
244        if (SwingUtilities.isEventDispatchThread() || paintSynchronously == false)
245        {
246          runnable.run();
247        }
248        else
249        {
250          try
251          {
252            SwingUtilities.invokeAndWait(runnable);
253          }
254          catch (Exception e)
255          {
256            Log.warn ("Failed to redraw the component.");
257          }
258        }
259    
260        cleanUp();
261      }
262    
263      private void prepareComponent (final Component c)
264      {
265        if (c instanceof JComponent)
266        {
267          final JComponent jc = (JComponent) c;
268          jc.setDoubleBuffered(false);
269          final Component[] childs = jc.getComponents();
270          for (int i = 0; i < childs.length; i++)
271          {
272            final Component child = childs[i];
273            prepareComponent(child);
274          }
275        }
276      }
277    }