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;
 | 
						|
  }
 | 
						|
}
 |