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);
}
/**