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

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