Source Code Cross Referenced for JViewport.java in  » 6.0-JDK-Core » swing » javax » swing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        package javax.swing;
0027
0028        import java.awt.*;
0029        import java.awt.event.*;
0030        import java.awt.image.VolatileImage;
0031        import java.awt.peer.ComponentPeer;
0032        import java.applet.Applet;
0033        import javax.swing.plaf.ViewportUI;
0034
0035        import javax.swing.event.*;
0036        import javax.swing.border.*;
0037        import javax.accessibility.*;
0038
0039        import java.io.Serializable;
0040
0041        /**
0042         * The "viewport" or "porthole" through which you see the underlying
0043         * information. When you scroll, what moves is the viewport. It is like
0044         * peering through a camera's viewfinder. Moving the viewfinder upwards
0045         * brings new things into view at the top of the picture and loses
0046         * things that were at the bottom.
0047         * <p>
0048         * By default, <code>JViewport</code> is opaque. To change this, use the
0049         * <code>setOpaque</code> method.
0050         * <p>
0051         * <b>NOTE:</b>We have implemented a faster scrolling algorithm that
0052         * does not require a buffer to draw in. The algorithm works as follows:
0053         * <ol><li>The view and parent view and checked to see if they are
0054         * <code>JComponents</code>,
0055         * if they aren't, stop and repaint the whole viewport.
0056         * <li>If the viewport is obscured by an ancestor, stop and repaint the whole
0057         * viewport.
0058         * <li>Compute the region that will become visible, if it is as big as
0059         * the viewport, stop and repaint the whole view region.
0060         * <li>Obtain the ancestor <code>Window</code>'s graphics and
0061         * do a <code>copyArea</code> on the scrolled region.
0062         * <li>Message the view to repaint the newly visible region.
0063         * <li>The next time paint is invoked on the viewport, if the clip region
0064         * is smaller than the viewport size a timer is kicked off to repaint the
0065         * whole region.
0066         * </ol>
0067         * In general this approach is much faster. Compared to the backing store
0068         * approach this avoids the overhead of maintaining an offscreen buffer and
0069         * having to do two <code>copyArea</code>s.
0070         * Compared to the non backing store case this
0071         * approach will greatly reduce the painted region.
0072         * <p>
0073         * This approach can cause slower times than the backing store approach
0074         * when the viewport is obscured by another window, or partially offscreen.
0075         * When another window
0076         * obscures the viewport the copyArea will copy garbage and a
0077         * paint event will be generated by the system to inform us we need to
0078         * paint the newly exposed region. The only way to handle this is to
0079         * repaint the whole viewport, which can cause slower performance than the
0080         * backing store case. In most applications very rarely will the user be
0081         * scrolling while the viewport is obscured by another window or offscreen,
0082         * so this optimization is usually worth the performance hit when obscured.
0083         * <p>
0084         * <strong>Warning:</strong> Swing is not thread safe. For more
0085         * information see <a
0086         * href="package-summary.html#threading">Swing's Threading
0087         * Policy</a>.
0088         * <p>
0089         * <strong>Warning:</strong>
0090         * Serialized objects of this class will not be compatible with
0091         * future Swing releases. The current serialization support is
0092         * appropriate for short term storage or RMI between applications running
0093         * the same version of Swing.  As of 1.4, support for long term storage
0094         * of all JavaBeans<sup><font size="-2">TM</font></sup>
0095         * has been added to the <code>java.beans</code> package.
0096         * Please see {@link java.beans.XMLEncoder}.
0097         *
0098         * @version 1.128 05/05/07
0099         * @author Hans Muller
0100         * @author Philip Milne
0101         * @see JScrollPane
0102         */
0103        public class JViewport extends JComponent implements  Accessible {
0104            /**
0105             * @see #getUIClassID
0106             * @see #readObject
0107             */
0108            private static final String uiClassID = "ViewportUI";
0109
0110            /** Property used to indicate window blitting should not be done.
0111             */
0112            static final Object EnableWindowBlit = "EnableWindowBlit";
0113
0114            /**
0115             * True when the viewport dimensions have been determined. 
0116             * The default is false.
0117             */
0118            protected boolean isViewSizeSet = false;
0119
0120            /**
0121             * The last <code>viewPosition</code> that we've painted, so we know how
0122             * much of the backing store image is valid.
0123             */
0124            protected Point lastPaintPosition = null;
0125
0126            /**
0127             * True when this viewport is maintaining an offscreen image of its
0128             * contents, so that some scrolling can take place using fast "bit-blit"
0129             * operations instead of by accessing the view object to construct the
0130             * display.  The default is <code>false</code>.
0131             *
0132             * @deprecated As of Java 2 platform v1.3
0133             * @see #setScrollMode
0134             */
0135            @Deprecated
0136            protected boolean backingStore = false;
0137
0138            /** The view image used for a backing store. */
0139            transient protected Image backingStoreImage = null;
0140
0141            /**
0142             * The <code>scrollUnderway</code> flag is used for components like
0143             * <code>JList</code>.  When the downarrow key is pressed on a
0144             * <code>JList</code> and the selected
0145             * cell is the last in the list, the <code>scrollpane</code> autoscrolls.
0146             * Here, the old selected cell needs repainting and so we need
0147             * a flag to make the viewport do the optimized painting
0148             * only when there is an explicit call to
0149             * <code>setViewPosition(Point)</code>.
0150             * When <code>setBounds</code> is called through other routes,
0151             * the flag is off and the view repaints normally.  Another approach
0152             * would be to remove this from the <code>JViewport</code>
0153             * class and have the <code>JList</code> manage this case by using
0154             * <code>setBackingStoreEnabled</code>.  The default is
0155             * <code>false</code>.
0156             */
0157            protected boolean scrollUnderway = false;
0158
0159            /*
0160             * Listener that is notified each time the view changes size.
0161             */
0162            private ComponentListener viewListener = null;
0163
0164            /* Only one <code>ChangeEvent</code> is needed per
0165             * <code>JViewport</code> instance since the
0166             * event's only (read-only) state is the source property.  The source
0167             * of events generated here is always "this".
0168             */
0169            private transient ChangeEvent changeEvent = null;
0170
0171            /**
0172             * Use <code>graphics.copyArea</code> to implement scrolling.
0173             * This is the fastest for most applications.
0174             *
0175             * @see #setScrollMode
0176             * @since 1.3
0177             */
0178            public static final int BLIT_SCROLL_MODE = 1;
0179
0180            /**
0181             * Draws viewport contents into an offscreen image.
0182             * This was previously the default mode for <code>JTable</code>.
0183             * This mode may offer advantages over "blit mode"
0184             * in some cases, but it requires a large chunk of extra RAM.
0185             *
0186             * @see #setScrollMode
0187             * @since 1.3
0188             */
0189            public static final int BACKINGSTORE_SCROLL_MODE = 2;
0190
0191            /**
0192             * This mode uses the very simple method of redrawing the entire
0193             * contents of the scrollpane each time it is scrolled.
0194             * This was the default behavior in Swing 1.0 and Swing 1.1.
0195             * Either of the other two options will provide better performance 
0196             * in most cases.
0197             *
0198             * @see #setScrollMode
0199             * @since 1.3
0200             */
0201            public static final int SIMPLE_SCROLL_MODE = 0;
0202
0203            /**
0204             * @see #setScrollMode
0205             * @since 1.3
0206             */
0207            private int scrollMode = BLIT_SCROLL_MODE;
0208
0209            //
0210            // Window blitting:
0211            //
0212            // As mentioned in the javadoc when using windowBlit a paint event
0213            // will be generated by the system if copyArea copies a non-visible
0214            // portion of the view (in other words, it copies garbage). We are
0215            // not guaranteed to receive the paint event before other mouse events,
0216            // so we can not be sure we haven't already copied garbage a bunch of
0217            // times to different parts of the view. For that reason when a blit
0218            // happens and the Component is obscured (the check for obscurity
0219            // is not supported on all platforms and is checked via ComponentPeer
0220            // methods) the ivar repaintAll is set to true. When paint is received
0221            // if repaintAll is true (we previously did a blit) it is set to
0222            // false, and if the clip region is smaller than the viewport
0223            // waitingForRepaint is set to true and a timer is started. When
0224            // the timer fires if waitingForRepaint is true, repaint is invoked.
0225            // In the mean time, if the view is asked to scroll and waitingForRepaint
0226            // is true, a blit will not happen, instead the non-backing store case
0227            // of scrolling will happen, which will reset waitingForRepaint.
0228            // waitingForRepaint is set to false in paint when the clip rect is
0229            // bigger (or equal) to the size of the viewport.
0230            // A Timer is used instead of just a repaint as it appeared to offer
0231            // better performance.
0232
0233            /**
0234             * This is set to true in <code>setViewPosition</code>
0235             * if doing a window blit and the viewport is obscured.
0236             */
0237            private transient boolean repaintAll;
0238
0239            /**
0240             * This is set to true in paint, if <code>repaintAll</code>
0241             * is true and the clip rectangle does not match the bounds.
0242             * If true, and scrolling happens the
0243             * repaint manager is not cleared which then allows for the repaint
0244             * previously invoked to succeed.
0245             */
0246            private transient boolean waitingForRepaint;
0247
0248            /**
0249             * Instead of directly invoking repaint, a <code>Timer</code>
0250             * is started and when it fires, repaint is invoked.
0251             */
0252            private transient Timer repaintTimer;
0253
0254            /**
0255             * Set to true in paintView when paint is invoked.
0256             */
0257            private transient boolean inBlitPaint;
0258
0259            /**
0260             * Whether or not a valid view has been installed.
0261             */
0262            private boolean hasHadValidView;
0263
0264            /** Creates a <code>JViewport</code>. */
0265            public JViewport() {
0266                super ();
0267                setLayout(createLayoutManager());
0268                setOpaque(true);
0269                updateUI();
0270                setInheritsPopupMenu(true);
0271            }
0272
0273            /**
0274             * Returns the L&F object that renders this component.
0275             *
0276             * @return a <code>ViewportUI</code> object
0277             * @since 1.3
0278             */
0279            public ViewportUI getUI() {
0280                return (ViewportUI) ui;
0281            }
0282
0283            /**
0284             * Sets the L&F object that renders this component.
0285             *
0286             * @param ui  the <code>ViewportUI</code> L&F object
0287             * @see UIDefaults#getUI
0288             * @beaninfo
0289             *        bound: true
0290             *       hidden: true
0291             *    attribute: visualUpdate true
0292             *  description: The UI object that implements the Component's LookAndFeel. 
0293             * @since 1.3
0294             */
0295            public void setUI(ViewportUI ui) {
0296                super .setUI(ui);
0297            }
0298
0299            /**
0300             * Resets the UI property to a value from the current look and feel.
0301             *
0302             * @see JComponent#updateUI
0303             */
0304            public void updateUI() {
0305                setUI((ViewportUI) UIManager.getUI(this ));
0306            }
0307
0308            /**
0309             * Returns a string that specifies the name of the L&F class
0310             * that renders this component.
0311             *
0312             * @return the string "ViewportUI"
0313             *
0314             * @see JComponent#getUIClassID
0315             * @see UIDefaults#getUI
0316             */
0317            public String getUIClassID() {
0318                return uiClassID;
0319            }
0320
0321            /**
0322             * Sets the <code>JViewport</code>'s one lightweight child,
0323             * which can be <code>null</code>.
0324             * (Since there is only one child which occupies the entire viewport,
0325             * the <code>constraints</code> and <code>index</code>
0326             * arguments are ignored.)
0327             *
0328             * @param child       the lightweight <code>child</code> of the viewport
0329             * @param constraints the <code>constraints</code> to be respected
0330             * @param index       the index
0331             * @see #setView
0332             */
0333            protected void addImpl(Component child, Object constraints,
0334                    int index) {
0335                setView(child);
0336            }
0337
0338            /**
0339             * Removes the <code>Viewport</code>s one lightweight child.
0340             *
0341             * @see #setView
0342             */
0343            public void remove(Component child) {
0344                child.removeComponentListener(viewListener);
0345                super .remove(child);
0346            }
0347
0348            /**
0349             * Scrolls the view so that <code>Rectangle</code>
0350             * within the view becomes visible.
0351             * <p>
0352             * This attempts to validate the view before scrolling if the
0353             * view is currently not valid - <code>isValid</code> returns false.
0354             * To avoid excessive validation when the containment hierarchy is
0355             * being created this will not validate if one of the ancestors does not
0356             * have a peer, or there is no validate root ancestor, or one of the
0357             * ancestors is not a <code>Window</code> or <code>Applet</code>.
0358             * <p>
0359             * Note that this method will not scroll outside of the
0360             * valid viewport; for example, if <code>contentRect</code> is larger
0361             * than the viewport, scrolling will be confined to the viewport's
0362             * bounds.
0363             *
0364             * @param contentRect the <code>Rectangle</code> to display
0365             * @see JComponent#isValidateRoot
0366             * @see java.awt.Component#isValid
0367             * @see java.awt.Component#getPeer
0368             */
0369            public void scrollRectToVisible(Rectangle contentRect) {
0370                Component view = getView();
0371
0372                if (view == null) {
0373                    return;
0374                } else {
0375                    if (!view.isValid()) {
0376                        // If the view is not valid, validate. scrollRectToVisible
0377                        // may fail if the view is not valid first, contentRect
0378                        // could be bigger than invalid size.
0379                        validateView();
0380                    }
0381                    int dx = 0, dy = 0;
0382
0383                    dx = positionAdjustment(getWidth(), contentRect.width,
0384                            contentRect.x);
0385                    dy = positionAdjustment(getHeight(), contentRect.height,
0386                            contentRect.y);
0387
0388                    if (dx != 0 || dy != 0) {
0389                        Point viewPosition = getViewPosition();
0390                        Dimension viewSize = view.getSize();
0391                        int startX = viewPosition.x;
0392                        int startY = viewPosition.y;
0393                        Dimension extent = getExtentSize();
0394
0395                        viewPosition.x -= dx;
0396                        viewPosition.y -= dy;
0397                        // Only constrain the location if the view is valid. If the
0398                        // the view isn't valid, it typically indicates the view
0399                        // isn't visible yet and most likely has a bogus size as will
0400                        // we, and therefore we shouldn't constrain the scrolling
0401                        if (view.isValid()) {
0402                            if (getParent().getComponentOrientation()
0403                                    .isLeftToRight()) {
0404                                if (viewPosition.x + extent.width > viewSize.width) {
0405                                    viewPosition.x = Math.max(0, viewSize.width
0406                                            - extent.width);
0407                                } else if (viewPosition.x < 0) {
0408                                    viewPosition.x = 0;
0409                                }
0410                            } else {
0411                                if (extent.width > viewSize.width) {
0412                                    viewPosition.x = viewSize.width
0413                                            - extent.width;
0414                                } else {
0415                                    viewPosition.x = Math.max(0, Math.min(
0416                                            viewSize.width - extent.width,
0417                                            viewPosition.x));
0418                                }
0419                            }
0420                            if (viewPosition.y + extent.height > viewSize.height) {
0421                                viewPosition.y = Math.max(0, viewSize.height
0422                                        - extent.height);
0423                            } else if (viewPosition.y < 0) {
0424                                viewPosition.y = 0;
0425                            }
0426                        }
0427                        if (viewPosition.x != startX
0428                                || viewPosition.y != startY) {
0429                            setViewPosition(viewPosition);
0430                            // NOTE: How JViewport currently works with the
0431                            // backing store is not foolproof. The sequence of
0432                            // events when setViewPosition
0433                            // (scrollRectToVisible) is called is to reset the
0434                            // views bounds, which causes a repaint on the
0435                            // visible region and sets an ivar indicating
0436                            // scrolling (scrollUnderway). When
0437                            // JViewport.paint is invoked if scrollUnderway is
0438                            // true, the backing store is blitted.  This fails
0439                            // if between the time setViewPosition is invoked
0440                            // and paint is received another repaint is queued
0441                            // indicating part of the view is invalid. There
0442                            // is no way for JViewport to notice another
0443                            // repaint has occured and it ends up blitting
0444                            // what is now a dirty region and the repaint is
0445                            // never delivered.
0446                            // It just so happens JTable encounters this
0447                            // behavior by way of scrollRectToVisible, for
0448                            // this reason scrollUnderway is set to false
0449                            // here, which effectively disables the backing
0450                            // store.
0451                            scrollUnderway = false;
0452                        }
0453                    }
0454                }
0455            }
0456
0457            /**
0458             * Ascends the <code>Viewport</code>'s parents stopping when
0459             * a component is found that returns
0460             * <code>true</code> to <code>isValidateRoot</code>.
0461             * If all the <code>Component</code>'s  parents are visible,
0462             * <code>validate</code> will then be invoked on it. The
0463             * <code>RepaintManager</code> is then invoked with 
0464             * <code>removeInvalidComponent</code>. This
0465             * is the synchronous version of a <code>revalidate</code>.
0466             */
0467            private void validateView() {
0468                Component validateRoot = null;
0469
0470                /* Find the first JComponent ancestor of this component whose
0471                 * isValidateRoot() method returns true.  
0472                 */
0473                for (Component c = this ; c != null; c = c.getParent()) {
0474                    if ((c instanceof  CellRendererPane)
0475                            || (c.getPeer() == null)) {
0476                        return;
0477                    }
0478                    if ((c instanceof  JComponent)
0479                            && (((JComponent) c).isValidateRoot())) {
0480                        validateRoot = c;
0481                        break;
0482                    }
0483                }
0484
0485                // If no validateRoot, nothing to validate from.
0486                if (validateRoot == null) {
0487                    return;
0488                }
0489
0490                // Make sure all ancestors are visible.
0491                Component root = null;
0492
0493                for (Component c = validateRoot; c != null; c = c.getParent()) {
0494                    // We don't check isVisible here, otherwise if the component
0495                    // is contained in something like a JTabbedPane when the
0496                    // component is made visible again it won't have scrolled
0497                    // to the correct location.
0498                    if (c.getPeer() == null) {
0499                        return;
0500                    }
0501                    if ((c instanceof  Window) || (c instanceof  Applet)) {
0502                        root = c;
0503                        break;
0504                    }
0505                }
0506
0507                // Make sure there is a Window ancestor.
0508                if (root == null) {
0509                    return;
0510                }
0511
0512                // Validate the root.
0513                validateRoot.validate();
0514
0515                // And let the RepaintManager it does not have to validate from
0516                // validateRoot anymore.
0517                RepaintManager rm = RepaintManager.currentManager(this );
0518
0519                if (rm != null) {
0520                    rm.removeInvalidComponent((JComponent) validateRoot);
0521                }
0522            }
0523
0524            /*  Used by the scrollRectToVisible method to determine the
0525             *  proper direction and amount to move by. The integer variables are named
0526             *  width, but this method is applicable to height also. The code assumes that
0527             *  parentWidth/childWidth are positive and childAt can be negative.
0528             */
0529            private int positionAdjustment(int parentWidth, int childWidth,
0530                    int childAt) {
0531
0532                //   +-----+
0533                //   | --- |     No Change
0534                //   +-----+
0535                if (childAt >= 0 && childWidth + childAt <= parentWidth) {
0536                    return 0;
0537                }
0538
0539                //   +-----+
0540                //  ---------   No Change
0541                //   +-----+
0542                if (childAt <= 0 && childWidth + childAt >= parentWidth) {
0543                    return 0;
0544                }
0545
0546                //   +-----+          +-----+
0547                //   |   ----    ->   | ----|
0548                //   +-----+          +-----+
0549                if (childAt > 0 && childWidth <= parentWidth) {
0550                    return -childAt + parentWidth - childWidth;
0551                }
0552
0553                //   +-----+             +-----+
0554                //   |  --------  ->     |--------
0555                //   +-----+             +-----+
0556                if (childAt >= 0 && childWidth >= parentWidth) {
0557                    return -childAt;
0558                }
0559
0560                //   +-----+          +-----+
0561                // ----    |     ->   |---- |
0562                //   +-----+          +-----+
0563                if (childAt <= 0 && childWidth <= parentWidth) {
0564                    return -childAt;
0565                }
0566
0567                //   +-----+             +-----+
0568                //-------- |      ->   --------|
0569                //   +-----+             +-----+
0570                if (childAt < 0 && childWidth >= parentWidth) {
0571                    return -childAt + parentWidth - childWidth;
0572                }
0573
0574                return 0;
0575            }
0576
0577            /**
0578             * The viewport "scrolls" its child (called the "view") by the
0579             * normal parent/child clipping (typically the view is moved in
0580             * the opposite direction of the scroll).  A non-<code>null</code> border,
0581             * or non-zero insets, isn't supported, to prevent the geometry
0582             * of this component from becoming complex enough to inhibit
0583             * subclassing.  To create a <code>JViewport</code> with a border,
0584             * add it to a <code>JPanel</code> that has a border.
0585             * <p>Note:  If <code>border</code> is non-<code>null</code>, this
0586             * method will throw an exception as borders are not supported on
0587             * a <code>JViewPort</code>.
0588             *
0589             * @param border the <code>Border</code> to set
0590             * @exception IllegalArgumentException this method is not implemented
0591             */
0592            public final void setBorder(Border border) {
0593                if (border != null) {
0594                    throw new IllegalArgumentException(
0595                            "JViewport.setBorder() not supported");
0596                }
0597            }
0598
0599            /**
0600             * Returns the insets (border) dimensions as (0,0,0,0), since borders
0601             * are not supported on a <code>JViewport</code>.
0602             *
0603             * @return a <code>Rectange</code> of zero dimension and zero origin
0604             * @see #setBorder
0605             */
0606            public final Insets getInsets() {
0607                return new Insets(0, 0, 0, 0);
0608            }
0609
0610            /**
0611             * Returns an <code>Insets</code> object containing this
0612             * <code>JViewport</code>s inset values.  The passed-in
0613             * <code>Insets</code> object will be reinitialized, and
0614             * all existing values within this object are overwritten.
0615             *
0616             * @param insets the <code>Insets</code> object which can be reused
0617             * @return this viewports inset values
0618             * @see #getInsets
0619             * @beaninfo
0620             *   expert: true
0621             */
0622            public final Insets getInsets(Insets insets) {
0623                insets.left = insets.top = insets.right = insets.bottom = 0;
0624                return insets;
0625            }
0626
0627            private Graphics getBackingStoreGraphics(Graphics g) {
0628                Graphics bsg = backingStoreImage.getGraphics();
0629                bsg.setColor(g.getColor());
0630                bsg.setFont(g.getFont());
0631                bsg.setClip(g.getClipBounds());
0632                return bsg;
0633            }
0634
0635            private void paintViaBackingStore(Graphics g) {
0636                Graphics bsg = getBackingStoreGraphics(g);
0637                try {
0638                    super .paint(bsg);
0639                    g.drawImage(backingStoreImage, 0, 0, this );
0640                } finally {
0641                    bsg.dispose();
0642                }
0643            }
0644
0645            private void paintViaBackingStore(Graphics g, Rectangle oClip) {
0646                Graphics bsg = getBackingStoreGraphics(g);
0647                try {
0648                    super .paint(bsg);
0649                    g.setClip(oClip);
0650                    g.drawImage(backingStoreImage, 0, 0, this );
0651                } finally {
0652                    bsg.dispose();
0653                }
0654            }
0655
0656            /**
0657             * The <code>JViewport</code> overrides the default implementation of
0658             * this method (in <code>JComponent</code>) to return false.
0659             * This ensures
0660             * that the drawing machinery will call the <code>Viewport</code>'s
0661             * <code>paint</code>
0662             * implementation rather than messaging the <code>JViewport</code>'s
0663             * children directly.
0664             *
0665             * @return false
0666             */
0667            public boolean isOptimizedDrawingEnabled() {
0668                return false;
0669            }
0670
0671            /**
0672             * Returns true if scroll mode is a BACKINGSTORE_SCROLL_MODE to cause
0673             * painting to originate from <code>JViewport</code>, or one of its
0674             * ancestors. Otherwise returns false.
0675             *
0676             * @return true if if scroll mode is a BACKINGSTORE_SCROLL_MODE.
0677             * @see JComponent#isPaintingOrigin()
0678             */
0679            boolean isPaintingOrigin() {
0680                if (scrollMode == BACKINGSTORE_SCROLL_MODE) {
0681                    return true;
0682                }
0683                return false;
0684            }
0685
0686            /**
0687             * Only used by the paint method below.
0688             */
0689            private Point getViewLocation() {
0690                Component view = getView();
0691                if (view != null) {
0692                    return view.getLocation();
0693                } else {
0694                    return new Point(0, 0);
0695                }
0696            }
0697
0698            /**
0699             * Depending on whether the <code>backingStore</code> is enabled,
0700             * either paint the image through the backing store or paint
0701             * just the recently exposed part, using the backing store
0702             * to "blit" the remainder.
0703             * <blockquote>
0704             * The term "blit" is the pronounced version of the PDP-10
0705             * BLT (BLock Transfer) instruction, which copied a block of
0706             * bits. (In case you were curious.)
0707             * </blockquote>
0708             *
0709             * @param g the <code>Graphics</code> context within which to paint
0710             */
0711            public void paint(Graphics g) {
0712                int width = getWidth();
0713                int height = getHeight();
0714
0715                if ((width <= 0) || (height <= 0)) {
0716                    return;
0717                }
0718
0719                if (inBlitPaint) {
0720                    // We invoked paint as part of copyArea cleanup, let it through.
0721                    super .paint(g);
0722                    return;
0723                }
0724
0725                if (repaintAll) {
0726                    repaintAll = false;
0727                    Rectangle clipB = g.getClipBounds();
0728                    if (clipB.width < getWidth() || clipB.height < getHeight()) {
0729                        waitingForRepaint = true;
0730                        if (repaintTimer == null) {
0731                            repaintTimer = createRepaintTimer();
0732                        }
0733                        repaintTimer.stop();
0734                        repaintTimer.start();
0735                        // We really don't need to paint, a future repaint will
0736                        // take care of it, but if we don't we get an ugly flicker.
0737                    } else {
0738                        if (repaintTimer != null) {
0739                            repaintTimer.stop();
0740                        }
0741                        waitingForRepaint = false;
0742                    }
0743                } else if (waitingForRepaint) {
0744                    // Need a complete repaint before resetting waitingForRepaint
0745                    Rectangle clipB = g.getClipBounds();
0746                    if (clipB.width >= getWidth()
0747                            && clipB.height >= getHeight()) {
0748                        waitingForRepaint = false;
0749                        repaintTimer.stop();
0750                    }
0751                }
0752
0753                if (!backingStore || isBlitting() || getView() == null) {
0754                    super .paint(g);
0755                    lastPaintPosition = getViewLocation();
0756                    return;
0757                }
0758
0759                // If the view is smaller than the viewport and we are not opaque
0760                // (that is, we won't paint our background), we should set the
0761                // clip. Otherwise, as the bounds of the view vary, we will
0762                // blit garbage into the exposed areas.
0763                Rectangle viewBounds = getView().getBounds();
0764                if (!isOpaque()) {
0765                    g.clipRect(0, 0, viewBounds.width, viewBounds.height);
0766                }
0767
0768                if (backingStoreImage == null) {
0769                    // Backing store is enabled but this is the first call to paint.
0770                    // Create the backing store, paint it and then copy to g.
0771                    // The backing store image will be created with the size of
0772                    // the viewport. We must make sure the clip region is the
0773                    // same size, otherwise when scrolling the backing image
0774                    // the region outside of the clipped region will not be painted,
0775                    // and result in empty areas.
0776                    backingStoreImage = createImage(width, height);
0777                    Rectangle clip = g.getClipBounds();
0778                    if (clip.width != width || clip.height != height) {
0779                        if (!isOpaque()) {
0780                            g.setClip(0, 0, Math.min(viewBounds.width, width),
0781                                    Math.min(viewBounds.height, height));
0782                        } else {
0783                            g.setClip(0, 0, width, height);
0784                        }
0785                        paintViaBackingStore(g, clip);
0786                    } else {
0787                        paintViaBackingStore(g);
0788                    }
0789                } else {
0790                    if (!scrollUnderway
0791                            || lastPaintPosition.equals(getViewLocation())) {
0792                        // No scrolling happened: repaint required area via backing store.
0793                        paintViaBackingStore(g);
0794                    } else {
0795                        // The image was scrolled. Manipulate the backing store and flush it to g.
0796                        Point blitFrom = new Point();
0797                        Point blitTo = new Point();
0798                        Dimension blitSize = new Dimension();
0799                        Rectangle blitPaint = new Rectangle();
0800
0801                        Point newLocation = getViewLocation();
0802                        int dx = newLocation.x - lastPaintPosition.x;
0803                        int dy = newLocation.y - lastPaintPosition.y;
0804                        boolean canBlit = computeBlit(dx, dy, blitFrom, blitTo,
0805                                blitSize, blitPaint);
0806                        if (!canBlit) {
0807                            // The image was either moved diagonally or
0808                            // moved by more than the image size: paint normally.
0809                            paintViaBackingStore(g);
0810                        } else {
0811                            int bdx = blitTo.x - blitFrom.x;
0812                            int bdy = blitTo.y - blitFrom.y;
0813
0814                            // Move the relevant part of the backing store.
0815                            Rectangle clip = g.getClipBounds();
0816                            // We don't want to inherit the clip region when copying
0817                            // bits, if it is inherited it will result in not moving
0818                            // all of the image resulting in garbage appearing on
0819                            // the screen.
0820                            g.setClip(0, 0, width, height);
0821                            Graphics bsg = getBackingStoreGraphics(g);
0822                            try {
0823                                bsg.copyArea(blitFrom.x, blitFrom.y,
0824                                        blitSize.width, blitSize.height, bdx,
0825                                        bdy);
0826
0827                                g.setClip(clip.x, clip.y, clip.width,
0828                                        clip.height);
0829                                // Paint the rest of the view; the part that has just been exposed.
0830                                Rectangle r = viewBounds
0831                                        .intersection(blitPaint);
0832                                bsg.setClip(r);
0833                                super .paint(bsg);
0834
0835                                // Copy whole of the backing store to g.
0836                                g.drawImage(backingStoreImage, 0, 0, this );
0837                            } finally {
0838                                bsg.dispose();
0839                            }
0840                        }
0841                    }
0842                }
0843                lastPaintPosition = getViewLocation();
0844                scrollUnderway = false;
0845            }
0846
0847            /**
0848             * Sets the bounds of this viewport.  If the viewport's width
0849             * or height has changed, fire a <code>StateChanged</code> event.
0850             *
0851             * @param x left edge of the origin
0852             * @param y top edge of the origin
0853             * @param w width in pixels
0854             * @param h height in pixels
0855             *
0856             * @see JComponent#reshape(int, int, int, int)
0857             */
0858            public void reshape(int x, int y, int w, int h) {
0859                boolean sizeChanged = (getWidth() != w) || (getHeight() != h);
0860                if (sizeChanged) {
0861                    backingStoreImage = null;
0862                }
0863                super .reshape(x, y, w, h);
0864                if (sizeChanged) {
0865                    fireStateChanged();
0866                }
0867            }
0868
0869            /**
0870             * Used to control the method of scrolling the viewport contents.
0871             * You may want to change this mode to get maximum performance for your
0872             * use case.
0873             *
0874             * @param mode one of the following values:
0875             * <ul>
0876             * <li> JViewport.BLIT_SCROLL_MODE
0877             * <li> JViewport.BACKINGSTORE_SCROLL_MODE
0878             * <li> JViewport.SIMPLE_SCROLL_MODE
0879             * </ul>
0880             *
0881             * @see #BLIT_SCROLL_MODE
0882             * @see #BACKINGSTORE_SCROLL_MODE
0883             * @see #SIMPLE_SCROLL_MODE
0884             *
0885             * @beaninfo
0886             *        bound: false
0887             *  description: Method of moving contents for incremental scrolls.
0888             *         enum: BLIT_SCROLL_MODE JViewport.BLIT_SCROLL_MODE
0889             *               BACKINGSTORE_SCROLL_MODE JViewport.BACKINGSTORE_SCROLL_MODE
0890             *               SIMPLE_SCROLL_MODE JViewport.SIMPLE_SCROLL_MODE
0891             *
0892             * @since 1.3
0893             */
0894            public void setScrollMode(int mode) {
0895                scrollMode = mode;
0896                if (mode == BACKINGSTORE_SCROLL_MODE) {
0897                    backingStore = true;
0898                } else {
0899                    backingStore = false;
0900                }
0901            }
0902
0903            /**
0904             * Returns the current scrolling mode.
0905             *
0906             * @return the <code>scrollMode</code> property
0907             * @see #setScrollMode
0908             * @since 1.3
0909             */
0910            public int getScrollMode() {
0911                return scrollMode;
0912            }
0913
0914            /**
0915             * Returns <code>true</code> if this viewport is maintaining
0916             * an offscreen image of its contents.
0917             *
0918             * @return <code>true</code> if <code>scrollMode</code> is
0919             *    <code>BACKINGSTORE_SCROLL_MODE</code>
0920             *
0921             * @deprecated As of Java 2 platform v1.3, replaced by
0922             *             <code>getScrollMode()</code>.
0923             */
0924            @Deprecated
0925            public boolean isBackingStoreEnabled() {
0926                return scrollMode == BACKINGSTORE_SCROLL_MODE;
0927            }
0928
0929            /**
0930             * If true if this viewport will maintain an offscreen
0931             * image of its contents.  The image is used to reduce the cost
0932             * of small one dimensional changes to the <code>viewPosition</code>.
0933             * Rather than repainting the entire viewport we use
0934             * <code>Graphics.copyArea</code> to effect some of the scroll.
0935             *
0936             * @param enabled if true, maintain an offscreen backing store
0937             *
0938             * @deprecated As of Java 2 platform v1.3, replaced by
0939             *             <code>setScrollMode()</code>.
0940             */
0941            @Deprecated
0942            public void setBackingStoreEnabled(boolean enabled) {
0943                if (enabled) {
0944                    setScrollMode(BACKINGSTORE_SCROLL_MODE);
0945                } else {
0946                    setScrollMode(BLIT_SCROLL_MODE);
0947                }
0948            }
0949
0950            private final boolean isBlitting() {
0951                Component view = getView();
0952                return (scrollMode == BLIT_SCROLL_MODE)
0953                        && (view instanceof  JComponent)
0954                        && ((JComponent) view).isOpaque();
0955            }
0956
0957            /**
0958             * Returns the <code>JViewport</code>'s one child or <code>null</code>.
0959             *
0960             * @return the viewports child, or <code>null</code> if none exists
0961             *
0962             * @see #setView
0963             */
0964            public Component getView() {
0965                return (getComponentCount() > 0) ? getComponent(0) : null;
0966            }
0967
0968            /**
0969             * Sets the <code>JViewport</code>'s one lightweight child
0970             * (<code>view</code>), which can be <code>null</code>.
0971             *
0972             * @param view the viewport's new lightweight child
0973             *
0974             * @see #getView
0975             */
0976            public void setView(Component view) {
0977
0978                /* Remove the viewport's existing children, if any.
0979                 * Note that removeAll() isn't used here because it
0980                 * doesn't call remove() (which JViewport overrides).
0981                 */
0982                int n = getComponentCount();
0983                for (int i = n - 1; i >= 0; i--) {
0984                    remove(getComponent(i));
0985                }
0986
0987                isViewSizeSet = false;
0988
0989                if (view != null) {
0990                    super .addImpl(view, null, -1);
0991                    viewListener = createViewListener();
0992                    view.addComponentListener(viewListener);
0993                }
0994
0995                if (hasHadValidView) {
0996                    // Only fire a change if a view has been installed.
0997                    fireStateChanged();
0998                } else if (view != null) {
0999                    hasHadValidView = true;
1000                }
1001
1002                revalidate();
1003                repaint();
1004            }
1005
1006            /**
1007             * If the view's size hasn't been explicitly set, return the
1008             * preferred size, otherwise return the view's current size.
1009             * If there is no view, return 0,0.
1010             *
1011             * @return a <code>Dimension</code> object specifying the size of the view
1012             */
1013            public Dimension getViewSize() {
1014                Component view = getView();
1015
1016                if (view == null) {
1017                    return new Dimension(0, 0);
1018                } else if (isViewSizeSet) {
1019                    return view.getSize();
1020                } else {
1021                    return view.getPreferredSize();
1022                }
1023            }
1024
1025            /**
1026             * Sets the size of the view.  A state changed event will be fired.
1027             *
1028             * @param newSize a <code>Dimension</code> object specifying the new
1029             *		size of the view
1030             */
1031            public void setViewSize(Dimension newSize) {
1032                Component view = getView();
1033                if (view != null) {
1034                    Dimension oldSize = view.getSize();
1035                    if (!newSize.equals(oldSize)) {
1036                        // scrollUnderway will be true if this is invoked as the
1037                        // result of a validate and setViewPosition was previously
1038                        // invoked.
1039                        scrollUnderway = false;
1040                        view.setSize(newSize);
1041                        isViewSizeSet = true;
1042                        fireStateChanged();
1043                    }
1044                }
1045            }
1046
1047            /**
1048             * Returns the view coordinates that appear in the upper left
1049             * hand corner of the viewport, or 0,0 if there's no view.
1050             *
1051             * @return a <code>Point</code> object giving the upper left coordinates
1052             */
1053            public Point getViewPosition() {
1054                Component view = getView();
1055                if (view != null) {
1056                    Point p = view.getLocation();
1057                    p.x = -p.x;
1058                    p.y = -p.y;
1059                    return p;
1060                } else {
1061                    return new Point(0, 0);
1062                }
1063            }
1064
1065            /**
1066             * Sets the view coordinates that appear in the upper left
1067             * hand corner of the viewport, does nothing if there's no view.
1068             *
1069             * @param p  a <code>Point</code> object giving the upper left coordinates
1070             */
1071            public void setViewPosition(Point p) {
1072                Component view = getView();
1073                if (view == null) {
1074                    return;
1075                }
1076
1077                int oldX, oldY, x = p.x, y = p.y;
1078
1079                /* Collect the old x,y values for the views location
1080                 * and do the song and dance to avoid allocating 
1081                 * a Rectangle object if we don't have to.
1082                 */
1083                if (view instanceof  JComponent) {
1084                    JComponent c = (JComponent) view;
1085                    oldX = c.getX();
1086                    oldY = c.getY();
1087                } else {
1088                    Rectangle r = view.getBounds();
1089                    oldX = r.x;
1090                    oldY = r.y;
1091                }
1092
1093                /* The view scrolls in the opposite direction to mouse 
1094                 * movement.
1095                 */
1096                int newX = -x;
1097                int newY = -y;
1098
1099                if ((oldX != newX) || (oldY != newY)) {
1100                    if (!waitingForRepaint && isBlitting()
1101                            && canUseWindowBlitter()) {
1102                        RepaintManager rm = RepaintManager.currentManager(this );
1103                        // The cast to JComponent will work, if view is not 
1104                        // a JComponent, isBlitting will return false.
1105                        JComponent jview = (JComponent) view;
1106                        Rectangle dirty = rm.getDirtyRegion(jview);
1107                        if (dirty == null
1108                                || !dirty.contains(jview.getVisibleRect())) {
1109                            rm.beginPaint();
1110                            try {
1111                                Graphics g = JComponent.safelyGetGraphics(this );
1112                                flushViewDirtyRegion(g, dirty);
1113                                view.setLocation(newX, newY);
1114                                g.setClip(0, 0, getWidth(), Math.min(
1115                                        getHeight(), jview.getHeight()));
1116                                // Repaint the complete component if the blit succeeded
1117                                // and needsRepaintAfterBlit returns true.
1118                                repaintAll = (windowBlitPaint(g) && needsRepaintAfterBlit());
1119                                g.dispose();
1120                                rm
1121                                        .markCompletelyClean((JComponent) getParent());
1122                                rm.markCompletelyClean(this );
1123                                rm.markCompletelyClean(jview);
1124                            } finally {
1125                                rm.endPaint();
1126                            }
1127                        } else {
1128                            // The visible region is dirty, no point in doing copyArea
1129                            view.setLocation(newX, newY);
1130                            repaintAll = false;
1131                        }
1132                    } else {
1133                        scrollUnderway = true;
1134                        // This calls setBounds(), and then repaint().
1135                        view.setLocation(newX, newY);
1136                        repaintAll = false;
1137                    }
1138                    fireStateChanged();
1139                }
1140            }
1141
1142            /**
1143             * Returns a rectangle whose origin is <code>getViewPosition</code>
1144             * and size is <code>getExtentSize</code>.
1145             * This is the visible part of the view, in view coordinates.
1146             *
1147             * @return a <code>Rectangle</code> giving the visible part of
1148             *		the view using view coordinates.
1149             */
1150            public Rectangle getViewRect() {
1151                return new Rectangle(getViewPosition(), getExtentSize());
1152            }
1153
1154            /**
1155             * Computes the parameters for a blit where the backing store image
1156             * currently contains <code>oldLoc</code> in the upper left hand corner
1157             * and we're scrolling to <code>newLoc</code>.
1158             * The parameters are modified
1159             * to return the values required for the blit.
1160             *
1161             * @param dx  the horizontal delta
1162             * @param dy  the vertical delta
1163             * @param blitFrom the <code>Point</code> we're blitting from
1164             * @param blitTo the <code>Point</code> we're blitting to
1165             * @param blitSize the <code>Dimension</code> of the area to blit
1166             * @param blitPaint the area to blit
1167             * @return  true if the parameters are modified and we're ready to blit;
1168             *		false otherwise
1169             */
1170            protected boolean computeBlit(int dx, int dy, Point blitFrom,
1171                    Point blitTo, Dimension blitSize, Rectangle blitPaint) {
1172                int dxAbs = Math.abs(dx);
1173                int dyAbs = Math.abs(dy);
1174                Dimension extentSize = getExtentSize();
1175
1176                if ((dx == 0) && (dy != 0) && (dyAbs < extentSize.height)) {
1177                    if (dy < 0) {
1178                        blitFrom.y = -dy;
1179                        blitTo.y = 0;
1180                        blitPaint.y = extentSize.height + dy;
1181                    } else {
1182                        blitFrom.y = 0;
1183                        blitTo.y = dy;
1184                        blitPaint.y = 0;
1185                    }
1186
1187                    blitPaint.x = blitFrom.x = blitTo.x = 0;
1188
1189                    blitSize.width = extentSize.width;
1190                    blitSize.height = extentSize.height - dyAbs;
1191
1192                    blitPaint.width = extentSize.width;
1193                    blitPaint.height = dyAbs;
1194
1195                    return true;
1196                }
1197
1198                else if ((dy == 0) && (dx != 0) && (dxAbs < extentSize.width)) {
1199                    if (dx < 0) {
1200                        blitFrom.x = -dx;
1201                        blitTo.x = 0;
1202                        blitPaint.x = extentSize.width + dx;
1203                    } else {
1204                        blitFrom.x = 0;
1205                        blitTo.x = dx;
1206                        blitPaint.x = 0;
1207                    }
1208
1209                    blitPaint.y = blitFrom.y = blitTo.y = 0;
1210
1211                    blitSize.width = extentSize.width - dxAbs;
1212                    blitSize.height = extentSize.height;
1213
1214                    blitPaint.width = dxAbs;
1215                    blitPaint.height = extentSize.height;
1216
1217                    return true;
1218                }
1219
1220                else {
1221                    return false;
1222                }
1223            }
1224
1225            /**
1226             * Returns the size of the visible part of the view in view coordinates.
1227             *
1228             * @return a <code>Dimension</code> object giving the size of the view
1229             */
1230            public Dimension getExtentSize() {
1231                return getSize();
1232            }
1233
1234            /**
1235             * Converts a size in pixel coordinates to view coordinates.
1236             * Subclasses of viewport that support "logical coordinates"
1237             * will override this method.
1238             *
1239             * @param size  a <code>Dimension</code> object using pixel coordinates
1240             * @return a <code>Dimension</code> object converted to view coordinates
1241             */
1242            public Dimension toViewCoordinates(Dimension size) {
1243                return new Dimension(size);
1244            }
1245
1246            /**
1247             * Converts a point in pixel coordinates to view coordinates.
1248             * Subclasses of viewport that support "logical coordinates"
1249             * will override this method.
1250             *
1251             * @param p  a <code>Point</code> object using pixel coordinates
1252             * @return a <code>Point</code> object converted to view coordinates
1253             */
1254            public Point toViewCoordinates(Point p) {
1255                return new Point(p);
1256            }
1257
1258            /**
1259             * Sets the size of the visible part of the view using view coordinates.
1260             *
1261             * @param newExtent  a <code>Dimension</code> object specifying
1262             *		the size of the view
1263             */
1264            public void setExtentSize(Dimension newExtent) {
1265                Dimension oldExtent = getExtentSize();
1266                if (!newExtent.equals(oldExtent)) {
1267                    setSize(newExtent);
1268                    fireStateChanged();
1269                }
1270            }
1271
1272            /**
1273             * A listener for the view.
1274             * <p>
1275             * <strong>Warning:</strong>
1276             * Serialized objects of this class will not be compatible with
1277             * future Swing releases. The current serialization support is
1278             * appropriate for short term storage or RMI between applications running
1279             * the same version of Swing.  As of 1.4, support for long term storage
1280             * of all JavaBeans<sup><font size="-2">TM</font></sup>
1281             * has been added to the <code>java.beans</code> package.
1282             * Please see {@link java.beans.XMLEncoder}.
1283             */
1284            protected class ViewListener extends ComponentAdapter implements 
1285                    Serializable {
1286                public void componentResized(ComponentEvent e) {
1287                    fireStateChanged();
1288                    revalidate();
1289                }
1290            }
1291
1292            /**
1293             * Creates a listener for the view.
1294             * @return a <code>ViewListener</code>
1295             */
1296            protected ViewListener createViewListener() {
1297                return new ViewListener();
1298            }
1299
1300            /**
1301             * Subclassers can override this to install a different
1302             * layout manager (or <code>null</code>) in the constructor.  Returns
1303             * the <code>LayoutManager</code> to install on the <code>JViewport</code>.
1304             *
1305             * @return a <code>LayoutManager</code>
1306             */
1307            protected LayoutManager createLayoutManager() {
1308                return ViewportLayout.SHARED_INSTANCE;
1309            }
1310
1311            /**
1312             * Adds a <code>ChangeListener</code> to the list that is
1313             * notified each time the view's
1314             * size, position, or the viewport's extent size has changed.
1315             *
1316             * @param l the <code>ChangeListener</code> to add
1317             * @see #removeChangeListener
1318             * @see #setViewPosition
1319             * @see #setViewSize
1320             * @see #setExtentSize
1321             */
1322            public void addChangeListener(ChangeListener l) {
1323                listenerList.add(ChangeListener.class, l);
1324            }
1325
1326            /**
1327             * Removes a <code>ChangeListener</code> from the list that's notified each
1328             * time the views size, position, or the viewports extent size
1329             * has changed.
1330             *
1331             * @param l the <code>ChangeListener</code> to remove
1332             * @see #addChangeListener
1333             */
1334            public void removeChangeListener(ChangeListener l) {
1335                listenerList.remove(ChangeListener.class, l);
1336            }
1337
1338            /**
1339             * Returns an array of all the <code>ChangeListener</code>s added
1340             * to this JViewport with addChangeListener().
1341             *
1342             * @return all of the <code>ChangeListener</code>s added or an empty
1343             *         array if no listeners have been added
1344             * @since 1.4
1345             */
1346            public ChangeListener[] getChangeListeners() {
1347                return (ChangeListener[]) listenerList
1348                        .getListeners(ChangeListener.class);
1349            }
1350
1351            /**
1352             * Notifies all <code>ChangeListeners</code> when the views
1353             * size, position, or the viewports extent size has changed.
1354             *
1355             * @see #addChangeListener
1356             * @see #removeChangeListener
1357             * @see EventListenerList
1358             */
1359            protected void fireStateChanged() {
1360                Object[] listeners = listenerList.getListenerList();
1361                for (int i = listeners.length - 2; i >= 0; i -= 2) {
1362                    if (listeners[i] == ChangeListener.class) {
1363                        if (changeEvent == null) {
1364                            changeEvent = new ChangeEvent(this );
1365                        }
1366                        ((ChangeListener) listeners[i + 1])
1367                                .stateChanged(changeEvent);
1368                    }
1369                }
1370            }
1371
1372            /**
1373             * Always repaint in the parents coordinate system to make sure
1374             * only one paint is performed by the <code>RepaintManager</code>.
1375             *
1376             * @param     tm   maximum time in milliseconds before update
1377             * @param     x    the <code>x</code> coordinate (pixels over from left)
1378             * @param     y    the <code>y</code> coordinate (pixels down from top)
1379             * @param     w    the width
1380             * @param     h   the height
1381             * @see       java.awt.Component#update(java.awt.Graphics)
1382             */
1383            public void repaint(long tm, int x, int y, int w, int h) {
1384                Container parent = getParent();
1385                if (parent != null)
1386                    parent.repaint(tm, x + getX(), y + getY(), w, h);
1387                else
1388                    super .repaint(tm, x, y, w, h);
1389            }
1390
1391            /**
1392             * Returns a string representation of this <code>JViewport</code>.
1393             * This method 
1394             * is intended to be used only for debugging purposes, and the 
1395             * content and format of the returned string may vary between      
1396             * implementations. The returned string may be empty but may not 
1397             * be <code>null</code>.
1398             * 
1399             * @return  a string representation of this <code>JViewport</code>
1400             */
1401            protected String paramString() {
1402                String isViewSizeSetString = (isViewSizeSet ? "true" : "false");
1403                String lastPaintPositionString = (lastPaintPosition != null ? lastPaintPosition
1404                        .toString()
1405                        : "");
1406                String scrollUnderwayString = (scrollUnderway ? "true"
1407                        : "false");
1408
1409                return super .paramString() + ",isViewSizeSet="
1410                        + isViewSizeSetString + ",lastPaintPosition="
1411                        + lastPaintPositionString + ",scrollUnderway="
1412                        + scrollUnderwayString;
1413            }
1414
1415            //
1416            // Following is used when doBlit is true.
1417            //
1418
1419            /**
1420             * Notifies listeners of a property change. This is subclassed to update
1421             * the <code>windowBlit</code> property.
1422             * (The <code>putClientProperty</code> property is final).
1423             *
1424             * @param propertyName a string containing the property name
1425             * @param oldValue the old value of the property
1426             * @param newValue  the new value of the property
1427             */
1428            protected void firePropertyChange(String propertyName,
1429                    Object oldValue, Object newValue) {
1430                super .firePropertyChange(propertyName, oldValue, newValue);
1431                if (propertyName.equals(EnableWindowBlit)) {
1432                    if (newValue != null) {
1433                        setScrollMode(BLIT_SCROLL_MODE);
1434                    } else {
1435                        setScrollMode(SIMPLE_SCROLL_MODE);
1436                    }
1437                }
1438            }
1439
1440            /**
1441             * Returns true if the component needs to be completely repainted after
1442             * a blit and a paint is received.
1443             */
1444            private boolean needsRepaintAfterBlit() {
1445                // Find the first heavy weight ancestor. isObscured and
1446                // canDetermineObscurity are only appropriate for heavy weights.
1447                Component heavyParent = getParent();
1448
1449                while (heavyParent != null && heavyParent.isLightweight()) {
1450                    heavyParent = heavyParent.getParent();
1451                }
1452
1453                if (heavyParent != null) {
1454                    ComponentPeer peer = heavyParent.getPeer();
1455
1456                    if (peer != null && peer.canDetermineObscurity()
1457                            && !peer.isObscured()) {
1458                        // The peer says we aren't obscured, therefore we can assume
1459                        // that we won't later be messaged to paint a portion that
1460                        // we tried to blit that wasn't valid.
1461                        // It is certainly possible that when we blited we were
1462                        // obscured, and by the time this is invoked we aren't, but the
1463                        // chances of that happening are pretty slim.
1464                        return false;
1465                    }
1466                }
1467                return true;
1468            }
1469
1470            private Timer createRepaintTimer() {
1471                Timer timer = new Timer(300, new ActionListener() {
1472                    public void actionPerformed(ActionEvent ae) {
1473                        // waitingForRepaint will be false if a paint came down
1474                        // with the complete clip rect, in which case we don't
1475                        // have to cause a repaint.
1476                        if (waitingForRepaint) {
1477                            repaint();
1478                        }
1479                    }
1480                });
1481                timer.setRepeats(false);
1482                return timer;
1483            }
1484
1485            /**
1486             * If the repaint manager has a dirty region for the view, the view is
1487             * asked to paint.
1488             *
1489             * @param g  the <code>Graphics</code> context within which to paint
1490             */
1491            private void flushViewDirtyRegion(Graphics g, Rectangle dirty) {
1492                JComponent view = (JComponent) getView();
1493                if (dirty != null && dirty.width > 0 && dirty.height > 0) {
1494                    dirty.x += view.getX();
1495                    dirty.y += view.getY();
1496                    Rectangle clip = g.getClipBounds();
1497                    if (clip == null) {
1498                        // Only happens in 1.2
1499                        g.setClip(0, 0, getWidth(), getHeight());
1500                    }
1501                    g.clipRect(dirty.x, dirty.y, dirty.width, dirty.height);
1502                    clip = g.getClipBounds();
1503                    // Only paint the dirty region if it is visible.
1504                    if (clip.width > 0 && clip.height > 0) {
1505                        paintView(g);
1506                    }
1507                }
1508            }
1509
1510            /**
1511             * Used when blitting.
1512             *
1513             * @param g  the <code>Graphics</code> context within which to paint
1514             * @return true if blitting succeeded; otherwise false
1515             */
1516            private boolean windowBlitPaint(Graphics g) {
1517                int width = getWidth();
1518                int height = getHeight();
1519
1520                if ((width == 0) || (height == 0)) {
1521                    return false;
1522                }
1523
1524                boolean retValue;
1525                RepaintManager rm = RepaintManager.currentManager(this );
1526                JComponent view = (JComponent) getView();
1527
1528                if (lastPaintPosition == null
1529                        || lastPaintPosition.equals(getViewLocation())) {
1530                    paintView(g);
1531                    retValue = false;
1532                } else {
1533                    // The image was scrolled. Manipulate the backing store and flush
1534                    // it to g.
1535                    Point blitFrom = new Point();
1536                    Point blitTo = new Point();
1537                    Dimension blitSize = new Dimension();
1538                    Rectangle blitPaint = new Rectangle();
1539
1540                    Point newLocation = getViewLocation();
1541                    int dx = newLocation.x - lastPaintPosition.x;
1542                    int dy = newLocation.y - lastPaintPosition.y;
1543                    boolean canBlit = computeBlit(dx, dy, blitFrom, blitTo,
1544                            blitSize, blitPaint);
1545                    if (!canBlit) {
1546                        paintView(g);
1547                        retValue = false;
1548                    } else {
1549                        // Prepare the rest of the view; the part that has just been
1550                        // exposed.
1551                        Rectangle r = view.getBounds().intersection(blitPaint);
1552                        r.x -= view.getX();
1553                        r.y -= view.getY();
1554
1555                        blitDoubleBuffered(view, g, r.x, r.y, r.width,
1556                                r.height, blitFrom.x, blitFrom.y, blitTo.x,
1557                                blitTo.y, blitSize.width, blitSize.height);
1558                        retValue = true;
1559                    }
1560                }
1561                lastPaintPosition = getViewLocation();
1562                return retValue;
1563            }
1564
1565            //
1566            // NOTE: the code below uses paintForceDoubleBuffered for historical
1567            // reasons.  If we're going to allow a blit we've already accounted for
1568            // everything that paintImmediately and _paintImmediately does, for that
1569            // reason we call into paintForceDoubleBuffered to diregard whether or
1570            // not setDoubleBuffered(true) was invoked on the view.
1571            //
1572
1573            private void blitDoubleBuffered(JComponent view, Graphics g,
1574                    int clipX, int clipY, int clipW, int clipH, int blitFromX,
1575                    int blitFromY, int blitToX, int blitToY, int blitW,
1576                    int blitH) {
1577                // NOTE:
1578                //   blitFrom/blitTo are in JViewport coordinates system
1579                //     not the views coordinate space.
1580                //   clip* are in the views coordinate space.
1581                RepaintManager rm = RepaintManager.currentManager(this );
1582                int bdx = blitToX - blitFromX;
1583                int bdy = blitToY - blitFromY;
1584
1585                // Shift the scrolled region
1586                rm.copyArea(this , g, blitFromX, blitFromY, blitW, blitH, bdx,
1587                        bdy, false);
1588
1589                // Paint the newly exposed region.
1590                int x = view.getX();
1591                int y = view.getY();
1592                g.translate(x, y);
1593                g.setClip(clipX, clipY, clipW, clipH);
1594                view.paintForceDoubleBuffered(g);
1595                g.translate(-x, -y);
1596            }
1597
1598            /**
1599             * Called to paint the view, usually when <code>blitPaint</code>
1600             * can not blit.
1601             *
1602             * @param g the <code>Graphics</code> context within which to paint
1603             */
1604            private void paintView(Graphics g) {
1605                Rectangle clip = g.getClipBounds();
1606                JComponent view = (JComponent) getView();
1607
1608                if (view.getWidth() >= getWidth()) {
1609                    // Graphics is relative to JViewport, need to map to view's
1610                    // coordinates space.
1611                    int x = view.getX();
1612                    int y = view.getY();
1613                    g.translate(x, y);
1614                    g.setClip(clip.x - x, clip.y - y, clip.width, clip.height);
1615                    view.paintForceDoubleBuffered(g);
1616                    g.translate(-x, -y);
1617                    g.setClip(clip.x, clip.y, clip.width, clip.height);
1618                } else {
1619                    // To avoid any problems that may result from the viewport being
1620                    // bigger than the view we start painting from the viewport.
1621                    try {
1622                        inBlitPaint = true;
1623                        paintForceDoubleBuffered(g);
1624                    } finally {
1625                        inBlitPaint = false;
1626                    }
1627                }
1628            }
1629
1630            /**
1631             * Returns true if the viewport is not obscured by one of its ancestors,
1632             * or its ancestors children and if the viewport is showing. Blitting
1633             * when the view isn't showing will work,
1634             * or rather <code>copyArea</code> will work,
1635             * but will not produce the expected behavior.
1636             */
1637            private boolean canUseWindowBlitter() {
1638                if (!isShowing()
1639                        || (!(getParent() instanceof  JComponent) && !(getView() instanceof  JComponent))) {
1640                    return false;
1641                }
1642                if (isPainting()) {
1643                    // We're in the process of painting, don't blit. If we were
1644                    // to blit we would draw on top of what we're already drawing,
1645                    // so bail.
1646                    return false;
1647                }
1648
1649                Rectangle dirtyRegion = RepaintManager.currentManager(this )
1650                        .getDirtyRegion((JComponent) getParent());
1651
1652                if (dirtyRegion != null && dirtyRegion.width > 0
1653                        && dirtyRegion.height > 0) {
1654                    // Part of the scrollpane needs to be repainted too, don't blit.
1655                    return false;
1656                }
1657
1658                Rectangle clip = new Rectangle(0, 0, getWidth(), getHeight());
1659                Rectangle oldClip = new Rectangle();
1660                Rectangle tmp2 = null;
1661                Container parent;
1662                Component lastParent = null;
1663                int x, y, w, h;
1664
1665                for (parent = this ; parent != null
1666                        && isLightweightComponent(parent); parent = parent
1667                        .getParent()) {
1668                    x = parent.getX();
1669                    y = parent.getY();
1670                    w = parent.getWidth();
1671                    h = parent.getHeight();
1672
1673                    oldClip.setBounds(clip);
1674                    SwingUtilities.computeIntersection(0, 0, w, h, clip);
1675                    if (!clip.equals(oldClip))
1676                        return false;
1677
1678                    if (lastParent != null
1679                            && parent instanceof  JComponent
1680                            && !((JComponent) parent)
1681                                    .isOptimizedDrawingEnabled()) {
1682                        Component comps[] = parent.getComponents();
1683                        int index = 0;
1684
1685                        for (int i = comps.length - 1; i >= 0; i--) {
1686                            if (comps[i] == lastParent) {
1687                                index = i - 1;
1688                                break;
1689                            }
1690                        }
1691
1692                        while (index >= 0) {
1693                            tmp2 = comps[index].getBounds(tmp2);
1694
1695                            if (tmp2.intersects(clip))
1696                                return false;
1697                            index--;
1698                        }
1699                    }
1700                    clip.x += x;
1701                    clip.y += y;
1702                    lastParent = parent;
1703                }
1704                if (parent == null) {
1705                    // No Window parent.
1706                    return false;
1707                }
1708                return true;
1709            }
1710
1711            /////////////////
1712            // Accessibility support
1713            ////////////////
1714
1715            /**
1716             * Gets the AccessibleContext associated with this JViewport. 
1717             * For viewports, the AccessibleContext takes the form of an 
1718             * AccessibleJViewport. 
1719             * A new AccessibleJViewport instance is created if necessary.
1720             *
1721             * @return an AccessibleJViewport that serves as the 
1722             *         AccessibleContext of this JViewport
1723             */
1724            public AccessibleContext getAccessibleContext() {
1725                if (accessibleContext == null) {
1726                    accessibleContext = new AccessibleJViewport();
1727                }
1728                return accessibleContext;
1729            }
1730
1731            /**
1732             * This class implements accessibility support for the 
1733             * <code>JViewport</code> class.  It provides an implementation of the 
1734             * Java Accessibility API appropriate to viewport user-interface elements.
1735             * <p>
1736             * <strong>Warning:</strong>
1737             * Serialized objects of this class will not be compatible with
1738             * future Swing releases. The current serialization support is
1739             * appropriate for short term storage or RMI between applications running
1740             * the same version of Swing.  As of 1.4, support for long term storage
1741             * of all JavaBeans<sup><font size="-2">TM</font></sup>
1742             * has been added to the <code>java.beans</code> package.
1743             * Please see {@link java.beans.XMLEncoder}.
1744             */
1745            protected class AccessibleJViewport extends AccessibleJComponent {
1746                /**
1747                 * Get the role of this object.
1748                 *
1749                 * @return an instance of AccessibleRole describing the role of
1750                 * the object
1751                 */
1752                public AccessibleRole getAccessibleRole() {
1753                    return AccessibleRole.VIEWPORT;
1754                }
1755            } // inner class AccessibleJViewport
1756        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.