Use Tree Navigation
public class

BasicSplitPaneUI.KeyboardDownRightHandler

extends Object
implements ActionListener
/*
 * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */



package javax.swing.plaf.basic;


import sun.swing.DefaultLookup;
import sun.swing.UIAction;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;
import java.awt.peer.ComponentPeer;
import java.awt.peer.LightweightPeer;
import java.beans.*;
import java.util.*;
import javax.swing.plaf.SplitPaneUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import sun.swing.SwingUtilities2;


/**
 * A Basic L&F implementation of the SplitPaneUI.
 *
 * @author Scott Violet
 * @author Steve Wilson
 * @author Ralph Kar
 */

public class BasicSplitPaneUI extends SplitPaneUI
{
   
/**
     * The divider used for non-continuous layout is added to the split pane
     * with this object.
     */

   
protected static final String NON_CONTINUOUS_DIVIDER =
       
"nonContinuousDivider";


   
/**
     * How far (relative) the divider does move when it is moved around by
     * the cursor keys on the keyboard.
     */

   
protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;


   
/**
     * JSplitPane instance this instance is providing
     * the look and feel for.
     */

   
protected JSplitPane splitPane;


   
/**
     * LayoutManager that is created and placed into the split pane.
     */

   
protected BasicHorizontalLayoutManager layoutManager;


   
/**
     * Instance of the divider for this JSplitPane.
     */

   
protected BasicSplitPaneDivider divider;


   
/**
     * Instance of the PropertyChangeListener for this JSplitPane.
     */

   
protected PropertyChangeListener propertyChangeListener;


   
/**
     * Instance of the FocusListener for this JSplitPane.
     */

   
protected FocusListener focusListener;

   
private Handler handler;


   
/**
     * Keys to use for forward focus traversal when the JComponent is
     * managing focus.
     */

   
private Set managingFocusForwardTraversalKeys;

   
/**
     * Keys to use for backward focus traversal when the JComponent is
     * managing focus.
     */

   
private Set managingFocusBackwardTraversalKeys;


   
/**
     * The size of the divider while the dragging session is valid.
     */

   
protected int dividerSize;


   
/**
     * Instance for the shadow of the divider when non continuous layout
     * is being used.
     */

   
protected Component nonContinuousLayoutDivider;


   
/**
     * Set to true in startDragging if any of the children
     * (not including the nonContinuousLayoutDivider) are heavy weights.
     */

   
protected boolean draggingHW;


   
/**
     * Location of the divider when the dragging session began.
     */

   
protected int beginDragDividerLocation;


   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke upKey;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke downKey;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke leftKey;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke rightKey;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke homeKey;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke endKey;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected KeyStroke dividerResizeToggleKey;

   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener keyboardUpLeftListener;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener keyboardDownRightListener;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener keyboardHomeListener;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener keyboardEndListener;
   
/**
     * As of Java 2 platform v1.3 this previously undocumented field is no
     * longer used.
     * Key bindings are now defined by the LookAndFeel, please refer to
     * the key bindings specification for further details.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener keyboardResizeToggleListener;


   
// Private data of the instance
   
private int         orientation;
   
private int         lastDragLocation;
   
private boolean     continuousLayout;
   
private boolean     dividerKeyboardResize;
   
private boolean     dividerLocationIsSet;  // needed for tracking
                                               
// the first occurrence of
                                               
// setDividerLocation()
   
private Color dividerDraggingColor;
   
private boolean rememberPaneSizes;

   
// Indicates wether the one of splitpane sides is expanded
   
private boolean keepHidden = false;

   
/** Indicates that we have painted once. */
   
// This is used by the LayoutManager to determine when it should use
   
// the divider location provided by the JSplitPane. This is used as there
   
// is no way to determine when the layout process has completed.
   
boolean             painted;
   
/** If true, setDividerLocation does nothing. */
   
boolean             ignoreDividerLocationChange;


   
/**
     * Creates a new BasicSplitPaneUI instance
     */

   
public static ComponentUI createUI(JComponent x) {
       
return new BasicSplitPaneUI();
   
}

   
static void loadActionMap(LazyActionMap map) {
        map
.put(new Actions(Actions.NEGATIVE_INCREMENT));
        map
.put(new Actions(Actions.POSITIVE_INCREMENT));
        map
.put(new Actions(Actions.SELECT_MIN));
        map
.put(new Actions(Actions.SELECT_MAX));
        map
.put(new Actions(Actions.START_RESIZE));
        map
.put(new Actions(Actions.TOGGLE_FOCUS));
        map
.put(new Actions(Actions.FOCUS_OUT_FORWARD));
        map
.put(new Actions(Actions.FOCUS_OUT_BACKWARD));
   
}



   
/**
     * Installs the UI.
     */

   
public void installUI(JComponent c) {
        splitPane
= (JSplitPane) c;
        dividerLocationIsSet
= false;
        dividerKeyboardResize
= false;
        keepHidden
= false;
        installDefaults
();
        installListeners
();
        installKeyboardActions
();
        setLastDragLocation
(-1);
   
}


   
/**
     * Installs the UI defaults.
     */

   
protected void installDefaults(){
       
LookAndFeel.installBorder(splitPane, "SplitPane.border");
       
LookAndFeel.installColors(splitPane, "SplitPane.background",
                                 
"SplitPane.foreground");
       
LookAndFeel.installProperty(splitPane, "opaque", Boolean.TRUE);

       
if (divider == null) divider = createDefaultDivider();
        divider
.setBasicSplitPaneUI(this);

       
Border    b = divider.getBorder();

       
if (b == null || !(b instanceof UIResource)) {
            divider
.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
       
}

        dividerDraggingColor
= UIManager.getColor("SplitPaneDivider.draggingColor");

        setOrientation
(splitPane.getOrientation());

       
// This plus 2 here is to provide backwards consistancy. Previously,
       
// the old size did not include the 2 pixel border around the divider,
       
// it now does.
       
Integer dividerSize = (Integer)UIManager.get("SplitPane.dividerSize");
       
if (divider == null) dividerSize = 10;
       
LookAndFeel.installProperty(splitPane, "dividerSize", dividerSize);

        divider
.setDividerSize(splitPane.getDividerSize());
        dividerSize
= divider.getDividerSize();
        splitPane
.add(divider, JSplitPane.DIVIDER);

        setContinuousLayout
(splitPane.isContinuousLayout());

        resetLayoutManager
();

       
/* Install the nonContinuousLayoutDivider here to avoid having to
        add/remove everything later. */

       
if(nonContinuousLayoutDivider == null) {
            setNonContinuousLayoutDivider
(
                                createDefaultNonContinuousLayoutDivider
(),
                               
true);
       
} else {
            setNonContinuousLayoutDivider
(nonContinuousLayoutDivider, true);
       
}

       
// focus forward traversal key
       
if (managingFocusForwardTraversalKeys==null) {
            managingFocusForwardTraversalKeys
= new HashSet();
            managingFocusForwardTraversalKeys
.add(
               
KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
       
}
        splitPane
.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
                                        managingFocusForwardTraversalKeys
);
       
// focus backward traversal key
       
if (managingFocusBackwardTraversalKeys==null) {
            managingFocusBackwardTraversalKeys
= new HashSet();
            managingFocusBackwardTraversalKeys
.add(
               
KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
       
}
        splitPane
.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
                                        managingFocusBackwardTraversalKeys
);
   
}


   
/**
     * Installs the event listeners for the UI.
     */

   
protected void installListeners() {
       
if ((propertyChangeListener = createPropertyChangeListener()) !=
           
null) {
            splitPane
.addPropertyChangeListener(propertyChangeListener);
       
}

       
if ((focusListener = createFocusListener()) != null) {
            splitPane
.addFocusListener(focusListener);
       
}
   
}


   
/**
     * Installs the keyboard actions for the UI.
     */

   
protected void installKeyboardActions() {
       
InputMap km = getInputMap(JComponent.
                                  WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
);

       
SwingUtilities.replaceUIInputMap(splitPane, JComponent.
                                       WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
,
                                       km
);
       
LazyActionMap.installLazyActionMap(splitPane, BasicSplitPaneUI.class,
                                           
"SplitPane.actionMap");
   
}

   
InputMap getInputMap(int condition) {
       
if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
           
return (InputMap)DefaultLookup.get(splitPane, this,
                                               
"SplitPane.ancestorInputMap");
       
}
       
return null;
   
}

   
/**
     * Uninstalls the UI.
     */

   
public void uninstallUI(JComponent c) {
        uninstallKeyboardActions
();
        uninstallListeners
();
        uninstallDefaults
();
        dividerLocationIsSet
= false;
        dividerKeyboardResize
= false;
        splitPane
= null;
   
}


   
/**
     * Uninstalls the UI defaults.
     */

   
protected void uninstallDefaults() {
       
if(splitPane.getLayout() == layoutManager) {
            splitPane
.setLayout(null);
       
}

       
if(nonContinuousLayoutDivider != null) {
            splitPane
.remove(nonContinuousLayoutDivider);
       
}

       
LookAndFeel.uninstallBorder(splitPane);

       
Border    b = divider.getBorder();

       
if (b instanceof UIResource) {
            divider
.setBorder(null);
       
}

        splitPane
.remove(divider);
        divider
.setBasicSplitPaneUI(null);
        layoutManager
= null;
        divider
= null;
        nonContinuousLayoutDivider
= null;

        setNonContinuousLayoutDivider
(null);

       
// sets the focus forward and backward traversal keys to null
       
// to restore the defaults
        splitPane
.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
        splitPane
.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
   
}


   
/**
     * Uninstalls the event listeners for the UI.
     */

   
protected void uninstallListeners() {
       
if (propertyChangeListener != null) {
            splitPane
.removePropertyChangeListener(propertyChangeListener);
            propertyChangeListener
= null;
       
}
       
if (focusListener != null) {
            splitPane
.removeFocusListener(focusListener);
            focusListener
= null;
       
}

        keyboardUpLeftListener
= null;
        keyboardDownRightListener
= null;
        keyboardHomeListener
= null;
        keyboardEndListener
= null;
        keyboardResizeToggleListener
= null;
        handler
= null;
   
}


   
/**
     * Uninstalls the keyboard actions for the UI.
     */

   
protected void uninstallKeyboardActions() {
       
SwingUtilities.replaceUIActionMap(splitPane, null);
       
SwingUtilities.replaceUIInputMap(splitPane, JComponent.
                                      WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
,
                                     
null);
   
}


   
/**
     * Creates a PropertyChangeListener for the JSplitPane UI.
     */

   
protected PropertyChangeListener createPropertyChangeListener() {
       
return getHandler();
   
}

   
private Handler getHandler() {
       
if (handler == null) {
            handler
= new Handler();
       
}
       
return handler;
   
}


   
/**
     * Creates a FocusListener for the JSplitPane UI.
     */

   
protected FocusListener createFocusListener() {
       
return getHandler();
   
}


   
/**
     * As of Java 2 platform v1.3 this method is no
     * longer used. Subclassers previously using this method should
     * instead create an Action wrapping the ActionListener, and register
     * that Action by overriding <code>installKeyboardActions</code> and
     * placing the Action in the SplitPane's ActionMap. Please refer to
     * the key bindings specification for further details.
     * <p>
     * Creates a ActionListener for the JSplitPane UI that listens for
     * specific key presses.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener createKeyboardUpLeftListener() {
       
return new KeyboardUpLeftHandler();
   
}


   
/**
     * As of Java 2 platform v1.3 this method is no
     * longer used. Subclassers previously using this method should
     * instead create an Action wrapping the ActionListener, and register
     * that Action by overriding <code>installKeyboardActions</code> and
     * placing the Action in the SplitPane's ActionMap. Please refer to
     * the key bindings specification for further details.
     * <p>
     * Creates a ActionListener for the JSplitPane UI that listens for
     * specific key presses.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener createKeyboardDownRightListener() {
       
return new KeyboardDownRightHandler();
   
}


   
/**
     * As of Java 2 platform v1.3 this method is no
     * longer used. Subclassers previously using this method should
     * instead create an Action wrapping the ActionListener, and register
     * that Action by overriding <code>installKeyboardActions</code> and
     * placing the Action in the SplitPane's ActionMap. Please refer to
     * the key bindings specification for further details.
     * <p>
     * Creates a ActionListener for the JSplitPane UI that listens for
     * specific key presses.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener createKeyboardHomeListener() {
       
return new KeyboardHomeHandler();
   
}


   
/**
     * As of Java 2 platform v1.3 this method is no
     * longer used. Subclassers previously using this method should
     * instead create an Action wrapping the ActionListener, and register
     * that Action by overriding <code>installKeyboardActions</code> and
     * placing the Action in the SplitPane's ActionMap. Please refer to
     * the key bindings specification for further details.
     * <p>
     * Creates a ActionListener for the JSplitPane UI that listens for
     * specific key presses.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener createKeyboardEndListener() {
       
return new KeyboardEndHandler();
   
}


   
/**
     * As of Java 2 platform v1.3 this method is no
     * longer used. Subclassers previously using this method should
     * instead create an Action wrapping the ActionListener, and register
     * that Action by overriding <code>installKeyboardActions</code> and
     * placing the Action in the SplitPane's ActionMap. Please refer to
     * the key bindings specification for further details.
     * <p>
     * Creates a ActionListener for the JSplitPane UI that listens for
     * specific key presses.
     *
     * @deprecated As of Java 2 platform v1.3.
     */

   
@Deprecated
   
protected ActionListener createKeyboardResizeToggleListener() {
       
return new KeyboardResizeToggleHandler();
   
}


   
/**
     * Returns the orientation for the JSplitPane.
     */

   
public int getOrientation() {
       
return orientation;
   
}


   
/**
     * Set the orientation for the JSplitPane.
     */

   
public void setOrientation(int orientation) {
       
this.orientation = orientation;
   
}


   
/**
     * Determines wether the JSplitPane is set to use a continuous layout.
     */

   
public boolean isContinuousLayout() {
       
return continuousLayout;
   
}


   
/**
     * Turn continuous layout on/off.
     */

   
public void setContinuousLayout(boolean b) {
        continuousLayout
= b;
   
}


   
/**
     * Returns the last drag location of the JSplitPane.
     */

   
public int getLastDragLocation() {
       
return lastDragLocation;
   
}


   
/**
     * Set the last drag location of the JSplitPane.
     */

   
public void setLastDragLocation(int l) {
        lastDragLocation
= l;
   
}

   
/**
     * @return increment via keyboard methods.
     */

   
int getKeyboardMoveIncrement() {
       
return 3;
   
}

   
/**
     * Implementation of the PropertyChangeListener
     * that the JSplitPane UI uses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class PropertyHandler implements PropertyChangeListener
   
{
       
// NOTE: This class exists only for backward compatability. All
       
// its functionality has been moved into Handler. If you need to add
       
// new functionality add it to the Handler, but make sure this
       
// class calls into the Handler.

       
/**
         * Messaged from the <code>JSplitPane</code> the receiver is
         * contained in.  May potentially reset the layout manager and cause a
         * <code>validate</code> to be sent.
         */

       
public void propertyChange(PropertyChangeEvent e) {
            getHandler
().propertyChange(e);
       
}
   
}


   
/**
     * Implementation of the FocusListener that the JSplitPane UI uses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class FocusHandler extends FocusAdapter
   
{
       
// NOTE: This class exists only for backward compatability. All
       
// its functionality has been moved into Handler. If you need to add
       
// new functionality add it to the Handler, but make sure this
       
// class calls into the Handler.
       
public void focusGained(FocusEvent ev) {
            getHandler
().focusGained(ev);
       
}

       
public void focusLost(FocusEvent ev) {
            getHandler
().focusLost(ev);
       
}
   
}


   
/**
     * Implementation of an ActionListener that the JSplitPane UI uses for
     * handling specific key presses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class KeyboardUpLeftHandler implements ActionListener
   
{
       
public void actionPerformed(ActionEvent ev) {
           
if (dividerKeyboardResize) {
                splitPane
.setDividerLocation(Math.max(0,getDividerLocation
                                 
(splitPane) - getKeyboardMoveIncrement()));
           
}
       
}
   
}

   
/**
     * Implementation of an ActionListener that the JSplitPane UI uses for
     * handling specific key presses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class KeyboardDownRightHandler implements ActionListener
   
{
       
public void actionPerformed(ActionEvent ev) {
           
if (dividerKeyboardResize) {
                splitPane
.setDividerLocation(getDividerLocation(splitPane) +
                                             getKeyboardMoveIncrement
());
           
}
       
}
   
}


   
/**
     * Implementation of an ActionListener that the JSplitPane UI uses for
     * handling specific key presses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class KeyboardHomeHandler implements ActionListener
   
{
       
public void actionPerformed(ActionEvent ev) {
           
if (dividerKeyboardResize) {
                splitPane
.setDividerLocation(0);
           
}
       
}
   
}


   
/**
     * Implementation of an ActionListener that the JSplitPane UI uses for
     * handling specific key presses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class KeyboardEndHandler implements ActionListener
   
{
       
public void actionPerformed(ActionEvent ev) {
           
if (dividerKeyboardResize) {
               
Insets   insets = splitPane.getInsets();
               
int      bottomI = (insets != null) ? insets.bottom : 0;
               
int      rightI = (insets != null) ? insets.right : 0;

               
if (orientation == JSplitPane.VERTICAL_SPLIT) {
                    splitPane
.setDividerLocation(splitPane.getHeight() -
                                       bottomI
);
               
}
               
else {
                    splitPane
.setDividerLocation(splitPane.getWidth() -
                                                 rightI
);
               
}
           
}
       
}
   
}


   
/**
     * Implementation of an ActionListener that the JSplitPane UI uses for
     * handling specific key presses.
     * <p>
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of BasicSplitPaneUI.
     */

   
public class KeyboardResizeToggleHandler implements ActionListener
   
{
       
public void actionPerformed(ActionEvent ev) {
           
if (!dividerKeyboardResize) {
                splitPane
.requestFocus();
           
}
       
}
   
}

   
/**
     * Returns the divider between the top Components.
     */

   
public BasicSplitPaneDivider getDivider() {
       
return divider;
   
}


   
/**
     * Returns the default non continuous layout divider, which is an
     * instanceof Canvas that fills the background in dark gray.
     */

   
protected Component createDefaultNonContinuousLayoutDivider() {
       
return new Canvas() {
           
public void paint(Graphics g) {
               
if(!isContinuousLayout() && getLastDragLocation() != -1) {
                   
Dimension      size = splitPane.getSize();

                    g
.setColor(dividerDraggingColor);
                   
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                        g
.fillRect(0, 0, dividerSize - 1, size.height - 1);
                   
} else {
                        g
.fillRect(0, 0, size.width - 1, dividerSize - 1);
                   
}
               
}
           
}
       
};
   
}


   
/**
     * Sets the divider to use when the splitPane is configured to
     * not continuously layout. This divider will only be used during a
     * dragging session. It is recommended that the passed in component
     * be a heavy weight.
     */

   
protected void setNonContinuousLayoutDivider(Component newDivider) {
        setNonContinuousLayoutDivider
(newDivider, true);
   
}


   
/**
     * Sets the divider to use.
     */

   
protected void setNonContinuousLayoutDivider(Component newDivider,
       
boolean rememberSizes) {
        rememberPaneSizes
= rememberSizes;
       
if(nonContinuousLayoutDivider != null && splitPane != null) {
            splitPane
.remove(nonContinuousLayoutDivider);
       
}
        nonContinuousLayoutDivider
= newDivider;
   
}

   
private void addHeavyweightDivider() {
       
if(nonContinuousLayoutDivider != null && splitPane != null) {

           
/* Needs to remove all the components and re-add them! YECK! */
           
// This is all done so that the nonContinuousLayoutDivider will
           
// be drawn on top of the other components, without this, one
           
// of the heavyweights will draw over the divider!
           
Component             leftC = splitPane.getLeftComponent();
           
Component             rightC = splitPane.getRightComponent();
           
int                   lastLocation = splitPane.
                                              getDividerLocation
();

           
if(leftC != null)
                splitPane
.setLeftComponent(null);
           
if(rightC != null)
                splitPane
.setRightComponent(null);
            splitPane
.remove(divider);
            splitPane
.add(nonContinuousLayoutDivider, BasicSplitPaneUI.
                          NON_CONTINUOUS_DIVIDER
,
                          splitPane
.getComponentCount());
            splitPane
.setLeftComponent(leftC);
            splitPane
.setRightComponent(rightC);
            splitPane
.add(divider, JSplitPane.DIVIDER);
           
if(rememberPaneSizes) {
                splitPane
.setDividerLocation(lastLocation);
           
}
       
}

   
}


   
/**
     * Returns the divider to use when the splitPane is configured to
     * not continuously layout. This divider will only be used during a
     * dragging session.
     */

   
public Component getNonContinuousLayoutDivider() {
       
return nonContinuousLayoutDivider;
   
}


   
/**
     * Returns the splitpane this instance is currently contained
     * in.
     */

   
public JSplitPane getSplitPane() {
       
return splitPane;
   
}


   
/**
     * Creates the default divider.
     */

   
public BasicSplitPaneDivider createDefaultDivider() {
       
return new BasicSplitPaneDivider(this);
   
}


   
/**
     * Messaged to reset the preferred sizes.
     */

   
public void resetToPreferredSizes(JSplitPane jc) {
       
if(splitPane != null) {
            layoutManager
.resetToPreferredSizes();
            splitPane
.revalidate();
            splitPane
.repaint();
       
}
   
}


   
/**
     * Sets the location of the divider to location.
     */

   
public void setDividerLocation(JSplitPane jc, int location) {
       
if (!ignoreDividerLocationChange) {
            dividerLocationIsSet
= true;
            splitPane
.revalidate();
            splitPane
.repaint();

           
if (keepHidden) {
               
Insets insets = splitPane.getInsets();
               
int orientation = splitPane.getOrientation();
               
if ((orientation == JSplitPane.VERTICAL_SPLIT &&
                     location
!= insets.top &&
                     location
!= splitPane.getHeight()-divider.getHeight()-insets.top) ||
                   
(orientation == JSplitPane.HORIZONTAL_SPLIT &&
                     location
!= insets.left &&
                     location
!= splitPane.getWidth()-divider.getWidth()-insets.left)) {
                    setKeepHidden
(false);
               
}
           
}
       
}
       
else {
            ignoreDividerLocationChange
= false;
       
}
   
}


   
/**
     * Returns the location of the divider, which may differ from what
     * the splitpane thinks the location of the divider is.
     */

   
public int getDividerLocation(JSplitPane jc) {
       
if(orientation == JSplitPane.HORIZONTAL_SPLIT)
           
return divider.getLocation().x;
       
return divider.getLocation().y;
   
}


   
/**
     * Gets the minimum location of the divider.
     */

   
public int getMinimumDividerLocation(JSplitPane jc) {
       
int       minLoc = 0;
       
Component leftC = splitPane.getLeftComponent();

       
if ((leftC != null) && (leftC.isVisible())) {
           
Insets    insets = splitPane.getInsets();
           
Dimension minSize = leftC.getMinimumSize();
           
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                minLoc
= minSize.width;
           
} else {
                minLoc
= minSize.height;
           
}
           
if(insets != null) {
               
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                    minLoc
+= insets.left;
               
} else {
                    minLoc
+= insets.top;
               
}
           
}
       
}
       
return minLoc;
   
}


   
/**
     * Gets the maximum location of the divider.
     */

   
public int getMaximumDividerLocation(JSplitPane jc) {
       
Dimension splitPaneSize = splitPane.getSize();
       
int       maxLoc = 0;
       
Component rightC = splitPane.getRightComponent();

       
if (rightC != null) {
           
Insets    insets = splitPane.getInsets();
           
Dimension minSize = new Dimension(0, 0);
           
if (rightC.isVisible()) {
                minSize
= rightC.getMinimumSize();
           
}
           
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                maxLoc
= splitPaneSize.width - minSize.width;
           
} else {
                maxLoc
= splitPaneSize.height - minSize.height;
           
}
            maxLoc
-= dividerSize;
           
if(insets != null) {
               
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                    maxLoc
-= insets.right;
               
} else {
                    maxLoc
-= insets.top;
               
}
           
}
       
}
       
return Math.max(getMinimumDividerLocation(splitPane), maxLoc);
   
}


   
/**
     * Messaged after the JSplitPane the receiver is providing the look
     * and feel for paints its children.
     */

   
public void finishedPaintingChildren(JSplitPane jc, Graphics g) {
       
if(jc == splitPane && getLastDragLocation() != -1 &&
           
!isContinuousLayout() && !draggingHW) {
           
Dimension      size = splitPane.getSize();

            g
.setColor(dividerDraggingColor);
           
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                g
.fillRect(getLastDragLocation(), 0, dividerSize - 1,
                           size
.height - 1);
           
} else {
                g
.fillRect(0, lastDragLocation, size.width - 1,
                           dividerSize
- 1);
           
}
       
}
   
}


   
/**
     * Messaged to paint the look and feel.
     */

   
public void paint(Graphics g, JComponent jc) {
       
if (!painted && splitPane.getDividerLocation()<0) {
            ignoreDividerLocationChange
= true;
            splitPane
.setDividerLocation(getDividerLocation(splitPane));
       
}
        painted
= true;
   
}


   
/**
     * Returns the preferred size for the passed in component,
     * This is passed off to the current layoutmanager.
     */

   
public Dimension getPreferredSize(JComponent jc) {
       
if(splitPane != null)
           
return layoutManager.preferredLayoutSize(splitPane);
       
return new Dimension(0, 0);
   
}


   
/**
     * Returns the minimum size for the passed in component,
     * This is passed off to the current layoutmanager.
     */

   
public Dimension getMinimumSize(JComponent jc) {
       
if(splitPane != null)
           
return layoutManager.minimumLayoutSize(splitPane);
       
return new Dimension(0, 0);
   
}


   
/**
     * Returns the maximum size for the passed in component,
     * This is passed off to the current layoutmanager.
     */

   
public Dimension getMaximumSize(JComponent jc) {
       
if(splitPane != null)
           
return layoutManager.maximumLayoutSize(splitPane);
       
return new Dimension(0, 0);
   
}


   
/**
     * Returns the insets. The insets are returned from the border insets
     * of the current border.
     */

   
public Insets getInsets(JComponent jc) {
       
return null;
   
}


   
/**
     * Resets the layout manager based on orientation and messages it
     * with invalidateLayout to pull in appropriate Components.
     */

   
protected void resetLayoutManager() {
       
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
            layoutManager
= new BasicHorizontalLayoutManager(0);
       
} else {
            layoutManager
= new BasicHorizontalLayoutManager(1);
       
}
        splitPane
.setLayout(layoutManager);
        layoutManager
.updateComponents();
        splitPane
.revalidate();
        splitPane
.repaint();
   
}

   
/**
     * Set the value to indicate if one of the splitpane sides is expanded.
     */

   
void setKeepHidden(boolean keepHidden) {
       
this.keepHidden = keepHidden;
   
}

   
/**
     * The value returned indicates if one of the splitpane sides is expanded.
     * @return true if one of the splitpane sides is expanded, false otherwise.
     */

   
private boolean getKeepHidden() {
       
return keepHidden;
   
}

   
/**
     * Should be messaged before the dragging session starts, resets
     * lastDragLocation and dividerSize.
     */

   
protected void startDragging() {
       
Component       leftC = splitPane.getLeftComponent();
       
Component       rightC = splitPane.getRightComponent();
       
ComponentPeer   cPeer;

        beginDragDividerLocation
= getDividerLocation(splitPane);
        draggingHW
= false;
       
if(leftC != null && (cPeer = leftC.getPeer()) != null &&
           
!(cPeer instanceof LightweightPeer)) {
            draggingHW
= true;
       
} else if(rightC != null && (cPeer = rightC.getPeer()) != null
                 
&& !(cPeer instanceof LightweightPeer)) {
            draggingHW
= true;
       
}
       
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
            setLastDragLocation
(divider.getBounds().x);
            dividerSize
= divider.getSize().width;
           
if(!isContinuousLayout() && draggingHW) {
                nonContinuousLayoutDivider
.setBounds
                       
(getLastDragLocation(), 0, dividerSize,
                         splitPane
.getHeight());
                      addHeavyweightDivider
();
           
}
       
} else {
            setLastDragLocation
(divider.getBounds().y);
            dividerSize
= divider.getSize().height;
           
if(!isContinuousLayout() && draggingHW) {
                nonContinuousLayoutDivider
.setBounds
                       
(0, getLastDragLocation(), splitPane.getWidth(),
                         dividerSize
);
                      addHeavyweightDivider
();
           
}
       
}
   
}


   
/**
     * Messaged during a dragging session to move the divider to the
     * passed in location. If continuousLayout is true the location is
     * reset and the splitPane validated.
     */

   
protected void dragDividerTo(int location) {
       
if(getLastDragLocation() != location) {
           
if(isContinuousLayout()) {
                splitPane
.setDividerLocation(location);
                setLastDragLocation
(location);
           
} else {
               
int lastLoc = getLastDragLocation();

                setLastDragLocation
(location);
               
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                   
if(draggingHW) {
                        nonContinuousLayoutDivider
.setLocation(
                            getLastDragLocation
(), 0);
                   
} else {
                       
int   splitHeight = splitPane.getHeight();
                        splitPane
.repaint(lastLoc, 0, dividerSize,
                                          splitHeight
);
                        splitPane
.repaint(location, 0, dividerSize,
                                          splitHeight
);
                   
}
               
} else {
                   
if(draggingHW) {
                        nonContinuousLayoutDivider
.setLocation(0,
                            getLastDragLocation
());
                   
} else {
                       
int    splitWidth = splitPane.getWidth();

                        splitPane
.repaint(0, lastLoc, splitWidth,
                                          dividerSize
);
                        splitPane
.repaint(0, location, splitWidth,
                                          dividerSize
);
                   
}
               
}
           
}
       
}
   
}


   
/**
     * Messaged to finish the dragging session. If not continuous display
     * the dividers location will be reset.
     */

   
protected void finishDraggingTo(int location) {
        dragDividerTo
(location);
        setLastDragLocation
(-1);
       
if(!isContinuousLayout()) {
           
Component   leftC = splitPane.getLeftComponent();
           
Rectangle   leftBounds = leftC.getBounds();

           
if (draggingHW) {
               
if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
                    nonContinuousLayoutDivider
.setLocation(-dividerSize, 0);
               
}
               
else {
                    nonContinuousLayoutDivider
.setLocation(0, -dividerSize);
               
}
                splitPane
.remove(nonContinuousLayoutDivider);
           
}
            splitPane
.setDividerLocation(location);
       
}
   
}


   
/**
     * As of Java 2 platform v1.3 this method is no longer used. Instead
     * you should set the border on the divider.
     * <p>
     * Returns the width of one side of the divider border.
     *
     * @deprecated As of Java 2 platform v1.3, instead set the border on the
     * divider.
     */

   
@Deprecated
   
protected int getDividerBorderSize() {
       
return 1;
   
}


   
/**
     * LayoutManager for JSplitPanes that have an orientation of
     * HORIZONTAL_SPLIT.
     */

   
public class BasicHorizontalLayoutManager implements LayoutManager2
   
{
       
/* left, right, divider. (in this exact order) */
       
protected int[]         sizes;
       
protected Component[]   components;
       
/** Size of the splitpane the last time laid out. */
       
private int             lastSplitPaneSize;
       
/** True if resetToPreferredSizes has been invoked. */
       
private boolean         doReset;
       
/** Axis, 0 for horizontal, or 1 for veritcal. */
       
private int             axis;


       
BasicHorizontalLayoutManager() {
           
this(0);
       
}

       
BasicHorizontalLayoutManager(int axis) {
           
this.axis = axis;
            components
= new Component[3];
            components
[0] = components[1] = components[2] = null;
            sizes
= new int[3];
       
}

       
//
       
// LayoutManager
       
//

       
/**
         * Does the actual layout.
         */

       
public void layoutContainer(Container container) {
           
Dimension   containerSize = container.getSize();

           
// If the splitpane has a zero size then no op out of here.
           
// If we execute this function now, we're going to cause ourselves
           
// much grief.
           
if (containerSize.height <= 0 || containerSize.width <= 0 ) {
                lastSplitPaneSize
= 0;
               
return;
           
}

           
int         spDividerLocation = splitPane.getDividerLocation();
           
Insets      insets = splitPane.getInsets();
           
int         availableSize = getAvailableSize(containerSize,
                                                         insets
);
           
int         newSize = getSizeForPrimaryAxis(containerSize);
           
int         beginLocation = getDividerLocation(splitPane);
           
int         dOffset = getSizeForPrimaryAxis(insets, true);
           
Dimension   dSize = (components[2] == null) ? null :
                                 components
[2].getPreferredSize();

           
if ((doReset && !dividerLocationIsSet) || spDividerLocation < 0) {
                resetToPreferredSizes
(availableSize);
           
}
           
else if (lastSplitPaneSize <= 0 ||
                     availableSize
== lastSplitPaneSize || !painted ||
                     
(dSize != null &&
                      getSizeForPrimaryAxis
(dSize) != sizes[2])) {
               
if (dSize != null) {
                    sizes
[2] = getSizeForPrimaryAxis(dSize);
               
}
               
else {
                    sizes
[2] = 0;
               
}
                setDividerLocation
(spDividerLocation - dOffset, availableSize);
                dividerLocationIsSet
= false;
           
}
           
else if (availableSize != lastSplitPaneSize) {
                distributeSpace
(availableSize - lastSplitPaneSize,
                                getKeepHidden
());
           
}
            doReset
= false;
            dividerLocationIsSet
= false;
            lastSplitPaneSize
= availableSize;

           
// Reset the bounds of each component
           
int nextLocation = getInitialLocation(insets);
           
int counter = 0;

           
while (counter < 3) {
               
if (components[counter] != null &&
                    components
[counter].isVisible()) {
                    setComponentToSize
(components[counter], sizes[counter],
                                       nextLocation
, insets, containerSize);
                    nextLocation
+= sizes[counter];
               
}
               
switch (counter) {
               
case 0:
                    counter
= 2;
                   
break;
               
case 2:
                    counter
= 1;
                   
break;
               
case 1:
                    counter
= 3;
                   
break;
               
}
           
}
           
if (painted) {
               
// This is tricky, there is never a good time for us
               
// to push the value to the splitpane, painted appears to
               
// the best time to do it. What is really needed is
               
// notification that layout has completed.
               
int      newLocation = getDividerLocation(splitPane);

               
if (newLocation != (spDividerLocation - dOffset)) {
                   
int  lastLocation = splitPane.getLastDividerLocation();

                    ignoreDividerLocationChange
= true;
                   
try {
                        splitPane
.setDividerLocation(newLocation);
                       
// This is not always needed, but is rather tricky
                       
// to determine when... The case this is needed for
                       
// is if the user sets the divider location to some
                       
// bogus value, say 0, and the actual value is 1, the
                       
// call to setDividerLocation(1) will preserve the
                       
// old value of 0, when we really want the divider
                       
// location value  before the call. This is needed for
                       
// the one touch buttons.
                        splitPane
.setLastDividerLocation(lastLocation);
                   
} finally {
                        ignoreDividerLocationChange
= false;
                   
}
               
}
           
}
       
}


       
/**
         * Adds the component at place.  Place must be one of
         * JSplitPane.LEFT, RIGHT, TOP, BOTTOM, or null (for the
         * divider).
         */

       
public void addLayoutComponent(String place, Component component) {
           
boolean isValid = true;

           
if(place != null) {
               
if(place.equals(JSplitPane.DIVIDER)) {
                   
/* Divider. */
                    components
[2] = component;
                    sizes
[2] = getSizeForPrimaryAxis(component.
                                                     getPreferredSize
());
               
} else if(place.equals(JSplitPane.LEFT) ||
                          place
.equals(JSplitPane.TOP)) {
                    components
[0] = component;
                    sizes
[0] = 0;
               
} else if(place.equals(JSplitPane.RIGHT) ||
                          place
.equals(JSplitPane.BOTTOM)) {
                    components
[1] = component;
                    sizes
[1] = 0;
               
} else if(!place.equals(
                                   
BasicSplitPaneUI.NON_CONTINUOUS_DIVIDER))
                    isValid
= false;
           
} else {
                isValid
= false;
           
}
           
if(!isValid)
               
throw new IllegalArgumentException("cannot add to layout: " +
                   
"unknown constraint: " +
                    place
);
            doReset
= true;
       
}


       
/**
         * Returns the minimum size needed to contain the children.
         * The width is the sum of all the childrens min widths and
         * the height is the largest of the childrens minimum heights.
         */

       
public Dimension minimumLayoutSize(Container container) {
           
int         minPrimary = 0;
           
int         minSecondary = 0;
           
Insets      insets = splitPane.getInsets();

           
for (int counter=0; counter<3; counter++) {
               
if(components[counter] != null) {
                   
Dimension   minSize = components[counter].getMinimumSize();
                   
int         secSize = getSizeForSecondaryAxis(minSize);

                    minPrimary
+= getSizeForPrimaryAxis(minSize);
                   
if(secSize > minSecondary)
                        minSecondary
= secSize;
               
}
           
}
           
if(insets != null) {
                minPrimary
+= getSizeForPrimaryAxis(insets, true) +
                              getSizeForPrimaryAxis
(insets, false);
                minSecondary
+= getSizeForSecondaryAxis(insets, true) +
                              getSizeForSecondaryAxis
(insets, false);
           
}
           
if (axis == 0) {
               
return new Dimension(minPrimary, minSecondary);
           
}
           
return new Dimension(minSecondary, minPrimary);
       
}


       
/**
         * Returns the preferred size needed to contain the children.
         * The width is the sum of all the childrens preferred widths and
         * the height is the largest of the childrens preferred heights.
         */

       
public Dimension preferredLayoutSize(Container container) {
           
int         prePrimary = 0;
           
int         preSecondary = 0;
           
Insets      insets = splitPane.getInsets();

           
for(int counter = 0; counter < 3; counter++) {
               
if(components[counter] != null) {
                   
Dimension   preSize = components[counter].
                                          getPreferredSize
();
                   
int         secSize = getSizeForSecondaryAxis(preSize);

                    prePrimary
+= getSizeForPrimaryAxis(preSize);
                   
if(secSize > preSecondary)
                        preSecondary
= secSize;
               
}
           
}
           
if(insets != null) {
                prePrimary
+= getSizeForPrimaryAxis(insets, true) +
                              getSizeForPrimaryAxis
(insets, false);
                preSecondary
+= getSizeForSecondaryAxis(insets, true) +
                              getSizeForSecondaryAxis
(insets, false);
           
}
           
if (axis == 0) {
               
return new Dimension(prePrimary, preSecondary);
           
}
           
return new Dimension(preSecondary, prePrimary);
       
}


       
/**
         * Removes the specified component from our knowledge.
         */

       
public void removeLayoutComponent(Component component) {
           
for(int counter = 0; counter < 3; counter++) {
               
if(components[counter] == component) {
                    components
[counter] = null;
                    sizes
[counter] = 0;
                    doReset
= true;
               
}
           
}
       
}


       
//
       
// LayoutManager2
       
//


       
/**
         * Adds the specified component to the layout, using the specified
         * constraint object.
         * @param comp the component to be added
         * @param constraints  where/how the component is added to the layout.
         */

       
public void addLayoutComponent(Component comp, Object constraints) {
           
if ((constraints == null) || (constraints instanceof String)) {
                addLayoutComponent
((String)constraints, comp);
           
} else {
               
throw new IllegalArgumentException("cannot add to layout: " +
                                                   
"constraint must be a " +
                                                   
"string (or null)");
           
}
       
}


       
/**
         * Returns the alignment along the x axis.  This specifies how
         * the component would like to be aligned relative to other
         * components.  The value should be a number between 0 and 1
         * where 0 represents alignment along the origin, 1 is aligned
         * the furthest away from the origin, 0.5 is centered, etc.
         */

       
public float getLayoutAlignmentX(Container target) {
           
return 0.0f;
       
}


       
/**
         * Returns the alignment along the y axis.  This specifies how
         * the component would like to be aligned relative to other
         * components.  The value should be a number between 0 and 1
         * where 0 represents alignment along the origin, 1 is aligned
         * the furthest away from the origin, 0.5 is centered, etc.
         */

       
public float getLayoutAlignmentY(Container target) {
           
return 0.0f;
       
}


       
/**
         * Does nothing. If the developer really wants to change the
         * size of one of the views JSplitPane.resetToPreferredSizes should
         * be messaged.
         */

       
public void invalidateLayout(Container c) {
       
}


       
/**
         * Returns the maximum layout size, which is Integer.MAX_VALUE
         * in both directions.
         */

       
public Dimension maximumLayoutSize(Container target) {
           
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
       
}


       
//
       
// New methods.
       
//

       
/**
         * Marks the receiver so that the next time this instance is
         * laid out it'll ask for the preferred sizes.
         */

       
public void resetToPreferredSizes() {
            doReset
= true;
       
}

       
/**
         * Resets the size of the Component at the passed in location.
         */

       
protected void resetSizeAt(int index) {
            sizes
[index] = 0;
            doReset
= true;
       
}


       
/**
         * Sets the sizes to <code>newSizes</code>.
         */

       
protected void setSizes(int[] newSizes) {
           
System.arraycopy(newSizes, 0, sizes, 0, 3);
       
}


       
/**
         * Returns the sizes of the components.
         */

       
protected int[] getSizes() {
           
int[]         retSizes = new int[3];

           
System.arraycopy(sizes, 0, retSizes, 0, 3);
           
return retSizes;
       
}


       
/**
         * Returns the width of the passed in Components preferred size.
         */

       
protected int getPreferredSizeOfComponent(Component c) {
           
return getSizeForPrimaryAxis(c.getPreferredSize());
       
}


       
/**
         * Returns the width of the passed in Components minimum size.
         */

       
int getMinimumSizeOfComponent(Component c) {
           
return getSizeForPrimaryAxis(c.getMinimumSize());
       
}


       
/**
         * Returns the width of the passed in component.
         */

       
protected int getSizeOfComponent(Component c) {
           
return getSizeForPrimaryAxis(c.getSize());
       
}


       
/**
         * Returns the available width based on the container size and
         * Insets.
         */

       
protected int getAvailableSize(Dimension containerSize,
                                       
Insets insets) {
           
if(insets == null)
               
return getSizeForPrimaryAxis(containerSize);
           
return (getSizeForPrimaryAxis(containerSize) -
                   
(getSizeForPrimaryAxis(insets, true) +
                     getSizeForPrimaryAxis
(insets, false)));
       
}


       
/**
         * Returns the left inset, unless the Insets are null in which case
         * 0 is returned.
         */

       
protected int getInitialLocation(Insets insets) {
           
if(insets != null)
               
return getSizeForPrimaryAxis(insets, true);
           
return 0;
       
}


       
/**
         * Sets the width of the component c to be size, placing its
         * x location at location, y to the insets.top and height
         * to the containersize.height less the top and bottom insets.
         */

       
protected void setComponentToSize(Component c, int size,
                                         
int location, Insets insets,
                                         
Dimension containerSize) {
           
if(insets != null) {
               
if (axis == 0) {
                    c
.setBounds(location, insets.top, size,
                                containerSize
.height -
                               
(insets.top + insets.bottom));
               
}
               
else {
                    c
.setBounds(insets.left, location, containerSize.width -
                               
(insets.left + insets.right), size);
               
}
           
}
           
else {
               
if (axis == 0) {
                    c
.setBounds(location, 0, size, containerSize.height);
               
}
               
else {
                    c
.setBounds(0, location, containerSize.width, size);
               
}
           
}
       
}

       
/**
         * If the axis == 0, the width is returned, otherwise the height.
         */

       
int getSizeForPrimaryAxis(Dimension size) {
           
if (axis == 0) {
               
return size.width;
           
}
           
return size.height;
       
}

       
/**
         * If the axis == 0, the width is returned, otherwise the height.
         */

       
int getSizeForSecondaryAxis(Dimension size) {
           
if (axis == 0) {
               
return size.height;
           
}
           
return size.width;
       
}

       
/**
         * Returns a particular value of the inset identified by the
         * axis and <code>isTop</code><p>
         *   axis isTop
         *    0    true    - left
         *    0    false   - right
         *    1    true    - top
         *    1    false   - bottom
         */

       
int getSizeForPrimaryAxis(Insets insets, boolean isTop) {
           
if (axis == 0) {
               
if (isTop) {
                   
return insets.left;
               
}
               
return insets.right;
           
}
           
if (isTop) {
               
return insets.top;
           
}
           
return insets.bottom;
       
}

       
/**
         * Returns a particular value of the inset identified by the
         * axis and <code>isTop</code><p>
         *   axis isTop
         *    0    true    - left
         *    0    false   - right
         *    1    true    - top
         *    1    false   - bottom
         */

       
int getSizeForSecondaryAxis(Insets insets, boolean isTop) {
           
if (axis == 0) {
               
if (isTop) {
                   
return insets.top;
               
}
               
return insets.bottom;
           
}
           
if (isTop) {
               
return insets.left;
           
}
           
return insets.right;
       
}

       
/**
         * Determines the components. This should be called whenever
         * a new instance of this is installed into an existing
         * SplitPane.
         */

       
protected void updateComponents() {
           
Component comp;

            comp
= splitPane.getLeftComponent();
           
if(components[0] != comp) {
                components
[0] = comp;
               
if(comp == null) {
                    sizes
[0] = 0;
               
} else {
                    sizes
[0] = -1;
               
}
           
}

            comp
= splitPane.getRightComponent();
           
if(components[1] != comp) {
                components
[1] = comp;
               
if(comp == null) {
                    sizes
[1] = 0;
               
} else {
                    sizes
[1] = -1;
               
}
           
}

           
/* Find the divider. */
           
Component[] children = splitPane.getComponents();
           
Component   oldDivider = components[2];

            components
[2] = null;
           
for(int counter = children.length - 1; counter >= 0; counter--) {
               
if(children[counter] != components[0] &&
                   children
[counter] != components[1] &&
                   children
[counter] != nonContinuousLayoutDivider) {
                   
if(oldDivider != children[counter]) {
                        components
[2] = children[counter];
                   
} else {
                        components
[2] = oldDivider;
                   
}
                   
break;
               
}
           
}
           
if(components[2] == null) {
                sizes
[2] = 0;
           
}
           
else {
                sizes
[2] = getSizeForPrimaryAxis(components[2].getPreferredSize());
           
}
       
}

       
/**
         * Resets the size of the first component to <code>leftSize</code>,
         * and the right component to the remainder of the space.
         */

       
void setDividerLocation(int leftSize, int availableSize) {
           
boolean          lValid = (components[0] != null &&
                                       components
[0].isVisible());
           
boolean          rValid = (components[1] != null &&
                                       components
[1].isVisible());
           
boolean          dValid = (components[2] != null &&
                                       components
[2].isVisible());
           
int              max = availableSize;

           
if (dValid) {
                max
-= sizes[2];
           
}
            leftSize
= Math.max(0, Math.min(leftSize, max));
           
if (lValid) {
               
if (rValid) {
                    sizes
[0] = leftSize;
                    sizes
[1] = max - leftSize;
               
}
               
else {
                    sizes
[0] = max;
                    sizes
[1] = 0;
               
}
           
}
           
else if (rValid) {
                sizes
[1] = max;
                sizes
[0] = 0;
           
}
       
}

       
/**
         * Returns an array of the minimum sizes of the components.
         */

       
int[] getPreferredSizes() {
           
int[]         retValue = new int[3];

           
for (int counter = 0; counter < 3; counter++) {
               
if (components[counter] != null &&
                    components
[counter].isVisible()) {
                    retValue
[counter] = getPreferredSizeOfComponent
                                       
(components[counter]);
               
}
               
else {
                    retValue
[counter] = -1;
               
}
           
}
           
return retValue;
       
}

       
/**
         * Returns an array of the minimum sizes of the components.
         */

       
int[] getMinimumSizes() {
           
int[]         retValue = new int[3];

           
for (int counter = 0; counter < 2; counter++) {
               
if (components[counter] != null &&
                    components
[counter].isVisible()) {
                    retValue
[counter] = getMinimumSizeOfComponent
                                       
(components[counter]);
               
}
               
else {
                    retValue
[counter] = -1;
               
}
           
}
            retValue
[2] = (components[2] != null) ?
                getMinimumSizeOfComponent
(components[2]) : -1;
           
return retValue;
       
}

       
/**
         * Resets the components to their preferred sizes.
         */

       
void resetToPreferredSizes(int availableSize) {
           
// Set the sizes to the preferred sizes (if fits), otherwise
           
// set to min sizes and distribute any extra space.
           
int[]       testSizes = getPreferredSizes();
           
int         totalSize = 0;

           
for (int counter = 0; counter < 3; counter++) {
               
if (testSizes[counter] != -1) {
                    totalSize
+= testSizes[counter];
               
}
           
}
           
if (totalSize > availableSize) {
                testSizes
= getMinimumSizes();

                totalSize
= 0;
               
for (int counter = 0; counter < 3; counter++) {
                   
if (testSizes[counter] != -1) {
                        totalSize
+= testSizes[counter];
                   
}
               
}
           
}
            setSizes
(testSizes);
            distributeSpace
(availableSize - totalSize, false);
       
}

       
/**
         * Distributes <code>space</code> between the two components
         * (divider won't get any extra space) based on the weighting. This
         * attempts to honor the min size of the components.
         *
         * @param keepHidden if true and one of the components is 0x0
         *                   it gets none of the extra space
         */

       
void distributeSpace(int space, boolean keepHidden) {
           
boolean          lValid = (components[0] != null &&
                                       components
[0].isVisible());
           
boolean          rValid = (components[1] != null &&
                                       components
[1].isVisible());

           
if (keepHidden) {
               
if (lValid && getSizeForPrimaryAxis(
                                 components
[0].getSize()) == 0) {
                    lValid
= false;
                   
if (rValid && getSizeForPrimaryAxis(
                                     components
[1].getSize()) == 0) {
                       
// Both aren't valid, force them both to be valid
                        lValid
= true;
                   
}
               
}
               
else if (rValid && getSizeForPrimaryAxis(
                                   components
[1].getSize()) == 0) {
                    rValid
= false;
               
}
           
}
           
if (lValid && rValid) {
               
double        weight = splitPane.getResizeWeight();
               
int           lExtra = (int)(weight * (double)space);
               
int           rExtra = (space - lExtra);

                sizes
[0] += lExtra;
                sizes
[1] += rExtra;

               
int           lMin = getMinimumSizeOfComponent(components[0]);
               
int           rMin = getMinimumSizeOfComponent(components[1]);
               
boolean       lMinValid = (sizes[0] >= lMin);
               
boolean       rMinValid = (sizes[1] >= rMin);

               
if (!lMinValid && !rMinValid) {
                   
if (sizes[0] < 0) {
                        sizes
[1] += sizes[0];
                        sizes
[0] = 0;
                   
}
                   
else if (sizes[1] < 0) {
                        sizes
[0] += sizes[1];
                        sizes
[1] = 0;
                   
}
               
}
               
else if (!lMinValid) {
                   
if (sizes[1] - (lMin - sizes[0]) < rMin) {
                       
// both below min, just make sure > 0
                       
if (sizes[0] < 0) {
                            sizes
[1] += sizes[0];
                            sizes
[0] = 0;
                       
}
                   
}
                   
else {
                        sizes
[1] -= (lMin - sizes[0]);
                        sizes
[0] = lMin;
                   
}
               
}
               
else if (!rMinValid) {
                   
if (sizes[0] - (rMin - sizes[1]) < lMin) {
                       
// both below min, just make sure > 0
                       
if (sizes[1] < 0) {
                            sizes
[0] += sizes[1];
                            sizes
[1] = 0;
                       
}
                   
}
                   
else {
                        sizes
[0] -= (rMin - sizes[1]);
                        sizes
[1] = rMin;
                   
}
               
}
               
if (sizes[0] < 0) {
                    sizes
[0] = 0;
               
}
               
if (sizes[1] < 0) {
                    sizes
[1] = 0;
               
}
           
}
           
else if (lValid) {
                sizes
[0] = Math.max(0, sizes[0] + space);
           
}
           
else if (rValid) {
                sizes
[1] = Math.max(0, sizes[1] + space);
           
}
       
}
   
}


   
/**
     * LayoutManager used for JSplitPanes with an orientation of
     * VERTICAL_SPLIT.
     * <p>
     */

   
public class BasicVerticalLayoutManager extends
           
BasicHorizontalLayoutManager
   
{
       
public BasicVerticalLayoutManager() {
           
super(1);
       
}
   
}


   
private class Handler implements FocusListener, PropertyChangeListener {
       
//
       
// PropertyChangeListener
       
//
       
/**
         * Messaged from the <code>JSplitPane</code> the receiver is
         * contained in.  May potentially reset the layout manager and cause a
         * <code>validate</code> to be sent.
         */

       
public void propertyChange(PropertyChangeEvent e) {
           
if(e.getSource() == splitPane) {
               
String changeName = e.getPropertyName();

               
if(changeName == JSplitPane.ORIENTATION_PROPERTY) {
                    orientation
= splitPane.getOrientation();
                    resetLayoutManager
();
               
} else if(changeName == JSplitPane.CONTINUOUS_LAYOUT_PROPERTY){
                    setContinuousLayout
(splitPane.isContinuousLayout());
                   
if(!isContinuousLayout()) {
                       
if(nonContinuousLayoutDivider == null) {
                            setNonContinuousLayoutDivider
(
                                createDefaultNonContinuousLayoutDivider
(),
                               
true);
                       
} else if(nonContinuousLayoutDivider.getParent() ==
                                 
null) {
                            setNonContinuousLayoutDivider
(
                                nonContinuousLayoutDivider
,
                               
true);
                       
}
                   
}
               
} else if(changeName == JSplitPane.DIVIDER_SIZE_PROPERTY){
                    divider
.setDividerSize(splitPane.getDividerSize());
                    dividerSize
= divider.getDividerSize();
                    splitPane
.revalidate();
                    splitPane
.repaint();
               
}
           
}
       
}

       
//
       
// FocusListener
       
//
       
public void focusGained(FocusEvent ev) {
            dividerKeyboardResize
= true;
            splitPane
.repaint();
       
}

       
public void focusLost(FocusEvent ev) {
            dividerKeyboardResize
= false;
            splitPane
.repaint();
       
}
   
}


   
private static class Actions extends UIAction {
       
private static final String NEGATIVE_INCREMENT = "negativeIncrement";
       
private static final String POSITIVE_INCREMENT = "positiveIncrement";
       
private static final String SELECT_MIN = "selectMin";
       
private static final String SELECT_MAX = "selectMax";
       
private static final String START_RESIZE = "startResize";
       
private static final String TOGGLE_FOCUS = "toggleFocus";
       
private static final String FOCUS_OUT_FORWARD = "focusOutForward";
       
private static final String FOCUS_OUT_BACKWARD = "focusOutBackward";

       
Actions(String key) {
           
super(key);
       
}

       
public void actionPerformed(ActionEvent ev) {
           
JSplitPane splitPane = (JSplitPane)ev.getSource();
           
BasicSplitPaneUI ui = (BasicSplitPaneUI)BasicLookAndFeel.
                      getUIOfType
(splitPane.getUI(), BasicSplitPaneUI.class);

           
if (ui == null) {
               
return;
           
}
           
String key = getName();
           
if (key == NEGATIVE_INCREMENT) {
               
if (ui.dividerKeyboardResize) {
                    splitPane
.setDividerLocation(Math.max(
                             
0, ui.getDividerLocation
                             
(splitPane) - ui.getKeyboardMoveIncrement()));
               
}
           
}
           
else if (key == POSITIVE_INCREMENT) {
               
if (ui.dividerKeyboardResize) {
                    splitPane
.setDividerLocation(
                        ui
.getDividerLocation(splitPane) +
                        ui
.getKeyboardMoveIncrement());
               
}
           
}
           
else if (key == SELECT_MIN) {
               
if (ui.dividerKeyboardResize) {
                    splitPane
.setDividerLocation(0);
               
}
           
}
           
else if (key == SELECT_MAX) {
               
if (ui.dividerKeyboardResize) {
                   
Insets   insets = splitPane.getInsets();
                   
int      bottomI = (insets != null) ? insets.bottom : 0;
                   
int      rightI = (insets != null) ? insets.right : 0;

                   
if (ui.orientation == JSplitPane.VERTICAL_SPLIT) {
                        splitPane
.setDividerLocation(splitPane.getHeight() -
                                                     bottomI
);
                   
}
                   
else {
                        splitPane
.setDividerLocation(splitPane.getWidth() -
                                                     rightI
);
                   
}
               
}
           
}
           
else if (key == START_RESIZE) {
               
if (!ui.dividerKeyboardResize) {
                    splitPane
.requestFocus();
               
} else {
                   
JSplitPane parentSplitPane =
                       
(JSplitPane)SwingUtilities.getAncestorOfClass(
                                         
JSplitPane.class, splitPane);
                   
if (parentSplitPane!=null) {
                        parentSplitPane
.requestFocus();
                   
}
               
}
           
}
           
else if (key == TOGGLE_FOCUS) {
                toggleFocus
(splitPane);
           
}
           
else if (key == FOCUS_OUT_FORWARD) {
                moveFocus
(splitPane, 1);
           
}
           
else if (key == FOCUS_OUT_BACKWARD) {
                moveFocus
(splitPane, -1);
           
}
       
}

       
private void moveFocus(JSplitPane splitPane, int direction) {
           
Container rootAncestor = splitPane.getFocusCycleRootAncestor();
           
FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
           
Component focusOn = (direction > 0) ?
                policy
.getComponentAfter(rootAncestor, splitPane) :
                policy
.getComponentBefore(rootAncestor, splitPane);
           
HashSet focusFrom = new HashSet();
           
if (splitPane.isAncestorOf(focusOn)) {
               
do {
                    focusFrom
.add(focusOn);
                    rootAncestor
= focusOn.getFocusCycleRootAncestor();
                    policy
= rootAncestor.getFocusTraversalPolicy();
                    focusOn
= (direction > 0) ?
                        policy
.getComponentAfter(rootAncestor, focusOn) :
                        policy
.getComponentBefore(rootAncestor, focusOn);
               
} while (splitPane.isAncestorOf(focusOn) &&
                         
!focusFrom.contains(focusOn));
           
}
           
if ( focusOn!=null && !splitPane.isAncestorOf(focusOn) ) {
                focusOn
.requestFocus();
           
}
       
}

       
private void toggleFocus(JSplitPane splitPane) {
           
Component left = splitPane.getLeftComponent();
           
Component right = splitPane.getRightComponent();

           
KeyboardFocusManager manager =
               
KeyboardFocusManager.getCurrentKeyboardFocusManager();
           
Component focus = manager.getFocusOwner();
           
Component focusOn = getNextSide(splitPane, focus);
           
if (focusOn != null) {
               
// don't change the focus if the new focused component belongs
               
// to the same splitpane and the same side
               
if ( focus!=null &&
                     
( (SwingUtilities.isDescendingFrom(focus, left) &&
                       
SwingUtilities.isDescendingFrom(focusOn, left)) ||
                       
(SwingUtilities.isDescendingFrom(focus, right) &&
                       
SwingUtilities.isDescendingFrom(focusOn, right)) ) ) {
                   
return;
               
}
               
SwingUtilities2.compositeRequestFocus(focusOn);
           
}
       
}

       
private Component getNextSide(JSplitPane splitPane, Component focus) {
           
Component left = splitPane.getLeftComponent();
           
Component right = splitPane.getRightComponent();
           
Component next = null;
           
if (focus!=null && SwingUtilities.isDescendingFrom(focus, left) &&
                right
!=null) {
               
next = getFirstAvailableComponent(right);
               
if (next != null) {
                   
return next;
               
}
           
}
           
JSplitPane parentSplitPane = (JSplitPane)SwingUtilities.getAncestorOfClass(JSplitPane.class, splitPane);
           
if (parentSplitPane!=null) {
               
// focus next side of the parent split pane
               
next = getNextSide(parentSplitPane, focus);
           
} else {
               
next = getFirstAvailableComponent(left);
               
if (next == null) {
                   
next = getFirstAvailableComponent(right);
               
}
           
}
           
return next;
       
}

       
private Component getFirstAvailableComponent(Component c) {
           
if (c!=null && c instanceof JSplitPane) {
               
JSplitPane sp = (JSplitPane)c;
               
Component left = getFirstAvailableComponent(sp.getLeftComponent());
               
if (left != null) {
                    c
= left;
               
} else {
                    c
= getFirstAvailableComponent(sp.getRightComponent());
               
}
           
}
           
return c;
       
}
   
}
}