Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / javax / swing / JViewport.java
blob5f20f0aa60a7665685154a6409b105f43602591f
1 /* JViewport.java --
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing;
41 import java.awt.Component;
42 import java.awt.Dimension;
43 import java.awt.Graphics;
44 import java.awt.Image;
45 import java.awt.Insets;
46 import java.awt.LayoutManager;
47 import java.awt.Point;
48 import java.awt.Rectangle;
49 import java.awt.event.ComponentAdapter;
50 import java.awt.event.ComponentEvent;
51 import java.io.Serializable;
53 import javax.accessibility.Accessible;
54 import javax.accessibility.AccessibleContext;
55 import javax.accessibility.AccessibleRole;
56 import javax.swing.border.Border;
57 import javax.swing.event.ChangeEvent;
58 import javax.swing.event.ChangeListener;
59 import javax.swing.plaf.ViewportUI;
61 /**
63 * <pre>
64 * _
65 * +-------------------------------+ ...........Y1 \
66 * | view | . \
67 * | (this component's child) | . > VY
68 * | | . / = Y2-Y1
69 * | +------------------------------+ ....Y2_/
70 * | | viewport | | .
71 * | | (this component) | | .
72 * | | | | .
73 * | | | | .
74 * | | | | .
75 * | | | | .
76 * | +------------------------------+ ....Y3
77 * | | .
78 * | . | . .
79 * | . | . .
80 * +---------.---------------------+ ...........Y4
81 * . . . .
82 * . . . .
83 * . . . .
84 * X1.......X2.....................X3.......X4
85 * \____ ___/
86 * \/
87 * VX = X2-X1
88 *</pre>
90 * <p>A viewport is, like all swing components, located at some position in
91 * the swing component tree; that location is exactly the same as any other
92 * components: the viewport's "bounds".</p>
94 * <p>But in terms of drawing its child, the viewport thinks of itself as
95 * covering a particular position <em>of the view's coordinate space</em>.
96 * For example, the {@link #getViewPosition} method returns
97 * the position <code>(VX,VY)</code> shown above, which is an position in
98 * "view space", even though this is <em>implemented</em> by positioning
99 * the underlying child at position <code>(-VX,-VY)</code></p>
102 public class JViewport extends JComponent implements Accessible
105 * Provides accessibility support for <code>JViewport</code>.
107 * @author Roman Kennke (roman@kennke.org)
109 protected class AccessibleJViewport extends AccessibleJComponent
112 * Creates a new instance of <code>AccessibleJViewport</code>.
114 public AccessibleJViewport()
116 // Nothing to do here.
120 * Returns the accessible role of <code>JViewport</code>, which is
121 * {@link AccessibleRole#VIEWPORT}.
123 * @return the accessible role of <code>JViewport</code>
125 public AccessibleRole getAccessibleRole()
127 return AccessibleRole.VIEWPORT;
132 * A {@link java.awt.event.ComponentListener} that listens for
133 * changes of the view's size. This triggers a revalidate() call on the
134 * viewport.
136 protected class ViewListener extends ComponentAdapter implements Serializable
138 private static final long serialVersionUID = -2812489404285958070L;
141 * Creates a new instance of ViewListener.
143 protected ViewListener()
145 // Nothing to do here.
149 * Receives notification when a component (in this case: the view
150 * component) changes it's size. This simply triggers a revalidate() on the
151 * viewport.
153 * @param ev the ComponentEvent describing the change
155 public void componentResized(ComponentEvent ev)
157 revalidate();
161 public static final int SIMPLE_SCROLL_MODE = 0;
162 public static final int BLIT_SCROLL_MODE = 1;
163 public static final int BACKINGSTORE_SCROLL_MODE = 2;
165 private static final long serialVersionUID = -6925142919680527970L;
167 protected boolean scrollUnderway;
168 protected boolean isViewSizeSet;
171 * This flag indicates whether we use a backing store for drawing.
173 * @deprecated since JDK 1.3
175 protected boolean backingStore;
178 * The backingstore image used for the backingstore and blit scroll methods.
180 protected Image backingStoreImage;
183 * The position at which the view has been drawn the last time. This is used
184 * to determine the bittable area.
186 protected Point lastPaintPosition;
188 ChangeEvent changeEvent = new ChangeEvent(this);
190 int scrollMode;
192 /**
193 * The width and height of the Viewport's area in terms of view
194 * coordinates. Typically this will be the same as the width and height
195 * of the viewport's bounds, unless the viewport transforms units of
196 * width and height, which it may do, for example if it magnifies or
197 * rotates its view.
199 * @see #toViewCoordinates(Dimension)
201 Dimension extentSize;
204 * The width and height of the view in its own coordinate space.
206 Dimension viewSize;
209 * The ViewListener instance.
211 ViewListener viewListener;
214 * Stores the location from where to blit. This is a cached Point object used
215 * in blitting calculations.
217 Point cachedBlitFrom;
220 * Stores the location where to blit to. This is a cached Point object used
221 * in blitting calculations.
223 Point cachedBlitTo;
226 * Stores the width of the blitted area. This is a cached Dimension object
227 * used in blitting calculations.
229 Dimension cachedBlitSize;
232 * Stores the bounds of the area that needs to be repainted. This is a cached
233 * Rectangle object used in blitting calculations.
235 Rectangle cachedBlitPaint;
237 boolean damaged = true;
240 * A flag indicating if the size of the viewport has changed since the
241 * last repaint. This is used in double buffered painting to check if we
242 * need a new double buffer, or can reuse the old one.
244 boolean sizeChanged = true;
246 public JViewport()
248 setOpaque(true);
249 String scrollModeProp =
250 System.getProperty("gnu.javax.swing.JViewport.scrollMode",
251 "BLIT");
252 int myScrollMode;
253 if (scrollModeProp.equalsIgnoreCase("simple"))
254 myScrollMode = SIMPLE_SCROLL_MODE;
255 else if (scrollModeProp.equalsIgnoreCase("backingstore"))
256 myScrollMode = BACKINGSTORE_SCROLL_MODE;
257 else
258 myScrollMode = BLIT_SCROLL_MODE;
259 setScrollMode(myScrollMode);
261 updateUI();
262 setLayout(createLayoutManager());
263 lastPaintPosition = new Point();
264 cachedBlitFrom = new Point();
265 cachedBlitTo = new Point();
266 cachedBlitSize = new Dimension();
267 cachedBlitPaint = new Rectangle();
270 public Dimension getExtentSize()
272 if (extentSize == null)
273 return toViewCoordinates(getSize());
274 else
275 return extentSize;
278 public Dimension toViewCoordinates(Dimension size)
280 return size;
283 public Point toViewCoordinates(Point p)
285 Point pos = getViewPosition();
286 return new Point(p.x + pos.x,
287 p.y + pos.y);
290 public void setExtentSize(Dimension newSize)
292 extentSize = newSize;
293 fireStateChanged();
297 * Returns the viewSize when set, or the preferred size of the set
298 * Component view. If no viewSize and no Component view is set an
299 * empty Dimension is returned.
301 public Dimension getViewSize()
303 if (isViewSizeSet)
304 return viewSize;
305 else
307 Component view = getView();
308 if (view != null)
309 return view.getPreferredSize();
310 else
311 return new Dimension();
316 public void setViewSize(Dimension newSize)
318 viewSize = newSize;
319 Component view = getView();
320 if (view != null)
322 if (newSize != view.getSize())
324 view.setSize(viewSize);
325 fireStateChanged();
328 isViewSizeSet = true;
332 * Get the viewport's position in view space. Despite confusing name,
333 * this really does return the viewport's (0,0) position in view space,
334 * not the view's position.
337 public Point getViewPosition()
339 Component view = getView();
340 if (view == null)
341 return new Point(0,0);
342 else
344 Point p = view.getLocation();
345 p.x = -p.x;
346 p.y = -p.y;
347 return p;
351 public void setViewPosition(Point p)
353 if (getViewPosition().equals(p))
354 return;
355 Component view = getView();
356 if (view != null)
358 Point q = new Point(-p.x, -p.y);
359 view.setLocation(q);
360 isViewSizeSet = false;
361 fireStateChanged();
363 repaint();
366 public Rectangle getViewRect()
368 return new Rectangle(getViewPosition(),
369 getExtentSize());
373 * @deprecated 1.4
375 public boolean isBackingStoreEnabled()
377 return scrollMode == BACKINGSTORE_SCROLL_MODE;
381 * @deprecated 1.4
383 public void setBackingStoreEnabled(boolean b)
385 if (b && scrollMode != BACKINGSTORE_SCROLL_MODE)
387 scrollMode = BACKINGSTORE_SCROLL_MODE;
388 fireStateChanged();
392 public void setScrollMode(int mode)
394 scrollMode = mode;
395 fireStateChanged();
398 public int getScrollMode()
400 return scrollMode;
403 public Component getView()
405 if (getComponentCount() == 0)
406 return null;
408 return getComponents()[0];
411 public void setView(Component v)
413 if (viewListener != null)
414 getView().removeComponentListener(viewListener);
416 if (v != null)
418 if (viewListener == null)
419 viewListener = createViewListener();
420 v.addComponentListener(viewListener);
421 add(v);
422 fireStateChanged();
424 revalidate();
425 repaint();
428 public void reshape(int x, int y, int w, int h)
430 if (w != getWidth() || h != getHeight())
431 sizeChanged = true;
432 super.reshape(x, y, w, h);
433 if (sizeChanged)
435 damaged = true;
436 fireStateChanged();
440 public final Insets getInsets()
442 return new Insets(0, 0, 0, 0);
445 public final Insets getInsets(Insets insets)
447 if (insets == null)
448 return getInsets();
449 insets.top = 0;
450 insets.bottom = 0;
451 insets.left = 0;
452 insets.right = 0;
453 return insets;
458 * Overridden to return <code>false</code>, so the JViewport's paint method
459 * gets called instead of directly calling the children. This is necessary
460 * in order to get a useful clipping and translation on the children.
462 * @return <code>false</code>
464 public boolean isOptimizedDrawingEnabled()
466 return false;
469 public void paint(Graphics g)
471 Component view = getView();
473 if (view == null)
474 return;
476 Point pos = getViewPosition();
477 Rectangle viewBounds = view.getBounds();
478 Rectangle portBounds = getBounds();
480 if (viewBounds.width == 0
481 || viewBounds.height == 0
482 || portBounds.width == 0
483 || portBounds.height == 0)
484 return;
486 switch (getScrollMode())
489 case JViewport.BACKINGSTORE_SCROLL_MODE:
490 paintBackingStore(g);
491 break;
492 case JViewport.BLIT_SCROLL_MODE:
493 paintBlit(g);
494 break;
495 case JViewport.SIMPLE_SCROLL_MODE:
496 default:
497 paintSimple(g);
498 break;
500 damaged = false;
503 public void addChangeListener(ChangeListener listener)
505 listenerList.add(ChangeListener.class, listener);
508 public void removeChangeListener(ChangeListener listener)
510 listenerList.remove(ChangeListener.class, listener);
513 public ChangeListener[] getChangeListeners()
515 return (ChangeListener[]) getListeners(ChangeListener.class);
519 * This method returns the String ID of the UI class of Separator.
521 * @return The UI class' String ID.
523 public String getUIClassID()
525 return "ViewportUI";
529 * This method resets the UI used to the Look and Feel defaults..
531 public void updateUI()
533 setUI((ViewportUI) UIManager.getUI(this));
537 * This method returns the viewport's UI delegate.
539 * @return The viewport's UI delegate.
541 public ViewportUI getUI()
543 return (ViewportUI) ui;
547 * This method sets the viewport's UI delegate.
549 * @param ui The viewport's UI delegate.
551 public void setUI(ViewportUI ui)
553 super.setUI(ui);
556 public final void setBorder(Border border)
558 if (border != null)
559 throw new IllegalArgumentException();
563 * Scrolls the view so that contentRect becomes visible.
565 * @param contentRect the rectangle to make visible within the view
567 public void scrollRectToVisible(Rectangle contentRect)
569 Component view = getView();
570 if (view == null)
571 return;
573 Point pos = getViewPosition();
574 Rectangle viewBounds = getView().getBounds();
575 Rectangle portBounds = getBounds();
577 if (isShowing())
578 getView().validate();
580 // If the bottom boundary of contentRect is below the port
581 // boundaries, scroll up as necessary.
582 if (contentRect.y + contentRect.height + viewBounds.y > portBounds.height)
583 pos.y = contentRect.y + contentRect.height - portBounds.height;
584 // If contentRect.y is above the port boundaries, scroll down to
585 // contentRect.y.
586 if (contentRect.y + viewBounds.y < 0)
587 pos.y = contentRect.y;
588 // If the right boundary of contentRect is right from the port
589 // boundaries, scroll left as necessary.
590 if (contentRect.x + contentRect.width + viewBounds.x > portBounds.width)
591 pos.x = contentRect.x + contentRect.width - portBounds.width;
592 // If contentRect.x is left from the port boundaries, scroll right to
593 // contentRect.x.
594 if (contentRect.x + viewBounds.x < 0)
595 pos.x = contentRect.x;
596 setViewPosition(pos);
600 * Returns the accessible context for this <code>JViewport</code>. This
601 * will be an instance of {@link AccessibleJViewport}.
603 * @return the accessible context for this <code>JViewport</code>
605 public AccessibleContext getAccessibleContext()
607 if (accessibleContext == null)
608 accessibleContext = new AccessibleJViewport();
609 return accessibleContext;
613 * Forward repaint to parent to make sure only one paint is performed by the
614 * RepaintManager.
616 * @param tm number of milliseconds to defer the repaint request
617 * @param x the X coordinate of the upper left corner of the dirty area
618 * @param y the Y coordinate of the upper left corner of the dirty area
619 * @param w the width of the dirty area
620 * @param h the height of the dirty area
622 public void repaint(long tm, int x, int y, int w, int h)
624 Component parent = getParent();
625 if (parent != null)
627 parent.repaint(tm, x + getX(), y + getY(), w, h);
631 protected void addImpl(Component comp, Object constraints, int index)
633 if (getComponentCount() > 0)
634 remove(getComponents()[0]);
636 super.addImpl(comp, constraints, index);
639 protected void fireStateChanged()
641 ChangeListener[] listeners = getChangeListeners();
642 for (int i = 0; i < listeners.length; ++i)
643 listeners[i].stateChanged(changeEvent);
647 * Creates a {@link ViewListener} that is supposed to listen for
648 * size changes on the view component.
650 * @return a ViewListener instance
652 protected ViewListener createViewListener()
654 return new ViewListener();
658 * Creates the LayoutManager that is used for this viewport. Override
659 * this method if you want to use a custom LayoutManager.
661 * @return a LayoutManager to use for this viewport
663 protected LayoutManager createLayoutManager()
665 return new ViewportLayout();
669 * Computes the parameters for the blitting scroll method. <code>dx</code>
670 * and <code>dy</code> specifiy the X and Y offset by which the viewport
671 * is scrolled. All other arguments are output parameters and are filled by
672 * this method.
674 * <code>blitFrom</code> holds the position of the blit rectangle in the
675 * viewport rectangle before scrolling, <code>blitTo</code> where the blitArea
676 * is copied to.
678 * <code>blitSize</code> holds the size of the blit area and
679 * <code>blitPaint</code> is the area of the view that needs to be painted.
681 * This method returns <code>true</code> if blitting is possible and
682 * <code>false</code> if the viewport has to be repainted completetly without
683 * blitting.
685 * @param dx the horizontal delta
686 * @param dy the vertical delta
687 * @param blitFrom the position from where to blit; set by this method
688 * @param blitTo the position where to blit area is copied to; set by this
689 * method
690 * @param blitSize the size of the blitted area; set by this method
691 * @param blitPaint the area that needs repainting; set by this method
693 * @return <code>true</code> if blitting is possible,
694 * <code>false</code> otherwise
696 protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
697 Dimension blitSize, Rectangle blitPaint)
699 if ((dx != 0 && dy != 0) || damaged)
700 // We cannot blit if the viewport is scrolled in both directions at
701 // once.
702 return false;
704 Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
706 // Compute the blitFrom and blitTo parameters.
707 blitFrom.x = portBounds.x;
708 blitFrom.y = portBounds.y;
709 blitTo.x = portBounds.x;
710 blitTo.y = portBounds.y;
712 if (dy > 0)
714 blitFrom.y = portBounds.y + dy;
716 else if (dy < 0)
718 blitTo.y = portBounds.y - dy;
720 else if (dx > 0)
722 blitFrom.x = portBounds.x + dx;
724 else if (dx < 0)
726 blitTo.x = portBounds.x - dx;
729 // Compute size of the blit area.
730 if (dx != 0)
732 blitSize.width = portBounds.width - Math.abs(dx);
733 blitSize.height = portBounds.height;
735 else if (dy != 0)
737 blitSize.width = portBounds.width;
738 blitSize.height = portBounds.height - Math.abs(dy);
741 // Compute the blitPaint parameter.
742 blitPaint.setBounds(portBounds);
743 if (dy > 0)
745 blitPaint.y = portBounds.y + portBounds.height - dy;
746 blitPaint.height = dy;
748 else if (dy < 0)
750 blitPaint.height = -dy;
752 if (dx > 0)
754 blitPaint.x = portBounds.x + portBounds.width - dx;
755 blitPaint.width = dx;
757 else if (dx < 0)
759 blitPaint.width = -dx;
762 return true;
766 * Paints the viewport in case we have a scrollmode of
767 * {@link #SIMPLE_SCROLL_MODE}.
769 * This simply paints the view directly on the surface of the viewport.
771 * @param g the graphics context to use
773 void paintSimple(Graphics g)
775 Point pos = getViewPosition();
776 Component view = getView();
777 boolean translated = false;
780 g.translate(-pos.x, -pos.y);
781 translated = true;
782 view.paint(g);
784 finally
786 if (translated)
787 g.translate (pos.x, pos.y);
792 * Paints the viewport in case we have a scroll mode of
793 * {@link #BACKINGSTORE_SCROLL_MODE}.
795 * This method uses a backing store image to paint the view to, which is then
796 * subsequently painted on the screen. This should make scrolling more
797 * smooth.
799 * @param g the graphics context to use
801 void paintBackingStore(Graphics g)
803 // If we have no backing store image yet or the size of the component has
804 // changed, we need to rebuild the backing store.
805 if (backingStoreImage == null || sizeChanged)
807 backingStoreImage = createImage(getWidth(), getHeight());
808 sizeChanged = false;
809 Graphics g2 = backingStoreImage.getGraphics();
810 paintSimple(g2);
811 g2.dispose();
813 // Otherwise we can perform the blitting on the backing store image:
814 // First we move the part that remains visible after scrolling, then
815 // we only need to paint the bit that becomes newly visible.
816 else
818 Graphics g2 = backingStoreImage.getGraphics();
819 Point viewPosition = getViewPosition();
820 int dx = viewPosition.x - lastPaintPosition.x;
821 int dy = viewPosition.y - lastPaintPosition.y;
822 boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
823 cachedBlitSize, cachedBlitPaint);
824 if (canBlit)
826 // Copy the part that remains visible during scrolling.
827 g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
828 cachedBlitSize.width, cachedBlitSize.height,
829 cachedBlitTo.x - cachedBlitFrom.x,
830 cachedBlitTo.y - cachedBlitFrom.y);
831 // Now paint the part that becomes newly visible.
832 g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y,
833 cachedBlitPaint.width, cachedBlitPaint.height);
834 paintSimple(g2);
836 // If blitting is not possible for some reason, fall back to repainting
837 // everything.
838 else
840 paintSimple(g2);
842 g2.dispose();
844 // Actually draw the backingstore image to the graphics context.
845 g.drawImage(backingStoreImage, 0, 0, this);
846 // Update the lastPaintPosition so that we know what is already drawn when
847 // we paint the next time.
848 lastPaintPosition.setLocation(getViewPosition());
852 * Paints the viewport in case we have a scrollmode of
853 * {@link #BLIT_SCROLL_MODE}.
855 * This paints the viewport using a backingstore and a blitting algorithm.
856 * Only the newly exposed area of the view is painted from the view painting
857 * methods, the remainder is copied from the backing store.
859 * @param g the graphics context to use
861 void paintBlit(Graphics g)
863 // We cannot perform blitted painting as it is described in Sun's API docs.
864 // There it is suggested that this painting method should blit directly
865 // on the parent window's surface. This is not possible because when using
866 // Swing's double buffering (at least our implementation), it would
867 // immediatly be painted when the buffer is painted on the screen. For this
868 // to work we would need a kind of hole in the buffer image. And honestly
869 // I find this method not very elegant.
870 // The alternative, blitting directly on the buffer image, is also not
871 // possible because the buffer image gets cleared everytime when an opaque
872 // parent component is drawn on it.
874 // What we do instead is falling back to the backing store approach which
875 // is in fact a mixed blitting/backing store approach where the blitting
876 // is performed on the backing store image and this is then drawn to the
877 // graphics context. This is very robust and works independent of the
878 // painting mechanism that is used by Swing. And it should have comparable
879 // performance characteristics as the blitting method.
880 paintBackingStore(g);