Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]
    1   /*
    2    * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.swing.plaf.basic;
   27   
   28   import sun.swing.DefaultLookup;
   29   import sun.swing.UIAction;
   30   
   31   import javax.swing;
   32   import javax.swing.event;
   33   import javax.swing.border;
   34   import javax.swing.plaf;
   35   
   36   import java.beans.PropertyChangeListener;
   37   import java.beans.PropertyChangeEvent;
   38   
   39   import java.awt.Component;
   40   import java.awt.Container;
   41   import java.awt.LayoutManager;
   42   import java.awt.Rectangle;
   43   import java.awt.Dimension;
   44   import java.awt.Point;
   45   import java.awt.Insets;
   46   import java.awt.Graphics;
   47   import java.awt.event;
   48   import java.io.Serializable;
   49   import java.awt.Toolkit;
   50   import java.awt.ComponentOrientation;
   51   
   52   /**
   53    * A default L&F implementation of ScrollPaneUI.
   54    *
   55    * @author Hans Muller
   56    */
   57   public class BasicScrollPaneUI
   58       extends ScrollPaneUI implements ScrollPaneConstants
   59   {
   60       protected JScrollPane scrollpane;
   61       protected ChangeListener vsbChangeListener;
   62       protected ChangeListener hsbChangeListener;
   63       protected ChangeListener viewportChangeListener;
   64       protected PropertyChangeListener spPropertyChangeListener;
   65       private MouseWheelListener mouseScrollListener;
   66   
   67       /**
   68        * PropertyChangeListener installed on the vertical scrollbar.
   69        */
   70       private PropertyChangeListener vsbPropertyChangeListener;
   71   
   72       /**
   73        * PropertyChangeListener installed on the horizontal scrollbar.
   74        */
   75       private PropertyChangeListener hsbPropertyChangeListener;
   76   
   77       private Handler handler;
   78   
   79       /**
   80        * State flag that shows whether setValue() was called from a user program
   81        * before the value of "extent" was set in right-to-left component
   82        * orientation.
   83        */
   84       private boolean setValueCalled = false;
   85   
   86   
   87       public static ComponentUI createUI(JComponent x) {
   88           return new BasicScrollPaneUI();
   89       }
   90   
   91       static void loadActionMap(LazyActionMap map) {
   92           map.put(new Actions(Actions.SCROLL_UP));
   93           map.put(new Actions(Actions.SCROLL_DOWN));
   94           map.put(new Actions(Actions.SCROLL_HOME));
   95           map.put(new Actions(Actions.SCROLL_END));
   96           map.put(new Actions(Actions.UNIT_SCROLL_UP));
   97           map.put(new Actions(Actions.UNIT_SCROLL_DOWN));
   98           map.put(new Actions(Actions.SCROLL_LEFT));
   99           map.put(new Actions(Actions.SCROLL_RIGHT));
  100           map.put(new Actions(Actions.UNIT_SCROLL_RIGHT));
  101           map.put(new Actions(Actions.UNIT_SCROLL_LEFT));
  102       }
  103   
  104   
  105   
  106       public void paint(Graphics g, JComponent c) {
  107           Border vpBorder = scrollpane.getViewportBorder();
  108           if (vpBorder != null) {
  109               Rectangle r = scrollpane.getViewportBorderBounds();
  110               vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height);
  111           }
  112       }
  113   
  114   
  115       /**
  116        * @return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE)
  117        */
  118       public Dimension getMaximumSize(JComponent c) {
  119           return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
  120       }
  121   
  122   
  123       protected void installDefaults(JScrollPane scrollpane)
  124       {
  125           LookAndFeel.installBorder(scrollpane, "ScrollPane.border");
  126           LookAndFeel.installColorsAndFont(scrollpane,
  127               "ScrollPane.background",
  128               "ScrollPane.foreground",
  129               "ScrollPane.font");
  130   
  131           Border vpBorder = scrollpane.getViewportBorder();
  132           if ((vpBorder == null) ||( vpBorder instanceof UIResource)) {
  133               vpBorder = UIManager.getBorder("ScrollPane.viewportBorder");
  134               scrollpane.setViewportBorder(vpBorder);
  135           }
  136           LookAndFeel.installProperty(scrollpane, "opaque", Boolean.TRUE);
  137       }
  138   
  139   
  140       protected void installListeners(JScrollPane c)
  141       {
  142           vsbChangeListener = createVSBChangeListener();
  143           vsbPropertyChangeListener = createVSBPropertyChangeListener();
  144           hsbChangeListener = createHSBChangeListener();
  145           hsbPropertyChangeListener = createHSBPropertyChangeListener();
  146           viewportChangeListener = createViewportChangeListener();
  147           spPropertyChangeListener = createPropertyChangeListener();
  148   
  149           JViewport viewport = scrollpane.getViewport();
  150           JScrollBar vsb = scrollpane.getVerticalScrollBar();
  151           JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  152   
  153           if (viewport != null) {
  154               viewport.addChangeListener(viewportChangeListener);
  155           }
  156           if (vsb != null) {
  157               vsb.getModel().addChangeListener(vsbChangeListener);
  158               vsb.addPropertyChangeListener(vsbPropertyChangeListener);
  159           }
  160           if (hsb != null) {
  161               hsb.getModel().addChangeListener(hsbChangeListener);
  162               hsb.addPropertyChangeListener(hsbPropertyChangeListener);
  163           }
  164   
  165           scrollpane.addPropertyChangeListener(spPropertyChangeListener);
  166   
  167       mouseScrollListener = createMouseWheelListener();
  168       scrollpane.addMouseWheelListener(mouseScrollListener);
  169   
  170       }
  171   
  172       protected void installKeyboardActions(JScrollPane c) {
  173           InputMap inputMap = getInputMap(JComponent.
  174                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  175   
  176           SwingUtilities.replaceUIInputMap(c, JComponent.
  177                                  WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
  178   
  179           LazyActionMap.installLazyActionMap(c, BasicScrollPaneUI.class,
  180                                              "ScrollPane.actionMap");
  181       }
  182   
  183       InputMap getInputMap(int condition) {
  184           if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  185               InputMap keyMap = (InputMap)DefaultLookup.get(scrollpane, this,
  186                                           "ScrollPane.ancestorInputMap");
  187               InputMap rtlKeyMap;
  188   
  189               if (scrollpane.getComponentOrientation().isLeftToRight() ||
  190                       ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollpane, this,
  191                       "ScrollPane.ancestorInputMap.RightToLeft")) == null)) {
  192                   return keyMap;
  193               } else {
  194                   rtlKeyMap.setParent(keyMap);
  195                   return rtlKeyMap;
  196               }
  197           }
  198           return null;
  199       }
  200   
  201       public void installUI(JComponent x) {
  202           scrollpane = (JScrollPane)x;
  203           installDefaults(scrollpane);
  204           installListeners(scrollpane);
  205           installKeyboardActions(scrollpane);
  206       }
  207   
  208   
  209       protected void uninstallDefaults(JScrollPane c) {
  210           LookAndFeel.uninstallBorder(scrollpane);
  211   
  212           if (scrollpane.getViewportBorder() instanceof UIResource) {
  213               scrollpane.setViewportBorder(null);
  214           }
  215       }
  216   
  217   
  218       protected void uninstallListeners(JComponent c) {
  219           JViewport viewport = scrollpane.getViewport();
  220           JScrollBar vsb = scrollpane.getVerticalScrollBar();
  221           JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  222   
  223           if (viewport != null) {
  224               viewport.removeChangeListener(viewportChangeListener);
  225           }
  226           if (vsb != null) {
  227               vsb.getModel().removeChangeListener(vsbChangeListener);
  228               vsb.removePropertyChangeListener(vsbPropertyChangeListener);
  229           }
  230           if (hsb != null) {
  231               hsb.getModel().removeChangeListener(hsbChangeListener);
  232               hsb.removePropertyChangeListener(hsbPropertyChangeListener);
  233           }
  234   
  235           scrollpane.removePropertyChangeListener(spPropertyChangeListener);
  236   
  237       if (mouseScrollListener != null) {
  238           scrollpane.removeMouseWheelListener(mouseScrollListener);
  239       }
  240   
  241           vsbChangeListener = null;
  242           hsbChangeListener = null;
  243           viewportChangeListener = null;
  244           spPropertyChangeListener = null;
  245           mouseScrollListener = null;
  246           handler = null;
  247       }
  248   
  249   
  250       protected void uninstallKeyboardActions(JScrollPane c) {
  251           SwingUtilities.replaceUIActionMap(c, null);
  252           SwingUtilities.replaceUIInputMap(c, JComponent.
  253                              WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
  254       }
  255   
  256   
  257       public void uninstallUI(JComponent c) {
  258           uninstallDefaults(scrollpane);
  259           uninstallListeners(scrollpane);
  260           uninstallKeyboardActions(scrollpane);
  261           scrollpane = null;
  262       }
  263   
  264       private Handler getHandler() {
  265           if (handler == null) {
  266               handler = new Handler();
  267           }
  268           return handler;
  269       }
  270   
  271       protected void syncScrollPaneWithViewport()
  272       {
  273           JViewport viewport = scrollpane.getViewport();
  274           JScrollBar vsb = scrollpane.getVerticalScrollBar();
  275           JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  276           JViewport rowHead = scrollpane.getRowHeader();
  277           JViewport colHead = scrollpane.getColumnHeader();
  278           boolean ltr = scrollpane.getComponentOrientation().isLeftToRight();
  279   
  280           if (viewport != null) {
  281               Dimension extentSize = viewport.getExtentSize();
  282               Dimension viewSize = viewport.getViewSize();
  283               Point viewPosition = viewport.getViewPosition();
  284   
  285               if (vsb != null) {
  286                   int extent = extentSize.height;
  287                   int max = viewSize.height;
  288                   int value = Math.max(0, Math.min(viewPosition.y, max - extent));
  289                   vsb.setValues(value, extent, 0, max);
  290               }
  291   
  292               if (hsb != null) {
  293                   int extent = extentSize.width;
  294                   int max = viewSize.width;
  295                   int value;
  296   
  297                   if (ltr) {
  298                       value = Math.max(0, Math.min(viewPosition.x, max - extent));
  299                   } else {
  300                       int currentValue = hsb.getValue();
  301   
  302                       /* Use a particular formula to calculate "value"
  303                        * until effective x coordinate is calculated.
  304                        */
  305                       if (setValueCalled && ((max - currentValue) == viewPosition.x)) {
  306                           value = Math.max(0, Math.min(max - extent, currentValue));
  307                           /* After "extent" is set, turn setValueCalled flag off.
  308                            */
  309                           if (extent != 0) {
  310                               setValueCalled = false;
  311                           }
  312                       } else {
  313                           if (extent > max) {
  314                               viewPosition.x = max - extent;
  315                               viewport.setViewPosition(viewPosition);
  316                               value = 0;
  317                           } else {
  318                              /* The following line can't handle a small value of
  319                               * viewPosition.x like Integer.MIN_VALUE correctly
  320                               * because (max - extent - viewPositoiin.x) causes
  321                               * an overflow. As a result, value becomes zero.
  322                               * (e.g. setViewPosition(Integer.MAX_VALUE, ...)
  323                               *       in a user program causes a overflow.
  324                               *       Its expected value is (max - extent).)
  325                               * However, this seems a trivial bug and adding a
  326                               * fix makes this often-called method slow, so I'll
  327                               * leave it until someone claims.
  328                               */
  329                               value = Math.max(0, Math.min(max - extent, max - extent - viewPosition.x));
  330                           }
  331                       }
  332                   }
  333                   hsb.setValues(value, extent, 0, max);
  334               }
  335   
  336               if (rowHead != null) {
  337                   Point p = rowHead.getViewPosition();
  338                   p.y = viewport.getViewPosition().y;
  339                   p.x = 0;
  340                   rowHead.setViewPosition(p);
  341               }
  342   
  343               if (colHead != null) {
  344                   Point p = colHead.getViewPosition();
  345                   if (ltr) {
  346                       p.x = viewport.getViewPosition().x;
  347                   } else {
  348                       p.x = Math.max(0, viewport.getViewPosition().x);
  349                   }
  350                   p.y = 0;
  351                   colHead.setViewPosition(p);
  352               }
  353           }
  354       }
  355   
  356       /**
  357        * Returns the baseline.
  358        *
  359        * @throws NullPointerException {@inheritDoc}
  360        * @throws IllegalArgumentException {@inheritDoc}
  361        * @see javax.swing.JComponent#getBaseline(int, int)
  362        * @since 1.6
  363        */
  364       public int getBaseline(JComponent c, int width, int height) {
  365           JViewport viewport = scrollpane.getViewport();
  366           Insets spInsets = scrollpane.getInsets();
  367           int y = spInsets.top;
  368           height = height - spInsets.top - spInsets.bottom;
  369           width = width - spInsets.left - spInsets.right;
  370           JViewport columnHeader = scrollpane.getColumnHeader();
  371           if (columnHeader != null && columnHeader.isVisible()) {
  372               Component header = columnHeader.getView();
  373               if (header != null && header.isVisible()) {
  374                   // Header is always given it's preferred size.
  375                   Dimension headerPref = header.getPreferredSize();
  376                   int baseline = header.getBaseline(headerPref.width,
  377                                                     headerPref.height);
  378                   if (baseline >= 0) {
  379                       return y + baseline;
  380                   }
  381               }
  382               Dimension columnPref = columnHeader.getPreferredSize();
  383               height -= columnPref.height;
  384               y += columnPref.height;
  385           }
  386           Component view = (viewport == null) ? null : viewport.getView();
  387           if (view != null && view.isVisible() &&
  388                   view.getBaselineResizeBehavior() ==
  389                   Component.BaselineResizeBehavior.CONSTANT_ASCENT) {
  390               Border viewportBorder = scrollpane.getViewportBorder();
  391               if (viewportBorder != null) {
  392                   Insets vpbInsets = viewportBorder.getBorderInsets(scrollpane);
  393                   y += vpbInsets.top;
  394                   height = height - vpbInsets.top - vpbInsets.bottom;
  395                   width = width - vpbInsets.left - vpbInsets.right;
  396               }
  397               if (view.getWidth() > 0 && view.getHeight() > 0) {
  398                   Dimension min = view.getMinimumSize();
  399                   width = Math.max(min.width, view.getWidth());
  400                   height = Math.max(min.height, view.getHeight());
  401               }
  402               if (width > 0 && height > 0) {
  403                   int baseline = view.getBaseline(width, height);
  404                   if (baseline > 0) {
  405                       return y + baseline;
  406                   }
  407               }
  408           }
  409           return -1;
  410       }
  411   
  412       /**
  413        * Returns an enum indicating how the baseline of the component
  414        * changes as the size changes.
  415        *
  416        * @throws NullPointerException {@inheritDoc}
  417        * @see javax.swing.JComponent#getBaseline(int, int)
  418        * @since 1.6
  419        */
  420       public Component.BaselineResizeBehavior getBaselineResizeBehavior(
  421               JComponent c) {
  422           super.getBaselineResizeBehavior(c);
  423           // Baseline is either from the header, in which case it's always
  424           // the same size and therefor can be created as CONSTANT_ASCENT.
  425           // If the header doesn't have a baseline than the baseline will only
  426           // be valid if it's BaselineResizeBehavior is
  427           // CONSTANT_ASCENT, so, return CONSTANT_ASCENT.
  428           return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
  429       }
  430   
  431   
  432       /**
  433        * Listener for viewport events.
  434        */
  435       public class ViewportChangeHandler implements ChangeListener
  436       {
  437   
  438           // NOTE: This class exists only for backward compatability. All
  439           // its functionality has been moved into Handler. If you need to add
  440           // new functionality add it to the Handler, but make sure this
  441           // class calls into the Handler.
  442   
  443           public void stateChanged(ChangeEvent e) {
  444               getHandler().stateChanged(e);
  445           }
  446       }
  447   
  448       protected ChangeListener createViewportChangeListener() {
  449           return getHandler();
  450       }
  451   
  452   
  453       /**
  454        * Horizontal scrollbar listener.
  455        */
  456       public class HSBChangeListener implements ChangeListener
  457       {
  458   
  459           // NOTE: This class exists only for backward compatability. All
  460           // its functionality has been moved into Handler. If you need to add
  461           // new functionality add it to the Handler, but make sure this
  462           // class calls into the Handler.
  463   
  464           public void stateChanged(ChangeEvent e)
  465           {
  466               getHandler().stateChanged(e);
  467           }
  468       }
  469   
  470       /**
  471        * Returns a <code>PropertyChangeListener</code> that will be installed
  472        * on the horizontal <code>JScrollBar</code>.
  473        */
  474       private PropertyChangeListener createHSBPropertyChangeListener() {
  475           return getHandler();
  476       }
  477   
  478       protected ChangeListener createHSBChangeListener() {
  479           return getHandler();
  480       }
  481   
  482   
  483       /**
  484        * Vertical scrollbar listener.
  485        */
  486       public class VSBChangeListener implements ChangeListener
  487       {
  488   
  489           // NOTE: This class exists only for backward compatability. All
  490           // its functionality has been moved into Handler. If you need to add
  491           // new functionality add it to the Handler, but make sure this
  492           // class calls into the Handler.
  493   
  494           public void stateChanged(ChangeEvent e)
  495           {
  496               getHandler().stateChanged(e);
  497           }
  498       }
  499   
  500   
  501       /**
  502        * Returns a <code>PropertyChangeListener</code> that will be installed
  503        * on the vertical <code>JScrollBar</code>.
  504        */
  505       private PropertyChangeListener createVSBPropertyChangeListener() {
  506           return getHandler();
  507       }
  508   
  509       protected ChangeListener createVSBChangeListener() {
  510           return getHandler();
  511       }
  512   
  513       /**
  514        * MouseWheelHandler is an inner class which implements the
  515        * MouseWheelListener interface.  MouseWheelHandler responds to
  516        * MouseWheelEvents by scrolling the JScrollPane appropriately.
  517        * If the scroll pane's
  518        * <code>isWheelScrollingEnabled</code>
  519        * method returns false, no scrolling occurs.
  520        *
  521        * @see javax.swing.JScrollPane#isWheelScrollingEnabled
  522        * @see #createMouseWheelListener
  523        * @see java.awt.event.MouseWheelListener
  524        * @see java.awt.event.MouseWheelEvent
  525        * @since 1.4
  526        */
  527       protected class MouseWheelHandler implements MouseWheelListener {
  528   
  529           // NOTE: This class exists only for backward compatability. All
  530           // its functionality has been moved into Handler. If you need to add
  531           // new functionality add it to the Handler, but make sure this
  532           // class calls into the Handler.
  533   
  534           /**
  535            * Called when the mouse wheel is rotated while over a
  536            * JScrollPane.
  537            *
  538            * @param e     MouseWheelEvent to be handled
  539            * @since 1.4
  540            */
  541           public void mouseWheelMoved(MouseWheelEvent e) {
  542               getHandler().mouseWheelMoved(e);
  543           }
  544       }
  545   
  546       /**
  547        * Creates an instance of MouseWheelListener, which is added to the
  548        * JScrollPane by installUI().  The returned MouseWheelListener is used
  549        * to handle mouse wheel-driven scrolling.
  550        *
  551        * @return      MouseWheelListener which implements wheel-driven scrolling
  552        * @see #installUI
  553        * @see MouseWheelHandler
  554        * @since 1.4
  555        */
  556       protected MouseWheelListener createMouseWheelListener() {
  557           return getHandler();
  558       }
  559   
  560       protected void updateScrollBarDisplayPolicy(PropertyChangeEvent e) {
  561           scrollpane.revalidate();
  562           scrollpane.repaint();
  563       }
  564   
  565   
  566       protected void updateViewport(PropertyChangeEvent e)
  567       {
  568           JViewport oldViewport = (JViewport)(e.getOldValue());
  569           JViewport newViewport = (JViewport)(e.getNewValue());
  570   
  571           if (oldViewport != null) {
  572               oldViewport.removeChangeListener(viewportChangeListener);
  573           }
  574   
  575           if (newViewport != null) {
  576               Point p = newViewport.getViewPosition();
  577               if (scrollpane.getComponentOrientation().isLeftToRight()) {
  578                   p.x = Math.max(p.x, 0);
  579               } else {
  580                   int max = newViewport.getViewSize().width;
  581                   int extent = newViewport.getExtentSize().width;
  582                   if (extent > max) {
  583                       p.x = max - extent;
  584                   } else {
  585                       p.x = Math.max(0, Math.min(max - extent, p.x));
  586                   }
  587               }
  588               p.y = Math.max(p.y, 0);
  589               newViewport.setViewPosition(p);
  590               newViewport.addChangeListener(viewportChangeListener);
  591           }
  592       }
  593   
  594   
  595       protected void updateRowHeader(PropertyChangeEvent e)
  596       {
  597           JViewport newRowHead = (JViewport)(e.getNewValue());
  598           if (newRowHead != null) {
  599               JViewport viewport = scrollpane.getViewport();
  600               Point p = newRowHead.getViewPosition();
  601               p.y = (viewport != null) ? viewport.getViewPosition().y : 0;
  602               newRowHead.setViewPosition(p);
  603           }
  604       }
  605   
  606   
  607       protected void updateColumnHeader(PropertyChangeEvent e)
  608       {
  609           JViewport newColHead = (JViewport)(e.getNewValue());
  610           if (newColHead != null) {
  611               JViewport viewport = scrollpane.getViewport();
  612               Point p = newColHead.getViewPosition();
  613               if (viewport == null) {
  614                   p.x = 0;
  615               } else {
  616                   if (scrollpane.getComponentOrientation().isLeftToRight()) {
  617                       p.x = viewport.getViewPosition().x;
  618                   } else {
  619                       p.x = Math.max(0, viewport.getViewPosition().x);
  620                   }
  621               }
  622               newColHead.setViewPosition(p);
  623               scrollpane.add(newColHead, COLUMN_HEADER);
  624           }
  625       }
  626   
  627       private void updateHorizontalScrollBar(PropertyChangeEvent pce) {
  628           updateScrollBar(pce, hsbChangeListener, hsbPropertyChangeListener);
  629       }
  630   
  631       private void updateVerticalScrollBar(PropertyChangeEvent pce) {
  632           updateScrollBar(pce, vsbChangeListener, vsbPropertyChangeListener);
  633       }
  634   
  635       private void updateScrollBar(PropertyChangeEvent pce, ChangeListener cl,
  636                                    PropertyChangeListener pcl) {
  637           JScrollBar sb = (JScrollBar)pce.getOldValue();
  638           if (sb != null) {
  639               if (cl != null) {
  640                   sb.getModel().removeChangeListener(cl);
  641               }
  642               if (pcl != null) {
  643                   sb.removePropertyChangeListener(pcl);
  644               }
  645           }
  646           sb = (JScrollBar)pce.getNewValue();
  647           if (sb != null) {
  648               if (cl != null) {
  649                   sb.getModel().addChangeListener(cl);
  650               }
  651               if (pcl != null) {
  652                   sb.addPropertyChangeListener(pcl);
  653               }
  654           }
  655       }
  656   
  657       public class PropertyChangeHandler implements PropertyChangeListener
  658       {
  659   
  660           // NOTE: This class exists only for backward compatability. All
  661           // its functionality has been moved into Handler. If you need to add
  662           // new functionality add it to the Handler, but make sure this
  663           // class calls into the Handler.
  664   
  665           public void propertyChange(PropertyChangeEvent e)
  666           {
  667               getHandler().propertyChange(e);
  668           }
  669       }
  670   
  671   
  672   
  673       /**
  674        * Creates an instance of PropertyChangeListener that's added to
  675        * the JScrollPane by installUI().  Subclasses can override this method
  676        * to return a custom PropertyChangeListener, e.g.
  677        * <pre>
  678        * class MyScrollPaneUI extends BasicScrollPaneUI {
  679        *    protected PropertyChangeListener <b>createPropertyChangeListener</b>() {
  680        *        return new MyPropertyChangeListener();
  681        *    }
  682        *    public class MyPropertyChangeListener extends PropertyChangeListener {
  683        *        public void propertyChange(PropertyChangeEvent e) {
  684        *            if (e.getPropertyName().equals("viewport")) {
  685        *                // do some extra work when the viewport changes
  686        *            }
  687        *            super.propertyChange(e);
  688        *        }
  689        *    }
  690        * }
  691        * </pre>
  692        *
  693        * @see java.beans.PropertyChangeListener
  694        * @see #installUI
  695        */
  696       protected PropertyChangeListener createPropertyChangeListener() {
  697           return getHandler();
  698       }
  699   
  700   
  701       private static class Actions extends UIAction {
  702           private static final String SCROLL_UP = "scrollUp";
  703           private static final String SCROLL_DOWN = "scrollDown";
  704           private static final String SCROLL_HOME = "scrollHome";
  705           private static final String SCROLL_END = "scrollEnd";
  706           private static final String UNIT_SCROLL_UP = "unitScrollUp";
  707           private static final String UNIT_SCROLL_DOWN = "unitScrollDown";
  708           private static final String SCROLL_LEFT = "scrollLeft";
  709           private static final String SCROLL_RIGHT = "scrollRight";
  710           private static final String UNIT_SCROLL_LEFT = "unitScrollLeft";
  711           private static final String UNIT_SCROLL_RIGHT = "unitScrollRight";
  712   
  713   
  714           Actions(String key) {
  715               super(key);
  716           }
  717   
  718           public void actionPerformed(ActionEvent e) {
  719               JScrollPane scrollPane = (JScrollPane)e.getSource();
  720               boolean ltr = scrollPane.getComponentOrientation().isLeftToRight();
  721               String key = getName();
  722   
  723               if (key == SCROLL_UP) {
  724                   scroll(scrollPane, SwingConstants.VERTICAL, -1, true);
  725               }
  726               else if (key == SCROLL_DOWN) {
  727                   scroll(scrollPane, SwingConstants.VERTICAL, 1, true);
  728               }
  729               else if (key == SCROLL_HOME) {
  730                   scrollHome(scrollPane);
  731               }
  732               else if (key == SCROLL_END) {
  733                   scrollEnd(scrollPane);
  734               }
  735               else if (key == UNIT_SCROLL_UP) {
  736                   scroll(scrollPane, SwingConstants.VERTICAL, -1, false);
  737               }
  738               else if (key == UNIT_SCROLL_DOWN) {
  739                   scroll(scrollPane, SwingConstants.VERTICAL, 1, false);
  740               }
  741               else if (key == SCROLL_LEFT) {
  742                   scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
  743                          true);
  744               }
  745               else if (key == SCROLL_RIGHT) {
  746                   scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
  747                          true);
  748               }
  749               else if (key == UNIT_SCROLL_LEFT) {
  750                   scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
  751                          false);
  752               }
  753               else if (key == UNIT_SCROLL_RIGHT) {
  754                   scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
  755                          false);
  756               }
  757           }
  758   
  759           private void scrollEnd(JScrollPane scrollpane) {
  760               JViewport vp = scrollpane.getViewport();
  761               Component view;
  762               if (vp != null && (view = vp.getView()) != null) {
  763                   Rectangle visRect = vp.getViewRect();
  764                   Rectangle bounds = view.getBounds();
  765                   if (scrollpane.getComponentOrientation().isLeftToRight()) {
  766                       vp.setViewPosition(new Point(bounds.width - visRect.width,
  767                                                bounds.height - visRect.height));
  768                   } else {
  769                       vp.setViewPosition(new Point(0,
  770                                                bounds.height - visRect.height));
  771                   }
  772               }
  773           }
  774   
  775           private void scrollHome(JScrollPane scrollpane) {
  776               JViewport vp = scrollpane.getViewport();
  777               Component view;
  778               if (vp != null && (view = vp.getView()) != null) {
  779                   if (scrollpane.getComponentOrientation().isLeftToRight()) {
  780                       vp.setViewPosition(new Point(0, 0));
  781                   } else {
  782                       Rectangle visRect = vp.getViewRect();
  783                       Rectangle bounds = view.getBounds();
  784                       vp.setViewPosition(new Point(bounds.width - visRect.width, 0));
  785                   }
  786               }
  787           }
  788   
  789           private void scroll(JScrollPane scrollpane, int orientation,
  790                               int direction, boolean block) {
  791               JViewport vp = scrollpane.getViewport();
  792               Component view;
  793               if (vp != null && (view = vp.getView()) != null) {
  794                   Rectangle visRect = vp.getViewRect();
  795                   Dimension vSize = view.getSize();
  796                   int amount;
  797   
  798                   if (view instanceof Scrollable) {
  799                       if (block) {
  800                           amount = ((Scrollable)view).getScrollableBlockIncrement
  801                                    (visRect, orientation, direction);
  802                       }
  803                       else {
  804                           amount = ((Scrollable)view).getScrollableUnitIncrement
  805                                    (visRect, orientation, direction);
  806                       }
  807                   }
  808                   else {
  809                       if (block) {
  810                           if (orientation == SwingConstants.VERTICAL) {
  811                               amount = visRect.height;
  812                           }
  813                           else {
  814                               amount = visRect.width;
  815                           }
  816                       }
  817                       else {
  818                           amount = 10;
  819                       }
  820                   }
  821                   if (orientation == SwingConstants.VERTICAL) {
  822                       visRect.y += (amount * direction);
  823                       if ((visRect.y + visRect.height) > vSize.height) {
  824                           visRect.y = Math.max(0, vSize.height - visRect.height);
  825                       }
  826                       else if (visRect.y < 0) {
  827                           visRect.y = 0;
  828                       }
  829                   }
  830                   else {
  831                       if (scrollpane.getComponentOrientation().isLeftToRight()) {
  832                           visRect.x += (amount * direction);
  833                           if ((visRect.x + visRect.width) > vSize.width) {
  834                               visRect.x = Math.max(0, vSize.width - visRect.width);
  835                           } else if (visRect.x < 0) {
  836                               visRect.x = 0;
  837                           }
  838                       } else {
  839                           visRect.x -= (amount * direction);
  840                           if (visRect.width > vSize.width) {
  841                               visRect.x = vSize.width - visRect.width;
  842                           } else {
  843                               visRect.x = Math.max(0, Math.min(vSize.width - visRect.width, visRect.x));
  844                           }
  845                       }
  846                   }
  847                   vp.setViewPosition(visRect.getLocation());
  848               }
  849           }
  850       }
  851   
  852   
  853       class Handler implements ChangeListener, PropertyChangeListener, MouseWheelListener {
  854           //
  855           // MouseWheelListener
  856           //
  857           public void mouseWheelMoved(MouseWheelEvent e) {
  858               if (scrollpane.isWheelScrollingEnabled() &&
  859                   e.getWheelRotation() != 0) {
  860                   JScrollBar toScroll = scrollpane.getVerticalScrollBar();
  861                   int direction = e.getWheelRotation() < 0 ? -1 : 1;
  862                   int orientation = SwingConstants.VERTICAL;
  863   
  864                   // find which scrollbar to scroll, or return if none
  865                   if (toScroll == null || !toScroll.isVisible()) {
  866                       toScroll = scrollpane.getHorizontalScrollBar();
  867                       if (toScroll == null || !toScroll.isVisible()) {
  868                           return;
  869                       }
  870                       orientation = SwingConstants.HORIZONTAL;
  871                   }
  872   
  873                   if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
  874                       JViewport vp = scrollpane.getViewport();
  875                       if (vp == null) { return; }
  876                       Component comp = vp.getView();
  877                       int units = Math.abs(e.getUnitsToScroll());
  878   
  879                       // When the scrolling speed is set to maximum, it's possible
  880                       // for a single wheel click to scroll by more units than
  881                       // will fit in the visible area.  This makes it
  882                       // hard/impossible to get to certain parts of the scrolling
  883                       // Component with the wheel.  To make for more accurate
  884                       // low-speed scrolling, we limit scrolling to the block
  885                       // increment if the wheel was only rotated one click.
  886                       boolean limitScroll = Math.abs(e.getWheelRotation()) == 1;
  887   
  888                       // Check if we should use the visibleRect trick
  889                       Object fastWheelScroll = toScroll.getClientProperty(
  890                                                  "JScrollBar.fastWheelScrolling");
  891                       if (Boolean.TRUE == fastWheelScroll &&
  892                           comp instanceof Scrollable) {
  893                           // 5078454: Under maximum acceleration, we may scroll
  894                           // by many 100s of units in ~1 second.
  895                           //
  896                           // BasicScrollBarUI.scrollByUnits() can bog down the EDT
  897                           // with repaints in this situation.  However, the
  898                           // Scrollable interface allows us to pass in an
  899                           // arbitrary visibleRect.  This allows us to accurately
  900                           // calculate the total scroll amount, and then update
  901                           // the GUI once.  This technique provides much faster
  902                           // accelerated wheel scrolling.
  903                           Scrollable scrollComp = (Scrollable) comp;
  904                           Rectangle viewRect = vp.getViewRect();
  905                           int startingX = viewRect.x;
  906                           boolean leftToRight =
  907                                    comp.getComponentOrientation().isLeftToRight();
  908                           int scrollMin = toScroll.getMinimum();
  909                           int scrollMax = toScroll.getMaximum() -
  910                                           toScroll.getModel().getExtent();
  911   
  912                           if (limitScroll) {
  913                               int blockIncr =
  914                                   scrollComp.getScrollableBlockIncrement(viewRect,
  915                                                                       orientation,
  916                                                                       direction);
  917                               if (direction < 0) {
  918                                   scrollMin = Math.max(scrollMin,
  919                                                  toScroll.getValue() - blockIncr);
  920                               }
  921                               else {
  922                                   scrollMax = Math.min(scrollMax,
  923                                                  toScroll.getValue() + blockIncr);
  924                               }
  925                           }
  926   
  927                           for (int i = 0; i < units; i++) {
  928                               int unitIncr =
  929                                   scrollComp.getScrollableUnitIncrement(viewRect,
  930                                                           orientation, direction);
  931                               // Modify the visible rect for the next unit, and
  932                               // check to see if we're at the end already.
  933                               if (orientation == SwingConstants.VERTICAL) {
  934                                   if (direction < 0) {
  935                                       viewRect.y -= unitIncr;
  936                                       if (viewRect.y <= scrollMin) {
  937                                           viewRect.y = scrollMin;
  938                                           break;
  939                                       }
  940                                   }
  941                                   else { // (direction > 0
  942                                       viewRect.y += unitIncr;
  943                                       if (viewRect.y >= scrollMax) {
  944                                           viewRect.y = scrollMax;
  945                                           break;
  946                                       }
  947                                   }
  948                               }
  949                               else {
  950                                   // Scroll left
  951                                   if ((leftToRight && direction < 0) ||
  952                                       (!leftToRight && direction > 0)) {
  953                                       viewRect.x -= unitIncr;
  954                                       if (leftToRight) {
  955                                           if (viewRect.x < scrollMin) {
  956                                               viewRect.x = scrollMin;
  957                                               break;
  958                                           }
  959                                       }
  960                                   }
  961                                   // Scroll right
  962                                   else if ((leftToRight && direction > 0) ||
  963                                       (!leftToRight && direction < 0)) {
  964                                       viewRect.x += unitIncr;
  965                                       if (leftToRight) {
  966                                           if (viewRect.x > scrollMax) {
  967                                               viewRect.x = scrollMax;
  968                                               break;
  969                                           }
  970                                       }
  971                                   }
  972                                   else {
  973                                       assert false : "Non-sensical ComponentOrientation / scroll direction";
  974                                   }
  975                               }
  976                           }
  977                           // Set the final view position on the ScrollBar
  978                           if (orientation == SwingConstants.VERTICAL) {
  979                               toScroll.setValue(viewRect.y);
  980                           }
  981                           else {
  982                               if (leftToRight) {
  983                                   toScroll.setValue(viewRect.x);
  984                               }
  985                               else {
  986                                   // rightToLeft scrollbars are oriented with
  987                                   // minValue on the right and maxValue on the
  988                                   // left.
  989                                   int newPos = toScroll.getValue() -
  990                                                          (viewRect.x - startingX);
  991                                   if (newPos < scrollMin) {
  992                                       newPos = scrollMin;
  993                                   }
  994                                   else if (newPos > scrollMax) {
  995                                       newPos = scrollMax;
  996                                   }
  997                                   toScroll.setValue(newPos);
  998                               }
  999                           }
 1000                       }
 1001                       else {
 1002                           // Viewport's view is not a Scrollable, or fast wheel
 1003                           // scrolling is not enabled.
 1004                           BasicScrollBarUI.scrollByUnits(toScroll, direction,
 1005                                                          units, limitScroll);
 1006                       }
 1007                   }
 1008                   else if (e.getScrollType() ==
 1009                            MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
 1010                       BasicScrollBarUI.scrollByBlock(toScroll, direction);
 1011                   }
 1012               }
 1013           }
 1014   
 1015           //
 1016           // ChangeListener: This is added to the vieport, and hsb/vsb models.
 1017           //
 1018           public void stateChanged(ChangeEvent e) {
 1019               JViewport viewport = scrollpane.getViewport();
 1020   
 1021               if (viewport != null) {
 1022                   if (e.getSource() == viewport) {
 1023                       viewportStateChanged(e);
 1024                   }
 1025                   else {
 1026                       JScrollBar hsb = scrollpane.getHorizontalScrollBar();
 1027                       if (hsb != null && e.getSource() == hsb.getModel()) {
 1028                           hsbStateChanged(viewport, e);
 1029                       }
 1030                       else {
 1031                           JScrollBar vsb = scrollpane.getVerticalScrollBar();
 1032                           if (vsb != null && e.getSource() == vsb.getModel()) {
 1033                               vsbStateChanged(viewport, e);
 1034                           }
 1035                       }
 1036                   }
 1037               }
 1038           }
 1039   
 1040           private void vsbStateChanged(JViewport viewport, ChangeEvent e) {
 1041               BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
 1042               Point p = viewport.getViewPosition();
 1043               p.y = model.getValue();
 1044               viewport.setViewPosition(p);
 1045           }
 1046   
 1047           private void hsbStateChanged(JViewport viewport, ChangeEvent e) {
 1048               BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
 1049               Point p = viewport.getViewPosition();
 1050               int value = model.getValue();
 1051               if (scrollpane.getComponentOrientation().isLeftToRight()) {
 1052                   p.x = value;
 1053               } else {
 1054                   int max = viewport.getViewSize().width;
 1055                   int extent = viewport.getExtentSize().width;
 1056                   int oldX = p.x;
 1057   
 1058                   /* Set new X coordinate based on "value".
 1059                    */
 1060                   p.x = max - extent - value;
 1061   
 1062                   /* If setValue() was called before "extent" was fixed,
 1063                    * turn setValueCalled flag on.
 1064                    */
 1065                   if ((extent == 0) && (value != 0) && (oldX == max)) {
 1066                       setValueCalled = true;
 1067                   } else {
 1068                       /* When a pane without a horizontal scroll bar was
 1069                        * reduced and the bar appeared, the viewport should
 1070                        * show the right side of the view.
 1071                        */
 1072                       if ((extent != 0) && (oldX < 0) && (p.x == 0)) {
 1073                           p.x += value;
 1074                       }
 1075                   }
 1076               }
 1077               viewport.setViewPosition(p);
 1078           }
 1079   
 1080           private void viewportStateChanged(ChangeEvent e) {
 1081               syncScrollPaneWithViewport();
 1082           }
 1083   
 1084   
 1085           //
 1086           // PropertyChangeListener: This is installed on both the JScrollPane
 1087           // and the horizontal/vertical scrollbars.
 1088           //
 1089   
 1090           // Listens for changes in the model property and reinstalls the
 1091           // horizontal/vertical PropertyChangeListeners.
 1092           public void propertyChange(PropertyChangeEvent e) {
 1093               if (e.getSource() == scrollpane) {
 1094                   scrollPanePropertyChange(e);
 1095               }
 1096               else {
 1097                   sbPropertyChange(e);
 1098               }
 1099           }
 1100   
 1101           private void scrollPanePropertyChange(PropertyChangeEvent e) {
 1102               String propertyName = e.getPropertyName();
 1103   
 1104               if (propertyName == "verticalScrollBarDisplayPolicy") {
 1105                   updateScrollBarDisplayPolicy(e);
 1106               }
 1107               else if (propertyName == "horizontalScrollBarDisplayPolicy") {
 1108                   updateScrollBarDisplayPolicy(e);
 1109               }
 1110               else if (propertyName == "viewport") {
 1111                   updateViewport(e);
 1112               }
 1113               else if (propertyName == "rowHeader") {
 1114                   updateRowHeader(e);
 1115               }
 1116               else if (propertyName == "columnHeader") {
 1117                   updateColumnHeader(e);
 1118               }
 1119               else if (propertyName == "verticalScrollBar") {
 1120                   updateVerticalScrollBar(e);
 1121               }
 1122               else if (propertyName == "horizontalScrollBar") {
 1123                   updateHorizontalScrollBar(e);
 1124               }
 1125               else if (propertyName == "componentOrientation") {
 1126                   scrollpane.revalidate();
 1127                   scrollpane.repaint();
 1128               }
 1129           }
 1130   
 1131           // PropertyChangeListener for the horizontal and vertical scrollbars.
 1132           private void sbPropertyChange(PropertyChangeEvent e) {
 1133               String propertyName = e.getPropertyName();
 1134               Object source = e.getSource();
 1135   
 1136               if ("model" == propertyName) {
 1137                   JScrollBar sb = scrollpane.getVerticalScrollBar();
 1138                   BoundedRangeModel oldModel = (BoundedRangeModel)e.
 1139                                        getOldValue();
 1140                   ChangeListener cl = null;
 1141   
 1142                   if (source == sb) {
 1143                       cl = vsbChangeListener;
 1144                   }
 1145                   else if (source == scrollpane.getHorizontalScrollBar()) {
 1146                       sb = scrollpane.getHorizontalScrollBar();
 1147                       cl = hsbChangeListener;
 1148                   }
 1149                   if (cl != null) {
 1150                       if (oldModel != null) {
 1151                           oldModel.removeChangeListener(cl);
 1152                       }
 1153                       if (sb.getModel() != null) {
 1154                           sb.getModel().addChangeListener(cl);
 1155                       }
 1156                   }
 1157               }
 1158               else if ("componentOrientation" == propertyName) {
 1159                   if (source == scrollpane.getHorizontalScrollBar()) {
 1160                       JScrollBar hsb = scrollpane.getHorizontalScrollBar();
 1161                       JViewport viewport = scrollpane.getViewport();
 1162                       Point p = viewport.getViewPosition();
 1163                       if (scrollpane.getComponentOrientation().isLeftToRight()) {
 1164                           p.x = hsb.getValue();
 1165                       } else {
 1166                           p.x = viewport.getViewSize().width - viewport.getExtentSize().width - hsb.getValue();
 1167                       }
 1168                       viewport.setViewPosition(p);
 1169                   }
 1170               }
 1171           }
 1172       }
 1173   }

Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]