/[classpath]/classpath/javax/swing/JViewport.java
ViewVC logotype

Diff of /classpath/javax/swing/JViewport.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.27 by abalkiss, Mon Sep 12 20:59:15 2005 UTC revision 1.28 by rabbit78, Thu Sep 22 14:35:30 2005 UTC
# Line 41  package javax.swing; Line 41  package javax.swing;
41  import java.awt.Component;  import java.awt.Component;
42  import java.awt.Dimension;  import java.awt.Dimension;
43  import java.awt.Graphics;  import java.awt.Graphics;
44    import java.awt.Image;
45  import java.awt.Insets;  import java.awt.Insets;
46  import java.awt.LayoutManager;  import java.awt.LayoutManager;
47  import java.awt.Point;  import java.awt.Point;
# Line 181  public class JViewport extends JComponen Line 182  public class JViewport extends JComponen
182      }      }
183    }    }
184    
   private static final long serialVersionUID = -6925142919680527970L;  
     
185    public static final int SIMPLE_SCROLL_MODE = 0;    public static final int SIMPLE_SCROLL_MODE = 0;
186    public static final int BLIT_SCROLL_MODE = 1;    public static final int BLIT_SCROLL_MODE = 1;
187    public static final int BACKINGSTORE_SCROLL_MODE = 2;    public static final int BACKINGSTORE_SCROLL_MODE = 2;
188    
189      private static final long serialVersionUID = -6925142919680527970L;
190      
191      protected boolean scrollUnderway;
192      protected boolean isViewSizeSet;
193    
194      /**
195       * This flag indicates whether we use a backing store for drawing.
196       *
197       * @deprecated since JDK 1.3
198       */
199      protected boolean backingStore;
200    
201      /**
202       * The backingstore image used for the backingstore and blit scroll methods.
203       */
204      protected Image backingStoreImage;
205    
206      /**
207       * The position at which the view has been drawn the last time. This is used
208       * to determine the bittable area.
209       */
210      protected Point lastPaintPosition;
211    
212    ChangeEvent changeEvent = new ChangeEvent(this);    ChangeEvent changeEvent = new ChangeEvent(this);
213    
214    int scrollMode;    int scrollMode;
215    
   protected boolean scrollUnderway;  
   protected boolean isViewSizeSet;  
   
216    /**    /**
217     * The width and height of the Viewport's area in terms of view     * The width and height of the Viewport's area in terms of view
218     * coordinates.  Typically this will be the same as the width and height     * coordinates.  Typically this will be the same as the width and height
# Line 201  public class JViewport extends JComponen Line 220  public class JViewport extends JComponen
220     * width and height, which it may do, for example if it magnifies or     * width and height, which it may do, for example if it magnifies or
221     * rotates its view.     * rotates its view.
222     *     *
223     * @see #toViewCoordinates     * @see #toViewCoordinates(Dimension)
224     */     */
225    Dimension extentSize;    Dimension extentSize;
226    
227    /**    /**
228     * The width and height of the view in its own coordinate space.     * The width and height of the view in its own coordinate space.
229     */     */
   
230    Dimension viewSize;    Dimension viewSize;
231    
   Point lastPaintPosition;  
   
232    /**    /**
233     * The ViewListener instance.     * The ViewListener instance.
234     */     */
235    ViewListener viewListener;    ViewListener viewListener;
236    
237    /**    /**
238     * The accessible context of this <code>JViewport</code>.     * Stores the location from where to blit. This is a cached Point object used
239       * in blitting calculations.
240     */     */
241    AccessibleContext accessibleContext;    Point cachedBlitFrom;
242    
243      /**
244       * Stores the location where to blit to. This is a cached Point object used
245       * in blitting calculations.
246       */
247      Point cachedBlitTo;
248    
249      /**
250       * Stores the width of the blitted area. This is a cached Dimension object
251       * used in blitting calculations.
252       */
253      Dimension cachedBlitSize;
254    
255      /**
256       * Stores the bounds of the area that needs to be repainted. This is a cached
257       * Rectangle object used in blitting calculations.
258       */
259      Rectangle cachedBlitPaint;
260    
261      boolean damaged = true;
262    
263    public JViewport()    public JViewport()
264    {    {
# Line 229  public class JViewport extends JComponen Line 266  public class JViewport extends JComponen
266      setScrollMode(BLIT_SCROLL_MODE);      setScrollMode(BLIT_SCROLL_MODE);
267      setLayout(createLayoutManager());      setLayout(createLayoutManager());
268      updateUI();      updateUI();
269        lastPaintPosition = new Point();
270        cachedBlitFrom = new Point();
271        cachedBlitTo = new Point();
272        cachedBlitSize = new Dimension();
273        cachedBlitPaint = new Rectangle();
274    }    }
275    
276    public Dimension getExtentSize()    public Dimension getExtentSize()
# Line 322  public class JViewport extends JComponen Line 364  public class JViewport extends JComponen
364          isViewSizeSet = false;          isViewSizeSet = false;
365          fireStateChanged();          fireStateChanged();
366        }        }
367        repaint();
368    }    }
369    
370    public Rectangle getViewRect()    public Rectangle getViewRect()
# Line 390  public class JViewport extends JComponen Line 433  public class JViewport extends JComponen
433    
434    public void revalidate()    public void revalidate()
435    {    {
436        damaged = true;
437      fireStateChanged();      fireStateChanged();
438      super.revalidate();      super.revalidate();
439    }    }
440    
441    public void reshape(int x, int y, int w, int h)    public void reshape(int x, int y, int w, int h)
442    {    {
443        damaged = true;
444      boolean changed =      boolean changed =
445        (x != getX())        (x != getX())
446        || (y != getY())        || (y != getY())
# Line 406  public class JViewport extends JComponen Line 451  public class JViewport extends JComponen
451        fireStateChanged();        fireStateChanged();
452    }    }
453            
   protected void addImpl(Component comp, Object constraints, int index)  
   {  
     if (getComponentCount() > 0)  
       remove(getComponents()[0]);  
       
     super.addImpl(comp, constraints, index);  
   }  
   
454    public final Insets getInsets()    public final Insets getInsets()
455    {    {
456      return new Insets(0,0,0,0);      return new Insets(0,0,0,0);
# Line 437  public class JViewport extends JComponen Line 474  public class JViewport extends JComponen
474    
475    public void paint(Graphics g)    public void paint(Graphics g)
476    {    {
477      paintComponent(g);      Component view = getView();
478    
479        if (view == null)
480          return;
481    
482        Point pos = getViewPosition();
483        Rectangle viewBounds = view.getBounds();
484        Rectangle portBounds = getBounds();
485    
486        if (viewBounds.width == 0
487            || viewBounds.height == 0
488            || portBounds.width == 0
489            || portBounds.height == 0)
490          return;
491    
492        switch (getScrollMode())
493          {
494    
495          case JViewport.BACKINGSTORE_SCROLL_MODE:
496            paintBackingStore(g);
497            break;
498          case JViewport.BLIT_SCROLL_MODE:
499            paintBlit(g);
500            break;
501          case JViewport.SIMPLE_SCROLL_MODE:
502          default:
503            paintSimple(g);
504            break;
505          }
506        damaged = false;
507    }    }
508    
509    public void addChangeListener(ChangeListener listener)    public void addChangeListener(ChangeListener listener)
# Line 455  public class JViewport extends JComponen Line 521  public class JViewport extends JComponen
521      return (ChangeListener[]) getListeners(ChangeListener.class);      return (ChangeListener[]) getListeners(ChangeListener.class);
522    }    }
523    
   protected void fireStateChanged()  
   {  
     ChangeListener[] listeners = getChangeListeners();  
     for (int i = 0; i < listeners.length; ++i)  
       listeners[i].stateChanged(changeEvent);  
   }  
   
524    /**    /**
525     * This method returns the String ID of the UI class of  Separator.     * This method returns the String ID of the UI class of  Separator.
526     *     *
# Line 507  public class JViewport extends JComponen Line 566  public class JViewport extends JComponen
566    }    }
567    
568    /**    /**
    * Creates a {@link ViewListener} that is supposed to listen for  
    * size changes on the view component.  
    *  
    * @return a ViewListener instance  
    */  
   protected ViewListener createViewListener()  
   {  
     return new ViewListener();  
   }  
   
   /**  
    * Creates the LayoutManager that is used for this viewport. Override  
    * this method if you want to use a custom LayoutManager.  
    *  
    * @return a LayoutManager to use for this viewport  
    */  
   protected LayoutManager createLayoutManager()  
   {  
     return new ViewportLayout();  
   }  
   
   /**  
569     * Scrolls the view so that contentRect becomes visible.     * Scrolls the view so that contentRect becomes visible.
570     *     *
571     * @param contentRect the rectangle to make visible within the view     * @param contentRect the rectangle to make visible within the view
# Line 581  public class JViewport extends JComponen Line 618  public class JViewport extends JComponen
618        accessibleContext = new AccessibleJViewport();        accessibleContext = new AccessibleJViewport();
619      return accessibleContext;      return accessibleContext;
620    }    }
621    
622      protected void addImpl(Component comp, Object constraints, int index)
623      {
624        if (getComponentCount() > 0)
625          remove(getComponents()[0]);
626        
627        super.addImpl(comp, constraints, index);
628      }
629    
630      protected void fireStateChanged()
631      {
632        ChangeListener[] listeners = getChangeListeners();
633        for (int i = 0; i < listeners.length; ++i)
634          listeners[i].stateChanged(changeEvent);
635      }
636    
637      /**
638       * Creates a {@link ViewListener} that is supposed to listen for
639       * size changes on the view component.
640       *
641       * @return a ViewListener instance
642       */
643      protected ViewListener createViewListener()
644      {
645        return new ViewListener();
646      }
647    
648      /**
649       * Creates the LayoutManager that is used for this viewport. Override
650       * this method if you want to use a custom LayoutManager.
651       *
652       * @return a LayoutManager to use for this viewport
653       */
654      protected LayoutManager createLayoutManager()
655      {
656        return new ViewportLayout();
657      }
658    
659      /**
660       * Computes the parameters for the blitting scroll method. <code>dx</code>
661       * and <code>dy</code> specifiy the X and Y offset by which the viewport
662       * is scrolled. All other arguments are output parameters and are filled by
663       * this method.
664       *
665       * <code>blitFrom</code> holds the position of the blit rectangle in the
666       * viewport rectangle before scrolling, <code>blitTo</code> where the blitArea
667       * is copied to.
668       *
669       * <code>blitSize</code> holds the size of the blit area and
670       * <code>blitPaint</code> is the area of the view that needs to be painted.
671       *
672       * This method returns <code>true</code> if blitting is possible and
673       * <code>false</code> if the viewport has to be repainted completetly without
674       * blitting.
675       *
676       * @param dx the horizontal delta
677       * @param dy the vertical delta
678       * @param blitFrom the position from where to blit; set by this method
679       * @param blitTo the position where to blit area is copied to; set by this
680       *        method
681       * @param blitSize the size of the blitted area; set by this method
682       * @param blitPaint the area that needs repainting; set by this method
683       *
684       * @return <code>true</code> if blitting is possible,
685       *         <code>false</code> otherwise
686       */
687      protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
688                                    Dimension blitSize, Rectangle blitPaint)
689      {
690        if ((dx != 0 && dy != 0) || damaged)
691          // We cannot blit if the viewport is scrolled in both directions at
692          // once.
693          return false;
694    
695        Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
696    
697        // Compute the blitFrom and blitTo parameters.
698        blitFrom.x = portBounds.x;
699        blitFrom.y = portBounds.y;
700        blitTo.x = portBounds.x;
701        blitTo.y = portBounds.y;
702    
703        if (dy > 0)
704          {
705            blitFrom.y = portBounds.y + dy;
706          }
707        else if (dy < 0)
708          {
709            blitTo.y = portBounds.y - dy;
710          }
711        else if (dx > 0)
712          {
713            blitFrom.x = portBounds.x + dx;
714          }
715        else if (dx < 0)
716          {
717            blitTo.x = portBounds.x - dx;
718          }
719    
720        // Compute size of the blit area.
721        if (dx != 0)
722          {
723            blitSize.width = portBounds.width - Math.abs(dx);
724            blitSize.height = portBounds.height;
725          }
726        else if (dy != 0)
727          {
728            blitSize.width = portBounds.width;
729            blitSize.height = portBounds.height - Math.abs(dy);
730          }
731    
732        // Compute the blitPaint parameter.
733        blitPaint.setBounds(portBounds);
734        if (dy > 0)
735          {
736            blitPaint.y = portBounds.y + portBounds.height - dy;
737            blitPaint.height = dy;
738          }
739        else if (dy < 0)
740          {
741            blitPaint.height = -dy;
742          }
743        if (dx > 0)
744          {
745            blitPaint.x = portBounds.x + portBounds.width - dx;
746            blitPaint.width = dx;
747          }
748        else if (dx < 0)
749          {
750            blitPaint.width = -dx;
751          }
752    
753        return true;
754      }
755    
756      /**
757       * Paints the viewport in case we have a scrollmode of
758       * {@link #SIMPLE_SCROLL_MODE}.
759       *
760       * This simply paints the view directly on the surface of the viewport.
761       *
762       * @param g the graphics context to use
763       */
764      void paintSimple(Graphics g)
765      {
766        Point pos = getViewPosition();
767        Component view = getView();
768        boolean translated = false;
769        try
770          {
771            g.translate(-pos.x, -pos.y);
772            translated = true;
773            view.paint(g);
774          }
775        finally
776          {
777            if (translated)
778              g.translate (pos.x, pos.y);
779          }
780      }
781    
782      /**
783       * Paints the viewport in case we have a scroll mode of
784       * {@link #BACKINGSTORE_SCROLL_MODE}.
785       *
786       * This method uses a backing store image to paint the view to, which is then
787       * subsequently painted on the screen. This should make scrolling more
788       * smooth.
789       *
790       * @param g the graphics context to use
791       */
792      void paintBackingStore(Graphics g)
793      {
794        // If we have no backing store image yet or the size of the component has
795        // changed, we need to rebuild the backing store.
796        if (backingStoreImage == null || damaged)
797          {
798            backingStoreImage = createImage(getWidth(), getHeight());
799            Graphics g2 = backingStoreImage.getGraphics();
800            paintSimple(g2);
801            g2.dispose();
802          }
803        // Otherwise we can perform the blitting on the backing store image:
804        // First we move the part that remains visible after scrolling, then
805        // we only need to paint the bit that becomes newly visible.
806        else
807          {
808            Graphics g2 = backingStoreImage.getGraphics();
809            Point viewPosition = getViewPosition();
810            int dx = viewPosition.x - lastPaintPosition.x;
811            int dy = viewPosition.y - lastPaintPosition.y;
812            boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
813                                          cachedBlitSize, cachedBlitPaint);
814            if (canBlit)
815              {
816                // Copy the part that remains visible during scrolling.
817                g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
818                            cachedBlitSize.width, cachedBlitSize.height,
819                            cachedBlitTo.x - cachedBlitFrom.x,
820                            cachedBlitTo.y - cachedBlitFrom.y);
821                // Now paint the part that becomes newly visible.
822                g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y,
823                           cachedBlitPaint.width, cachedBlitPaint.height);
824                paintSimple(g2);
825              }
826            // If blitting is not possible for some reason, fall back to repainting
827            // everything.
828            else
829              {
830                paintSimple(g2);
831              }
832            g2.dispose();
833          }
834        // Actually draw the backingstore image to the graphics context.
835        g.drawImage(backingStoreImage, 0, 0, this);
836        // Update the lastPaintPosition so that we know what is already drawn when
837        // we paint the next time.
838        lastPaintPosition.setLocation(getViewPosition());
839      }
840    
841      /**
842       * Paints the viewport in case we have a scrollmode of
843       * {@link #BLIT_SCROLL_MODE}.
844       *
845       * This paints the viewport using a backingstore and a blitting algorithm.
846       * Only the newly exposed area of the view is painted from the view painting
847       * methods, the remainder is copied from the backing store.
848       *
849       * @param g the graphics context to use
850       */
851      void paintBlit(Graphics g)
852      {
853        // We cannot perform blitted painting as it is described in Sun's API docs.
854        // There it is suggested that this painting method should blit directly
855        // on the parent window's surface. This is not possible because when using
856        // Swing's double buffering (at least our implementation), it would
857        // immediatly be painted when the buffer is painted on the screen. For this
858        // to work we would need a kind of hole in the buffer image. And honestly
859        // I find this method not very elegant.
860        // The alternative, blitting directly on the buffer image, is also not
861        // possible because the buffer image gets cleared everytime when an opaque
862        // parent component is drawn on it.
863    
864        // What we do instead is falling back to the backing store approach which
865        // is in fact a mixed blitting/backing store approach where the blitting
866        // is performed on the backing store image and this is then drawn to the
867        // graphics context. This is very robust and works independent of the
868        // painting mechanism that is used by Swing. And it should have comparable
869        // performance characteristics as the blitting method.
870        paintBackingStore(g);
871      }
872  }  }

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.28

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26