This fixes the oneTouchExpandable support for JSplitPane in the Basic and Metal L&F.

2006-08-14  Roman Kennke  <[EMAIL PROTECTED]>

        PR 28693
        * javax/swing/plaf/basic/BasicSplitPaneDivider.java
        (BasicOneTouchButton): New inner class.
        (DividerLayout.changeButtonOrientation): Removed.
        (DividerLayout.positionButtons): Moved into layoutContainer.
        (DividerLayout.layoutContainer): Reworked for correct layout.
        (OneTouchAction): New inner class.
        (centerOneTouchButtons): New field.
        (BasicSplitPaneDivider): Initialize centerOneTouchButton from
        UIManager.
        (createLeftOneTouchButton): Reimplemented to return
        BasicOneTouchButton.
        (createRightOneTouchButton): Reimplemented to return
        BasicOneTouchButton.
        (getPreferredSize): Reimplemented to return fixed preferredSize.
        (oneTouchExpandableChanged): Add OneTouchAction action to
        buttons. Don't install mouse listeners.
        (MouseHandler.mousePressed): Removed handling of one touch buttons.
        (paint): Don't trigger extra paint for buttons.
        (propertyChange): Revalidate splitPane when orientation is changed.
        (setBasicSplitPaneUI): Call oneTouchExpandableChanged only when
        oneTouchExpandable is true.
        * javax/swing/plaf/basic/BasicSplitPaneUI.java
        (installDefaults): Install dividerSize on the divider too.
        * javax/swing/plaf/metal/MetalSplitPaneDivider.java
        (MetalDividerLayout): Removed. Functionality is already
        in BasicSplitPaneDivider.DividerLayout.
        (MetalOneTouchButton): New inner class.
        (BUTTON_SPRITE): New constant field.
        (MetalSplitPaneDivider): Don't change layout.
        (createLeftOneTouchButton): Overridden to return custom button
        for Metal.
        (createRightOneTouchButton): Overridden to return custom button
        for Metal.
        (paint): Don't trigger button painting. Call super instead.

/Roman
Index: javax/swing/plaf/basic/BasicSplitPaneDivider.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java,v
retrieving revision 1.15
diff -u -1 -2 -r1.15 BasicSplitPaneDivider.java
--- javax/swing/plaf/basic/BasicSplitPaneDivider.java	14 Feb 2006 22:44:53 -0000	1.15
+++ javax/swing/plaf/basic/BasicSplitPaneDivider.java	14 Aug 2006 13:36:46 -0000
@@ -29,58 +29,262 @@
 modules, and to copy and distribute the resulting executable under
 terms of your choice, provided that you also meet, for each linked
 independent module, the terms and conditions of the license of that
 module.  An independent module is a module which is not derived from
 or based on this library.  If you modify this library, you may extend
 this exception to your version of the library, but you are not
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing.plaf.basic;
 
+import java.awt.Color;
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.Insets;
 import java.awt.LayoutManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 
 import javax.swing.JButton;
 import javax.swing.JSplitPane;
-import javax.swing.SwingConstants;
+import javax.swing.UIManager;
 import javax.swing.border.Border;
 
 /**
  * The divider that separates the two parts of a JSplitPane in the Basic look
  * and feel.
  * 
  * <p>
  * Implementation status: We do not have a real implementation yet. Currently,
  * it is mostly a stub to allow compiling other parts of the
  * javax.swing.plaf.basic package, although some parts are already
  * functional.
  * </p>
  *
  * @author Sascha Brawer (brawer_AT_dandelis.ch)
  */
 public class BasicSplitPaneDivider extends Container
   implements PropertyChangeListener
 {
   /**
+   * The buttons used as one touch buttons.
+   */
+  private class BasicOneTouchButton
+    extends JButton
+  {
+    /**
+     * Denotes a left button.
+     */
+    static final int LEFT = 0;
+
+    /**
+     * Denotes a right button.
+     */
+    static final int RIGHT = 1;
+
+    /**
+     * The x points for the arrow.
+     */
+    private int[] xpoints;
+
+    /**
+     * The y points for the arrow.
+     */
+    private int[] ypoints;
+
+    /**
+     * Either LEFT or RIGHT.
+     */
+    private int direction;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param dir either LEFT or RIGHT
+     */
+    BasicOneTouchButton(int dir)
+    {
+      direction = dir;
+      xpoints = new int[3];
+      ypoints = new int[3];
+    }
+
+    /**
+     * Never allow borders.
+     */
+    public void setBorder(Border b)
+    {
+    }
+
+    /**
+     * Never allow focus traversal.
+     */
+    public boolean isFocusTraversable()
+    {
+      return false;
+    }
+
+    /**
+     * Paints the one touch button.
+     */
+    public void paint(Graphics g)
+    {
+      if (splitPane != null)
+	{
+	  // Fill background.
+	  g.setColor(splitPane.getBackground());
+	  g.fillRect(0, 0, getWidth(), getHeight());
+
+	  // Draw arrow.
+	  int size;
+	  if (direction == LEFT)
+	    {
+	      if (orientation == JSplitPane.VERTICAL_SPLIT)
+		{
+		  size = Math.min(getHeight(), ONE_TOUCH_SIZE);
+		  xpoints[0] = 0;
+		  xpoints[1] = size / 2;
+		  xpoints[2] = size;
+		  ypoints[0] = size;
+		  ypoints[1] = 0;
+		  ypoints[2] = size;
+		}
+	      else
+		{
+		  size = Math.min(getWidth(), ONE_TOUCH_SIZE);
+		  xpoints[0] = size;
+		  xpoints[1] = 0;
+		  xpoints[2] = size;
+		  ypoints[0] = 0;
+		  ypoints[1] = size / 2;
+		  ypoints[2] = size;
+		}
+	    }
+	  else
+	    {
+	      if (orientation == JSplitPane.VERTICAL_SPLIT)
+		{
+		  size = Math.min(getHeight(), ONE_TOUCH_SIZE);
+		  xpoints[0] = 0;
+		  xpoints[1] = size / 2;
+		  xpoints[2] = size;
+		  ypoints[0] = 0;
+		  ypoints[1] = size;
+		  ypoints[2] = 0;
+		}
+	      else
+		{
+		  size = Math.min(getWidth(), ONE_TOUCH_SIZE);
+		  xpoints[0] = 0;
+		  xpoints[1] = size;
+		  xpoints[2] = 0;
+		  ypoints[0] = 0;
+		  ypoints[1] = size / 2;
+		  ypoints[2] = size;
+		}
+	    }
+	  g.setColor(Color.BLACK);
+	  g.fillPolygon(xpoints, ypoints, 3);
+	}
+    }
+  }
+
+  /**
+   * Listens for actions on the one touch buttons.
+   */
+  private class OneTouchAction
+    implements ActionListener
+  {
+
+    public void actionPerformed(ActionEvent ev)
+    {
+      Insets insets = splitPane.getInsets();
+      int lastLoc = splitPane.getLastDividerLocation();
+      int currentLoc = splitPaneUI.getDividerLocation(splitPane);
+      int newLoc;
+
+      if (ev.getSource() == leftButton)
+	{
+	  if (orientation == JSplitPane.VERTICAL_SPLIT)
+	    {
+	      if (currentLoc
+		  >= splitPane.getHeight() - insets.bottom - getHeight())
+		{
+		  newLoc = Math.min(splitPane.getMaximumDividerLocation(),
+				    lastLoc);
+		}
+	      else
+		{
+		  newLoc = insets.top;
+		}
+	    }
+	  else
+	    {
+	      if (currentLoc
+		  >= splitPane.getWidth() - insets.right - getWidth())
+		{
+		  newLoc = Math.min(splitPane.getMaximumDividerLocation(),
+				    lastLoc);
+		}
+	      else
+		{
+		  newLoc = insets.left;
+		}
+	    }
+	}
+      else
+	{
+	  if (orientation == JSplitPane.VERTICAL_SPLIT)
+	    {
+	      if (currentLoc == insets.top)
+		{
+		  newLoc = Math.min(splitPane.getMaximumDividerLocation(),
+				    lastLoc);
+		}
+	      else
+		{
+		  newLoc = splitPane.getHeight() - insets.top - getHeight();
+		}
+	    }
+	  else
+	    {
+	      if (currentLoc == insets.left)
+		{
+		  newLoc = Math.min(splitPane.getMaximumDividerLocation(),
+				    lastLoc);
+		}
+	      else
+		{
+		  newLoc = splitPane.getWidth() - insets.left - getWidth();
+		}
+	    }
+	}
+      if (currentLoc != newLoc)
+	{
+	  splitPane.setDividerLocation(newLoc);
+	  splitPane.setLastDividerLocation(currentLoc);
+	}
+    }
+  }
+
+  /**
    * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1
    * on MacOS X 10.1.5.
    */
   static final long serialVersionUID = 1463404307042803342L;
 
   /**
    * The width and height of the little buttons for showing and hiding parts
    * of a JSplitPane in a single mouse click.
    */
   protected static final int ONE_TOUCH_SIZE = 6;
 
   /** The distance the one touch buttons will sit from the divider's edges. */
@@ -152,33 +356,43 @@
   // This int should be able to take 3 values.
   // left (top), middle, right(bottom)
   //    0          1          2
 
   /**
    * Keeps track of where the divider should be placed when using one touch
    * expand buttons.
    * This is package-private to avoid an accessor method.
    */
   transient int currentDividerLocation = 1;
 
   /**
+   * Indicates if the ont touch buttons are laid out centered or at the
+   * top/left.
+   *
+   * Package private to avoid accessor method.
+   */
+  boolean centerOneTouchButtons;
+
+  /**
    * Constructs a new divider.
    *
    * @param ui the UI delegate of the enclosing <code>JSplitPane</code>.
    */
   public BasicSplitPaneDivider(BasicSplitPaneUI ui)
   {
     setLayout(new DividerLayout());
     setBasicSplitPaneUI(ui);
     setDividerSize(splitPane.getDividerSize());
+    centerOneTouchButtons =
+      UIManager.getBoolean("SplitPane.centerOneTouchButtons");
   }
 
   /**
    * Sets the delegate object that is responsible for the UI of the [EMAIL PROTECTED]
    * javax.swing.JSplitPane} containing this divider.
    *
    * @param newUI the UI delegate, or <code>null</code> to release the
    *        connection to the current delegate.
    */
   public void setBasicSplitPaneUI(BasicSplitPaneUI newUI)
   {
     /* Remove the connection to the existing JSplitPane. */
@@ -193,25 +407,26 @@
 
     /* Establish the connection to the new JSplitPane. */
     splitPaneUI = newUI;
     if (splitPaneUI != null)
       splitPane = newUI.getSplitPane();
     if (splitPane != null)
       {
 	splitPane.addPropertyChangeListener(this);
 	addMouseListener(mouseHandler);
 	addMouseMotionListener(mouseHandler);
 	hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider();
 	orientation = splitPane.getOrientation();
-	oneTouchExpandableChanged();
+        if (splitPane.isOneTouchExpandable())
+          oneTouchExpandableChanged();
       }
   }
 
   /**
    * Returns the delegate object that is responsible for the UI of the [EMAIL PROTECTED]
    * javax.swing.JSplitPane} containing this divider.
    *
    * @return The UI for the JSplitPane.
    */
   public BasicSplitPaneUI getBasicSplitPaneUI()
   {
     return splitPaneUI;
@@ -284,25 +499,30 @@
     else
       return super.getInsets();
   }
 
   /**
    * Returns the preferred size of this divider, which is
    * <code>dividerSize</code> by <code>dividerSize</code> pixels.
    *
    * @return The preferred size of the divider.
    */
   public Dimension getPreferredSize()
   {
-    return getLayout().preferredLayoutSize(this);
+    Dimension d;
+    if (orientation == JSplitPane.HORIZONTAL_SPLIT)
+      d = new Dimension(getDividerSize(), 1);
+    else
+      d = new Dimension(1, getDividerSize());
+    return d;
   }
 
   /**
    * Returns the minimal size of this divider, which is
    * <code>dividerSize</code> by <code>dividerSize</code> pixels.
    *
    * @return The minimal size of the divider.
    */
   public Dimension getMinimumSize()
   {
     return getPreferredSize();
   }
@@ -311,122 +531,102 @@
    * Processes events from the <code>JSplitPane</code> that contains this
    * divider.
    *
    * @param e The PropertyChangeEvent.
    */
   public void propertyChange(PropertyChangeEvent e)
   {
     if (e.getPropertyName().equals(JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY))
       oneTouchExpandableChanged();
     else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY))
       {
 	orientation = splitPane.getOrientation();
-	if (splitPane.isOneTouchExpandable())
-	  {
-	    layout();
-	    repaint();
-	  }
+        invalidate();
+        if (splitPane != null)
+          splitPane.revalidate();
       }
     else if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY))
       dividerSize = splitPane.getDividerSize();
   }
 
   /**
    * Paints the divider by painting its border.
    *
    * @param g The Graphics Object to paint with.
    */
   public void paint(Graphics g)
   {
     Dimension dividerSize;
 
     super.paint(g);
     if (border != null)
       {
 	dividerSize = getSize();
 	border.paintBorder(this, g, 0, 0, dividerSize.width, dividerSize.height);
       }
-    if (splitPane.isOneTouchExpandable())
-      {
-        ((BasicArrowButton) rightButton).paint(g);
-        ((BasicArrowButton) leftButton).paint(g);
-      }
   }
 
   /**
    * Reacts to changes of the <code>oneToughExpandable</code> property of the
    * containing <code>JSplitPane</code>.
    */
   protected void oneTouchExpandableChanged()
   {
     if (splitPane.isOneTouchExpandable())
       {
 	leftButton = createLeftOneTouchButton();
-	rightButton = createRightOneTouchButton();
-	add(leftButton);
-	add(rightButton);
+	if (leftButton != null)
+	  leftButton.addActionListener(new OneTouchAction());
 
-	leftButton.addMouseListener(mouseHandler);
-	rightButton.addMouseListener(mouseHandler);
+	rightButton = createRightOneTouchButton();
+	if (rightButton != null)
+	  rightButton.addActionListener(new OneTouchAction());
 
-	// Set it to 1.
-	currentDividerLocation = 1;
-      }
-    else
-      {
+	// Only add them when both are non-null.
 	if (leftButton != null && rightButton != null)
-	  {
-	    leftButton.removeMouseListener(mouseHandler);
-	    rightButton.removeMouseListener(mouseHandler);
-
-	    remove(leftButton);
-	    remove(rightButton);
-	    leftButton = null;
-	    rightButton = null;
+          {
+            add(leftButton);
+            add(rightButton);
 	  }
       }
-    layout();
-    repaint();
+    invalidate();
+    if (splitPane != null)
+      splitPane.revalidate();
   }
 
   /**
    * Creates a button for showing and hiding the left (or top) part of a
    * <code>JSplitPane</code>.
    *
    * @return The left one touch button.
    */
   protected JButton createLeftOneTouchButton()
   {
-    int dir = SwingConstants.WEST;
-    if (orientation == JSplitPane.VERTICAL_SPLIT)
-      dir = SwingConstants.NORTH;
-    JButton button = new BasicArrowButton(dir);
-    button.setBorder(null);
-
+    JButton button = new BasicOneTouchButton(BasicOneTouchButton.LEFT);
+    button.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE));
+    button.setRequestFocusEnabled(false);
     return button;
   }
 
   /**
    * Creates a button for showing and hiding the right (or bottom) part of a
    * <code>JSplitPane</code>.
    *
    * @return The right one touch button.
    */
   protected JButton createRightOneTouchButton()
   {
-    int dir = SwingConstants.EAST;
-    if (orientation == JSplitPane.VERTICAL_SPLIT)
-      dir = SwingConstants.SOUTH;
-    JButton button = new BasicArrowButton(dir);
-    button.setBorder(null);
+    JButton button = new BasicOneTouchButton(BasicOneTouchButton.RIGHT);
+    button.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE));
+    button.setRequestFocusEnabled(false);
     return button;
   }
 
   /**
    * Prepares the divider for dragging by calling the
    * <code>startDragging</code> method of the UI delegate of the enclosing
    * <code>JSplitPane</code>.
    *
    * @see BasicSplitPaneUI#startDragging()
    */
   protected void prepareForDragging()
   {
@@ -512,43 +712,24 @@
     implements MouseMotionListener
   {
     /** Keeps track of whether a drag is occurring. */
     private transient boolean isDragging;
 
     /**
      * This method is called when the mouse is pressed.
      *
      * @param e The MouseEvent.
      */
     public void mousePressed(MouseEvent e)
     {
-      if (splitPane.isOneTouchExpandable())
-        {
-	  if (e.getSource() == leftButton)
-	    {
-	      currentDividerLocation--;
-	      if (currentDividerLocation < 0)
-		currentDividerLocation = 0;
-	      moveDividerTo(currentDividerLocation);
-	      return;
-	    }
-	  else if (e.getSource() == rightButton)
-	    {
-	      currentDividerLocation++;
-	      if (currentDividerLocation > 2)
-		currentDividerLocation = 2;
-	      moveDividerTo(currentDividerLocation);
-	      return;
-	    }
-        }
       isDragging = true;
       currentDividerLocation = 1;
       if (orientation == JSplitPane.HORIZONTAL_SPLIT)
 	dragger = new DragController(e);
       else
 	dragger = new VerticalDragController(e);
       prepareForDragging();
     }
 
     /**
      * This method is called when the mouse is released.
      *
@@ -788,28 +969,83 @@
     public void addLayoutComponent(String string, Component c)
     {
       // Do nothing.
     }
 
     /**
      * This method is called to lay out the container.
      *
      * @param c The container to lay out.
      */
     public void layoutContainer(Container c)
     {
-      if (splitPane.isOneTouchExpandable())
+      if (leftButton != null && rightButton != null
+          && c == BasicSplitPaneDivider.this)
         {
-	  changeButtonOrientation();
-	  positionButtons();
+          if (splitPane.isOneTouchExpandable())
+            {
+              Insets insets = getInsets();
+              if (orientation == JSplitPane.HORIZONTAL_SPLIT)
+                {
+                  int size = getWidth() - insets.left - insets.right;
+                  size = Math.max(size, 0);
+                  size = Math.min(size, ONE_TOUCH_SIZE);
+                  int x, y;
+                  if (centerOneTouchButtons)
+                    {
+                      y = insets.top;
+                      x = (getWidth() - size) / 2;
+                    }
+                  else
+                    {
+                      x = insets.left;
+                      y = 0;
+                    }
+                  
+                  leftButton.setBounds(x, y + ONE_TOUCH_OFFSET, size,
+                                       size * 2);
+                  rightButton.setBounds(x, y + ONE_TOUCH_OFFSET
+                                        + ONE_TOUCH_SIZE * 2, size, size * 2);
+                  System.err.println("leftButton:" + leftButton.getBounds());
+                }
+              else
+                {
+                  int size = getHeight() - insets.top - insets.bottom;
+                  size = Math.max(size, 0);
+                  size = Math.min(size, ONE_TOUCH_SIZE);
+                  int x, y;
+                  if (centerOneTouchButtons)
+                    {
+                      x = insets.left;
+                      y = (getHeight() - size) / 2;
+                    }
+                  else
+                    {
+                      x = 0;
+                      y = insets.top;
+                    }
+                  leftButton.setBounds(x + ONE_TOUCH_OFFSET, y, size * 2,
+                                       size);
+                  rightButton.setBounds(x + ONE_TOUCH_OFFSET
+                                        + ONE_TOUCH_SIZE * 2, y, size * 2,
+                                        size);
+                }
+            }
+          else
+            {
+              // The JDK sets this bounds for disabled one touch buttons, so
+              // do we.
+              leftButton.setBounds(-5, -5, 1, 1);
+              rightButton.setBounds(-5, -5, 1, 1);
+            }
         }
     }
 
     /**
      * This method returns the minimum layout size.
      *
      * @param c The container to calculate for.
      *
      * @return The minimum layout size.
      */
     public Dimension minimumLayoutSize(Container c)
     {
@@ -829,59 +1065,14 @@
     }
 
     /**
      * This method is called when a component is removed.
      *
      * @param c The component to remove.
      */
     public void removeLayoutComponent(Component c)
     {
       // Do nothing.
     }
 
-    /**
-     * This method changes the button orientation when the orientation of the
-     * SplitPane changes.
-     */
-    private void changeButtonOrientation()
-    {
-      if (orientation == JSplitPane.HORIZONTAL_SPLIT)
-        {
-	  ((BasicArrowButton) rightButton).setDirection(SwingConstants.EAST);
-	  ((BasicArrowButton) leftButton).setDirection(SwingConstants.WEST);
-        }
-      else
-        {
-	  ((BasicArrowButton) rightButton).setDirection(SwingConstants.SOUTH);
-	  ((BasicArrowButton) leftButton).setDirection(SwingConstants.NORTH);
-        }
-    }
-
-    /**
-     * This method sizes and positions the buttons.
-     */
-    private void positionButtons()
-    {
-      int w = 0;
-      int h = 0;
-      if (orientation == JSplitPane.HORIZONTAL_SPLIT)
-        {
-	  rightButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET);
-	  leftButton.setLocation(ONE_TOUCH_OFFSET,
-	                         ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE);
-	  w = dividerSize - 2 * ONE_TOUCH_OFFSET;
-	  h = 2 * ONE_TOUCH_SIZE;
-        }
-      else
-        {
-	  leftButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET);
-	  rightButton.setLocation(ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE,
-	                          ONE_TOUCH_OFFSET);
-	  h = dividerSize - 2 * ONE_TOUCH_OFFSET;
-	  w = 2 * ONE_TOUCH_SIZE;
-        }
-      Dimension dims = new Dimension(w, h);
-      leftButton.setSize(dims);
-      rightButton.setSize(dims);
-    }
   }
 }
Index: javax/swing/plaf/basic/BasicSplitPaneUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java,v
retrieving revision 1.30
diff -u -1 -2 -r1.30 BasicSplitPaneUI.java
--- javax/swing/plaf/basic/BasicSplitPaneUI.java	6 Jun 2006 20:45:25 -0000	1.30
+++ javax/swing/plaf/basic/BasicSplitPaneUI.java	14 Aug 2006 13:36:46 -0000
@@ -998,26 +998,28 @@
    */
   protected void installDefaults()
   {
     LookAndFeel.installColors(splitPane, "SplitPane.background",
                               "SplitPane.foreground");
     LookAndFeel.installBorder(splitPane, "SplitPane.border");
     divider = createDefaultDivider();
     divider.setBorder(UIManager.getBorder("SplitPaneDivider.border"));
     resetLayoutManager();
     nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider();
     splitPane.add(divider, JSplitPane.DIVIDER);
 
-    // There is no need to add the nonContinuousLayoutDivider
-    splitPane.setDividerSize(UIManager.getInt("SplitPane.dividerSize"));
+    // There is no need to add the nonContinuousLayoutDivider.
+    dividerSize = UIManager.getInt("SplitPane.dividerSize");
+    splitPane.setDividerSize(dividerSize);
+    divider.setDividerSize(dividerSize);
     splitPane.setOpaque(true);
   }
 
   /**
    * This method uninstalls the defaults and nulls any objects created during
    * install.
    */
   protected void uninstallDefaults()
   {
     layoutManager = null;
     splitPane.remove(divider);
     divider = null;
Index: javax/swing/plaf/metal/MetalSplitPaneDivider.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java,v
retrieving revision 1.9
diff -u -1 -2 -r1.9 MetalSplitPaneDivider.java
--- javax/swing/plaf/metal/MetalSplitPaneDivider.java	6 Jun 2006 20:45:25 -0000	1.9
+++ javax/swing/plaf/metal/MetalSplitPaneDivider.java	14 Aug 2006 13:36:46 -0000
@@ -29,66 +29,221 @@
 modules, and to copy and distribute the resulting executable under
 terms of your choice, provided that you also meet, for each linked
 independent module, the terms and conditions of the license of that
 module.  An independent module is a module which is not derived from
 or based on this library.  If you modify this library, you may extend
 this exception to your version of the library, but you are not
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 package javax.swing.plaf.metal;
 
 import java.awt.Color;
-import java.awt.Component;
-import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.Graphics;
-import java.awt.LayoutManager;
-import java.awt.Point;
 
+import javax.swing.JButton;
 import javax.swing.JSplitPane;
-import javax.swing.SwingConstants;
 import javax.swing.UIManager;
 import javax.swing.border.Border;
-import javax.swing.plaf.basic.BasicArrowButton;
 import javax.swing.plaf.basic.BasicSplitPaneDivider;
 
 /**
  * The divider that is used by the [EMAIL PROTECTED] MetalSplitPaneUI}.
  *
  * @author Roman Kennke ([EMAIL PROTECTED])
  */
 class MetalSplitPaneDivider extends BasicSplitPaneDivider
 {
+  /**
+   * The button pixel data, as indices into the colors array below.
+   */
+  static final byte[][] BUTTON_SPRITE = {{ 0, 0, 0, 2, 2, 0, 0, 0, 0 },
+                                         { 0, 0, 2, 1, 1, 1, 0, 0, 0 },
+                                         { 0, 2, 1, 1, 1, 1, 1, 0, 0 },
+                                         { 2, 1, 1, 1, 1, 1, 1, 1, 0 },
+                                         { 0, 3, 3, 3, 3, 3, 3, 3, 3 }};
+
+  private class MetalOneTouchButton
+    extends JButton
+  {
+    /**
+     * Denotes a left button.
+     */
+    static final int LEFT = 0;
+
+    /**
+     * Denotes a right button.
+     */
+    static final int RIGHT = 1;
+
+    /**
+     * The colors for the button sprite.
+     */
+    private Color[] colors;
+
+    /**
+     * Either LEFT or RIGHT.
+     */
+    private int direction;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param dir either LEFT or RIGHT
+     */
+    MetalOneTouchButton(int dir)
+    {
+      direction = dir;
+      colors = new Color[4];
+    }
+
+    /**
+     * Never allow borders.
+     */
+    public void setBorder(Border b)
+    {
+    }
+
+    /**
+     * Never allow focus traversal.
+     */
+    public boolean isFocusTraversable()
+    {
+      return false;
+    }
+
+    /**
+     * Paints the one touch button.
+     */
+    public void paint(Graphics g)
+    {
+      if (splitPane != null)
+        {
+          // Update colors here to reflect dynamic changes to the theme.
+          colors[0] = getBackground();
+          colors[1] = MetalLookAndFeel.getPrimaryControlDarkShadow();
+          colors[2] = MetalLookAndFeel.getPrimaryControlInfo();
+          colors[3] = MetalLookAndFeel.getPrimaryControlHighlight();
+
+          // Fill background.
+          g.setColor(getBackground());
+          g.fillRect(0, 0, getWidth(), getHeight());
+
+          // Pressed buttons have slightly different color mapping.
+          if (getModel().isPressed())
+            colors[1] = colors[2];
+
+          if (direction == LEFT)
+            {
+              if (orientation == JSplitPane.VERTICAL_SPLIT)
+                {
+                  // Draw the sprite as it is.
+                  for (int y = 0; y < BUTTON_SPRITE.length; y++)
+                    {
+                      byte[] line = BUTTON_SPRITE[y];
+                      for (int x = 0; x < line.length; x++)
+                        {
+                          int c = line[x];
+                          if (c != 0)
+                            {
+                              g.setColor(colors[c]);
+                              g.fillRect(x, y, 1, 1);
+                            }
+                        }
+                    }
+                }
+              else
+                {
+                  // Draw the sprite with swapped X and Y axis.
+                  for (int y = 0; y < BUTTON_SPRITE.length; y++)
+                    {
+                      byte[] line = BUTTON_SPRITE[y];
+                      for (int x = 0; x < line.length; x++)
+                        {
+                          int c = line[x];
+                          if (c != 0)
+                            {
+                              g.setColor(colors[c]);
+                              g.fillRect(y, x, 1, 1);
+                            }
+                        }
+                    }
+                }
+            }
+          else
+            {
+              if (orientation == JSplitPane.VERTICAL_SPLIT)
+                {
+                  // Draw sprite mirrored.
+                  int ySize = BUTTON_SPRITE.length;
+                  for (int y = 0; y < ySize; y++)
+                    {
+                      byte[] line = BUTTON_SPRITE[y];
+                      int xSize = line.length;
+                      for (int x = 0; x < xSize; x++)
+                        {
+                          int c = line[x];
+                          if (c != 0)
+                            {
+                              g.setColor(colors[c]);
+                              g.fillRect(xSize - x - 1, ySize - y - 1, 1, 1);
+                            }
+                        }
+                    }
+                }
+              else
+                {
+                  // Draw sprite mirrored and X-Y-swapped.
+                  int ySize = BUTTON_SPRITE.length;
+                  for (int y = 0; y < ySize; y++)
+                    {
+                      byte[] line = BUTTON_SPRITE[y];
+                      int xSize = line.length;
+                      for (int x = 0; x < xSize; x++)
+                        {
+                          int c = line[x];
+                          if (c != 0)
+                            {
+                              g.setColor(colors[c]);
+                              g.fillRect(ySize - y - 1, xSize - x - 1, 1, 1);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+  }
+
   /** The dark color in the pattern. */
   Color dark;
 
   /** The light color in the pattern. */
   Color light;
   
   /** The JSplitPane the divider is on. */
   JSplitPane splitPane;
 
   /** The split pane orientation. */
   int orientation;
   
   /**
    * Creates a new instance of <code>MetalSplitPaneDivider</code>.
    *
    * @param ui the <code>MetalSplitPaneUI</code> that uses this divider
    */
   public MetalSplitPaneDivider(MetalSplitPaneUI ui, Color light, Color dark)
   {
     super(ui);
-    setLayout(new MetalDividerLayout());
     this.splitPane = super.splitPane;
     this.orientation = super.orientation;
     this.light = light;
     this.dark = dark;
   }
 
   /**
    * Paints the divider.
    *
    * @param g the <code>Graphics</code> context to use for painting
    */
   public void paint(Graphics g)
@@ -99,133 +254,31 @@
       {
         g.setColor(UIManager.getColor("SplitPane.dividerFocusColor"));
         g.fillRect(0, 0, s.width, s.height);
       }
     
     // Paint border if one exists.
     Border border = getBorder();
     if (border != null)
       border.paintBorder(this, g, 0, 0, s.width, s.height);
 
     MetalUtils.fillMetalPattern(splitPane, g, 2, 2, s.width - 4, s.height - 4,
                                 light, dark);
-    if (splitPane.isOneTouchExpandable())
-      {
-        ((BasicArrowButton) rightButton).paint(g);
-        ((BasicArrowButton) leftButton).paint(g);
-      }
+    super.paint(g);
   }
-  
-  /**
-   * This helper class acts as the Layout Manager for the divider.
-   */
-  public class MetalDividerLayout implements LayoutManager
-  {
-    /** The right button. */
-    BasicArrowButton rb;
-    
-    /** The left button. */
-    BasicArrowButton lb;
-    
-    /**
-     * Creates a new DividerLayout object.
-     */
-    public MetalDividerLayout()
-    {
-      // Nothing to do here
-    }
-
-    /**
-     * This method is called when a Component is added.
-     *
-     * @param string The constraints string.
-     * @param c The Component to add.
-     */
-    public void addLayoutComponent(String string, Component c)
-    {
-      // Nothing to do here, constraints are set depending on
-      // orientation in layoutContainer
-    }
-    
-    /**
-     * This method is called to lay out the container.
-     *
-     * @param c The container to lay out.
-     */
-    public void layoutContainer(Container c)
-    {
-      // The only components we care about setting up are the
-      // one touch buttons.
-      if (splitPane.isOneTouchExpandable())
-        {
-          if (c.getComponentCount() == 2)
-            {
-              Component c1 = c.getComponent(0);
-              Component c2 = c.getComponent(1);
-              if ((c1 instanceof BasicArrowButton)
-                  && (c2 instanceof BasicArrowButton))
-                {
-                  lb = (BasicArrowButton) c1;
-                  rb = (BasicArrowButton) c2;
-                }
-            }
-          if (rb != null && lb != null)
-            {
-              Point p = getLocation();
-              lb.setSize(lb.getPreferredSize());
-              rb.setSize(rb.getPreferredSize());
-              lb.setLocation(p.x, p.y);
-              
-              if (orientation == JSplitPane.HORIZONTAL_SPLIT)
-                {
-                  rb.setDirection(SwingConstants.EAST);
-                  lb.setDirection(SwingConstants.WEST);
-                  rb.setLocation(p.x, p.y + lb.getHeight());
-                }
-              else
-                {
-                  rb.setDirection(SwingConstants.SOUTH);
-                  lb.setDirection(SwingConstants.NORTH);
-                  rb.setLocation(p.x + lb.getWidth(), p.y);
-                }
-            }
-        }
-    }
-
-    /**
-     * This method returns the minimum layout size.
-     *
-     * @param c The container to calculate for.
-     *
-     * @return The minimum layout size.
-     */
-    public Dimension minimumLayoutSize(Container c)
-    {
-      return preferredLayoutSize(c);
-    }
 
-    /**
-     * This method returns the preferred layout size.
-     *
-     * @param c The container to calculate for.
-     *
-     * @return The preferred layout size.
-     */
-    public Dimension preferredLayoutSize(Container c)
-    {
-      int dividerSize = getDividerSize();
-      return new Dimension(dividerSize, dividerSize);
-    }
+  protected JButton createLeftOneTouchButton()
+  {
+    JButton b = new MetalOneTouchButton(MetalOneTouchButton.LEFT);
+    b.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE));
+    b.setRequestFocusEnabled(false);
+    return b;
+  }
 
-    /**
-     * This method is called when a component is removed.
-     *
-     * @param c The component to remove.
-     */
-    public void removeLayoutComponent(Component c)
-    {
-      // Nothing to do here. If buttons are removed
-      // they will not be layed out when layoutContainer is 
-      // called.
-    }
+  protected JButton createRightOneTouchButton()
+  {
+    JButton b = new MetalOneTouchButton(MetalOneTouchButton.RIGHT);
+    b.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE));
+    b.setRequestFocusEnabled(false);
+    return b;
   }
 }

Reply via email to