This fixes a problem where the JSplitPane doesn't correctly honour the
minimumSizes of its components. All these changes are accompanied by
Mauve tests. I know I fixed this once (see
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22952 and
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22955 ) and don't want this
to happen again.

2006-10-09  Roman Kennke  <[EMAIL PROTECTED]>

        PR 29325
        * javax/swing/JSplitPane.java
        (dividerLocation): New field. Stores the divider location.
        (JSplitPane): Initialize dividerLocation with -1.
        (addImpl): Removed unneeded local variables.
        (getDividerLocation): Manage dividerLocation in the JSplitPane
        class, not in the UI.
        (setDividerLocation): Manage dividerLocation in the JSplitPane
        class, not in the UI. Only call the UI method for notification.
        * javax/swing/plaf/basic/BasicSplitPaneUI.java
        (BasicHorizontalLayoutManager.layoutContainer): Fetch divider
        location from the JSplitPane. Honour the minimumSize, but only
        if the divider location hasn't been set explicitly.
        (BasicHorizontalLayoutManager.minimumLayoutSize): Removed
unneeded
        statement.
        (BasicHorizontalLayoutManager.preferredLayoutSize): Removed
unneeded
        statement.
        (BasicHorizontalLayoutManager.resetToPreferredSizes): Don't
touch
        the divider location.
        (dividerLocationSet): New field.
        (dividerLocation): Removed field.
        (createActionMap): Fetch and set divider location on the
JSplitPane.
        (getDividerLocation): Return the actual real divider location.
        (getMaximumSize): Removed unneeded cast.
        (getPreferredSize): Removed unneeded cast.
        (getMinimumSize): Removed unneeded cast.
        (installUI): Initialize dividerLocationSet with false.
        (uninstallUI): Initialize dividerLocationSet with false.
        (setDividerLocation): Set dividerLocationSet to true.


/Roman

Index: javax/swing/JSplitPane.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JSplitPane.java,v
retrieving revision 1.19
diff -u -1 -5 -r1.19 JSplitPane.java
--- javax/swing/JSplitPane.java	21 Jun 2006 12:39:22 -0000	1.19
+++ javax/swing/JSplitPane.java	9 Oct 2006 13:49:10 -0000
@@ -235,30 +235,35 @@
   /** The size of the divider. */
   protected int dividerSize = 10;
 
   /** The last location of the divider given by the UI. */
   protected int lastDividerLocation;
 
   /** The orientation of the JSplitPane. */
   protected int orientation;
 
   /** The component on the top or left. */
   protected Component leftComponent;
 
   /** The component on the right or bottom. */
   protected Component rightComponent;
 
+  /**
+   * The divider location.
+   */
+  private int dividerLocation;
+
   /** Determines how extra space should be allocated. */
   private transient double resizeWeight;
 
   /**
    * Indicates if the dividerSize property has been set by a client program or
    * by the UI.
    *
    * @see #setUIProperty(String, Object)
    * @see LookAndFeel#installProperty(JComponent, String, Object)
    */
   private boolean clientDividerSizeSet = false;
 
   /**
    * Indicates if the oneTouchExpandable property has been set by a client
    * program or by the UI.
@@ -276,31 +281,31 @@
    * @param newContinuousLayout The layout mode to use.
    * @param newLeftComponent The left component.
    * @param newRightComponent The right component.
    *
    * @throws IllegalArgumentException DOCUMENT ME!
    */
   public JSplitPane(int newOrientation, boolean newContinuousLayout,
                     Component newLeftComponent, Component newRightComponent)
   {
     if (newOrientation != HORIZONTAL_SPLIT && newOrientation != VERTICAL_SPLIT)
       throw new IllegalArgumentException("orientation is invalid.");
     orientation = newOrientation;
     continuousLayout = newContinuousLayout;
     setLeftComponent(newLeftComponent);
     setRightComponent(newRightComponent);
-
+    dividerLocation = -1;
     updateUI();
   }
 
   /**
    * Creates a new JSplitPane object using nonContinuousLayout mode, the given
    * orientation and left and right components.
    *
    * @param newOrientation The orientation to use.
    * @param newLeftComponent The left component.
    * @param newRightComponent The right component.
    */
   public JSplitPane(int newOrientation, Component newLeftComponent,
                     Component newRightComponent)
   {
     this(newOrientation, false, newLeftComponent, newRightComponent);
@@ -343,34 +348,30 @@
    * This method adds a component to the JSplitPane. The constraints object is
    * a string that identifies where this component should go. If the
    * constraints is not a known one, it will throw an
    * IllegalArgumentException. The valid constraints are LEFT, TOP, RIGHT,
    * BOTTOM and DIVIDER.
    *
    * @param comp The component to add.
    * @param constraints The constraints string to use.
    * @param index Where to place to component in the list of components.
    *
    * @throws IllegalArgumentException When the constraints is not a known 
    * identifier.
    */
   protected void addImpl(Component comp, Object constraints, int index)
   {
-    int left = 0;
-    int right = 1;
-    int div = 2;
-    int place;
     if (constraints == null)
       {
         if (leftComponent == null)
           constraints = LEFT;
         else if (rightComponent == null)
           constraints = RIGHT;
       }
 
     if (constraints instanceof String)
       {
         String placement = (String) constraints;
 
         if (placement.equals(BOTTOM) || placement.equals(RIGHT))
           {
             if (rightComponent != null)
@@ -419,34 +420,31 @@
    * @return The bottom component.
    */
   public Component getBottomComponent()
   {
     return rightComponent;
   }
 
   /**
    * This method returns the location of the divider. This method is passed to
    * the UI.
    *
    * @return The location of the divider.
    */
   public int getDividerLocation()
   {
-    if (ui != null)
-      return ((SplitPaneUI) ui).getDividerLocation(this);
-    else
-      return -1;
+    return dividerLocation;
   }
 
   /**
    * This method returns the size of the divider.
    *
    * @return The size of the divider.
    */
   public int getDividerSize()
   {
     return dividerSize;
   }
 
   /**
    * This method returns the last divider location.
    *
@@ -710,41 +708,37 @@
 
     int max = ((orientation == HORIZONTAL_SPLIT) ? getWidth() : getHeight())
               - getDividerSize();
     setDividerLocation((int) (proportionalLocation * max));
   }
 
   /**
    * This method sets the location of the divider.
    * 
    * @param location The location of the divider. The negative value forces to
    *          compute the new location from the preferred sizes of the split
    *          pane components.
    */
   public void setDividerLocation(int location)
   {
-    if (ui != null && location != getDividerLocation())
-      {
-        int oldLocation = getDividerLocation();        
-        if (location < 0)
-          ((SplitPaneUI) ui).resetToPreferredSizes(this);
-        else
-            ((SplitPaneUI) ui).setDividerLocation(this, location);
-        
-        firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation, 
-                           getDividerLocation());
-      }
+    int oldLocation = dividerLocation;
+    dividerLocation = location;
+    SplitPaneUI ui = getUI();
+    if (ui != null)
+      ui.setDividerLocation(this, location);
+    firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation, 
+                       location);
   }
 
   /**
    * This method sets the size of the divider.
    *
    * @param newSize The size of the divider.
    */
   public void setDividerSize(int newSize)
   {
     clientDividerSizeSet = true;
     if (newSize != dividerSize)
       {
         int oldSize = dividerSize;
         dividerSize = newSize;
         firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, dividerSize);
Index: javax/swing/plaf/basic/BasicSplitPaneUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java,v
retrieving revision 1.33
diff -u -1 -5 -r1.33 BasicSplitPaneUI.java
--- javax/swing/plaf/basic/BasicSplitPaneUI.java	1 Sep 2006 18:23:57 -0000	1.33
+++ javax/swing/plaf/basic/BasicSplitPaneUI.java	9 Oct 2006 13:49:10 -0000
@@ -308,32 +308,41 @@
     /**
      * This method lays out the components in the container.
      *
      * @param container The container to lay out.
      */
     public void layoutContainer(Container container)
     {
       if (container instanceof JSplitPane)
         {
           JSplitPane split = (JSplitPane) container;
           distributeExtraSpace();
           Insets insets = split.getInsets();
           Dimension dims = split.getSize();
           int loc = getInitialLocation(insets);
           int available = getAvailableSize(dims, insets);
-          sizes[0] = getDividerLocation(split) - loc;
+          sizes[0] = split.getDividerLocation();
           sizes[1] = available - sizes[0] - sizes[2];
+
+          // According to a Mauve test we only honour the minimum
+          // size of the components, when the dividerLocation hasn't
+          // been excplicitly set.
+          if (! dividerLocationSet)
+            {
+              sizes[0] = Math.max(sizes[0], minimumSizeOfComponent(0));
+              sizes[1] = Math.max(sizes[1], minimumSizeOfComponent(1));
+            }
           // The size of the divider won't change.
 
           // Layout component#1.
           setComponentToSize(components[0], sizes[0], loc, insets, dims);
           // Layout divider.
           loc += sizes[0];
           setComponentToSize(components[2], sizes[2], loc, insets, dims);
           // Layout component#2. 
           loc += sizes[2];
           setComponentToSize(components[1], sizes[1], loc, insets, dims);
         }
     }
 
     /**
      * This method returns the maximum size for the container given the
@@ -351,31 +360,30 @@
 
     /**
      * This method returns the container's minimum size. The  minimum width is
      * the sum of all the component's minimum widths. The minimum height is
      * the maximum of  all the components' minimum heights.
      *
      * @param target The container to measure.
      *
      * @return The minimum size.
      */
     public Dimension minimumLayoutSize(Container target)
     {
       Dimension dim = new Dimension();
       if (target instanceof JSplitPane)
         {
-          JSplitPane split = (JSplitPane) target;
           int primary = 0;
           int secondary = 0;
           for (int i = 0; i < components.length; i++)
             {
               if (components[i] != null)
                 {
                   Dimension dims = components[i].getMinimumSize();
                   primary += axis == SwingConstants.HORIZONTAL ? dims.width
                                                                : dims.height;
                   int sec = axis == SwingConstants.HORIZONTAL ? dims.height
                                                               : dims.width;
                   secondary = Math.max(sec, secondary);
                 }
             }
           int width = axis == SwingConstants.HORIZONTAL ? primary : secondary;
@@ -389,31 +397,30 @@
 
     /**
      * This method returns the container's preferred size. The preferred width
      * is the sum of all the component's preferred widths. The preferred
      * height is the maximum of all the components' preferred heights.
      *
      * @param target The container to measure.
      *
      * @return The preferred size.
      */
     public Dimension preferredLayoutSize(Container target)
     {
       Dimension dim = new Dimension();
       if (target instanceof JSplitPane)
         {
-          JSplitPane split = (JSplitPane) target;
           int primary = 0;
           int secondary = 0;
           for (int i = 0; i < components.length; i++)
             {
               if (components[i] != null)
                 {
                   Dimension dims = components[i].getPreferredSize();
                   primary += axis == SwingConstants.HORIZONTAL ? dims.width
                                                                : dims.height;
                   int sec = axis == SwingConstants.HORIZONTAL ? dims.height
                                                               : dims.width;
                   secondary = Math.max(sec, secondary);
                 }
             }
           int width = axis == SwingConstants.HORIZONTAL ? primary : secondary;
@@ -448,32 +455,30 @@
      * @param index The index of the component to reset.
      */
     protected void resetSizeAt(int index)
     {
       if (components[index] != null)
         sizes[index] = getPreferredSizeOfComponent(components[index]);
     }
 
     /**
      * This method resets the sizes of all the components.
      */
     public void resetToPreferredSizes()
     {
       for (int i = 0; i < components.length; i++)
         resetSizeAt(i);
-      setDividerLocation(splitPane,
-                         getInitialLocation(splitPane.getInsets()) + sizes[0]);
     }
 
     /**
      * This methods sets the bounds of the given component. The width is the
      * size. The height is the container size minus the  top and bottom
      * inset. The x coordinate is the location given.  The y coordinate is
      * the top inset.
      *
      * @param c The component to set.
      * @param size The width of the component.
      * @param location The x coordinate.
      * @param insets The insets to use.
      * @param containerSize The height of the container.
      */
     protected void setComponentToSize(Component c, int size, int location,
@@ -845,31 +850,37 @@
   protected boolean draggingHW;
 
   /**
    * The constraints object used when adding the non-continuous divider to the
    * JSplitPane.
    */
   protected static final String NON_CONTINUOUS_DIVIDER
     = "nonContinuousDivider";
 
   /** The dark divider used when dragging in non-continuous layout mode. */
   protected Component nonContinuousLayoutDivider;
 
   /** The JSplitPane that this UI draws. */
   protected JSplitPane splitPane;
 
-  private int dividerLocation;
+  /**
+   * True, when setDividerLocation() has been called at least
+   * once on the JSplitPane, false otherwise.
+   *
+   * This is package private to avoid a synthetic accessor method.
+   */
+  boolean dividerLocationSet;
 
   /**
    * Creates a new BasicSplitPaneUI object.
    */
   public BasicSplitPaneUI()
   {
     // Nothing to do here.
   }
 
   /**
    * This method creates a new BasicSplitPaneUI for the given JComponent.
    *
    * @param x The JComponent to create a UI for.
    *
    * @return A new BasicSplitPaneUI.
@@ -877,47 +888,49 @@
   public static ComponentUI createUI(JComponent x)
   {
     return new BasicSplitPaneUI();
   }
 
   /**
    * This method installs the BasicSplitPaneUI for the given JComponent.
    *
    * @param c The JComponent to install the UI for.
    */
   public void installUI(JComponent c)
   {
     if (c instanceof JSplitPane)
       {
         splitPane = (JSplitPane) c;
+        dividerLocationSet = false;
         installDefaults();
         installListeners();
         installKeyboardActions();
       }
   }
 
   /**
    * This method uninstalls the BasicSplitPaneUI for the given JComponent.
    *
    * @param c The JComponent to uninstall the UI for.
    */
   public void uninstallUI(JComponent c)
   {
     uninstallKeyboardActions();
     uninstallListeners();
     uninstallDefaults();
 
+    dividerLocationSet = false;
     splitPane = null;
   }
 
   /**
    * This method installs the defaults given by the Look and Feel.
    */
   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();
@@ -1042,41 +1055,45 @@
               }
             }
     );
     map.put("selectMin", 
             new AbstractAction("selectMin") {
               public void actionPerformed(ActionEvent event)
               {
                 splitPane.setDividerLocation(0.0);
               }
             }
     );
     map.put("negativeIncrement", 
             new AbstractAction("negativeIncrement") {
               public void actionPerformed(ActionEvent event)
               {
-                setDividerLocation(splitPane, Math.max(dividerLocation 
-                    - KEYBOARD_DIVIDER_MOVE_OFFSET, 0));
+                int oldLoc = splitPane.getDividerLocation();
+                int newLoc =
+                  Math.max(oldLoc - KEYBOARD_DIVIDER_MOVE_OFFSET, 0);
+                splitPane.setDividerLocation(newLoc);
               }
             }
     );
     map.put("positiveIncrement", 
             new AbstractAction("positiveIncrement") {
               public void actionPerformed(ActionEvent event)
               {
-                setDividerLocation(splitPane, dividerLocation 
-                    + KEYBOARD_DIVIDER_MOVE_OFFSET);
+                int oldLoc = splitPane.getDividerLocation();
+                int newLoc =
+                  Math.max(oldLoc + KEYBOARD_DIVIDER_MOVE_OFFSET, 0);
+                splitPane.setDividerLocation(newLoc);
               }
             }
     );
     map.put("focusOutBackward",
             new AbstractAction("focusOutBackward") {
               public void actionPerformed(ActionEvent event)
               {
                 // FIXME: implement this
               }
             }
     );    
     map.put("focusOutForward",
             new AbstractAction("focusOutForward") {
               public void actionPerformed(ActionEvent event)
               {
@@ -1342,45 +1359,50 @@
    * @param jc The JSplitPane to reset.
    */
   public void resetToPreferredSizes(JSplitPane jc)
   {
     layoutManager.resetToPreferredSizes();
   }
 
   /**
    * This method sets the location of the divider.
    *
    * @param jc The JSplitPane to set the divider location in.
    * @param location The new location of the divider.
    */
   public void setDividerLocation(JSplitPane jc, int location)
   {
-    dividerLocation = location;
+    dividerLocationSet = true;
     splitPane.revalidate();
     splitPane.repaint();
   }
 
   /**
    * This method returns the location of the divider.
    *
    * @param jc The JSplitPane to retrieve the location for.
    *
    * @return The location of the divider.
    */
   public int getDividerLocation(JSplitPane jc)
   {
-    return dividerLocation;
+    int loc;
+    if (jc.getOrientation() == JSplitPane.HORIZONTAL_SPLIT)
+      loc = divider.getX();
+    else
+      loc = divider.getY();
+    return loc;
   }
 
   /**
    * This method returns the smallest value possible for the location of the
    * divider.
    *
    * @param jc The JSplitPane.
    *
    * @return The minimum divider location.
    */
   public int getMinimumDividerLocation(JSplitPane jc)
   {
     int value = layoutManager.getInitialLocation(jc.getInsets());
     if (layoutManager.components[0] != null)
       value += layoutManager.minimumSizeOfComponent(0);
@@ -1429,55 +1451,55 @@
    */
   public void paint(Graphics g, JComponent jc)
   {
     // TODO: What should be done here?
   }
 
   /**
    * This method returns the preferred size of the JSplitPane.
    *
    * @param jc The JSplitPane.
    *
    * @return The preferred size of the JSplitPane.
    */
   public Dimension getPreferredSize(JComponent jc)
   {
-    return layoutManager.preferredLayoutSize((Container) jc);
+    return layoutManager.preferredLayoutSize(jc);
   }
 
   /**
    * This method returns the minimum size of the JSplitPane.
    *
    * @param jc The JSplitPane.
    *
    * @return The minimum size of the JSplitPane.
    */
   public Dimension getMinimumSize(JComponent jc)
   {
-    return layoutManager.minimumLayoutSize((Container) jc);
+    return layoutManager.minimumLayoutSize(jc);
   }
 
   /**
    * This method returns the maximum size of the JSplitPane.
    *
    * @param jc The JSplitPane.
    *
    * @return The maximum size of the JSplitPane.
    */
   public Dimension getMaximumSize(JComponent jc)
   {
-    return layoutManager.maximumLayoutSize((Container) jc);
+    return layoutManager.maximumLayoutSize(jc);
   }
 
   /**
    * This method returns the border insets of the current border.
    *
    * @param jc The JSplitPane.
    *
    * @return The current border insets.
    */
   public Insets getInsets(JComponent jc)
   {
     return splitPane.getBorder().getBorderInsets(splitPane);
   }
 
   /**

Reply via email to