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

    1   /*
    2    * Copyright (c) 1997, 2011, 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   
   27   package javax.swing.plaf.basic;
   28   
   29   
   30   import sun.swing.DefaultLookup;
   31   import sun.swing.UIAction;
   32   import javax.swing;
   33   import javax.swing.border.Border;
   34   import java.awt;
   35   import java.awt.event;
   36   import java.awt.peer.ComponentPeer;
   37   import java.awt.peer.LightweightPeer;
   38   import java.beans;
   39   import java.util;
   40   import javax.swing.plaf.SplitPaneUI;
   41   import javax.swing.plaf.ComponentUI;
   42   import javax.swing.plaf.UIResource;
   43   import sun.swing.SwingUtilities2;
   44   
   45   
   46   /**
   47    * A Basic L&F implementation of the SplitPaneUI.
   48    *
   49    * @author Scott Violet
   50    * @author Steve Wilson
   51    * @author Ralph Kar
   52    */
   53   public class BasicSplitPaneUI extends SplitPaneUI
   54   {
   55       /**
   56        * The divider used for non-continuous layout is added to the split pane
   57        * with this object.
   58        */
   59       protected static final String NON_CONTINUOUS_DIVIDER =
   60           "nonContinuousDivider";
   61   
   62   
   63       /**
   64        * How far (relative) the divider does move when it is moved around by
   65        * the cursor keys on the keyboard.
   66        */
   67       protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;
   68   
   69   
   70       /**
   71        * JSplitPane instance this instance is providing
   72        * the look and feel for.
   73        */
   74       protected JSplitPane splitPane;
   75   
   76   
   77       /**
   78        * LayoutManager that is created and placed into the split pane.
   79        */
   80       protected BasicHorizontalLayoutManager layoutManager;
   81   
   82   
   83       /**
   84        * Instance of the divider for this JSplitPane.
   85        */
   86       protected BasicSplitPaneDivider divider;
   87   
   88   
   89       /**
   90        * Instance of the PropertyChangeListener for this JSplitPane.
   91        */
   92       protected PropertyChangeListener propertyChangeListener;
   93   
   94   
   95       /**
   96        * Instance of the FocusListener for this JSplitPane.
   97        */
   98       protected FocusListener focusListener;
   99   
  100       private Handler handler;
  101   
  102   
  103       /**
  104        * Keys to use for forward focus traversal when the JComponent is
  105        * managing focus.
  106        */
  107       private Set<KeyStroke> managingFocusForwardTraversalKeys;
  108   
  109       /**
  110        * Keys to use for backward focus traversal when the JComponent is
  111        * managing focus.
  112        */
  113       private Set<KeyStroke> managingFocusBackwardTraversalKeys;
  114   
  115   
  116       /**
  117        * The size of the divider while the dragging session is valid.
  118        */
  119       protected int dividerSize;
  120   
  121   
  122       /**
  123        * Instance for the shadow of the divider when non continuous layout
  124        * is being used.
  125        */
  126       protected Component nonContinuousLayoutDivider;
  127   
  128   
  129       /**
  130        * Set to true in startDragging if any of the children
  131        * (not including the nonContinuousLayoutDivider) are heavy weights.
  132        */
  133       protected boolean draggingHW;
  134   
  135   
  136       /**
  137        * Location of the divider when the dragging session began.
  138        */
  139       protected int beginDragDividerLocation;
  140   
  141   
  142       /**
  143        * As of Java 2 platform v1.3 this previously undocumented field is no
  144        * longer used.
  145        * Key bindings are now defined by the LookAndFeel, please refer to
  146        * the key bindings specification for further details.
  147        *
  148        * @deprecated As of Java 2 platform v1.3.
  149        */
  150       @Deprecated
  151       protected KeyStroke upKey;
  152       /**
  153        * As of Java 2 platform v1.3 this previously undocumented field is no
  154        * longer used.
  155        * Key bindings are now defined by the LookAndFeel, please refer to
  156        * the key bindings specification for further details.
  157        *
  158        * @deprecated As of Java 2 platform v1.3.
  159        */
  160       @Deprecated
  161       protected KeyStroke downKey;
  162       /**
  163        * As of Java 2 platform v1.3 this previously undocumented field is no
  164        * longer used.
  165        * Key bindings are now defined by the LookAndFeel, please refer to
  166        * the key bindings specification for further details.
  167        *
  168        * @deprecated As of Java 2 platform v1.3.
  169        */
  170       @Deprecated
  171       protected KeyStroke leftKey;
  172       /**
  173        * As of Java 2 platform v1.3 this previously undocumented field is no
  174        * longer used.
  175        * Key bindings are now defined by the LookAndFeel, please refer to
  176        * the key bindings specification for further details.
  177        *
  178        * @deprecated As of Java 2 platform v1.3.
  179        */
  180       @Deprecated
  181       protected KeyStroke rightKey;
  182       /**
  183        * As of Java 2 platform v1.3 this previously undocumented field is no
  184        * longer used.
  185        * Key bindings are now defined by the LookAndFeel, please refer to
  186        * the key bindings specification for further details.
  187        *
  188        * @deprecated As of Java 2 platform v1.3.
  189        */
  190       @Deprecated
  191       protected KeyStroke homeKey;
  192       /**
  193        * As of Java 2 platform v1.3 this previously undocumented field is no
  194        * longer used.
  195        * Key bindings are now defined by the LookAndFeel, please refer to
  196        * the key bindings specification for further details.
  197        *
  198        * @deprecated As of Java 2 platform v1.3.
  199        */
  200       @Deprecated
  201       protected KeyStroke endKey;
  202       /**
  203        * As of Java 2 platform v1.3 this previously undocumented field is no
  204        * longer used.
  205        * Key bindings are now defined by the LookAndFeel, please refer to
  206        * the key bindings specification for further details.
  207        *
  208        * @deprecated As of Java 2 platform v1.3.
  209        */
  210       @Deprecated
  211       protected KeyStroke dividerResizeToggleKey;
  212   
  213       /**
  214        * As of Java 2 platform v1.3 this previously undocumented field is no
  215        * longer used.
  216        * Key bindings are now defined by the LookAndFeel, please refer to
  217        * the key bindings specification for further details.
  218        *
  219        * @deprecated As of Java 2 platform v1.3.
  220        */
  221       @Deprecated
  222       protected ActionListener keyboardUpLeftListener;
  223       /**
  224        * As of Java 2 platform v1.3 this previously undocumented field is no
  225        * longer used.
  226        * Key bindings are now defined by the LookAndFeel, please refer to
  227        * the key bindings specification for further details.
  228        *
  229        * @deprecated As of Java 2 platform v1.3.
  230        */
  231       @Deprecated
  232       protected ActionListener keyboardDownRightListener;
  233       /**
  234        * As of Java 2 platform v1.3 this previously undocumented field is no
  235        * longer used.
  236        * Key bindings are now defined by the LookAndFeel, please refer to
  237        * the key bindings specification for further details.
  238        *
  239        * @deprecated As of Java 2 platform v1.3.
  240        */
  241       @Deprecated
  242       protected ActionListener keyboardHomeListener;
  243       /**
  244        * As of Java 2 platform v1.3 this previously undocumented field is no
  245        * longer used.
  246        * Key bindings are now defined by the LookAndFeel, please refer to
  247        * the key bindings specification for further details.
  248        *
  249        * @deprecated As of Java 2 platform v1.3.
  250        */
  251       @Deprecated
  252       protected ActionListener keyboardEndListener;
  253       /**
  254        * As of Java 2 platform v1.3 this previously undocumented field is no
  255        * longer used.
  256        * Key bindings are now defined by the LookAndFeel, please refer to
  257        * the key bindings specification for further details.
  258        *
  259        * @deprecated As of Java 2 platform v1.3.
  260        */
  261       @Deprecated
  262       protected ActionListener keyboardResizeToggleListener;
  263   
  264   
  265       // Private data of the instance
  266       private int         orientation;
  267       private int         lastDragLocation;
  268       private boolean     continuousLayout;
  269       private boolean     dividerKeyboardResize;
  270       private boolean     dividerLocationIsSet;  // needed for tracking
  271                                                  // the first occurrence of
  272                                                  // setDividerLocation()
  273       private Color dividerDraggingColor;
  274       private boolean rememberPaneSizes;
  275   
  276       // Indicates wether the one of splitpane sides is expanded
  277       private boolean keepHidden = false;
  278   
  279       /** Indicates that we have painted once. */
  280       // This is used by the LayoutManager to determine when it should use
  281       // the divider location provided by the JSplitPane. This is used as there
  282       // is no way to determine when the layout process has completed.
  283       boolean             painted;
  284       /** If true, setDividerLocation does nothing. */
  285       boolean             ignoreDividerLocationChange;
  286   
  287   
  288       /**
  289        * Creates a new BasicSplitPaneUI instance
  290        */
  291       public static ComponentUI createUI(JComponent x) {
  292           return new BasicSplitPaneUI();
  293       }
  294   
  295       static void loadActionMap(LazyActionMap map) {
  296           map.put(new Actions(Actions.NEGATIVE_INCREMENT));
  297           map.put(new Actions(Actions.POSITIVE_INCREMENT));
  298           map.put(new Actions(Actions.SELECT_MIN));
  299           map.put(new Actions(Actions.SELECT_MAX));
  300           map.put(new Actions(Actions.START_RESIZE));
  301           map.put(new Actions(Actions.TOGGLE_FOCUS));
  302           map.put(new Actions(Actions.FOCUS_OUT_FORWARD));
  303           map.put(new Actions(Actions.FOCUS_OUT_BACKWARD));
  304       }
  305   
  306   
  307   
  308       /**
  309        * Installs the UI.
  310        */
  311       public void installUI(JComponent c) {
  312           splitPane = (JSplitPane) c;
  313           dividerLocationIsSet = false;
  314           dividerKeyboardResize = false;
  315           keepHidden = false;
  316           installDefaults();
  317           installListeners();
  318           installKeyboardActions();
  319           setLastDragLocation(-1);
  320       }
  321   
  322   
  323       /**
  324        * Installs the UI defaults.
  325        */
  326       protected void installDefaults(){
  327           LookAndFeel.installBorder(splitPane, "SplitPane.border");
  328           LookAndFeel.installColors(splitPane, "SplitPane.background",
  329                                     "SplitPane.foreground");
  330           LookAndFeel.installProperty(splitPane, "opaque", Boolean.TRUE);
  331   
  332           if (divider == null) divider = createDefaultDivider();
  333           divider.setBasicSplitPaneUI(this);
  334   
  335           Border    b = divider.getBorder();
  336   
  337           if (b == null || !(b instanceof UIResource)) {
  338               divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
  339           }
  340   
  341           dividerDraggingColor = UIManager.getColor("SplitPaneDivider.draggingColor");
  342   
  343           setOrientation(splitPane.getOrientation());
  344   
  345           // note: don't rename this temp variable to dividerSize
  346           // since it will conflict with "this.dividerSize" field
  347           Integer temp = (Integer)UIManager.get("SplitPane.dividerSize");
  348           LookAndFeel.installProperty(splitPane, "dividerSize", temp == null? 10: temp);
  349   
  350           divider.setDividerSize(splitPane.getDividerSize());
  351           dividerSize = divider.getDividerSize();
  352           splitPane.add(divider, JSplitPane.DIVIDER);
  353   
  354           setContinuousLayout(splitPane.isContinuousLayout());
  355   
  356           resetLayoutManager();
  357   
  358           /* Install the nonContinuousLayoutDivider here to avoid having to
  359           add/remove everything later. */
  360           if(nonContinuousLayoutDivider == null) {
  361               setNonContinuousLayoutDivider(
  362                                   createDefaultNonContinuousLayoutDivider(),
  363                                   true);
  364           } else {
  365               setNonContinuousLayoutDivider(nonContinuousLayoutDivider, true);
  366           }
  367   
  368           // focus forward traversal key
  369           if (managingFocusForwardTraversalKeys==null) {
  370               managingFocusForwardTraversalKeys = new HashSet<KeyStroke>();
  371               managingFocusForwardTraversalKeys.add(
  372                   KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
  373           }
  374           splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
  375                                           managingFocusForwardTraversalKeys);
  376           // focus backward traversal key
  377           if (managingFocusBackwardTraversalKeys==null) {
  378               managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>();
  379               managingFocusBackwardTraversalKeys.add(
  380                   KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
  381           }
  382           splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
  383                                           managingFocusBackwardTraversalKeys);
  384       }
  385   
  386   
  387       /**
  388        * Installs the event listeners for the UI.
  389        */
  390       protected void installListeners() {
  391           if ((propertyChangeListener = createPropertyChangeListener()) !=
  392               null) {
  393               splitPane.addPropertyChangeListener(propertyChangeListener);
  394           }
  395   
  396           if ((focusListener = createFocusListener()) != null) {
  397               splitPane.addFocusListener(focusListener);
  398           }
  399       }
  400   
  401   
  402       /**
  403        * Installs the keyboard actions for the UI.
  404        */
  405       protected void installKeyboardActions() {
  406           InputMap km = getInputMap(JComponent.
  407                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  408   
  409           SwingUtilities.replaceUIInputMap(splitPane, JComponent.
  410                                          WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  411                                          km);
  412           LazyActionMap.installLazyActionMap(splitPane, BasicSplitPaneUI.class,
  413                                              "SplitPane.actionMap");
  414       }
  415   
  416       InputMap getInputMap(int condition) {
  417           if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  418               return (InputMap)DefaultLookup.get(splitPane, this,
  419                                                  "SplitPane.ancestorInputMap");
  420           }
  421           return null;
  422       }
  423   
  424       /**
  425        * Uninstalls the UI.
  426        */
  427       public void uninstallUI(JComponent c) {
  428           uninstallKeyboardActions();
  429           uninstallListeners();
  430           uninstallDefaults();
  431           dividerLocationIsSet = false;
  432           dividerKeyboardResize = false;
  433           splitPane = null;
  434       }
  435   
  436   
  437       /**
  438        * Uninstalls the UI defaults.
  439        */
  440       protected void uninstallDefaults() {
  441           if(splitPane.getLayout() == layoutManager) {
  442               splitPane.setLayout(null);
  443           }
  444   
  445           if(nonContinuousLayoutDivider != null) {
  446               splitPane.remove(nonContinuousLayoutDivider);
  447           }
  448   
  449           LookAndFeel.uninstallBorder(splitPane);
  450   
  451           Border    b = divider.getBorder();
  452   
  453           if (b instanceof UIResource) {
  454               divider.setBorder(null);
  455           }
  456   
  457           splitPane.remove(divider);
  458           divider.setBasicSplitPaneUI(null);
  459           layoutManager = null;
  460           divider = null;
  461           nonContinuousLayoutDivider = null;
  462   
  463           setNonContinuousLayoutDivider(null);
  464   
  465           // sets the focus forward and backward traversal keys to null
  466           // to restore the defaults
  467           splitPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
  468           splitPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
  469       }
  470   
  471   
  472       /**
  473        * Uninstalls the event listeners for the UI.
  474        */
  475       protected void uninstallListeners() {
  476           if (propertyChangeListener != null) {
  477               splitPane.removePropertyChangeListener(propertyChangeListener);
  478               propertyChangeListener = null;
  479           }
  480           if (focusListener != null) {
  481               splitPane.removeFocusListener(focusListener);
  482               focusListener = null;
  483           }
  484   
  485           keyboardUpLeftListener = null;
  486           keyboardDownRightListener = null;
  487           keyboardHomeListener = null;
  488           keyboardEndListener = null;
  489           keyboardResizeToggleListener = null;
  490           handler = null;
  491       }
  492   
  493   
  494       /**
  495        * Uninstalls the keyboard actions for the UI.
  496        */
  497       protected void uninstallKeyboardActions() {
  498           SwingUtilities.replaceUIActionMap(splitPane, null);
  499           SwingUtilities.replaceUIInputMap(splitPane, JComponent.
  500                                         WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  501                                         null);
  502       }
  503   
  504   
  505       /**
  506        * Creates a PropertyChangeListener for the JSplitPane UI.
  507        */
  508       protected PropertyChangeListener createPropertyChangeListener() {
  509           return getHandler();
  510       }
  511   
  512       private Handler getHandler() {
  513           if (handler == null) {
  514               handler = new Handler();
  515           }
  516           return handler;
  517       }
  518   
  519   
  520       /**
  521        * Creates a FocusListener for the JSplitPane UI.
  522        */
  523       protected FocusListener createFocusListener() {
  524           return getHandler();
  525       }
  526   
  527   
  528       /**
  529        * As of Java 2 platform v1.3 this method is no
  530        * longer used. Subclassers previously using this method should
  531        * instead create an Action wrapping the ActionListener, and register
  532        * that Action by overriding <code>installKeyboardActions</code> and
  533        * placing the Action in the SplitPane's ActionMap. Please refer to
  534        * the key bindings specification for further details.
  535        * <p>
  536        * Creates a ActionListener for the JSplitPane UI that listens for
  537        * specific key presses.
  538        *
  539        * @deprecated As of Java 2 platform v1.3.
  540        */
  541       @Deprecated
  542       protected ActionListener createKeyboardUpLeftListener() {
  543           return new KeyboardUpLeftHandler();
  544       }
  545   
  546   
  547       /**
  548        * As of Java 2 platform v1.3 this method is no
  549        * longer used. Subclassers previously using this method should
  550        * instead create an Action wrapping the ActionListener, and register
  551        * that Action by overriding <code>installKeyboardActions</code> and
  552        * placing the Action in the SplitPane's ActionMap. Please refer to
  553        * the key bindings specification for further details.
  554        * <p>
  555        * Creates a ActionListener for the JSplitPane UI that listens for
  556        * specific key presses.
  557        *
  558        * @deprecated As of Java 2 platform v1.3.
  559        */
  560       @Deprecated
  561       protected ActionListener createKeyboardDownRightListener() {
  562           return new KeyboardDownRightHandler();
  563       }
  564   
  565   
  566       /**
  567        * As of Java 2 platform v1.3 this method is no
  568        * longer used. Subclassers previously using this method should
  569        * instead create an Action wrapping the ActionListener, and register
  570        * that Action by overriding <code>installKeyboardActions</code> and
  571        * placing the Action in the SplitPane's ActionMap. Please refer to
  572        * the key bindings specification for further details.
  573        * <p>
  574        * Creates a ActionListener for the JSplitPane UI that listens for
  575        * specific key presses.
  576        *
  577        * @deprecated As of Java 2 platform v1.3.
  578        */
  579       @Deprecated
  580       protected ActionListener createKeyboardHomeListener() {
  581           return new KeyboardHomeHandler();
  582       }
  583   
  584   
  585       /**
  586        * As of Java 2 platform v1.3 this method is no
  587        * longer used. Subclassers previously using this method should
  588        * instead create an Action wrapping the ActionListener, and register
  589        * that Action by overriding <code>installKeyboardActions</code> and
  590        * placing the Action in the SplitPane's ActionMap. Please refer to
  591        * the key bindings specification for further details.
  592        * <p>
  593        * Creates a ActionListener for the JSplitPane UI that listens for
  594        * specific key presses.
  595        *
  596        * @deprecated As of Java 2 platform v1.3.
  597        */
  598       @Deprecated
  599       protected ActionListener createKeyboardEndListener() {
  600           return new KeyboardEndHandler();
  601       }
  602   
  603   
  604       /**
  605        * As of Java 2 platform v1.3 this method is no
  606        * longer used. Subclassers previously using this method should
  607        * instead create an Action wrapping the ActionListener, and register
  608        * that Action by overriding <code>installKeyboardActions</code> and
  609        * placing the Action in the SplitPane's ActionMap. Please refer to
  610        * the key bindings specification for further details.
  611        * <p>
  612        * Creates a ActionListener for the JSplitPane UI that listens for
  613        * specific key presses.
  614        *
  615        * @deprecated As of Java 2 platform v1.3.
  616        */
  617       @Deprecated
  618       protected ActionListener createKeyboardResizeToggleListener() {
  619           return new KeyboardResizeToggleHandler();
  620       }
  621   
  622   
  623       /**
  624        * Returns the orientation for the JSplitPane.
  625        */
  626       public int getOrientation() {
  627           return orientation;
  628       }
  629   
  630   
  631       /**
  632        * Set the orientation for the JSplitPane.
  633        */
  634       public void setOrientation(int orientation) {
  635           this.orientation = orientation;
  636       }
  637   
  638   
  639       /**
  640        * Determines wether the JSplitPane is set to use a continuous layout.
  641        */
  642       public boolean isContinuousLayout() {
  643           return continuousLayout;
  644       }
  645   
  646   
  647       /**
  648        * Turn continuous layout on/off.
  649        */
  650       public void setContinuousLayout(boolean b) {
  651           continuousLayout = b;
  652       }
  653   
  654   
  655       /**
  656        * Returns the last drag location of the JSplitPane.
  657        */
  658       public int getLastDragLocation() {
  659           return lastDragLocation;
  660       }
  661   
  662   
  663       /**
  664        * Set the last drag location of the JSplitPane.
  665        */
  666       public void setLastDragLocation(int l) {
  667           lastDragLocation = l;
  668       }
  669   
  670       /**
  671        * @return increment via keyboard methods.
  672        */
  673       int getKeyboardMoveIncrement() {
  674           return 3;
  675       }
  676   
  677       /**
  678        * Implementation of the PropertyChangeListener
  679        * that the JSplitPane UI uses.
  680        * <p>
  681        * This class should be treated as a &quot;protected&quot; inner class.
  682        * Instantiate it only within subclasses of BasicSplitPaneUI.
  683        */
  684       public class PropertyHandler implements PropertyChangeListener
  685       {
  686           // NOTE: This class exists only for backward compatability. All
  687           // its functionality has been moved into Handler. If you need to add
  688           // new functionality add it to the Handler, but make sure this
  689           // class calls into the Handler.
  690   
  691           /**
  692            * Messaged from the <code>JSplitPane</code> the receiver is
  693            * contained in.  May potentially reset the layout manager and cause a
  694            * <code>validate</code> to be sent.
  695            */
  696           public void propertyChange(PropertyChangeEvent e) {
  697               getHandler().propertyChange(e);
  698           }
  699       }
  700   
  701   
  702       /**
  703        * Implementation of the FocusListener that the JSplitPane UI uses.
  704        * <p>
  705        * This class should be treated as a &quot;protected&quot; inner class.
  706        * Instantiate it only within subclasses of BasicSplitPaneUI.
  707        */
  708       public class FocusHandler extends FocusAdapter
  709       {
  710           // NOTE: This class exists only for backward compatability. All
  711           // its functionality has been moved into Handler. If you need to add
  712           // new functionality add it to the Handler, but make sure this
  713           // class calls into the Handler.
  714           public void focusGained(FocusEvent ev) {
  715               getHandler().focusGained(ev);
  716           }
  717   
  718           public void focusLost(FocusEvent ev) {
  719               getHandler().focusLost(ev);
  720           }
  721       }
  722   
  723   
  724       /**
  725        * Implementation of an ActionListener that the JSplitPane UI uses for
  726        * handling specific key presses.
  727        * <p>
  728        * This class should be treated as a &quot;protected&quot; inner class.
  729        * Instantiate it only within subclasses of BasicSplitPaneUI.
  730        */
  731       public class KeyboardUpLeftHandler implements ActionListener
  732       {
  733           public void actionPerformed(ActionEvent ev) {
  734               if (dividerKeyboardResize) {
  735                   splitPane.setDividerLocation(Math.max(0,getDividerLocation
  736                                     (splitPane) - getKeyboardMoveIncrement()));
  737               }
  738           }
  739       }
  740   
  741       /**
  742        * Implementation of an ActionListener that the JSplitPane UI uses for
  743        * handling specific key presses.
  744        * <p>
  745        * This class should be treated as a &quot;protected&quot; inner class.
  746        * Instantiate it only within subclasses of BasicSplitPaneUI.
  747        */
  748       public class KeyboardDownRightHandler implements ActionListener
  749       {
  750           public void actionPerformed(ActionEvent ev) {
  751               if (dividerKeyboardResize) {
  752                   splitPane.setDividerLocation(getDividerLocation(splitPane) +
  753                                                getKeyboardMoveIncrement());
  754               }
  755           }
  756       }
  757   
  758   
  759       /**
  760        * Implementation of an ActionListener that the JSplitPane UI uses for
  761        * handling specific key presses.
  762        * <p>
  763        * This class should be treated as a &quot;protected&quot; inner class.
  764        * Instantiate it only within subclasses of BasicSplitPaneUI.
  765        */
  766       public class KeyboardHomeHandler implements ActionListener
  767       {
  768           public void actionPerformed(ActionEvent ev) {
  769               if (dividerKeyboardResize) {
  770                   splitPane.setDividerLocation(0);
  771               }
  772           }
  773       }
  774   
  775   
  776       /**
  777        * Implementation of an ActionListener that the JSplitPane UI uses for
  778        * handling specific key presses.
  779        * <p>
  780        * This class should be treated as a &quot;protected&quot; inner class.
  781        * Instantiate it only within subclasses of BasicSplitPaneUI.
  782        */
  783       public class KeyboardEndHandler implements ActionListener
  784       {
  785           public void actionPerformed(ActionEvent ev) {
  786               if (dividerKeyboardResize) {
  787                   Insets   insets = splitPane.getInsets();
  788                   int      bottomI = (insets != null) ? insets.bottom : 0;
  789                   int      rightI = (insets != null) ? insets.right : 0;
  790   
  791                   if (orientation == JSplitPane.VERTICAL_SPLIT) {
  792                       splitPane.setDividerLocation(splitPane.getHeight() -
  793                                          bottomI);
  794                   }
  795                   else {
  796                       splitPane.setDividerLocation(splitPane.getWidth() -
  797                                                    rightI);
  798                   }
  799               }
  800           }
  801       }
  802   
  803   
  804       /**
  805        * Implementation of an ActionListener that the JSplitPane UI uses for
  806        * handling specific key presses.
  807        * <p>
  808        * This class should be treated as a &quot;protected&quot; inner class.
  809        * Instantiate it only within subclasses of BasicSplitPaneUI.
  810        */
  811       public class KeyboardResizeToggleHandler implements ActionListener
  812       {
  813           public void actionPerformed(ActionEvent ev) {
  814               if (!dividerKeyboardResize) {
  815                   splitPane.requestFocus();
  816               }
  817           }
  818       }
  819   
  820       /**
  821        * Returns the divider between the top Components.
  822        */
  823       public BasicSplitPaneDivider getDivider() {
  824           return divider;
  825       }
  826   
  827   
  828       /**
  829        * Returns the default non continuous layout divider, which is an
  830        * instance of {@code Canvas} that fills in the background with dark gray.
  831        */
  832       protected Component createDefaultNonContinuousLayoutDivider() {
  833           return new Canvas() {
  834               public void paint(Graphics g) {
  835                   if(!isContinuousLayout() && getLastDragLocation() != -1) {
  836                       Dimension      size = splitPane.getSize();
  837   
  838                       g.setColor(dividerDraggingColor);
  839                       if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  840                           g.fillRect(0, 0, dividerSize - 1, size.height - 1);
  841                       } else {
  842                           g.fillRect(0, 0, size.width - 1, dividerSize - 1);
  843                       }
  844                   }
  845               }
  846           };
  847       }
  848   
  849   
  850       /**
  851        * Sets the divider to use when the splitPane is configured to
  852        * not continuously layout. This divider will only be used during a
  853        * dragging session. It is recommended that the passed in component
  854        * be a heavy weight.
  855        */
  856       protected void setNonContinuousLayoutDivider(Component newDivider) {
  857           setNonContinuousLayoutDivider(newDivider, true);
  858       }
  859   
  860   
  861       /**
  862        * Sets the divider to use.
  863        */
  864       protected void setNonContinuousLayoutDivider(Component newDivider,
  865           boolean rememberSizes) {
  866           rememberPaneSizes = rememberSizes;
  867           if(nonContinuousLayoutDivider != null && splitPane != null) {
  868               splitPane.remove(nonContinuousLayoutDivider);
  869           }
  870           nonContinuousLayoutDivider = newDivider;
  871       }
  872   
  873       private void addHeavyweightDivider() {
  874           if(nonContinuousLayoutDivider != null && splitPane != null) {
  875   
  876               /* Needs to remove all the components and re-add them! YECK! */
  877               // This is all done so that the nonContinuousLayoutDivider will
  878               // be drawn on top of the other components, without this, one
  879               // of the heavyweights will draw over the divider!
  880               Component             leftC = splitPane.getLeftComponent();
  881               Component             rightC = splitPane.getRightComponent();
  882               int                   lastLocation = splitPane.
  883                                                 getDividerLocation();
  884   
  885               if(leftC != null)
  886                   splitPane.setLeftComponent(null);
  887               if(rightC != null)
  888                   splitPane.setRightComponent(null);
  889               splitPane.remove(divider);
  890               splitPane.add(nonContinuousLayoutDivider, BasicSplitPaneUI.
  891                             NON_CONTINUOUS_DIVIDER,
  892                             splitPane.getComponentCount());
  893               splitPane.setLeftComponent(leftC);
  894               splitPane.setRightComponent(rightC);
  895               splitPane.add(divider, JSplitPane.DIVIDER);
  896               if(rememberPaneSizes) {
  897                   splitPane.setDividerLocation(lastLocation);
  898               }
  899           }
  900   
  901       }
  902   
  903   
  904       /**
  905        * Returns the divider to use when the splitPane is configured to
  906        * not continuously layout. This divider will only be used during a
  907        * dragging session.
  908        */
  909       public Component getNonContinuousLayoutDivider() {
  910           return nonContinuousLayoutDivider;
  911       }
  912   
  913   
  914       /**
  915        * Returns the splitpane this instance is currently contained
  916        * in.
  917        */
  918       public JSplitPane getSplitPane() {
  919           return splitPane;
  920       }
  921   
  922   
  923       /**
  924        * Creates the default divider.
  925        */
  926       public BasicSplitPaneDivider createDefaultDivider() {
  927           return new BasicSplitPaneDivider(this);
  928       }
  929   
  930   
  931       /**
  932        * Messaged to reset the preferred sizes.
  933        */
  934       public void resetToPreferredSizes(JSplitPane jc) {
  935           if(splitPane != null) {
  936               layoutManager.resetToPreferredSizes();
  937               splitPane.revalidate();
  938               splitPane.repaint();
  939           }
  940       }
  941   
  942   
  943       /**
  944        * Sets the location of the divider to location.
  945        */
  946       public void setDividerLocation(JSplitPane jc, int location) {
  947           if (!ignoreDividerLocationChange) {
  948               dividerLocationIsSet = true;
  949               splitPane.revalidate();
  950               splitPane.repaint();
  951   
  952               if (keepHidden) {
  953                   Insets insets = splitPane.getInsets();
  954                   int orientation = splitPane.getOrientation();
  955                   if ((orientation == JSplitPane.VERTICAL_SPLIT &&
  956                        location != insets.top &&
  957                        location != splitPane.getHeight()-divider.getHeight()-insets.top) ||
  958                       (orientation == JSplitPane.HORIZONTAL_SPLIT &&
  959                        location != insets.left &&
  960                        location != splitPane.getWidth()-divider.getWidth()-insets.left)) {
  961                       setKeepHidden(false);
  962                   }
  963               }
  964           }
  965           else {
  966               ignoreDividerLocationChange = false;
  967           }
  968       }
  969   
  970   
  971       /**
  972        * Returns the location of the divider, which may differ from what
  973        * the splitpane thinks the location of the divider is.
  974        */
  975       public int getDividerLocation(JSplitPane jc) {
  976           if(orientation == JSplitPane.HORIZONTAL_SPLIT)
  977               return divider.getLocation().x;
  978           return divider.getLocation().y;
  979       }
  980   
  981   
  982       /**
  983        * Gets the minimum location of the divider.
  984        */
  985       public int getMinimumDividerLocation(JSplitPane jc) {
  986           int       minLoc = 0;
  987           Component leftC = splitPane.getLeftComponent();
  988   
  989           if ((leftC != null) && (leftC.isVisible())) {
  990               Insets    insets = splitPane.getInsets();
  991               Dimension minSize = leftC.getMinimumSize();
  992               if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  993                   minLoc = minSize.width;
  994               } else {
  995                   minLoc = minSize.height;
  996               }
  997               if(insets != null) {
  998                   if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  999                       minLoc += insets.left;
 1000                   } else {
 1001                       minLoc += insets.top;
 1002                   }
 1003               }
 1004           }
 1005           return minLoc;
 1006       }
 1007   
 1008   
 1009       /**
 1010        * Gets the maximum location of the divider.
 1011        */
 1012       public int getMaximumDividerLocation(JSplitPane jc) {
 1013           Dimension splitPaneSize = splitPane.getSize();
 1014           int       maxLoc = 0;
 1015           Component rightC = splitPane.getRightComponent();
 1016   
 1017           if (rightC != null) {
 1018               Insets    insets = splitPane.getInsets();
 1019               Dimension minSize = new Dimension(0, 0);
 1020               if (rightC.isVisible()) {
 1021                   minSize = rightC.getMinimumSize();
 1022               }
 1023               if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1024                   maxLoc = splitPaneSize.width - minSize.width;
 1025               } else {
 1026                   maxLoc = splitPaneSize.height - minSize.height;
 1027               }
 1028               maxLoc -= dividerSize;
 1029               if(insets != null) {
 1030                   if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1031                       maxLoc -= insets.right;
 1032                   } else {
 1033                       maxLoc -= insets.top;
 1034                   }
 1035               }
 1036           }
 1037           return Math.max(getMinimumDividerLocation(splitPane), maxLoc);
 1038       }
 1039   
 1040   
 1041       /**
 1042        * Called when the specified split pane has finished painting
 1043        * its children.
 1044        */
 1045       public void finishedPaintingChildren(JSplitPane sp, Graphics g) {
 1046           if(sp == splitPane && getLastDragLocation() != -1 &&
 1047              !isContinuousLayout() && !draggingHW) {
 1048               Dimension      size = splitPane.getSize();
 1049   
 1050               g.setColor(dividerDraggingColor);
 1051               if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1052                   g.fillRect(getLastDragLocation(), 0, dividerSize - 1,
 1053                              size.height - 1);
 1054               } else {
 1055                   g.fillRect(0, lastDragLocation, size.width - 1,
 1056                              dividerSize - 1);
 1057               }
 1058           }
 1059       }
 1060   
 1061   
 1062       /**
 1063        * @inheritDoc
 1064        */
 1065       public void paint(Graphics g, JComponent jc) {
 1066           if (!painted && splitPane.getDividerLocation()<0) {
 1067               ignoreDividerLocationChange = true;
 1068               splitPane.setDividerLocation(getDividerLocation(splitPane));
 1069           }
 1070           painted = true;
 1071       }
 1072   
 1073   
 1074       /**
 1075        * Returns the preferred size for the passed in component,
 1076        * This is passed off to the current layoutmanager.
 1077        */
 1078       public Dimension getPreferredSize(JComponent jc) {
 1079           if(splitPane != null)
 1080               return layoutManager.preferredLayoutSize(splitPane);
 1081           return new Dimension(0, 0);
 1082       }
 1083   
 1084   
 1085       /**
 1086        * Returns the minimum size for the passed in component,
 1087        * This is passed off to the current layoutmanager.
 1088        */
 1089       public Dimension getMinimumSize(JComponent jc) {
 1090           if(splitPane != null)
 1091               return layoutManager.minimumLayoutSize(splitPane);
 1092           return new Dimension(0, 0);
 1093       }
 1094   
 1095   
 1096       /**
 1097        * Returns the maximum size for the passed in component,
 1098        * This is passed off to the current layoutmanager.
 1099        */
 1100       public Dimension getMaximumSize(JComponent jc) {
 1101           if(splitPane != null)
 1102               return layoutManager.maximumLayoutSize(splitPane);
 1103           return new Dimension(0, 0);
 1104       }
 1105   
 1106   
 1107       /**
 1108        * Returns the insets. The insets are returned from the border insets
 1109        * of the current border.
 1110        */
 1111       public Insets getInsets(JComponent jc) {
 1112           return null;
 1113       }
 1114   
 1115   
 1116       /**
 1117        * Resets the layout manager based on orientation and messages it
 1118        * with invalidateLayout to pull in appropriate Components.
 1119        */
 1120       protected void resetLayoutManager() {
 1121           if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1122               layoutManager = new BasicHorizontalLayoutManager(0);
 1123           } else {
 1124               layoutManager = new BasicHorizontalLayoutManager(1);
 1125           }
 1126           splitPane.setLayout(layoutManager);
 1127           layoutManager.updateComponents();
 1128           splitPane.revalidate();
 1129           splitPane.repaint();
 1130       }
 1131   
 1132       /**
 1133        * Set the value to indicate if one of the splitpane sides is expanded.
 1134        */
 1135       void setKeepHidden(boolean keepHidden) {
 1136           this.keepHidden = keepHidden;
 1137       }
 1138   
 1139       /**
 1140        * The value returned indicates if one of the splitpane sides is expanded.
 1141        * @return true if one of the splitpane sides is expanded, false otherwise.
 1142        */
 1143       private boolean getKeepHidden() {
 1144           return keepHidden;
 1145       }
 1146   
 1147       /**
 1148        * Should be messaged before the dragging session starts, resets
 1149        * lastDragLocation and dividerSize.
 1150        */
 1151       protected void startDragging() {
 1152           Component       leftC = splitPane.getLeftComponent();
 1153           Component       rightC = splitPane.getRightComponent();
 1154           ComponentPeer   cPeer;
 1155   
 1156           beginDragDividerLocation = getDividerLocation(splitPane);
 1157           draggingHW = false;
 1158           if(leftC != null && (cPeer = leftC.getPeer()) != null &&
 1159              !(cPeer instanceof LightweightPeer)) {
 1160               draggingHW = true;
 1161           } else if(rightC != null && (cPeer = rightC.getPeer()) != null
 1162                     && !(cPeer instanceof LightweightPeer)) {
 1163               draggingHW = true;
 1164           }
 1165           if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1166               setLastDragLocation(divider.getBounds().x);
 1167               dividerSize = divider.getSize().width;
 1168               if(!isContinuousLayout() && draggingHW) {
 1169                   nonContinuousLayoutDivider.setBounds
 1170                           (getLastDragLocation(), 0, dividerSize,
 1171                            splitPane.getHeight());
 1172                         addHeavyweightDivider();
 1173               }
 1174           } else {
 1175               setLastDragLocation(divider.getBounds().y);
 1176               dividerSize = divider.getSize().height;
 1177               if(!isContinuousLayout() && draggingHW) {
 1178                   nonContinuousLayoutDivider.setBounds
 1179                           (0, getLastDragLocation(), splitPane.getWidth(),
 1180                            dividerSize);
 1181                         addHeavyweightDivider();
 1182               }
 1183           }
 1184       }
 1185   
 1186   
 1187       /**
 1188        * Messaged during a dragging session to move the divider to the
 1189        * passed in location. If continuousLayout is true the location is
 1190        * reset and the splitPane validated.
 1191        */
 1192       protected void dragDividerTo(int location) {
 1193           if(getLastDragLocation() != location) {
 1194               if(isContinuousLayout()) {
 1195                   splitPane.setDividerLocation(location);
 1196                   setLastDragLocation(location);
 1197               } else {
 1198                   int lastLoc = getLastDragLocation();
 1199   
 1200                   setLastDragLocation(location);
 1201                   if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1202                       if(draggingHW) {
 1203                           nonContinuousLayoutDivider.setLocation(
 1204                               getLastDragLocation(), 0);
 1205                       } else {
 1206                           int   splitHeight = splitPane.getHeight();
 1207                           splitPane.repaint(lastLoc, 0, dividerSize,
 1208                                             splitHeight);
 1209                           splitPane.repaint(location, 0, dividerSize,
 1210                                             splitHeight);
 1211                       }
 1212                   } else {
 1213                       if(draggingHW) {
 1214                           nonContinuousLayoutDivider.setLocation(0,
 1215                               getLastDragLocation());
 1216                       } else {
 1217                           int    splitWidth = splitPane.getWidth();
 1218   
 1219                           splitPane.repaint(0, lastLoc, splitWidth,
 1220                                             dividerSize);
 1221                           splitPane.repaint(0, location, splitWidth,
 1222                                             dividerSize);
 1223                       }
 1224                   }
 1225               }
 1226           }
 1227       }
 1228   
 1229   
 1230       /**
 1231        * Messaged to finish the dragging session. If not continuous display
 1232        * the dividers location will be reset.
 1233        */
 1234       protected void finishDraggingTo(int location) {
 1235           dragDividerTo(location);
 1236           setLastDragLocation(-1);
 1237           if(!isContinuousLayout()) {
 1238               Component   leftC = splitPane.getLeftComponent();
 1239               Rectangle   leftBounds = leftC.getBounds();
 1240   
 1241               if (draggingHW) {
 1242                   if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
 1243                       nonContinuousLayoutDivider.setLocation(-dividerSize, 0);
 1244                   }
 1245                   else {
 1246                       nonContinuousLayoutDivider.setLocation(0, -dividerSize);
 1247                   }
 1248                   splitPane.remove(nonContinuousLayoutDivider);
 1249               }
 1250               splitPane.setDividerLocation(location);
 1251           }
 1252       }
 1253   
 1254   
 1255       /**
 1256        * As of Java 2 platform v1.3 this method is no longer used. Instead
 1257        * you should set the border on the divider.
 1258        * <p>
 1259        * Returns the width of one side of the divider border.
 1260        *
 1261        * @deprecated As of Java 2 platform v1.3, instead set the border on the
 1262        * divider.
 1263        */
 1264       @Deprecated
 1265       protected int getDividerBorderSize() {
 1266           return 1;
 1267       }
 1268   
 1269   
 1270       /**
 1271        * LayoutManager for JSplitPanes that have an orientation of
 1272        * HORIZONTAL_SPLIT.
 1273        */
 1274       public class BasicHorizontalLayoutManager implements LayoutManager2
 1275       {
 1276           /* left, right, divider. (in this exact order) */
 1277           protected int[]         sizes;
 1278           protected Component[]   components;
 1279           /** Size of the splitpane the last time laid out. */
 1280           private int             lastSplitPaneSize;
 1281           /** True if resetToPreferredSizes has been invoked. */
 1282           private boolean         doReset;
 1283           /** Axis, 0 for horizontal, or 1 for veritcal. */
 1284           private int             axis;
 1285   
 1286   
 1287           BasicHorizontalLayoutManager() {
 1288               this(0);
 1289           }
 1290   
 1291           BasicHorizontalLayoutManager(int axis) {
 1292               this.axis = axis;
 1293               components = new Component[3];
 1294               components[0] = components[1] = components[2] = null;
 1295               sizes = new int[3];
 1296           }
 1297   
 1298           //
 1299           // LayoutManager
 1300           //
 1301   
 1302           /**
 1303            * Does the actual layout.
 1304            */
 1305           public void layoutContainer(Container container) {
 1306               Dimension   containerSize = container.getSize();
 1307   
 1308               // If the splitpane has a zero size then no op out of here.
 1309               // If we execute this function now, we're going to cause ourselves
 1310               // much grief.
 1311               if (containerSize.height <= 0 || containerSize.width <= 0 ) {
 1312                   lastSplitPaneSize = 0;
 1313                   return;
 1314               }
 1315   
 1316               int         spDividerLocation = splitPane.getDividerLocation();
 1317               Insets      insets = splitPane.getInsets();
 1318               int         availableSize = getAvailableSize(containerSize,
 1319                                                            insets);
 1320               int         newSize = getSizeForPrimaryAxis(containerSize);
 1321               int         beginLocation = getDividerLocation(splitPane);
 1322               int         dOffset = getSizeForPrimaryAxis(insets, true);
 1323               Dimension   dSize = (components[2] == null) ? null :
 1324                                    components[2].getPreferredSize();
 1325   
 1326               if ((doReset && !dividerLocationIsSet) || spDividerLocation < 0) {
 1327                   resetToPreferredSizes(availableSize);
 1328               }
 1329               else if (lastSplitPaneSize <= 0 ||
 1330                        availableSize == lastSplitPaneSize || !painted ||
 1331                        (dSize != null &&
 1332                         getSizeForPrimaryAxis(dSize) != sizes[2])) {
 1333                   if (dSize != null) {
 1334                       sizes[2] = getSizeForPrimaryAxis(dSize);
 1335                   }
 1336                   else {
 1337                       sizes[2] = 0;
 1338                   }
 1339                   setDividerLocation(spDividerLocation - dOffset, availableSize);
 1340                   dividerLocationIsSet = false;
 1341               }
 1342               else if (availableSize != lastSplitPaneSize) {
 1343                   distributeSpace(availableSize - lastSplitPaneSize,
 1344                                   getKeepHidden());
 1345               }
 1346               doReset = false;
 1347               dividerLocationIsSet = false;
 1348               lastSplitPaneSize = availableSize;
 1349   
 1350               // Reset the bounds of each component
 1351               int nextLocation = getInitialLocation(insets);
 1352               int counter = 0;
 1353   
 1354               while (counter < 3) {
 1355                   if (components[counter] != null &&
 1356                       components[counter].isVisible()) {
 1357                       setComponentToSize(components[counter], sizes[counter],
 1358                                          nextLocation, insets, containerSize);
 1359                       nextLocation += sizes[counter];
 1360                   }
 1361                   switch (counter) {
 1362                   case 0:
 1363                       counter = 2;
 1364                       break;
 1365                   case 2:
 1366                       counter = 1;
 1367                       break;
 1368                   case 1:
 1369                       counter = 3;
 1370                       break;
 1371                   }
 1372               }
 1373               if (painted) {
 1374                   // This is tricky, there is never a good time for us
 1375                   // to push the value to the splitpane, painted appears to
 1376                   // the best time to do it. What is really needed is
 1377                   // notification that layout has completed.
 1378                   int      newLocation = getDividerLocation(splitPane);
 1379   
 1380                   if (newLocation != (spDividerLocation - dOffset)) {
 1381                       int  lastLocation = splitPane.getLastDividerLocation();
 1382   
 1383                       ignoreDividerLocationChange = true;
 1384                       try {
 1385                           splitPane.setDividerLocation(newLocation);
 1386                           // This is not always needed, but is rather tricky
 1387                           // to determine when... The case this is needed for
 1388                           // is if the user sets the divider location to some
 1389                           // bogus value, say 0, and the actual value is 1, the
 1390                           // call to setDividerLocation(1) will preserve the
 1391                           // old value of 0, when we really want the divider
 1392                           // location value  before the call. This is needed for
 1393                           // the one touch buttons.
 1394                           splitPane.setLastDividerLocation(lastLocation);
 1395                       } finally {
 1396                           ignoreDividerLocationChange = false;
 1397                       }
 1398                   }
 1399               }
 1400           }
 1401   
 1402   
 1403           /**
 1404            * Adds the component at place.  Place must be one of
 1405            * JSplitPane.LEFT, RIGHT, TOP, BOTTOM, or null (for the
 1406            * divider).
 1407            */
 1408           public void addLayoutComponent(String place, Component component) {
 1409               boolean isValid = true;
 1410   
 1411               if(place != null) {
 1412                   if(place.equals(JSplitPane.DIVIDER)) {
 1413                       /* Divider. */
 1414                       components[2] = component;
 1415                       sizes[2] = getSizeForPrimaryAxis(component.
 1416                                                        getPreferredSize());
 1417                   } else if(place.equals(JSplitPane.LEFT) ||
 1418                             place.equals(JSplitPane.TOP)) {
 1419                       components[0] = component;
 1420                       sizes[0] = 0;
 1421                   } else if(place.equals(JSplitPane.RIGHT) ||
 1422                             place.equals(JSplitPane.BOTTOM)) {
 1423                       components[1] = component;
 1424                       sizes[1] = 0;
 1425                   } else if(!place.equals(
 1426                                       BasicSplitPaneUI.NON_CONTINUOUS_DIVIDER))
 1427                       isValid = false;
 1428               } else {
 1429                   isValid = false;
 1430               }
 1431               if(!isValid)
 1432                   throw new IllegalArgumentException("cannot add to layout: " +
 1433                       "unknown constraint: " +
 1434                       place);
 1435               doReset = true;
 1436           }
 1437   
 1438   
 1439           /**
 1440            * Returns the minimum size needed to contain the children.
 1441            * The width is the sum of all the childrens min widths and
 1442            * the height is the largest of the childrens minimum heights.
 1443            */
 1444           public Dimension minimumLayoutSize(Container container) {
 1445               int         minPrimary = 0;
 1446               int         minSecondary = 0;
 1447               Insets      insets = splitPane.getInsets();
 1448   
 1449               for (int counter=0; counter<3; counter++) {
 1450                   if(components[counter] != null) {
 1451                       Dimension   minSize = components[counter].getMinimumSize();
 1452                       int         secSize = getSizeForSecondaryAxis(minSize);
 1453   
 1454                       minPrimary += getSizeForPrimaryAxis(minSize);
 1455                       if(secSize > minSecondary)
 1456                           minSecondary = secSize;
 1457                   }
 1458               }
 1459               if(insets != null) {
 1460                   minPrimary += getSizeForPrimaryAxis(insets, true) +
 1461                                 getSizeForPrimaryAxis(insets, false);
 1462                   minSecondary += getSizeForSecondaryAxis(insets, true) +
 1463                                 getSizeForSecondaryAxis(insets, false);
 1464               }
 1465               if (axis == 0) {
 1466                   return new Dimension(minPrimary, minSecondary);
 1467               }
 1468               return new Dimension(minSecondary, minPrimary);
 1469           }
 1470   
 1471   
 1472           /**
 1473            * Returns the preferred size needed to contain the children.
 1474            * The width is the sum of all the childrens preferred widths and
 1475            * the height is the largest of the childrens preferred heights.
 1476            */
 1477           public Dimension preferredLayoutSize(Container container) {
 1478               int         prePrimary = 0;
 1479               int         preSecondary = 0;
 1480               Insets      insets = splitPane.getInsets();
 1481   
 1482               for(int counter = 0; counter < 3; counter++) {
 1483                   if(components[counter] != null) {
 1484                       Dimension   preSize = components[counter].
 1485                                             getPreferredSize();
 1486                       int         secSize = getSizeForSecondaryAxis(preSize);
 1487   
 1488                       prePrimary += getSizeForPrimaryAxis(preSize);
 1489                       if(secSize > preSecondary)
 1490                           preSecondary = secSize;
 1491                   }
 1492               }
 1493               if(insets != null) {
 1494                   prePrimary += getSizeForPrimaryAxis(insets, true) +
 1495                                 getSizeForPrimaryAxis(insets, false);
 1496                   preSecondary += getSizeForSecondaryAxis(insets, true) +
 1497                                 getSizeForSecondaryAxis(insets, false);
 1498               }
 1499               if (axis == 0) {
 1500                   return new Dimension(prePrimary, preSecondary);
 1501               }
 1502               return new Dimension(preSecondary, prePrimary);
 1503           }
 1504   
 1505   
 1506           /**
 1507            * Removes the specified component from our knowledge.
 1508            */
 1509           public void removeLayoutComponent(Component component) {
 1510               for(int counter = 0; counter < 3; counter++) {
 1511                   if(components[counter] == component) {
 1512                       components[counter] = null;
 1513                       sizes[counter] = 0;
 1514                       doReset = true;
 1515                   }
 1516               }
 1517           }
 1518   
 1519   
 1520           //
 1521           // LayoutManager2
 1522           //
 1523   
 1524   
 1525           /**
 1526            * Adds the specified component to the layout, using the specified
 1527            * constraint object.
 1528            * @param comp the component to be added
 1529            * @param constraints  where/how the component is added to the layout.
 1530            */
 1531           public void addLayoutComponent(Component comp, Object constraints) {
 1532               if ((constraints == null) || (constraints instanceof String)) {
 1533                   addLayoutComponent((String)constraints, comp);
 1534               } else {
 1535                   throw new IllegalArgumentException("cannot add to layout: " +
 1536                                                      "constraint must be a " +
 1537                                                      "string (or null)");
 1538               }
 1539           }
 1540   
 1541   
 1542           /**
 1543            * Returns the alignment along the x axis.  This specifies how
 1544            * the component would like to be aligned relative to other
 1545            * components.  The value should be a number between 0 and 1
 1546            * where 0 represents alignment along the origin, 1 is aligned
 1547            * the furthest away from the origin, 0.5 is centered, etc.
 1548            */
 1549           public float getLayoutAlignmentX(Container target) {
 1550               return 0.0f;
 1551           }
 1552   
 1553   
 1554           /**
 1555            * Returns the alignment along the y axis.  This specifies how
 1556            * the component would like to be aligned relative to other
 1557            * components.  The value should be a number between 0 and 1
 1558            * where 0 represents alignment along the origin, 1 is aligned
 1559            * the furthest away from the origin, 0.5 is centered, etc.
 1560            */
 1561           public float getLayoutAlignmentY(Container target) {
 1562               return 0.0f;
 1563           }
 1564   
 1565   
 1566           /**
 1567            * Does nothing. If the developer really wants to change the
 1568            * size of one of the views JSplitPane.resetToPreferredSizes should
 1569            * be messaged.
 1570            */
 1571           public void invalidateLayout(Container c) {
 1572           }
 1573   
 1574   
 1575           /**
 1576            * Returns the maximum layout size, which is Integer.MAX_VALUE
 1577            * in both directions.
 1578            */
 1579           public Dimension maximumLayoutSize(Container target) {
 1580               return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 1581           }
 1582   
 1583   
 1584           //
 1585           // New methods.
 1586           //
 1587   
 1588           /**
 1589            * Marks the receiver so that the next time this instance is
 1590            * laid out it'll ask for the preferred sizes.
 1591            */
 1592           public void resetToPreferredSizes() {
 1593               doReset = true;
 1594           }
 1595   
 1596           /**
 1597            * Resets the size of the Component at the passed in location.
 1598            */
 1599           protected void resetSizeAt(int index) {
 1600               sizes[index] = 0;
 1601               doReset = true;
 1602           }
 1603   
 1604   
 1605           /**
 1606            * Sets the sizes to <code>newSizes</code>.
 1607            */
 1608           protected void setSizes(int[] newSizes) {
 1609               System.arraycopy(newSizes, 0, sizes, 0, 3);
 1610           }
 1611   
 1612   
 1613           /**
 1614            * Returns the sizes of the components.
 1615            */
 1616           protected int[] getSizes() {
 1617               int[]         retSizes = new int[3];
 1618   
 1619               System.arraycopy(sizes, 0, retSizes, 0, 3);
 1620               return retSizes;
 1621           }
 1622   
 1623   
 1624           /**
 1625            * Returns the width of the passed in Components preferred size.
 1626            */
 1627           protected int getPreferredSizeOfComponent(Component c) {
 1628               return getSizeForPrimaryAxis(c.getPreferredSize());
 1629           }
 1630   
 1631   
 1632           /**
 1633            * Returns the width of the passed in Components minimum size.
 1634            */
 1635           int getMinimumSizeOfComponent(Component c) {
 1636               return getSizeForPrimaryAxis(c.getMinimumSize());
 1637           }
 1638   
 1639   
 1640           /**
 1641            * Returns the width of the passed in component.
 1642            */
 1643           protected int getSizeOfComponent(Component c) {
 1644               return getSizeForPrimaryAxis(c.getSize());
 1645           }
 1646   
 1647   
 1648           /**
 1649            * Returns the available width based on the container size and
 1650            * Insets.
 1651            */
 1652           protected int getAvailableSize(Dimension containerSize,
 1653                                          Insets insets) {
 1654               if(insets == null)
 1655                   return getSizeForPrimaryAxis(containerSize);
 1656               return (getSizeForPrimaryAxis(containerSize) -
 1657                       (getSizeForPrimaryAxis(insets, true) +
 1658                        getSizeForPrimaryAxis(insets, false)));
 1659           }
 1660   
 1661   
 1662           /**
 1663            * Returns the left inset, unless the Insets are null in which case
 1664            * 0 is returned.
 1665            */
 1666           protected int getInitialLocation(Insets insets) {
 1667               if(insets != null)
 1668                   return getSizeForPrimaryAxis(insets, true);
 1669               return 0;
 1670           }
 1671   
 1672   
 1673           /**
 1674            * Sets the width of the component c to be size, placing its
 1675            * x location at location, y to the insets.top and height
 1676            * to the containersize.height less the top and bottom insets.
 1677            */
 1678           protected void setComponentToSize(Component c, int size,
 1679                                             int location, Insets insets,
 1680                                             Dimension containerSize) {
 1681               if(insets != null) {
 1682                   if (axis == 0) {
 1683                       c.setBounds(location, insets.top, size,
 1684                                   containerSize.height -
 1685                                   (insets.top + insets.bottom));
 1686                   }
 1687                   else {
 1688                       c.setBounds(insets.left, location, containerSize.width -
 1689                                   (insets.left + insets.right), size);
 1690                   }
 1691               }
 1692               else {
 1693                   if (axis == 0) {
 1694                       c.setBounds(location, 0, size, containerSize.height);
 1695                   }
 1696                   else {
 1697                       c.setBounds(0, location, containerSize.width, size);
 1698                   }
 1699               }
 1700           }
 1701   
 1702           /**
 1703            * If the axis == 0, the width is returned, otherwise the height.
 1704            */
 1705           int getSizeForPrimaryAxis(Dimension size) {
 1706               if (axis == 0) {
 1707                   return size.width;
 1708               }
 1709               return size.height;
 1710           }
 1711   
 1712           /**
 1713            * If the axis == 0, the width is returned, otherwise the height.
 1714            */
 1715           int getSizeForSecondaryAxis(Dimension size) {
 1716               if (axis == 0) {
 1717                   return size.height;
 1718               }
 1719               return size.width;
 1720           }
 1721   
 1722           /**
 1723            * Returns a particular value of the inset identified by the
 1724            * axis and <code>isTop</code><p>
 1725            *   axis isTop
 1726            *    0    true    - left
 1727            *    0    false   - right
 1728            *    1    true    - top
 1729            *    1    false   - bottom
 1730            */
 1731           int getSizeForPrimaryAxis(Insets insets, boolean isTop) {
 1732               if (axis == 0) {
 1733                   if (isTop) {
 1734                       return insets.left;
 1735                   }
 1736                   return insets.right;
 1737               }
 1738               if (isTop) {
 1739                   return insets.top;
 1740               }
 1741               return insets.bottom;
 1742           }
 1743   
 1744           /**
 1745            * Returns a particular value of the inset identified by the
 1746            * axis and <code>isTop</code><p>
 1747            *   axis isTop
 1748            *    0    true    - left
 1749            *    0    false   - right
 1750            *    1    true    - top
 1751            *    1    false   - bottom
 1752            */
 1753           int getSizeForSecondaryAxis(Insets insets, boolean isTop) {
 1754               if (axis == 0) {
 1755                   if (isTop) {
 1756                       return insets.top;
 1757                   }
 1758                   return insets.bottom;
 1759               }
 1760               if (isTop) {
 1761                   return insets.left;
 1762               }
 1763               return insets.right;
 1764           }
 1765   
 1766           /**
 1767            * Determines the components. This should be called whenever
 1768            * a new instance of this is installed into an existing
 1769            * SplitPane.
 1770            */
 1771           protected void updateComponents() {
 1772               Component comp;
 1773   
 1774               comp = splitPane.getLeftComponent();
 1775               if(components[0] != comp) {
 1776                   components[0] = comp;
 1777                   if(comp == null) {
 1778                       sizes[0] = 0;
 1779                   } else {
 1780                       sizes[0] = -1;
 1781                   }
 1782               }
 1783   
 1784               comp = splitPane.getRightComponent();
 1785               if(components[1] != comp) {
 1786                   components[1] = comp;
 1787                   if(comp == null) {
 1788                       sizes[1] = 0;
 1789                   } else {
 1790                       sizes[1] = -1;
 1791                   }
 1792               }
 1793   
 1794               /* Find the divider. */
 1795               Component[] children = splitPane.getComponents();
 1796               Component   oldDivider = components[2];
 1797   
 1798               components[2] = null;
 1799               for(int counter = children.length - 1; counter >= 0; counter--) {
 1800                   if(children[counter] != components[0] &&
 1801                      children[counter] != components[1] &&
 1802                      children[counter] != nonContinuousLayoutDivider) {
 1803                       if(oldDivider != children[counter]) {
 1804                           components[2] = children[counter];
 1805                       } else {
 1806                           components[2] = oldDivider;
 1807                       }
 1808                       break;
 1809                   }
 1810               }
 1811               if(components[2] == null) {
 1812                   sizes[2] = 0;
 1813               }
 1814               else {
 1815                   sizes[2] = getSizeForPrimaryAxis(components[2].getPreferredSize());
 1816               }
 1817           }
 1818   
 1819           /**
 1820            * Resets the size of the first component to <code>leftSize</code>,
 1821            * and the right component to the remainder of the space.
 1822            */
 1823           void setDividerLocation(int leftSize, int availableSize) {
 1824               boolean          lValid = (components[0] != null &&
 1825                                          components[0].isVisible());
 1826               boolean          rValid = (components[1] != null &&
 1827                                          components[1].isVisible());
 1828               boolean          dValid = (components[2] != null &&
 1829                                          components[2].isVisible());
 1830               int              max = availableSize;
 1831   
 1832               if (dValid) {
 1833                   max -= sizes[2];
 1834               }
 1835               leftSize = Math.max(0, Math.min(leftSize, max));
 1836               if (lValid) {
 1837                   if (rValid) {
 1838                       sizes[0] = leftSize;
 1839                       sizes[1] = max - leftSize;
 1840                   }
 1841                   else {
 1842                       sizes[0] = max;
 1843                       sizes[1] = 0;
 1844                   }
 1845               }
 1846               else if (rValid) {
 1847                   sizes[1] = max;
 1848                   sizes[0] = 0;
 1849               }
 1850           }
 1851   
 1852           /**
 1853            * Returns an array of the minimum sizes of the components.
 1854            */
 1855           int[] getPreferredSizes() {
 1856               int[]         retValue = new int[3];
 1857   
 1858               for (int counter = 0; counter < 3; counter++) {
 1859                   if (components[counter] != null &&
 1860                       components[counter].isVisible()) {
 1861                       retValue[counter] = getPreferredSizeOfComponent
 1862                                           (components[counter]);
 1863                   }
 1864                   else {
 1865                       retValue[counter] = -1;
 1866                   }
 1867               }
 1868               return retValue;
 1869           }
 1870   
 1871           /**
 1872            * Returns an array of the minimum sizes of the components.
 1873            */
 1874           int[] getMinimumSizes() {
 1875               int[]         retValue = new int[3];
 1876   
 1877               for (int counter = 0; counter < 2; counter++) {
 1878                   if (components[counter] != null &&
 1879                       components[counter].isVisible()) {
 1880                       retValue[counter] = getMinimumSizeOfComponent
 1881                                           (components[counter]);
 1882                   }
 1883                   else {
 1884                       retValue[counter] = -1;
 1885                   }
 1886               }
 1887               retValue[2] = (components[2] != null) ?
 1888                   getMinimumSizeOfComponent(components[2]) : -1;
 1889               return retValue;
 1890           }
 1891   
 1892           /**
 1893            * Resets the components to their preferred sizes.
 1894            */
 1895           void resetToPreferredSizes(int availableSize) {
 1896               // Set the sizes to the preferred sizes (if fits), otherwise
 1897               // set to min sizes and distribute any extra space.
 1898               int[]       testSizes = getPreferredSizes();
 1899               int         totalSize = 0;
 1900   
 1901               for (int counter = 0; counter < 3; counter++) {
 1902                   if (testSizes[counter] != -1) {
 1903                       totalSize += testSizes[counter];
 1904                   }
 1905               }
 1906               if (totalSize > availableSize) {
 1907                   testSizes = getMinimumSizes();
 1908   
 1909                   totalSize = 0;
 1910                   for (int counter = 0; counter < 3; counter++) {
 1911                       if (testSizes[counter] != -1) {
 1912                           totalSize += testSizes[counter];
 1913                       }
 1914                   }
 1915               }
 1916               setSizes(testSizes);
 1917               distributeSpace(availableSize - totalSize, false);
 1918           }
 1919   
 1920           /**
 1921            * Distributes <code>space</code> between the two components
 1922            * (divider won't get any extra space) based on the weighting. This
 1923            * attempts to honor the min size of the components.
 1924            *
 1925            * @param keepHidden if true and one of the components is 0x0
 1926            *                   it gets none of the extra space
 1927            */
 1928           void distributeSpace(int space, boolean keepHidden) {
 1929               boolean          lValid = (components[0] != null &&
 1930                                          components[0].isVisible());
 1931               boolean          rValid = (components[1] != null &&
 1932                                          components[1].isVisible());
 1933   
 1934               if (keepHidden) {
 1935                   if (lValid && getSizeForPrimaryAxis(
 1936                                    components[0].getSize()) == 0) {
 1937                       lValid = false;
 1938                       if (rValid && getSizeForPrimaryAxis(
 1939                                        components[1].getSize()) == 0) {
 1940                           // Both aren't valid, force them both to be valid
 1941                           lValid = true;
 1942                       }
 1943                   }
 1944                   else if (rValid && getSizeForPrimaryAxis(
 1945                                      components[1].getSize()) == 0) {
 1946                       rValid = false;
 1947                   }
 1948               }
 1949               if (lValid && rValid) {
 1950                   double        weight = splitPane.getResizeWeight();
 1951                   int           lExtra = (int)(weight * (double)space);
 1952                   int           rExtra = (space - lExtra);
 1953   
 1954                   sizes[0] += lExtra;
 1955                   sizes[1] += rExtra;
 1956   
 1957                   int           lMin = getMinimumSizeOfComponent(components[0]);
 1958                   int           rMin = getMinimumSizeOfComponent(components[1]);
 1959                   boolean       lMinValid = (sizes[0] >= lMin);
 1960                   boolean       rMinValid = (sizes[1] >= rMin);
 1961   
 1962                   if (!lMinValid && !rMinValid) {
 1963                       if (sizes[0] < 0) {
 1964                           sizes[1] += sizes[0];
 1965                           sizes[0] = 0;
 1966                       }
 1967                       else if (sizes[1] < 0) {
 1968                           sizes[0] += sizes[1];
 1969                           sizes[1] = 0;
 1970                       }
 1971                   }
 1972                   else if (!lMinValid) {
 1973                       if (sizes[1] - (lMin - sizes[0]) < rMin) {
 1974                           // both below min, just make sure > 0
 1975                           if (sizes[0] < 0) {
 1976                               sizes[1] += sizes[0];
 1977                               sizes[0] = 0;
 1978                           }
 1979                       }
 1980                       else {
 1981                           sizes[1] -= (lMin - sizes[0]);
 1982                           sizes[0] = lMin;
 1983                       }
 1984                   }
 1985                   else if (!rMinValid) {
 1986                       if (sizes[0] - (rMin - sizes[1]) < lMin) {
 1987                           // both below min, just make sure > 0
 1988                           if (sizes[1] < 0) {
 1989                               sizes[0] += sizes[1];
 1990                               sizes[1] = 0;
 1991                           }
 1992                       }
 1993                       else {
 1994                           sizes[0] -= (rMin - sizes[1]);
 1995                           sizes[1] = rMin;
 1996                       }
 1997                   }
 1998                   if (sizes[0] < 0) {
 1999                       sizes[0] = 0;
 2000                   }
 2001                   if (sizes[1] < 0) {
 2002                       sizes[1] = 0;
 2003                   }
 2004               }
 2005               else if (lValid) {
 2006                   sizes[0] = Math.max(0, sizes[0] + space);
 2007               }
 2008               else if (rValid) {
 2009                   sizes[1] = Math.max(0, sizes[1] + space);
 2010               }
 2011           }
 2012       }
 2013   
 2014   
 2015       /**
 2016        * LayoutManager used for JSplitPanes with an orientation of
 2017        * VERTICAL_SPLIT.
 2018        * <p>
 2019        */
 2020       public class BasicVerticalLayoutManager extends
 2021               BasicHorizontalLayoutManager
 2022       {
 2023           public BasicVerticalLayoutManager() {
 2024               super(1);
 2025           }
 2026       }
 2027   
 2028   
 2029       private class Handler implements FocusListener, PropertyChangeListener {
 2030           //
 2031           // PropertyChangeListener
 2032           //
 2033           /**
 2034            * Messaged from the <code>JSplitPane</code> the receiver is
 2035            * contained in.  May potentially reset the layout manager and cause a
 2036            * <code>validate</code> to be sent.
 2037            */
 2038           public void propertyChange(PropertyChangeEvent e) {
 2039               if(e.getSource() == splitPane) {
 2040                   String changeName = e.getPropertyName();
 2041   
 2042                   if(changeName == JSplitPane.ORIENTATION_PROPERTY) {
 2043                       orientation = splitPane.getOrientation();
 2044                       resetLayoutManager();
 2045                   } else if(changeName == JSplitPane.CONTINUOUS_LAYOUT_PROPERTY){
 2046                       setContinuousLayout(splitPane.isContinuousLayout());
 2047                       if(!isContinuousLayout()) {
 2048                           if(nonContinuousLayoutDivider == null) {
 2049                               setNonContinuousLayoutDivider(
 2050                                   createDefaultNonContinuousLayoutDivider(),
 2051                                   true);
 2052                           } else if(nonContinuousLayoutDivider.getParent() ==
 2053                                     null) {
 2054                               setNonContinuousLayoutDivider(
 2055                                   nonContinuousLayoutDivider,
 2056                                   true);
 2057                           }
 2058                       }
 2059                   } else if(changeName == JSplitPane.DIVIDER_SIZE_PROPERTY){
 2060                       divider.setDividerSize(splitPane.getDividerSize());
 2061                       dividerSize = divider.getDividerSize();
 2062                       splitPane.revalidate();
 2063                       splitPane.repaint();
 2064                   }
 2065               }
 2066           }
 2067   
 2068           //
 2069           // FocusListener
 2070           //
 2071           public void focusGained(FocusEvent ev) {
 2072               dividerKeyboardResize = true;
 2073               splitPane.repaint();
 2074           }
 2075   
 2076           public void focusLost(FocusEvent ev) {
 2077               dividerKeyboardResize = false;
 2078               splitPane.repaint();
 2079           }
 2080       }
 2081   
 2082   
 2083       private static class Actions extends UIAction {
 2084           private static final String NEGATIVE_INCREMENT = "negativeIncrement";
 2085           private static final String POSITIVE_INCREMENT = "positiveIncrement";
 2086           private static final String SELECT_MIN = "selectMin";
 2087           private static final String SELECT_MAX = "selectMax";
 2088           private static final String START_RESIZE = "startResize";
 2089           private static final String TOGGLE_FOCUS = "toggleFocus";
 2090           private static final String FOCUS_OUT_FORWARD = "focusOutForward";
 2091           private static final String FOCUS_OUT_BACKWARD = "focusOutBackward";
 2092   
 2093           Actions(String key) {
 2094               super(key);
 2095           }
 2096   
 2097           public void actionPerformed(ActionEvent ev) {
 2098               JSplitPane splitPane = (JSplitPane)ev.getSource();
 2099               BasicSplitPaneUI ui = (BasicSplitPaneUI)BasicLookAndFeel.
 2100                         getUIOfType(splitPane.getUI(), BasicSplitPaneUI.class);
 2101   
 2102               if (ui == null) {
 2103                   return;
 2104               }
 2105               String key = getName();
 2106               if (key == NEGATIVE_INCREMENT) {
 2107                   if (ui.dividerKeyboardResize) {
 2108                       splitPane.setDividerLocation(Math.max(
 2109                                 0, ui.getDividerLocation
 2110                                 (splitPane) - ui.getKeyboardMoveIncrement()));
 2111                   }
 2112               }
 2113               else if (key == POSITIVE_INCREMENT) {
 2114                   if (ui.dividerKeyboardResize) {
 2115                       splitPane.setDividerLocation(
 2116                           ui.getDividerLocation(splitPane) +
 2117                           ui.getKeyboardMoveIncrement());
 2118                   }
 2119               }
 2120               else if (key == SELECT_MIN) {
 2121                   if (ui.dividerKeyboardResize) {
 2122                       splitPane.setDividerLocation(0);
 2123                   }
 2124               }
 2125               else if (key == SELECT_MAX) {
 2126                   if (ui.dividerKeyboardResize) {
 2127                       Insets   insets = splitPane.getInsets();
 2128                       int      bottomI = (insets != null) ? insets.bottom : 0;
 2129                       int      rightI = (insets != null) ? insets.right : 0;
 2130   
 2131                       if (ui.orientation == JSplitPane.VERTICAL_SPLIT) {
 2132                           splitPane.setDividerLocation(splitPane.getHeight() -
 2133                                                        bottomI);
 2134                       }
 2135                       else {
 2136                           splitPane.setDividerLocation(splitPane.getWidth() -
 2137                                                        rightI);
 2138                       }
 2139                   }
 2140               }
 2141               else if (key == START_RESIZE) {
 2142                   if (!ui.dividerKeyboardResize) {
 2143                       splitPane.requestFocus();
 2144                   } else {
 2145                       JSplitPane parentSplitPane =
 2146                           (JSplitPane)SwingUtilities.getAncestorOfClass(
 2147                                            JSplitPane.class, splitPane);
 2148                       if (parentSplitPane!=null) {
 2149                           parentSplitPane.requestFocus();
 2150                       }
 2151                   }
 2152               }
 2153               else if (key == TOGGLE_FOCUS) {
 2154                   toggleFocus(splitPane);
 2155               }
 2156               else if (key == FOCUS_OUT_FORWARD) {
 2157                   moveFocus(splitPane, 1);
 2158               }
 2159               else if (key == FOCUS_OUT_BACKWARD) {
 2160                   moveFocus(splitPane, -1);
 2161               }
 2162           }
 2163   
 2164           private void moveFocus(JSplitPane splitPane, int direction) {
 2165               Container rootAncestor = splitPane.getFocusCycleRootAncestor();
 2166               FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
 2167               Component focusOn = (direction > 0) ?
 2168                   policy.getComponentAfter(rootAncestor, splitPane) :
 2169                   policy.getComponentBefore(rootAncestor, splitPane);
 2170               HashSet<Component> focusFrom = new HashSet<Component>();
 2171               if (splitPane.isAncestorOf(focusOn)) {
 2172                   do {
 2173                       focusFrom.add(focusOn);
 2174                       rootAncestor = focusOn.getFocusCycleRootAncestor();
 2175                       policy = rootAncestor.getFocusTraversalPolicy();
 2176                       focusOn = (direction > 0) ?
 2177                           policy.getComponentAfter(rootAncestor, focusOn) :
 2178                           policy.getComponentBefore(rootAncestor, focusOn);
 2179                   } while (splitPane.isAncestorOf(focusOn) &&
 2180                            !focusFrom.contains(focusOn));
 2181               }
 2182               if ( focusOn!=null && !splitPane.isAncestorOf(focusOn) ) {
 2183                   focusOn.requestFocus();
 2184               }
 2185           }
 2186   
 2187           private void toggleFocus(JSplitPane splitPane) {
 2188               Component left = splitPane.getLeftComponent();
 2189               Component right = splitPane.getRightComponent();
 2190   
 2191               KeyboardFocusManager manager =
 2192                   KeyboardFocusManager.getCurrentKeyboardFocusManager();
 2193               Component focus = manager.getFocusOwner();
 2194               Component focusOn = getNextSide(splitPane, focus);
 2195               if (focusOn != null) {
 2196                   // don't change the focus if the new focused component belongs
 2197                   // to the same splitpane and the same side
 2198                   if ( focus!=null &&
 2199                        ( (SwingUtilities.isDescendingFrom(focus, left) &&
 2200                           SwingUtilities.isDescendingFrom(focusOn, left)) ||
 2201                          (SwingUtilities.isDescendingFrom(focus, right) &&
 2202                           SwingUtilities.isDescendingFrom(focusOn, right)) ) ) {
 2203                       return;
 2204                   }
 2205                   SwingUtilities2.compositeRequestFocus(focusOn);
 2206               }
 2207           }
 2208   
 2209           private Component getNextSide(JSplitPane splitPane, Component focus) {
 2210               Component left = splitPane.getLeftComponent();
 2211               Component right = splitPane.getRightComponent();
 2212               Component next;
 2213               if (focus!=null && SwingUtilities.isDescendingFrom(focus, left) &&
 2214                   right!=null) {
 2215                   next = getFirstAvailableComponent(right);
 2216                   if (next != null) {
 2217                       return next;
 2218                   }
 2219               }
 2220               JSplitPane parentSplitPane = (JSplitPane)SwingUtilities.getAncestorOfClass(JSplitPane.class, splitPane);
 2221               if (parentSplitPane!=null) {
 2222                   // focus next side of the parent split pane
 2223                   next = getNextSide(parentSplitPane, focus);
 2224               } else {
 2225                   next = getFirstAvailableComponent(left);
 2226                   if (next == null) {
 2227                       next = getFirstAvailableComponent(right);
 2228                   }
 2229               }
 2230               return next;
 2231           }
 2232   
 2233           private Component getFirstAvailableComponent(Component c) {
 2234               if (c!=null && c instanceof JSplitPane) {
 2235                   JSplitPane sp = (JSplitPane)c;
 2236                   Component left = getFirstAvailableComponent(sp.getLeftComponent());
 2237                   if (left != null) {
 2238                       c = left;
 2239                   } else {
 2240                       c = getFirstAvailableComponent(sp.getRightComponent());
 2241                   }
 2242               }
 2243               return c;
 2244           }
 2245       }
 2246   }

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