0001 /*
0002 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.swing;
0027
0028 import java.beans.ConstructorProperties;
0029 import javax.swing.plaf.*;
0030 import javax.accessibility.*;
0031
0032 import java.awt.*;
0033
0034 import java.io.ObjectOutputStream;
0035 import java.io.ObjectInputStream;
0036 import java.io.IOException;
0037
0038 /**
0039 * <code>JSplitPane</code> is used to divide two (and only two)
0040 * <code>Component</code>s. The two <code>Component</code>s
0041 * are graphically divided based on the look and feel
0042 * implementation, and the two <code>Component</code>s can then be
0043 * interactively resized by the user.
0044 * Information on using <code>JSplitPane</code> is in
0045 * <a
0046 href="http://java.sun.com/docs/books/tutorial/uiswing/components/splitpane.html">How to Use Split Panes</a> in
0047 * <em>The Java Tutorial</em>.
0048 * <p>
0049 * The two <code>Component</code>s in a split pane can be aligned
0050 * left to right using
0051 * <code>JSplitPane.HORIZONTAL_SPLIT</code>, or top to bottom using
0052 * <code>JSplitPane.VERTICAL_SPLIT</code>.
0053 * The preferred way to change the size of the <code>Component</code>s
0054 * is to invoke
0055 * <code>setDividerLocation</code> where <code>location</code> is either
0056 * the new x or y position, depending on the orientation of the
0057 * <code>JSplitPane</code>.
0058 * <p>
0059 * To resize the <code>Component</code>s to their preferred sizes invoke
0060 * <code>resetToPreferredSizes</code>.
0061 * <p>
0062 * When the user is resizing the <code>Component</code>s the minimum
0063 * size of the <code>Components</code> is used to determine the
0064 * maximum/minimum position the <code>Component</code>s
0065 * can be set to. If the minimum size of the two
0066 * components is greater than the size of the split pane the divider
0067 * will not allow you to resize it. To alter the minimum size of a
0068 * <code>JComponent</code>, see {@link JComponent#setMinimumSize}.
0069 * <p>
0070 * When the user resizes the split pane the new space is distributed between
0071 * the two components based on the <code>resizeWeight</code> property.
0072 * A value of 0,
0073 * the default, indicates the right/bottom component gets all the space,
0074 * where as a value of 1 indicates the left/top component gets all the space.
0075 * <p>
0076 * <strong>Warning:</strong> Swing is not thread safe. For more
0077 * information see <a
0078 * href="package-summary.html#threading">Swing's Threading
0079 * Policy</a>.
0080 * <p>
0081 * <strong>Warning:</strong>
0082 * Serialized objects of this class will not be compatible with
0083 * future Swing releases. The current serialization support is
0084 * appropriate for short term storage or RMI between applications running
0085 * the same version of Swing. As of 1.4, support for long term storage
0086 * of all JavaBeans<sup><font size="-2">TM</font></sup>
0087 * has been added to the <code>java.beans</code> package.
0088 * Please see {@link java.beans.XMLEncoder}.
0089 *
0090 * @see #setDividerLocation
0091 * @see #resetToPreferredSizes
0092 *
0093 * @version 1.84 05/05/07
0094 * @author Scott Violet
0095 */
0096 public class JSplitPane extends JComponent implements Accessible {
0097 /**
0098 * @see #getUIClassID
0099 * @see #readObject
0100 */
0101 private static final String uiClassID = "SplitPaneUI";
0102
0103 /**
0104 * Vertical split indicates the <code>Component</code>s are
0105 * split along the y axis. For example the two
0106 * <code>Component</code>s will be split one on top of the other.
0107 */
0108 public final static int VERTICAL_SPLIT = 0;
0109
0110 /**
0111 * Horizontal split indicates the <code>Component</code>s are
0112 * split along the x axis. For example the two
0113 * <code>Component</code>s will be split one to the left of the
0114 * other.
0115 */
0116 public final static int HORIZONTAL_SPLIT = 1;
0117
0118 /**
0119 * Used to add a <code>Component</code> to the left of the other
0120 * <code>Component</code>.
0121 */
0122 public final static String LEFT = "left";
0123
0124 /**
0125 * Used to add a <code>Component</code> to the right of the other
0126 * <code>Component</code>.
0127 */
0128 public final static String RIGHT = "right";
0129
0130 /**
0131 * Used to add a <code>Component</code> above the other
0132 * <code>Component</code>.
0133 */
0134 public final static String TOP = "top";
0135
0136 /**
0137 * Used to add a <code>Component</code> below the other
0138 * <code>Component</code>.
0139 */
0140 public final static String BOTTOM = "bottom";
0141
0142 /**
0143 * Used to add a <code>Component</code> that will represent the divider.
0144 */
0145 public final static String DIVIDER = "divider";
0146
0147 /**
0148 * Bound property name for orientation (horizontal or vertical).
0149 */
0150 public final static String ORIENTATION_PROPERTY = "orientation";
0151
0152 /**
0153 * Bound property name for continuousLayout.
0154 */
0155 public final static String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout";
0156
0157 /**
0158 * Bound property name for border.
0159 */
0160 public final static String DIVIDER_SIZE_PROPERTY = "dividerSize";
0161
0162 /**
0163 * Bound property for oneTouchExpandable.
0164 */
0165 public final static String ONE_TOUCH_EXPANDABLE_PROPERTY = "oneTouchExpandable";
0166
0167 /**
0168 * Bound property for lastLocation.
0169 */
0170 public final static String LAST_DIVIDER_LOCATION_PROPERTY = "lastDividerLocation";
0171
0172 /**
0173 * Bound property for the dividerLocation.
0174 * @since 1.3
0175 */
0176 public final static String DIVIDER_LOCATION_PROPERTY = "dividerLocation";
0177
0178 /**
0179 * Bound property for weight.
0180 * @since 1.3
0181 */
0182 public final static String RESIZE_WEIGHT_PROPERTY = "resizeWeight";
0183
0184 /**
0185 * How the views are split.
0186 */
0187 protected int orientation;
0188
0189 /**
0190 * Whether or not the views are continuously redisplayed while
0191 * resizing.
0192 */
0193 protected boolean continuousLayout;
0194
0195 /**
0196 * The left or top component.
0197 */
0198 protected Component leftComponent;
0199
0200 /**
0201 * The right or bottom component.
0202 */
0203 protected Component rightComponent;
0204
0205 /**
0206 * Size of the divider.
0207 */
0208 protected int dividerSize;
0209 private boolean dividerSizeSet = false;
0210
0211 /**
0212 * Is a little widget provided to quickly expand/collapse the
0213 * split pane?
0214 */
0215 protected boolean oneTouchExpandable;
0216 private boolean oneTouchExpandableSet;
0217
0218 /**
0219 * Previous location of the split pane.
0220 */
0221 protected int lastDividerLocation;
0222
0223 /**
0224 * How to distribute extra space.
0225 */
0226 private double resizeWeight;
0227
0228 /**
0229 * Location of the divider, at least the value that was set, the UI may
0230 * have a different value.
0231 */
0232 private int dividerLocation;
0233
0234 /**
0235 * Creates a new <code>JSplitPane</code> configured to arrange the child
0236 * components side-by-side horizontally with no continuous
0237 * layout, using two buttons for the components.
0238 */
0239 public JSplitPane() {
0240 this (JSplitPane.HORIZONTAL_SPLIT, false, new JButton(UIManager
0241 .getString("SplitPane.leftButtonText")), new JButton(
0242 UIManager.getString("SplitPane.rightButtonText")));
0243 }
0244
0245 /**
0246 * Creates a new <code>JSplitPane</code> configured with the
0247 * specified orientation and no continuous layout.
0248 *
0249 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
0250 * <code>JSplitPane.VERTICAL_SPLIT</code>
0251 * @exception IllegalArgumentException if <code>orientation</code>
0252 * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT.
0253 */
0254 @ConstructorProperties({"orientation"})
0255 public JSplitPane(int newOrientation) {
0256 this (newOrientation, false);
0257 }
0258
0259 /**
0260 * Creates a new <code>JSplitPane</code> with the specified
0261 * orientation and redrawing style.
0262 *
0263 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
0264 * <code>JSplitPane.VERTICAL_SPLIT</code>
0265 * @param newContinuousLayout a boolean, true for the components to
0266 * redraw continuously as the divider changes position, false
0267 * to wait until the divider position stops changing to redraw
0268 * @exception IllegalArgumentException if <code>orientation</code>
0269 * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT
0270 */
0271 public JSplitPane(int newOrientation, boolean newContinuousLayout) {
0272 this (newOrientation, newContinuousLayout, null, null);
0273 }
0274
0275 /**
0276 * Creates a new <code>JSplitPane</code> with the specified
0277 * orientation and
0278 * with the specified components that do not do continuous
0279 * redrawing.
0280 *
0281 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
0282 * <code>JSplitPane.VERTICAL_SPLIT</code>
0283 * @param newLeftComponent the <code>Component</code> that will
0284 * appear on the left
0285 * of a horizontally-split pane, or at the top of a
0286 * vertically-split pane
0287 * @param newRightComponent the <code>Component</code> that will
0288 * appear on the right
0289 * of a horizontally-split pane, or at the bottom of a
0290 * vertically-split pane
0291 * @exception IllegalArgumentException if <code>orientation</code>
0292 * is not one of: HORIZONTAL_SPLIT or VERTICAL_SPLIT
0293 */
0294 public JSplitPane(int newOrientation, Component newLeftComponent,
0295 Component newRightComponent) {
0296 this (newOrientation, false, newLeftComponent, newRightComponent);
0297 }
0298
0299 /**
0300 * Creates a new <code>JSplitPane</code> with the specified
0301 * orientation and
0302 * redrawing style, and with the specified components.
0303 *
0304 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
0305 * <code>JSplitPane.VERTICAL_SPLIT</code>
0306 * @param newContinuousLayout a boolean, true for the components to
0307 * redraw continuously as the divider changes position, false
0308 * to wait until the divider position stops changing to redraw
0309 * @param newLeftComponent the <code>Component</code> that will
0310 * appear on the left
0311 * of a horizontally-split pane, or at the top of a
0312 * vertically-split pane
0313 * @param newRightComponent the <code>Component</code> that will
0314 * appear on the right
0315 * of a horizontally-split pane, or at the bottom of a
0316 * vertically-split pane
0317 * @exception IllegalArgumentException if <code>orientation</code>
0318 * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT
0319 */
0320 public JSplitPane(int newOrientation, boolean newContinuousLayout,
0321 Component newLeftComponent, Component newRightComponent) {
0322 super ();
0323
0324 dividerLocation = -1;
0325 setLayout(null);
0326 setUIProperty("opaque", Boolean.TRUE);
0327 orientation = newOrientation;
0328 if (orientation != HORIZONTAL_SPLIT
0329 && orientation != VERTICAL_SPLIT)
0330 throw new IllegalArgumentException(
0331 "cannot create JSplitPane, "
0332 + "orientation must be one of "
0333 + "JSplitPane.HORIZONTAL_SPLIT "
0334 + "or JSplitPane.VERTICAL_SPLIT");
0335 continuousLayout = newContinuousLayout;
0336 if (newLeftComponent != null)
0337 setLeftComponent(newLeftComponent);
0338 if (newRightComponent != null)
0339 setRightComponent(newRightComponent);
0340 updateUI();
0341
0342 }
0343
0344 /**
0345 * Sets the L&F object that renders this component.
0346 *
0347 * @param ui the <code>SplitPaneUI</code> L&F object
0348 * @see UIDefaults#getUI
0349 * @beaninfo
0350 * bound: true
0351 * hidden: true
0352 * attribute: visualUpdate true
0353 * description: The UI object that implements the Component's LookAndFeel.
0354 */
0355 public void setUI(SplitPaneUI ui) {
0356 if ((SplitPaneUI) this .ui != ui) {
0357 super .setUI(ui);
0358 revalidate();
0359 }
0360 }
0361
0362 /**
0363 * Returns the <code>SplitPaneUI</code> that is providing the
0364 * current look and feel.
0365 *
0366 * @return the <code>SplitPaneUI</code> object that renders this component
0367 * @beaninfo
0368 * expert: true
0369 * description: The L&F object that renders this component.
0370 */
0371 public SplitPaneUI getUI() {
0372 return (SplitPaneUI) ui;
0373 }
0374
0375 /**
0376 * Notification from the <code>UIManager</code> that the L&F has changed.
0377 * Replaces the current UI object with the latest version from the
0378 * <code>UIManager</code>.
0379 *
0380 * @see JComponent#updateUI
0381 */
0382 public void updateUI() {
0383 setUI((SplitPaneUI) UIManager.getUI(this ));
0384 revalidate();
0385 }
0386
0387 /**
0388 * Returns the name of the L&F class that renders this component.
0389 *
0390 * @return the string "SplitPaneUI"
0391 * @see JComponent#getUIClassID
0392 * @see UIDefaults#getUI
0393 * @beaninfo
0394 * expert: true
0395 * description: A string that specifies the name of the L&F class.
0396 */
0397 public String getUIClassID() {
0398 return uiClassID;
0399 }
0400
0401 /**
0402 * Sets the size of the divider.
0403 *
0404 * @param newSize an integer giving the size of the divider in pixels
0405 * @beaninfo
0406 * bound: true
0407 * description: The size of the divider.
0408 */
0409 public void setDividerSize(int newSize) {
0410 int oldSize = dividerSize;
0411
0412 dividerSizeSet = true;
0413 if (oldSize != newSize) {
0414 dividerSize = newSize;
0415 firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, newSize);
0416 }
0417 }
0418
0419 /**
0420 * Returns the size of the divider.
0421 *
0422 * @return an integer giving the size of the divider in pixels
0423 */
0424 public int getDividerSize() {
0425 return dividerSize;
0426 }
0427
0428 /**
0429 * Sets the component to the left (or above) the divider.
0430 *
0431 * @param comp the <code>Component</code> to display in that position
0432 */
0433 public void setLeftComponent(Component comp) {
0434 if (comp == null) {
0435 if (leftComponent != null) {
0436 remove(leftComponent);
0437 leftComponent = null;
0438 }
0439 } else {
0440 add(comp, JSplitPane.LEFT);
0441 }
0442 }
0443
0444 /**
0445 * Returns the component to the left (or above) the divider.
0446 *
0447 * @return the <code>Component</code> displayed in that position
0448 * @beaninfo
0449 * preferred: true
0450 * description: The component to the left (or above) the divider.
0451 */
0452 public Component getLeftComponent() {
0453 return leftComponent;
0454 }
0455
0456 /**
0457 * Sets the component above, or to the left of the divider.
0458 *
0459 * @param comp the <code>Component</code> to display in that position
0460 * @beaninfo
0461 * description: The component above, or to the left of the divider.
0462 */
0463 public void setTopComponent(Component comp) {
0464 setLeftComponent(comp);
0465 }
0466
0467 /**
0468 * Returns the component above, or to the left of the divider.
0469 *
0470 * @return the <code>Component</code> displayed in that position
0471 */
0472 public Component getTopComponent() {
0473 return leftComponent;
0474 }
0475
0476 /**
0477 * Sets the component to the right (or below) the divider.
0478 *
0479 * @param comp the <code>Component</code> to display in that position
0480 * @beaninfo
0481 * preferred: true
0482 * description: The component to the right (or below) the divider.
0483 */
0484 public void setRightComponent(Component comp) {
0485 if (comp == null) {
0486 if (rightComponent != null) {
0487 remove(rightComponent);
0488 rightComponent = null;
0489 }
0490 } else {
0491 add(comp, JSplitPane.RIGHT);
0492 }
0493 }
0494
0495 /**
0496 * Returns the component to the right (or below) the divider.
0497 *
0498 * @return the <code>Component</code> displayed in that position
0499 */
0500 public Component getRightComponent() {
0501 return rightComponent;
0502 }
0503
0504 /**
0505 * Sets the component below, or to the right of the divider.
0506 *
0507 * @param comp the <code>Component</code> to display in that position
0508 * @beaninfo
0509 * description: The component below, or to the right of the divider.
0510 */
0511 public void setBottomComponent(Component comp) {
0512 setRightComponent(comp);
0513 }
0514
0515 /**
0516 * Returns the component below, or to the right of the divider.
0517 *
0518 * @return the <code>Component</code> displayed in that position
0519 */
0520 public Component getBottomComponent() {
0521 return rightComponent;
0522 }
0523
0524 /**
0525 * Sets the value of the <code>oneTouchExpandable</code> property,
0526 * which must be <code>true</code> for the
0527 * <code>JSplitPane</code> to provide a UI widget
0528 * on the divider to quickly expand/collapse the divider.
0529 * The default value of this property is <code>false</code>.
0530 * Some look and feels might not support one-touch expanding;
0531 * they will ignore this property.
0532 *
0533 * @param newValue <code>true</code> to specify that the split pane should provide a
0534 * collapse/expand widget
0535 * @beaninfo
0536 * bound: true
0537 * description: UI widget on the divider to quickly
0538 * expand/collapse the divider.
0539 *
0540 * @see #isOneTouchExpandable
0541 */
0542 public void setOneTouchExpandable(boolean newValue) {
0543 boolean oldValue = oneTouchExpandable;
0544
0545 oneTouchExpandable = newValue;
0546 oneTouchExpandableSet = true;
0547 firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue,
0548 newValue);
0549 repaint();
0550 }
0551
0552 /**
0553 * Gets the <code>oneTouchExpandable</code> property.
0554 *
0555 * @return the value of the <code>oneTouchExpandable</code> property
0556 * @see #setOneTouchExpandable
0557 */
0558 public boolean isOneTouchExpandable() {
0559 return oneTouchExpandable;
0560 }
0561
0562 /**
0563 * Sets the last location the divider was at to
0564 * <code>newLastLocation</code>.
0565 *
0566 * @param newLastLocation an integer specifying the last divider location
0567 * in pixels, from the left (or upper) edge of the pane to the
0568 * left (or upper) edge of the divider
0569 * @beaninfo
0570 * bound: true
0571 * description: The last location the divider was at.
0572 */
0573 public void setLastDividerLocation(int newLastLocation) {
0574 int oldLocation = lastDividerLocation;
0575
0576 lastDividerLocation = newLastLocation;
0577 firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldLocation,
0578 newLastLocation);
0579 }
0580
0581 /**
0582 * Returns the last location the divider was at.
0583 *
0584 * @return an integer specifying the last divider location as a count
0585 * of pixels from the left (or upper) edge of the pane to the
0586 * left (or upper) edge of the divider
0587 */
0588 public int getLastDividerLocation() {
0589 return lastDividerLocation;
0590 }
0591
0592 /**
0593 * Sets the orientation, or how the splitter is divided. The options
0594 * are:<ul>
0595 * <li>JSplitPane.VERTICAL_SPLIT (above/below orientation of components)
0596 * <li>JSplitPane.HORIZONTAL_SPLIT (left/right orientation of components)
0597 * </ul>
0598 *
0599 * @param orientation an integer specifying the orientation
0600 * @exception IllegalArgumentException if orientation is not one of:
0601 * HORIZONTAL_SPLIT or VERTICAL_SPLIT.
0602 * @beaninfo
0603 * bound: true
0604 * description: The orientation, or how the splitter is divided.
0605 * enum: HORIZONTAL_SPLIT JSplitPane.HORIZONTAL_SPLIT
0606 * VERTICAL_SPLIT JSplitPane.VERTICAL_SPLIT
0607 */
0608 public void setOrientation(int orientation) {
0609 if ((orientation != VERTICAL_SPLIT)
0610 && (orientation != HORIZONTAL_SPLIT)) {
0611 throw new IllegalArgumentException(
0612 "JSplitPane: orientation must " + "be one of "
0613 + "JSplitPane.VERTICAL_SPLIT or "
0614 + "JSplitPane.HORIZONTAL_SPLIT");
0615 }
0616
0617 int oldOrientation = this .orientation;
0618
0619 this .orientation = orientation;
0620 firePropertyChange(ORIENTATION_PROPERTY, oldOrientation,
0621 orientation);
0622 }
0623
0624 /**
0625 * Returns the orientation.
0626 *
0627 * @return an integer giving the orientation
0628 * @see #setOrientation
0629 */
0630 public int getOrientation() {
0631 return orientation;
0632 }
0633
0634 /**
0635 * Sets the value of the <code>continuousLayout</code> property,
0636 * which must be <code>true</code> for the child components
0637 * to be continuously
0638 * redisplayed and laid out during user intervention.
0639 * The default value of this property is <code>false</code>.
0640 * Some look and feels might not support continuous layout;
0641 * they will ignore this property.
0642 *
0643 * @param newContinuousLayout <code>true</code> if the components
0644 * should continuously be redrawn as the divider changes position
0645 * @beaninfo
0646 * bound: true
0647 * description: Whether the child components are
0648 * continuously redisplayed and laid out during
0649 * user intervention.
0650 * @see #isContinuousLayout
0651 */
0652 public void setContinuousLayout(boolean newContinuousLayout) {
0653 boolean oldCD = continuousLayout;
0654
0655 continuousLayout = newContinuousLayout;
0656 firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldCD,
0657 newContinuousLayout);
0658 }
0659
0660 /**
0661 * Gets the <code>continuousLayout</code> property.
0662 *
0663 * @return the value of the <code>continuousLayout</code> property
0664 * @see #setContinuousLayout
0665 */
0666 public boolean isContinuousLayout() {
0667 return continuousLayout;
0668 }
0669
0670 /**
0671 * Specifies how to distribute extra space when the size of the split pane
0672 * changes. A value of 0, the default,
0673 * indicates the right/bottom component gets all the extra space (the
0674 * left/top component acts fixed), where as a value of 1 specifies the
0675 * left/top component gets all the extra space (the right/bottom component
0676 * acts fixed). Specifically, the left/top component gets (weight * diff)
0677 * extra space and the right/bottom component gets (1 - weight) * diff
0678 * extra space.
0679 *
0680 * @param value as described above
0681 * @exception IllegalArgumentException if <code>value</code> is < 0 or > 1
0682 * @since 1.3
0683 * @beaninfo
0684 * bound: true
0685 * description: Specifies how to distribute extra space when the split pane
0686 * resizes.
0687 */
0688 public void setResizeWeight(double value) {
0689 if (value < 0 || value > 1) {
0690 throw new IllegalArgumentException(
0691 "JSplitPane weight must be between 0 and 1");
0692 }
0693 double oldWeight = resizeWeight;
0694
0695 resizeWeight = value;
0696 firePropertyChange(RESIZE_WEIGHT_PROPERTY, oldWeight, value);
0697 }
0698
0699 /**
0700 * Returns the number that determines how extra space is distributed.
0701 * @return how extra space is to be distributed on a resize of the
0702 * split pane
0703 * @since 1.3
0704 */
0705 public double getResizeWeight() {
0706 return resizeWeight;
0707 }
0708
0709 /**
0710 * Lays out the <code>JSplitPane</code> layout based on the preferred size
0711 * of the children components. This will likely result in changing
0712 * the divider location.
0713 */
0714 public void resetToPreferredSizes() {
0715 SplitPaneUI ui = getUI();
0716
0717 if (ui != null) {
0718 ui.resetToPreferredSizes(this );
0719 }
0720 }
0721
0722 /**
0723 * Sets the divider location as a percentage of the
0724 * <code>JSplitPane</code>'s size.
0725 * <p>
0726 * This method is implemented in terms of
0727 * <code>setDividerLocation(int)</code>.
0728 * This method immediately changes the size of the split pane based on
0729 * its current size. If the split pane is not correctly realized and on
0730 * screen, this method will have no effect (new divider location will
0731 * become (current size * proportionalLocation) which is 0).
0732 *
0733 * @param proportionalLocation a double-precision floating point value
0734 * that specifies a percentage, from zero (top/left) to 1.0
0735 * (bottom/right)
0736 * @exception IllegalArgumentException if the specified location is < 0
0737 * or > 1.0
0738 * @beaninfo
0739 * description: The location of the divider.
0740 */
0741 public void setDividerLocation(double proportionalLocation) {
0742 if (proportionalLocation < 0.0 || proportionalLocation > 1.0) {
0743 throw new IllegalArgumentException(
0744 "proportional location must "
0745 + "be between 0.0 and 1.0.");
0746 }
0747 if (getOrientation() == VERTICAL_SPLIT) {
0748 setDividerLocation((int) ((double) (getHeight() - getDividerSize()) * proportionalLocation));
0749 } else {
0750 setDividerLocation((int) ((double) (getWidth() - getDividerSize()) * proportionalLocation));
0751 }
0752 }
0753
0754 /**
0755 * Sets the location of the divider. This is passed off to the
0756 * look and feel implementation, and then listeners are notified. A value
0757 * less than 0 implies the divider should be reset to a value that
0758 * attempts to honor the preferred size of the left/top component.
0759 * After notifying the listeners, the last divider location is updated,
0760 * via <code>setLastDividerLocation</code>.
0761 *
0762 * @param location an int specifying a UI-specific value (typically a
0763 * pixel count)
0764 * @beaninfo
0765 * bound: true
0766 * description: The location of the divider.
0767 */
0768 public void setDividerLocation(int location) {
0769 int oldValue = dividerLocation;
0770
0771 dividerLocation = location;
0772
0773 // Notify UI.
0774 SplitPaneUI ui = getUI();
0775
0776 if (ui != null) {
0777 ui.setDividerLocation(this , location);
0778 }
0779
0780 // Then listeners
0781 firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldValue,
0782 location);
0783
0784 // And update the last divider location.
0785 setLastDividerLocation(oldValue);
0786 }
0787
0788 /**
0789 * Returns the last value passed to <code>setDividerLocation</code>.
0790 * The value returned from this method may differ from the actual
0791 * divider location (if <code>setDividerLocation</code> was passed a
0792 * value bigger than the curent size).
0793 *
0794 * @return an integer specifying the location of the divider
0795 */
0796 public int getDividerLocation() {
0797 return dividerLocation;
0798 }
0799
0800 /**
0801 * Returns the minimum location of the divider from the look and feel
0802 * implementation.
0803 *
0804 * @return an integer specifying a UI-specific value for the minimum
0805 * location (typically a pixel count); or -1 if the UI is
0806 * <code>null</code>
0807 * @beaninfo
0808 * description: The minimum location of the divider from the L&F.
0809 */
0810 public int getMinimumDividerLocation() {
0811 SplitPaneUI ui = getUI();
0812
0813 if (ui != null) {
0814 return ui.getMinimumDividerLocation(this );
0815 }
0816 return -1;
0817 }
0818
0819 /**
0820 * Returns the maximum location of the divider from the look and feel
0821 * implementation.
0822 *
0823 * @return an integer specifying a UI-specific value for the maximum
0824 * location (typically a pixel count); or -1 if the UI is
0825 * <code>null</code>
0826 */
0827 public int getMaximumDividerLocation() {
0828 SplitPaneUI ui = getUI();
0829
0830 if (ui != null) {
0831 return ui.getMaximumDividerLocation(this );
0832 }
0833 return -1;
0834 }
0835
0836 /**
0837 * Removes the child component, <code>component</code> from the
0838 * pane. Resets the <code>leftComponent</code> or
0839 * <code>rightComponent</code> instance variable, as necessary.
0840 *
0841 * @param component the <code>Component</code> to remove
0842 */
0843 public void remove(Component component) {
0844 if (component == leftComponent) {
0845 leftComponent = null;
0846 } else if (component == rightComponent) {
0847 rightComponent = null;
0848 }
0849 super .remove(component);
0850
0851 // Update the JSplitPane on the screen
0852 revalidate();
0853 repaint();
0854 }
0855
0856 /**
0857 * Removes the <code>Component</code> at the specified index.
0858 * Updates the <code>leftComponent</code> and <code>rightComponent</code>
0859 * instance variables as necessary, and then messages super.
0860 *
0861 * @param index an integer specifying the component to remove, where
0862 * 1 specifies the left/top component and 2 specifies the
0863 * bottom/right component
0864 */
0865 public void remove(int index) {
0866 Component comp = getComponent(index);
0867
0868 if (comp == leftComponent) {
0869 leftComponent = null;
0870 } else if (comp == rightComponent) {
0871 rightComponent = null;
0872 }
0873 super .remove(index);
0874
0875 // Update the JSplitPane on the screen
0876 revalidate();
0877 repaint();
0878 }
0879
0880 /**
0881 * Removes all the child components from the split pane. Resets the
0882 * <code>leftComonent</code> and <code>rightComponent</code>
0883 * instance variables.
0884 */
0885 public void removeAll() {
0886 leftComponent = rightComponent = null;
0887 super .removeAll();
0888
0889 // Update the JSplitPane on the screen
0890 revalidate();
0891 repaint();
0892 }
0893
0894 /**
0895 * Returns true, so that calls to <code>revalidate</code>
0896 * on any descendant of this <code>JSplitPane</code>
0897 * will cause a request to be queued that
0898 * will validate the <code>JSplitPane</code> and all its descendants.
0899 *
0900 * @return true
0901 * @see JComponent#revalidate
0902 *
0903 * @beaninfo
0904 * hidden: true
0905 */
0906 public boolean isValidateRoot() {
0907 return true;
0908 }
0909
0910 /**
0911 * Adds the specified component to this split pane.
0912 * If <code>constraints</code> identifies the left/top or
0913 * right/bottom child component, and a component with that identifier
0914 * was previously added, it will be removed and then <code>comp</code>
0915 * will be added in its place. If <code>constraints</code> is not
0916 * one of the known identifiers the layout manager may throw an
0917 * <code>IllegalArgumentException</code>.
0918 * <p>
0919 * The possible constraints objects (Strings) are:
0920 * <ul>
0921 * <li>JSplitPane.TOP
0922 * <li>JSplitPane.LEFT
0923 * <li>JSplitPane.BOTTOM
0924 * <li>JSplitPane.RIGHT
0925 * </ul>
0926 * If the <code>constraints</code> object is <code>null</code>,
0927 * the component is added in the
0928 * first available position (left/top if open, else right/bottom).
0929 *
0930 * @param comp the component to add
0931 * @param constraints an <code>Object</code> specifying the
0932 * layout constraints
0933 * (position) for this component
0934 * @param index an integer specifying the index in the container's
0935 * list.
0936 * @exception IllegalArgumentException if the <code>constraints</code>
0937 * object does not match an existing component
0938 * @see java.awt.Container#addImpl(Component, Object, int)
0939 */
0940 protected void addImpl(Component comp, Object constraints, int index) {
0941 Component toRemove;
0942
0943 if (constraints != null && !(constraints instanceof String)) {
0944 throw new IllegalArgumentException("cannot add to layout: "
0945 + "constraint must be a string " + "(or null)");
0946 }
0947
0948 /* If the constraints are null and the left/right component is
0949 invalid, add it at the left/right component. */
0950 if (constraints == null) {
0951 if (getLeftComponent() == null) {
0952 constraints = JSplitPane.LEFT;
0953 } else if (getRightComponent() == null) {
0954 constraints = JSplitPane.RIGHT;
0955 }
0956 }
0957
0958 /* Find the Component that already exists and remove it. */
0959 if (constraints != null
0960 && (constraints.equals(JSplitPane.LEFT) || constraints
0961 .equals(JSplitPane.TOP))) {
0962 toRemove = getLeftComponent();
0963 if (toRemove != null) {
0964 remove(toRemove);
0965 }
0966 leftComponent = comp;
0967 index = -1;
0968 } else if (constraints != null
0969 && (constraints.equals(JSplitPane.RIGHT) || constraints
0970 .equals(JSplitPane.BOTTOM))) {
0971 toRemove = getRightComponent();
0972 if (toRemove != null) {
0973 remove(toRemove);
0974 }
0975 rightComponent = comp;
0976 index = -1;
0977 } else if (constraints != null
0978 && constraints.equals(JSplitPane.DIVIDER)) {
0979 index = -1;
0980 }
0981 /* LayoutManager should raise for else condition here. */
0982
0983 super .addImpl(comp, constraints, index);
0984
0985 // Update the JSplitPane on the screen
0986 revalidate();
0987 repaint();
0988 }
0989
0990 /**
0991 * Subclassed to message the UI with <code>finishedPaintingChildren</code>
0992 * after super has been messaged, as well as painting the border.
0993 *
0994 * @param g the <code>Graphics</code> context within which to paint
0995 */
0996 protected void paintChildren(Graphics g) {
0997 super .paintChildren(g);
0998
0999 SplitPaneUI ui = getUI();
1000
1001 if (ui != null) {
1002 Graphics tempG = g.create();
1003 ui.finishedPaintingChildren(this , tempG);
1004 tempG.dispose();
1005 }
1006 }
1007
1008 /**
1009 * See <code>readObject</code> and <code>writeObject</code> in
1010 * <code>JComponent</code> for more
1011 * information about serialization in Swing.
1012 */
1013 private void writeObject(ObjectOutputStream s) throws IOException {
1014 s.defaultWriteObject();
1015 if (getUIClassID().equals(uiClassID)) {
1016 byte count = JComponent.getWriteObjCounter(this );
1017 JComponent.setWriteObjCounter(this , --count);
1018 if (count == 0 && ui != null) {
1019 ui.installUI(this );
1020 }
1021 }
1022 }
1023
1024 void setUIProperty(String propertyName, Object value) {
1025 if (propertyName == "dividerSize") {
1026 if (!dividerSizeSet) {
1027 setDividerSize(((Number) value).intValue());
1028 dividerSizeSet = false;
1029 }
1030 } else if (propertyName == "oneTouchExpandable") {
1031 if (!oneTouchExpandableSet) {
1032 setOneTouchExpandable(((Boolean) value).booleanValue());
1033 oneTouchExpandableSet = false;
1034 }
1035 } else {
1036 super .setUIProperty(propertyName, value);
1037 }
1038 }
1039
1040 /**
1041 * Returns a string representation of this <code>JSplitPane</code>.
1042 * This method
1043 * is intended to be used only for debugging purposes, and the
1044 * content and format of the returned string may vary between
1045 * implementations. The returned string may be empty but may not
1046 * be <code>null</code>.
1047 *
1048 * @return a string representation of this <code>JSplitPane</code>.
1049 */
1050 protected String paramString() {
1051 String orientationString = (orientation == HORIZONTAL_SPLIT ? "HORIZONTAL_SPLIT"
1052 : "VERTICAL_SPLIT");
1053 String continuousLayoutString = (continuousLayout ? "true"
1054 : "false");
1055 String oneTouchExpandableString = (oneTouchExpandable ? "true"
1056 : "false");
1057
1058 return super .paramString() + ",continuousLayout="
1059 + continuousLayoutString + ",dividerSize="
1060 + dividerSize + ",lastDividerLocation="
1061 + lastDividerLocation + ",oneTouchExpandable="
1062 + oneTouchExpandableString + ",orientation="
1063 + orientationString;
1064 }
1065
1066 ///////////////////////////
1067 // Accessibility support //
1068 ///////////////////////////
1069
1070 /**
1071 * Gets the AccessibleContext associated with this JSplitPane.
1072 * For split panes, the AccessibleContext takes the form of an
1073 * AccessibleJSplitPane.
1074 * A new AccessibleJSplitPane instance is created if necessary.
1075 *
1076 * @return an AccessibleJSplitPane that serves as the
1077 * AccessibleContext of this JSplitPane
1078 * @beaninfo
1079 * expert: true
1080 * description: The AccessibleContext associated with this SplitPane.
1081 */
1082 public AccessibleContext getAccessibleContext() {
1083 if (accessibleContext == null) {
1084 accessibleContext = new AccessibleJSplitPane();
1085 }
1086 return accessibleContext;
1087 }
1088
1089 /**
1090 * This class implements accessibility support for the
1091 * <code>JSplitPane</code> class. It provides an implementation of the
1092 * Java Accessibility API appropriate to split pane user-interface elements.
1093 * <p>
1094 * <strong>Warning:</strong>
1095 * Serialized objects of this class will not be compatible with
1096 * future Swing releases. The current serialization support is
1097 * appropriate for short term storage or RMI between applications running
1098 * the same version of Swing. As of 1.4, support for long term storage
1099 * of all JavaBeans<sup><font size="-2">TM</font></sup>
1100 * has been added to the <code>java.beans</code> package.
1101 * Please see {@link java.beans.XMLEncoder}.
1102 */
1103 protected class AccessibleJSplitPane extends AccessibleJComponent
1104 implements AccessibleValue {
1105 /**
1106 * Gets the state set of this object.
1107 *
1108 * @return an instance of AccessibleState containing the current state
1109 * of the object
1110 * @see AccessibleState
1111 */
1112 public AccessibleStateSet getAccessibleStateSet() {
1113 AccessibleStateSet states = super .getAccessibleStateSet();
1114 // FIXME: [[[WDW - Should also add BUSY if this implements
1115 // Adjustable at some point. If this happens, we probably
1116 // should also add actions.]]]
1117 if (getOrientation() == VERTICAL_SPLIT) {
1118 states.add(AccessibleState.VERTICAL);
1119 } else {
1120 states.add(AccessibleState.HORIZONTAL);
1121 }
1122 return states;
1123 }
1124
1125 /**
1126 * Get the AccessibleValue associated with this object. In the
1127 * implementation of the Java Accessibility API for this class,
1128 * return this object, which is responsible for implementing the
1129 * AccessibleValue interface on behalf of itself.
1130 *
1131 * @return this object
1132 */
1133 public AccessibleValue getAccessibleValue() {
1134 return this ;
1135 }
1136
1137 /**
1138 * Gets the accessible value of this object.
1139 *
1140 * @return a localized String describing the value of this object
1141 */
1142 public Number getCurrentAccessibleValue() {
1143 return new Integer(getDividerLocation());
1144 }
1145
1146 /**
1147 * Sets the value of this object as a Number.
1148 *
1149 * @return True if the value was set.
1150 */
1151 public boolean setCurrentAccessibleValue(Number n) {
1152 // TIGER - 4422535
1153 if (n == null) {
1154 return false;
1155 }
1156 setDividerLocation(n.intValue());
1157 return true;
1158 }
1159
1160 /**
1161 * Gets the minimum accessible value of this object.
1162 *
1163 * @return The minimum value of this object.
1164 */
1165 public Number getMinimumAccessibleValue() {
1166 return new Integer(getUI().getMinimumDividerLocation(
1167 JSplitPane.this ));
1168 }
1169
1170 /**
1171 * Gets the maximum accessible value of this object.
1172 *
1173 * @return The maximum value of this object.
1174 */
1175 public Number getMaximumAccessibleValue() {
1176 return new Integer(getUI().getMaximumDividerLocation(
1177 JSplitPane.this ));
1178 }
1179
1180 /**
1181 * Gets the role of this object.
1182 *
1183 * @return an instance of AccessibleRole describing the role of
1184 * the object
1185 * @see AccessibleRole
1186 */
1187 public AccessibleRole getAccessibleRole() {
1188 return AccessibleRole.SPLIT_PANE;
1189 }
1190 } // inner class AccessibleJSplitPane
1191 }
|