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

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

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