mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			949 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			949 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* JViewport.java --
 | |
|    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package javax.swing;
 | |
| 
 | |
| import gnu.classpath.SystemProperties;
 | |
| 
 | |
| import java.awt.Component;
 | |
| import java.awt.Dimension;
 | |
| import java.awt.Graphics;
 | |
| import java.awt.Image;
 | |
| import java.awt.Insets;
 | |
| import java.awt.LayoutManager;
 | |
| import java.awt.Point;
 | |
| import java.awt.Rectangle;
 | |
| import java.awt.Shape;
 | |
| import java.awt.event.ComponentAdapter;
 | |
| import java.awt.event.ComponentEvent;
 | |
| import java.io.Serializable;
 | |
| 
 | |
| import javax.accessibility.Accessible;
 | |
| import javax.accessibility.AccessibleContext;
 | |
| import javax.accessibility.AccessibleRole;
 | |
| import javax.swing.border.Border;
 | |
| import javax.swing.event.ChangeEvent;
 | |
| import javax.swing.event.ChangeListener;
 | |
| import javax.swing.plaf.ViewportUI;
 | |
| 
 | |
| /**
 | |
|  *
 | |
|  * <pre>
 | |
|  *                                                     _
 | |
|  *   +-------------------------------+    ...........Y1 \
 | |
|  *   |  view                         |                .  \
 | |
|  *   |  (this component's child)     |                .   > VY
 | |
|  *   |                               |                .  / = Y2-Y1
 | |
|  *   |         +------------------------------+  ....Y2_/
 | |
|  *   |         | viewport            |        |       .
 | |
|  *   |         | (this component)    |        |       .
 | |
|  *   |         |                     |        |       .
 | |
|  *   |         |                     |        |       .
 | |
|  *   |         |                     |        |       .
 | |
|  *   |         |                     |        |       .
 | |
|  *   |         +------------------------------+  ....Y3
 | |
|  *   |                               |                .
 | |
|  *   |         .                     |        .       .
 | |
|  *   |         .                     |        .       .
 | |
|  *   +---------.---------------------+    ...........Y4
 | |
|  *   .         .                     .        .
 | |
|  *   .         .                     .        .
 | |
|  *   .         .                     .        .
 | |
|  *   X1.......X2.....................X3.......X4
 | |
|  *   \____  ___/
 | |
|  *        \/
 | |
|  *        VX = X2-X1
 | |
|  *</pre>
 | |
|  *
 | |
|  * <p>A viewport is, like all swing components, located at some position in
 | |
|  * the swing component tree; that location is exactly the same as any other
 | |
|  * components: the viewport's "bounds".</p>
 | |
|  *
 | |
|  * <p>But in terms of drawing its child, the viewport thinks of itself as
 | |
|  * covering a particular position <em>of the view's coordinate space</em>.
 | |
|  * For example, the {@link #getViewPosition} method returns
 | |
|  * the position <code>(VX,VY)</code> shown above, which is an position in
 | |
|  * "view space", even though this is <em>implemented</em> by positioning
 | |
|  * the underlying child at position <code>(-VX,-VY)</code></p>
 | |
|  *
 | |
|  */
 | |
| public class JViewport extends JComponent implements Accessible
 | |
| {
 | |
|   /**
 | |
|    * Provides accessibility support for <code>JViewport</code>.
 | |
|    *
 | |
|    * @author Roman Kennke (roman@kennke.org)
 | |
|    */
 | |
|   protected class AccessibleJViewport extends AccessibleJComponent
 | |
|   {
 | |
|     /**
 | |
|      * Creates a new instance of <code>AccessibleJViewport</code>.
 | |
|      */
 | |
|     protected AccessibleJViewport()
 | |
|     {
 | |
|       // Nothing to do here.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the accessible role of <code>JViewport</code>, which is
 | |
|      * {@link AccessibleRole#VIEWPORT}.
 | |
|      *
 | |
|      * @return the accessible role of <code>JViewport</code>
 | |
|      */
 | |
|     public AccessibleRole getAccessibleRole()
 | |
|     {
 | |
|       return AccessibleRole.VIEWPORT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A {@link java.awt.event.ComponentListener} that listens for
 | |
|    * changes of the view's size. This triggers a revalidate() call on the
 | |
|    * viewport.
 | |
|    */
 | |
|   protected class ViewListener extends ComponentAdapter implements Serializable
 | |
|   {
 | |
|     private static final long serialVersionUID = -2812489404285958070L;
 | |
| 
 | |
|     /**
 | |
|      * Creates a new instance of ViewListener.
 | |
|      */
 | |
|     protected ViewListener()
 | |
|     {
 | |
|       // Nothing to do here.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Receives notification when a component (in this case: the view
 | |
|      * component) changes it's size. This simply triggers a revalidate() on the
 | |
|      * viewport.
 | |
|      *
 | |
|      * @param ev the ComponentEvent describing the change
 | |
|      */
 | |
|     public void componentResized(ComponentEvent ev)
 | |
|     {
 | |
|       // Fire state change, because resizing the view means changing the
 | |
|       // extentSize.
 | |
|       fireStateChanged();
 | |
|       revalidate();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public static final int SIMPLE_SCROLL_MODE = 0;
 | |
|   public static final int BLIT_SCROLL_MODE = 1;
 | |
|   public static final int BACKINGSTORE_SCROLL_MODE = 2;
 | |
| 
 | |
|   private static final long serialVersionUID = -6925142919680527970L;
 | |
| 
 | |
|   /**
 | |
|    * The default scrollmode to be used by all JViewports as determined by
 | |
|    * the system property gnu.javax.swing.JViewport.scrollMode.
 | |
|    */
 | |
|   private static final int defaultScrollMode;
 | |
| 
 | |
|   protected boolean scrollUnderway;
 | |
|   protected boolean isViewSizeSet;
 | |
| 
 | |
|   /**
 | |
|    * This flag indicates whether we use a backing store for drawing.
 | |
|    *
 | |
|    * @deprecated since JDK 1.3
 | |
|    */
 | |
|   protected boolean backingStore;
 | |
| 
 | |
|   /**
 | |
|    * The backingstore image used for the backingstore and blit scroll methods.
 | |
|    */
 | |
|   protected Image backingStoreImage;
 | |
| 
 | |
|   /**
 | |
|    * The position at which the view has been drawn the last time. This is used
 | |
|    * to determine the bittable area.
 | |
|    */
 | |
|   protected Point lastPaintPosition;
 | |
| 
 | |
|   ChangeEvent changeEvent = new ChangeEvent(this);
 | |
| 
 | |
|   int scrollMode;
 | |
| 
 | |
|   /**
 | |
|    * The ViewListener instance.
 | |
|    */
 | |
|   ViewListener viewListener;
 | |
| 
 | |
|   /**
 | |
|    * Stores the location from where to blit. This is a cached Point object used
 | |
|    * in blitting calculations.
 | |
|    */
 | |
|   Point cachedBlitFrom;
 | |
| 
 | |
|   /**
 | |
|    * Stores the location where to blit to. This is a cached Point object used
 | |
|    * in blitting calculations.
 | |
|    */
 | |
|   Point cachedBlitTo;
 | |
| 
 | |
|   /**
 | |
|    * Stores the width of the blitted area. This is a cached Dimension object
 | |
|    * used in blitting calculations.
 | |
|    */
 | |
|   Dimension cachedBlitSize;
 | |
| 
 | |
|   /**
 | |
|    * Stores the bounds of the area that needs to be repainted. This is a cached
 | |
|    * Rectangle object used in blitting calculations.
 | |
|    */
 | |
|   Rectangle cachedBlitPaint;
 | |
| 
 | |
|   boolean damaged = true;
 | |
| 
 | |
|   /**
 | |
|    * A flag indicating if the size of the viewport has changed since the
 | |
|    * last repaint. This is used in double buffered painting to check if we
 | |
|    * need a new double buffer, or can reuse the old one.
 | |
|    */
 | |
|   boolean sizeChanged = true;
 | |
| 
 | |
|   /**
 | |
|    * Indicates if this JViewport is the paint root or not. If it is not, then
 | |
|    * we may not assume that the offscreen buffer still has the right content
 | |
|    * because parent components may have cleared the background already.
 | |
|    */
 | |
|   private boolean isPaintRoot = false;
 | |
| 
 | |
|   /**
 | |
|    * Initializes the default setting for the scrollMode property.
 | |
|    */
 | |
|   static
 | |
|   {
 | |
|     String scrollModeProp =
 | |
|       SystemProperties.getProperty("gnu.swing.scrollmode", "BACKINGSTORE");
 | |
|     if (scrollModeProp.equalsIgnoreCase("simple"))
 | |
|       defaultScrollMode = SIMPLE_SCROLL_MODE;
 | |
|     else if (scrollModeProp.equalsIgnoreCase("backingstore"))
 | |
|       defaultScrollMode = BACKINGSTORE_SCROLL_MODE;
 | |
|     else
 | |
|       defaultScrollMode = BLIT_SCROLL_MODE;
 | |
|   }
 | |
| 
 | |
|   public JViewport()
 | |
|   {
 | |
|     setOpaque(true);
 | |
|     setScrollMode(defaultScrollMode);
 | |
|     updateUI();
 | |
|     setLayout(createLayoutManager());
 | |
|     lastPaintPosition = new Point();
 | |
|     cachedBlitFrom = new Point();
 | |
|     cachedBlitTo = new Point();
 | |
|     cachedBlitSize = new Dimension();
 | |
|     cachedBlitPaint = new Rectangle();
 | |
|   }
 | |
| 
 | |
|   public Dimension getExtentSize()
 | |
|   {
 | |
|     return getSize();
 | |
|   }
 | |
| 
 | |
|   public Dimension toViewCoordinates(Dimension size)
 | |
|   {
 | |
|     return size;
 | |
|   }
 | |
| 
 | |
|   public Point toViewCoordinates(Point p)
 | |
|   {
 | |
|     Point pos = getViewPosition();
 | |
|     return new Point(p.x + pos.x,
 | |
|                      p.y + pos.y);
 | |
|   }
 | |
| 
 | |
|   public void setExtentSize(Dimension newSize)
 | |
|   {
 | |
|     Dimension oldExtent = getExtentSize();
 | |
|     if (! newSize.equals(oldExtent))
 | |
|       {
 | |
|         setSize(newSize);
 | |
|         fireStateChanged();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the viewSize when set, or the preferred size of the set
 | |
|    * Component view.  If no viewSize and no Component view is set an
 | |
|    * empty Dimension is returned.
 | |
|    */
 | |
|   public Dimension getViewSize()
 | |
|   {
 | |
|     Dimension size;
 | |
|     Component view = getView();
 | |
|     if (view != null)
 | |
|       {
 | |
|         if (isViewSizeSet)
 | |
|           size = view.getSize();
 | |
|         else
 | |
|           size = view.getPreferredSize();
 | |
|       }
 | |
|     else
 | |
|       size = new Dimension(0, 0);
 | |
|     return size;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   public void setViewSize(Dimension newSize)
 | |
|   {
 | |
|     Component view = getView();
 | |
|     if (view != null)
 | |
|       {
 | |
|         if (! newSize.equals(view.getSize()))
 | |
|           {
 | |
|             scrollUnderway = false;
 | |
|             view.setSize(newSize);
 | |
|             isViewSizeSet = true;
 | |
|             fireStateChanged();
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the viewport's position in view space. Despite confusing name,
 | |
|    * this really does return the viewport's (0,0) position in view space,
 | |
|    * not the view's position.
 | |
|    */
 | |
| 
 | |
|   public Point getViewPosition()
 | |
|   {
 | |
|     Component view = getView();
 | |
|     if (view == null)
 | |
|       return new Point(0,0);
 | |
|     else
 | |
|       {
 | |
|         Point p = view.getLocation();
 | |
|         p.x = -p.x;
 | |
|         p.y = -p.y;
 | |
|         return p;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void setViewPosition(Point p)
 | |
|   {
 | |
|     Component view = getView();
 | |
|     if (view != null && ! p.equals(getViewPosition()))
 | |
|       {
 | |
|         scrollUnderway = true;
 | |
|         view.setLocation(-p.x, -p.y);
 | |
|         fireStateChanged();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public Rectangle getViewRect()
 | |
|   {
 | |
|     return new Rectangle(getViewPosition(), getExtentSize());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @deprecated 1.4
 | |
|    */
 | |
|   public boolean isBackingStoreEnabled()
 | |
|   {
 | |
|     return scrollMode == BACKINGSTORE_SCROLL_MODE;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @deprecated 1.4
 | |
|    */
 | |
|   public void setBackingStoreEnabled(boolean b)
 | |
|   {
 | |
|     if (b && scrollMode != BACKINGSTORE_SCROLL_MODE)
 | |
|       {
 | |
|         scrollMode = BACKINGSTORE_SCROLL_MODE;
 | |
|         fireStateChanged();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void setScrollMode(int mode)
 | |
|   {
 | |
|     scrollMode = mode;
 | |
|     fireStateChanged();
 | |
|   }
 | |
| 
 | |
|   public int getScrollMode()
 | |
|   {
 | |
|     return scrollMode;
 | |
|   }
 | |
| 
 | |
|   public Component getView()
 | |
|   {
 | |
|     if (getComponentCount() == 0)
 | |
|       return null;
 | |
| 
 | |
|     return getComponents()[0];
 | |
|   }
 | |
| 
 | |
|   public void setView(Component v)
 | |
|   {
 | |
|     Component currView = getView();
 | |
|     if (viewListener != null && currView != null)
 | |
|       currView.removeComponentListener(viewListener);
 | |
| 
 | |
|     if (v != null)
 | |
|       {
 | |
|         if (viewListener == null)
 | |
|           viewListener = createViewListener();
 | |
|         v.addComponentListener(viewListener);
 | |
|         add(v);
 | |
|         fireStateChanged();
 | |
|       }
 | |
|     revalidate();
 | |
|     repaint();
 | |
|   }
 | |
| 
 | |
|   public void reshape(int x, int y, int w, int h)
 | |
|   {
 | |
|     if (w != getWidth() || h != getHeight())
 | |
|       sizeChanged = true;
 | |
|     super.reshape(x, y, w, h);
 | |
|     if (sizeChanged)
 | |
|       {
 | |
|         damaged = true;
 | |
|         fireStateChanged();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public final Insets getInsets()
 | |
|   {
 | |
|     return new Insets(0, 0, 0, 0);
 | |
|   }
 | |
| 
 | |
|   public final Insets getInsets(Insets insets)
 | |
|   {
 | |
|     if (insets == null)
 | |
|       return getInsets();
 | |
|     insets.top = 0;
 | |
|     insets.bottom = 0;
 | |
|     insets.left = 0;
 | |
|     insets.right = 0;
 | |
|     return insets;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Overridden to return <code>false</code>, so the JViewport's paint method
 | |
|    * gets called instead of directly calling the children. This is necessary
 | |
|    * in order to get a useful clipping and translation on the children.
 | |
|    *
 | |
|    * @return <code>false</code>
 | |
|    */
 | |
|   public boolean isOptimizedDrawingEnabled()
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   public void paint(Graphics g)
 | |
|   {
 | |
|     Component view = getView();
 | |
| 
 | |
|     if (view == null)
 | |
|       return;
 | |
| 
 | |
|     Rectangle viewBounds = view.getBounds();
 | |
|     Rectangle portBounds = getBounds();
 | |
| 
 | |
|     if (viewBounds.width == 0
 | |
|         || viewBounds.height == 0
 | |
|         || portBounds.width == 0
 | |
|         || portBounds.height == 0)
 | |
|       return;
 | |
| 
 | |
|     switch (getScrollMode())
 | |
|       {
 | |
| 
 | |
|       case JViewport.BACKINGSTORE_SCROLL_MODE:
 | |
|         paintBackingStore(g);
 | |
|         break;
 | |
|       case JViewport.BLIT_SCROLL_MODE:
 | |
|         paintBlit(g);
 | |
|         break;
 | |
|       case JViewport.SIMPLE_SCROLL_MODE:
 | |
|       default:
 | |
|         paintSimple(g);
 | |
|         break;
 | |
|       }
 | |
|     damaged = false;
 | |
|   }
 | |
| 
 | |
|   public void addChangeListener(ChangeListener listener)
 | |
|   {
 | |
|     listenerList.add(ChangeListener.class, listener);
 | |
|   }
 | |
| 
 | |
|   public void removeChangeListener(ChangeListener listener)
 | |
|   {
 | |
|     listenerList.remove(ChangeListener.class, listener);
 | |
|   }
 | |
| 
 | |
|   public ChangeListener[] getChangeListeners()
 | |
|   {
 | |
|     return (ChangeListener[]) getListeners(ChangeListener.class);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the String ID of the UI class of  Separator.
 | |
|    *
 | |
|    * @return The UI class' String ID.
 | |
|    */
 | |
|   public String getUIClassID()
 | |
|   {
 | |
|     return "ViewportUI";
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method resets the UI used to the Look and Feel defaults..
 | |
|    */
 | |
|   public void updateUI()
 | |
|   {
 | |
|     setUI((ViewportUI) UIManager.getUI(this));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the viewport's UI delegate.
 | |
|    *
 | |
|    * @return The viewport's UI delegate.
 | |
|    */
 | |
|   public ViewportUI getUI()
 | |
|   {
 | |
|     return (ViewportUI) ui;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method sets the viewport's UI delegate.
 | |
|    *
 | |
|    * @param ui The viewport's UI delegate.
 | |
|    */
 | |
|   public void setUI(ViewportUI ui)
 | |
|   {
 | |
|     super.setUI(ui);
 | |
|   }
 | |
| 
 | |
|   public final void setBorder(Border border)
 | |
|   {
 | |
|     if (border != null)
 | |
|       throw new IllegalArgumentException();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Scrolls the view so that contentRect becomes visible.
 | |
|    *
 | |
|    * @param contentRect the rectangle to make visible within the view
 | |
|    */
 | |
|   public void scrollRectToVisible(Rectangle contentRect)
 | |
|   {
 | |
|     Component view = getView();
 | |
|     if (view == null)
 | |
|       return;
 | |
| 
 | |
|     Point pos = getViewPosition();
 | |
|     // We get the contentRect in the viewport coordinates. But we want to
 | |
|     // calculate with view coordinates.
 | |
|     int contentX = contentRect.x + pos.x;
 | |
|     int contentY = contentRect.y + pos.y;
 | |
|     Rectangle viewBounds = getView().getBounds();
 | |
|     Rectangle portBounds = getBounds();
 | |
| 
 | |
|     if (isShowing())
 | |
|       getView().validate();
 | |
| 
 | |
|     // If the bottom boundary of contentRect is below the port
 | |
|     // boundaries, scroll up as necessary.
 | |
|     if (contentY + contentRect.height + viewBounds.y > portBounds.height)
 | |
|       pos.y = contentY + contentRect.height - portBounds.height;
 | |
|     // If contentY is above the port boundaries, scroll down to
 | |
|     // contentY.
 | |
|     if (contentY + viewBounds.y < 0)
 | |
|       pos.y = contentY;
 | |
|     // If the right boundary of contentRect is right from the port
 | |
|     // boundaries, scroll left as necessary.
 | |
|     if (contentX + contentRect.width + viewBounds.x > portBounds.width)
 | |
|       pos.x = contentX + contentRect.width - portBounds.width;
 | |
|     // If contentX is left from the port boundaries, scroll right to
 | |
|     // contentRect.x.
 | |
|     if (contentX + viewBounds.x < 0)
 | |
|       pos.x = contentX;
 | |
|     setViewPosition(pos);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the accessible context for this <code>JViewport</code>. This
 | |
|    * will be an instance of {@link AccessibleJViewport}.
 | |
|    *
 | |
|    * @return the accessible context for this <code>JViewport</code>
 | |
|    */
 | |
|   public AccessibleContext getAccessibleContext()
 | |
|   {
 | |
|     if (accessibleContext == null)
 | |
|       accessibleContext = new AccessibleJViewport();
 | |
|     return accessibleContext;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Forward repaint to parent to make sure only one paint is performed by the
 | |
|    * RepaintManager.
 | |
|    *
 | |
|    * @param tm number of milliseconds to defer the repaint request
 | |
|    * @param x the X coordinate of the upper left corner of the dirty area
 | |
|    * @param y the Y coordinate of the upper left corner of the dirty area
 | |
|    * @param w the width of the dirty area
 | |
|    * @param h the height of the dirty area
 | |
|    */
 | |
|   public void repaint(long tm, int x, int y, int w, int h)
 | |
|   {
 | |
|     Component parent = getParent();
 | |
|     if (parent != null)
 | |
|       parent.repaint(tm, x + getX(), y + getY(), w, h);
 | |
|     else
 | |
|       super.repaint(tm, x, y, w, h);
 | |
|   }
 | |
| 
 | |
|   protected void addImpl(Component comp, Object constraints, int index)
 | |
|   {
 | |
|     if (getComponentCount() > 0)
 | |
|       remove(getComponents()[0]);
 | |
| 
 | |
|     super.addImpl(comp, constraints, index);
 | |
|   }
 | |
| 
 | |
|   protected void fireStateChanged()
 | |
|   {
 | |
|     ChangeListener[] listeners = getChangeListeners();
 | |
|     for (int i = 0; i < listeners.length; ++i)
 | |
|       listeners[i].stateChanged(changeEvent);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Computes the parameters for the blitting scroll method. <code>dx</code>
 | |
|    * and <code>dy</code> specifiy the X and Y offset by which the viewport
 | |
|    * is scrolled. All other arguments are output parameters and are filled by
 | |
|    * this method.
 | |
|    *
 | |
|    * <code>blitFrom</code> holds the position of the blit rectangle in the
 | |
|    * viewport rectangle before scrolling, <code>blitTo</code> where the blitArea
 | |
|    * is copied to.
 | |
|    *
 | |
|    * <code>blitSize</code> holds the size of the blit area and
 | |
|    * <code>blitPaint</code> is the area of the view that needs to be painted.
 | |
|    *
 | |
|    * This method returns <code>true</code> if blitting is possible and
 | |
|    * <code>false</code> if the viewport has to be repainted completetly without
 | |
|    * blitting.
 | |
|    *
 | |
|    * @param dx the horizontal delta
 | |
|    * @param dy the vertical delta
 | |
|    * @param blitFrom the position from where to blit; set by this method
 | |
|    * @param blitTo the position where to blit area is copied to; set by this
 | |
|    *        method
 | |
|    * @param blitSize the size of the blitted area; set by this method
 | |
|    * @param blitPaint the area that needs repainting; set by this method
 | |
|    *
 | |
|    * @return <code>true</code> if blitting is possible,
 | |
|    *         <code>false</code> otherwise
 | |
|    */
 | |
|   protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
 | |
|                                 Dimension blitSize, Rectangle blitPaint)
 | |
|   {
 | |
|     if ((dx != 0 && dy != 0) || (dy == 0 && dy == 0) || damaged)
 | |
|       // We cannot blit if the viewport is scrolled in both directions at
 | |
|       // once. Also, we do not want to blit if the viewport is not scrolled at
 | |
|       // all, because that probably means the view component repaints itself
 | |
|       // and the buffer needs updating.
 | |
|       return false;
 | |
| 
 | |
|     Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
 | |
| 
 | |
|     // Compute the blitFrom and blitTo parameters.
 | |
|     blitFrom.x = portBounds.x;
 | |
|     blitFrom.y = portBounds.y;
 | |
|     blitTo.x = portBounds.x;
 | |
|     blitTo.y = portBounds.y;
 | |
| 
 | |
|     if (dy > 0)
 | |
|       {
 | |
|         blitFrom.y = portBounds.y + dy;
 | |
|       }
 | |
|     else if (dy < 0)
 | |
|       {
 | |
|         blitTo.y = portBounds.y - dy;
 | |
|       }
 | |
|     else if (dx > 0)
 | |
|       {
 | |
|         blitFrom.x = portBounds.x + dx;
 | |
|       }
 | |
|     else if (dx < 0)
 | |
|       {
 | |
|         blitTo.x = portBounds.x - dx;
 | |
|       }
 | |
| 
 | |
|     // Compute size of the blit area.
 | |
|     if (dx != 0)
 | |
|       {
 | |
|         blitSize.width = portBounds.width - Math.abs(dx);
 | |
|         blitSize.height = portBounds.height;
 | |
|       }
 | |
|     else if (dy != 0)
 | |
|       {
 | |
|         blitSize.width = portBounds.width;
 | |
|         blitSize.height = portBounds.height - Math.abs(dy);
 | |
|       }
 | |
| 
 | |
|     // Compute the blitPaint parameter.
 | |
|     blitPaint.setBounds(portBounds);
 | |
|     if (dy > 0)
 | |
|       {
 | |
|         blitPaint.y = portBounds.y + portBounds.height - dy;
 | |
|         blitPaint.height = dy;
 | |
|       }
 | |
|     else if (dy < 0)
 | |
|       {
 | |
|         blitPaint.height = -dy;
 | |
|       }
 | |
|     if (dx > 0)
 | |
|       {
 | |
|         blitPaint.x = portBounds.x + portBounds.width - dx;
 | |
|         blitPaint.width = dx;
 | |
|       }
 | |
|     else if (dx < 0)
 | |
|       {
 | |
|         blitPaint.width = -dx;
 | |
|       }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Paints the viewport in case we have a scrollmode of
 | |
|    * {@link #SIMPLE_SCROLL_MODE}.
 | |
|    *
 | |
|    * This simply paints the view directly on the surface of the viewport.
 | |
|    *
 | |
|    * @param g the graphics context to use
 | |
|    */
 | |
|   void paintSimple(Graphics g)
 | |
|   {
 | |
|     // We need to call this to properly clear the background.
 | |
|     paintComponent(g);
 | |
| 
 | |
|     Point pos = getViewPosition();
 | |
|     Component view = getView();
 | |
|     Shape oldClip = g.getClip();
 | |
|     g.clipRect(0, 0, getWidth(), getHeight());
 | |
|     boolean translated = false;
 | |
|     try
 | |
|       {
 | |
|         g.translate(-pos.x, -pos.y);
 | |
|         translated = true;
 | |
|         view.paint(g);
 | |
|       }
 | |
|     finally
 | |
|       {
 | |
|         if (translated)
 | |
|           g.translate (pos.x, pos.y);
 | |
|         g.setClip(oldClip);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Paints the viewport in case we have a scroll mode of
 | |
|    * {@link #BACKINGSTORE_SCROLL_MODE}.
 | |
|    *
 | |
|    * This method uses a backing store image to paint the view to, which is then
 | |
|    * subsequently painted on the screen. This should make scrolling more
 | |
|    * smooth.
 | |
|    *
 | |
|    * @param g the graphics context to use
 | |
|    */
 | |
|   void paintBackingStore(Graphics g)
 | |
|   {
 | |
|     // If we have no backing store image yet or the size of the component has
 | |
|     // changed, we need to rebuild the backing store.
 | |
|     if (backingStoreImage == null || sizeChanged)
 | |
|       {
 | |
|         backingStoreImage = createImage(getWidth(), getHeight());
 | |
|         sizeChanged = false;
 | |
|         Graphics g2 = backingStoreImage.getGraphics();
 | |
|         paintSimple(g2);
 | |
|         g2.dispose();
 | |
|       }
 | |
|     // Otherwise we can perform the blitting on the backing store image:
 | |
|     // First we move the part that remains visible after scrolling, then
 | |
|     // we only need to paint the bit that becomes newly visible.
 | |
|     else
 | |
|       {
 | |
|         Graphics g2 = backingStoreImage.getGraphics();
 | |
|         Point viewPosition = getViewPosition();
 | |
|         int dx = viewPosition.x - lastPaintPosition.x;
 | |
|         int dy = viewPosition.y - lastPaintPosition.y;
 | |
|         boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
 | |
|                                       cachedBlitSize, cachedBlitPaint);
 | |
|         if (canBlit && isPaintRoot)
 | |
|           {
 | |
|             // Copy the part that remains visible during scrolling.
 | |
|             if (cachedBlitSize.width > 0 && cachedBlitSize.height > 0)
 | |
|               {
 | |
|                 g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
 | |
|                             cachedBlitSize.width, cachedBlitSize.height,
 | |
|                             cachedBlitTo.x - cachedBlitFrom.x,
 | |
|                             cachedBlitTo.y - cachedBlitFrom.y);
 | |
|               }
 | |
|             // Now paint the part that becomes newly visible.
 | |
|             g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y,
 | |
|                        cachedBlitPaint.width, cachedBlitPaint.height);
 | |
|             paintSimple(g2);
 | |
|           }
 | |
|         // If blitting is not possible for some reason, fall back to repainting
 | |
|         // everything.
 | |
|         else
 | |
|           {
 | |
|             // If the image has not been scrolled at all, only the changed
 | |
|             // clip must be updated in the buffer.
 | |
|             if (dx == 0 && dy == 0)
 | |
|               g2.setClip(g.getClip());
 | |
| 
 | |
|             paintSimple(g2);
 | |
|           }
 | |
|         g2.dispose();
 | |
|       }
 | |
|     // Actually draw the backingstore image to the graphics context.
 | |
|     g.drawImage(backingStoreImage, 0, 0, this);
 | |
|     // Update the lastPaintPosition so that we know what is already drawn when
 | |
|     // we paint the next time.
 | |
|     lastPaintPosition.setLocation(getViewPosition());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Paints the viewport in case we have a scrollmode of
 | |
|    * {@link #BLIT_SCROLL_MODE}.
 | |
|    *
 | |
|    * This paints the viewport using a backingstore and a blitting algorithm.
 | |
|    * Only the newly exposed area of the view is painted from the view painting
 | |
|    * methods, the remainder is copied from the backing store.
 | |
|    *
 | |
|    * @param g the graphics context to use
 | |
|    */
 | |
|   void paintBlit(Graphics g)
 | |
|   {
 | |
|     // First we move the part that remains visible after scrolling, then
 | |
|     // we only need to paint the bit that becomes newly visible.
 | |
|     Point viewPosition = getViewPosition();
 | |
|     int dx = viewPosition.x - lastPaintPosition.x;
 | |
|     int dy = viewPosition.y - lastPaintPosition.y;
 | |
|     boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
 | |
|                                   cachedBlitSize, cachedBlitPaint);
 | |
|     if (canBlit && isPaintRoot)
 | |
|       {
 | |
|         // Copy the part that remains visible during scrolling.
 | |
|         if (cachedBlitSize.width > 0 && cachedBlitSize.width > 0)
 | |
|           {
 | |
|             g.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
 | |
|                        cachedBlitSize.width, cachedBlitSize.height,
 | |
|                        cachedBlitTo.x - cachedBlitFrom.x,
 | |
|                        cachedBlitTo.y - cachedBlitFrom.y);
 | |
|           }
 | |
|         // Now paint the part that becomes newly visible.
 | |
|         Shape oldClip = g.getClip();
 | |
|         g.clipRect(cachedBlitPaint.x, cachedBlitPaint.y,
 | |
|                   cachedBlitPaint.width, cachedBlitPaint.height);
 | |
|         try
 | |
|           {
 | |
|             paintSimple(g);
 | |
|           }
 | |
|         finally
 | |
|           {
 | |
|             g.setClip(oldClip);
 | |
|           }
 | |
|       }
 | |
|     // If blitting is not possible for some reason, fall back to repainting
 | |
|     // everything.
 | |
|     else
 | |
|       paintSimple(g);
 | |
|     lastPaintPosition.setLocation(getViewPosition());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Overridden from JComponent to set the {@link #isPaintRoot} flag.
 | |
|    *
 | |
|    * @param x the rectangle to paint, X coordinate
 | |
|    * @param y the rectangle to paint, Y coordinate
 | |
|    * @param w the rectangle to paint, width
 | |
|    * @param h the rectangle to paint, height
 | |
|    */
 | |
|   void paintImmediately2(int x, int y, int w, int h)
 | |
|   {
 | |
|     isPaintRoot = true;
 | |
|     super.paintImmediately2(x, y, w, h);
 | |
|     isPaintRoot = false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true when the JViewport is using a backbuffer, so that we
 | |
|    * can update our backbuffer correctly.
 | |
|    */
 | |
|   boolean isPaintRoot()
 | |
|   {
 | |
|     return scrollMode == BACKINGSTORE_SCROLL_MODE;
 | |
|   }
 | |
| }
 |