123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949 |
- /* 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;
- }
- }
|