src/java.desktop/share/classes/javax/swing/JSplitPane.java

Print this page


   1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 
  28 package javax.swing;
  29 
  30 
  31 
  32 import java.beans.ConstructorProperties;
  33 import javax.swing.plaf.*;
  34 import javax.accessibility.*;
  35 
  36 import java.awt.*;
  37 
  38 import java.io.ObjectOutputStream;
  39 import java.io.ObjectInputStream;
  40 import java.io.IOException;
  41 
  42 
  43 
  44 /**
  45  * <code>JSplitPane</code> is used to divide two (and only two)
  46  * <code>Component</code>s. The two <code>Component</code>s
  47  * are graphically divided based on the look and feel
  48  * implementation, and the two <code>Component</code>s can then be
  49  * interactively resized by the user.
  50  * Information on using <code>JSplitPane</code> is in
  51  * <a
  52  href="http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html">How to Use Split Panes</a> in
  53  * <em>The Java Tutorial</em>.
  54  * <p>
  55  * The two <code>Component</code>s in a split pane can be aligned
  56  * left to right using
  57  * <code>JSplitPane.HORIZONTAL_SPLIT</code>, or top to bottom using
  58  * <code>JSplitPane.VERTICAL_SPLIT</code>.
  59  * The preferred way to change the size of the <code>Component</code>s
  60  * is to invoke
  61  * <code>setDividerLocation</code> where <code>location</code> is either
  62  * the new x or y position, depending on the orientation of the
  63  * <code>JSplitPane</code>.


  82  * <strong>Warning:</strong> Swing is not thread safe. For more
  83  * information see <a
  84  * href="package-summary.html#threading">Swing's Threading
  85  * Policy</a>.
  86  * <p>
  87  * <strong>Warning:</strong>
  88  * Serialized objects of this class will not be compatible with
  89  * future Swing releases. The current serialization support is
  90  * appropriate for short term storage or RMI between applications running
  91  * the same version of Swing.  As of 1.4, support for long term storage
  92  * of all JavaBeans&trade;
  93  * has been added to the <code>java.beans</code> package.
  94  * Please see {@link java.beans.XMLEncoder}.
  95  *
  96  * @see #setDividerLocation
  97  * @see #resetToPreferredSizes
  98  *
  99  * @author Scott Violet
 100  * @since 1.2
 101  */

 102 @SuppressWarnings("serial") // Same-version serialization only
 103 public class JSplitPane extends JComponent implements Accessible
 104 {
 105     /**
 106      * @see #getUIClassID
 107      * @see #readObject
 108      */
 109     private static final String uiClassID = "SplitPaneUI";
 110 
 111     /**
 112      * Vertical split indicates the <code>Component</code>s are
 113      * split along the y axis.  For example the two
 114      * <code>Component</code>s will be split one on top of the other.
 115      */
 116     public final static int VERTICAL_SPLIT = 0;
 117 
 118     /**
 119      * Horizontal split indicates the <code>Component</code>s are
 120      * split along the x axis.  For example the two
 121      * <code>Component</code>s will be split one to the left of the


 348         if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT)
 349             throw new IllegalArgumentException("cannot create JSplitPane, " +
 350                                                "orientation must be one of " +
 351                                                "JSplitPane.HORIZONTAL_SPLIT " +
 352                                                "or JSplitPane.VERTICAL_SPLIT");
 353         continuousLayout = newContinuousLayout;
 354         if (newLeftComponent != null)
 355             setLeftComponent(newLeftComponent);
 356         if (newRightComponent != null)
 357             setRightComponent(newRightComponent);
 358         updateUI();
 359 
 360     }
 361 
 362 
 363     /**
 364      * Sets the L&amp;F object that renders this component.
 365      *
 366      * @param ui  the <code>SplitPaneUI</code> L&amp;F object
 367      * @see UIDefaults#getUI
 368      * @beaninfo
 369      *        bound: true
 370      *       hidden: true
 371      *    attribute: visualUpdate true
 372      *  description: The UI object that implements the Component's LookAndFeel.
 373      */
 374     public void setUI(SplitPaneUI ui) {
 375         if ((SplitPaneUI)this.ui != ui) {
 376             super.setUI(ui);
 377             revalidate();
 378         }
 379     }
 380 
 381 
 382     /**
 383      * Returns the <code>SplitPaneUI</code> that is providing the
 384      * current look and feel.
 385      *
 386      * @return the <code>SplitPaneUI</code> object that renders this component
 387      * @beaninfo
 388      *       expert: true
 389      *  description: The L&amp;F object that renders this component.
 390      */


 391     public SplitPaneUI getUI() {
 392         return (SplitPaneUI)ui;
 393     }
 394 
 395 
 396     /**
 397      * Notification from the <code>UIManager</code> that the L&amp;F has changed.
 398      * Replaces the current UI object with the latest version from the
 399      * <code>UIManager</code>.
 400      *
 401      * @see JComponent#updateUI
 402      */
 403     public void updateUI() {
 404         setUI((SplitPaneUI)UIManager.getUI(this));
 405         revalidate();
 406     }
 407 
 408 
 409     /**
 410      * Returns the name of the L&amp;F class that renders this component.
 411      *
 412      * @return the string "SplitPaneUI"
 413      * @see JComponent#getUIClassID
 414      * @see UIDefaults#getUI
 415      * @beaninfo
 416      *       expert: true
 417      *  description: A string that specifies the name of the L&amp;F class.
 418      */


 419     public String getUIClassID() {
 420         return uiClassID;
 421     }
 422 
 423 
 424     /**
 425      * Sets the size of the divider.
 426      *
 427      * @param newSize an integer giving the size of the divider in pixels
 428      * @beaninfo
 429      *        bound: true
 430      *  description: The size of the divider.
 431      */


 432     public void setDividerSize(int newSize) {
 433         int           oldSize = dividerSize;
 434 
 435         dividerSizeSet = true;
 436         if (oldSize != newSize) {
 437             dividerSize = newSize;
 438             firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, newSize);
 439         }
 440     }
 441 
 442 
 443     /**
 444      * Returns the size of the divider.
 445      *
 446      * @return an integer giving the size of the divider in pixels
 447      */
 448     public int getDividerSize() {
 449         return dividerSize;
 450     }
 451 


 454      * Sets the component to the left (or above) the divider.
 455      *
 456      * @param comp the <code>Component</code> to display in that position
 457      */
 458     public void setLeftComponent(Component comp) {
 459         if (comp == null) {
 460             if (leftComponent != null) {
 461                 remove(leftComponent);
 462                 leftComponent = null;
 463             }
 464         } else {
 465             add(comp, JSplitPane.LEFT);
 466         }
 467     }
 468 
 469 
 470     /**
 471      * Returns the component to the left (or above) the divider.
 472      *
 473      * @return the <code>Component</code> displayed in that position
 474      * @beaninfo
 475      *    preferred: true
 476      *  description: The component to the left (or above) the divider.
 477      */


 478     public Component getLeftComponent() {
 479         return leftComponent;
 480     }
 481 
 482 
 483     /**
 484      * Sets the component above, or to the left of the divider.
 485      *
 486      * @param comp the <code>Component</code> to display in that position
 487      * @beaninfo
 488      *  description: The component above, or to the left of the divider.
 489      */


 490     public void setTopComponent(Component comp) {
 491         setLeftComponent(comp);
 492     }
 493 
 494 
 495     /**
 496      * Returns the component above, or to the left of the divider.
 497      *
 498      * @return the <code>Component</code> displayed in that position
 499      */
 500     public Component getTopComponent() {
 501         return leftComponent;
 502     }
 503 
 504 
 505     /**
 506      * Sets the component to the right (or below) the divider.
 507      *
 508      * @param comp the <code>Component</code> to display in that position
 509      * @beaninfo
 510      *    preferred: true
 511      *  description: The component to the right (or below) the divider.
 512      */


 513     public void setRightComponent(Component comp) {
 514         if (comp == null) {
 515             if (rightComponent != null) {
 516                 remove(rightComponent);
 517                 rightComponent = null;
 518             }
 519         } else {
 520             add(comp, JSplitPane.RIGHT);
 521         }
 522     }
 523 
 524 
 525     /**
 526      * Returns the component to the right (or below) the divider.
 527      *
 528      * @return the <code>Component</code> displayed in that position
 529      */
 530     public Component getRightComponent() {
 531         return rightComponent;
 532     }
 533 
 534 
 535     /**
 536      * Sets the component below, or to the right of the divider.
 537      *
 538      * @param comp the <code>Component</code> to display in that position
 539      * @beaninfo
 540      *  description: The component below, or to the right of the divider.
 541      */


 542     public void setBottomComponent(Component comp) {
 543         setRightComponent(comp);
 544     }
 545 
 546 
 547     /**
 548      * Returns the component below, or to the right of the divider.
 549      *
 550      * @return the <code>Component</code> displayed in that position
 551      */
 552     public Component getBottomComponent() {
 553         return rightComponent;
 554     }
 555 
 556 
 557     /**
 558      * Sets the value of the <code>oneTouchExpandable</code> property,
 559      * which must be <code>true</code> for the
 560      * <code>JSplitPane</code> to provide a UI widget
 561      * on the divider to quickly expand/collapse the divider.
 562      * The default value of this property is <code>false</code>.
 563      * Some look and feels might not support one-touch expanding;
 564      * they will ignore this property.
 565      *
 566      * @param newValue <code>true</code> to specify that the split pane should provide a
 567      *        collapse/expand widget
 568      * @beaninfo
 569      *        bound: true
 570      *  description: UI widget on the divider to quickly
 571      *               expand/collapse the divider.
 572      *
 573      * @see #isOneTouchExpandable
 574      */


 575     public void setOneTouchExpandable(boolean newValue) {
 576         boolean           oldValue = oneTouchExpandable;
 577 
 578         oneTouchExpandable = newValue;
 579         oneTouchExpandableSet = true;
 580         firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue, newValue);
 581         repaint();
 582     }
 583 
 584 
 585     /**
 586      * Gets the <code>oneTouchExpandable</code> property.
 587      *
 588      * @return the value of the <code>oneTouchExpandable</code> property
 589      * @see #setOneTouchExpandable
 590      */
 591     public boolean isOneTouchExpandable() {
 592         return oneTouchExpandable;
 593     }
 594 
 595 
 596     /**
 597      * Sets the last location the divider was at to
 598      * <code>newLastLocation</code>.
 599      *
 600      * @param newLastLocation an integer specifying the last divider location
 601      *        in pixels, from the left (or upper) edge of the pane to the
 602      *        left (or upper) edge of the divider
 603      * @beaninfo
 604      *        bound: true
 605      *  description: The last location the divider was at.
 606      */


 607     public void setLastDividerLocation(int newLastLocation) {
 608         int               oldLocation = lastDividerLocation;
 609 
 610         lastDividerLocation = newLastLocation;
 611         firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldLocation,
 612                            newLastLocation);
 613     }
 614 
 615 
 616     /**
 617      * Returns the last location the divider was at.
 618      *
 619      * @return an integer specifying the last divider location as a count
 620      *       of pixels from the left (or upper) edge of the pane to the
 621      *       left (or upper) edge of the divider
 622      */
 623     public int getLastDividerLocation() {
 624         return lastDividerLocation;
 625     }
 626 
 627 
 628     /**
 629      * Sets the orientation, or how the splitter is divided. The options
 630      * are:<ul>
 631      * <li>JSplitPane.VERTICAL_SPLIT  (above/below orientation of components)
 632      * <li>JSplitPane.HORIZONTAL_SPLIT  (left/right orientation of components)
 633      * </ul>
 634      *
 635      * @param orientation an integer specifying the orientation
 636      * @exception IllegalArgumentException if orientation is not one of:
 637      *        HORIZONTAL_SPLIT or VERTICAL_SPLIT.
 638      * @beaninfo
 639      *        bound: true
 640      *  description: The orientation, or how the splitter is divided.
 641      *         enum: HORIZONTAL_SPLIT JSplitPane.HORIZONTAL_SPLIT
 642      *               VERTICAL_SPLIT   JSplitPane.VERTICAL_SPLIT
 643      */




 644     public void setOrientation(int orientation) {
 645         if ((orientation != VERTICAL_SPLIT) &&
 646             (orientation != HORIZONTAL_SPLIT)) {
 647            throw new IllegalArgumentException("JSplitPane: orientation must " +
 648                                               "be one of " +
 649                                               "JSplitPane.VERTICAL_SPLIT or " +
 650                                               "JSplitPane.HORIZONTAL_SPLIT");
 651         }
 652 
 653         int           oldOrientation = this.orientation;
 654 
 655         this.orientation = orientation;
 656         firePropertyChange(ORIENTATION_PROPERTY, oldOrientation, orientation);
 657     }
 658 
 659 
 660     /**
 661      * Returns the orientation.
 662      *
 663      * @return an integer giving the orientation
 664      * @see #setOrientation
 665      */
 666     public int getOrientation() {
 667         return orientation;
 668     }
 669 
 670 
 671     /**
 672      * Sets the value of the <code>continuousLayout</code> property,
 673      * which must be <code>true</code> for the child components
 674      * to be continuously
 675      * redisplayed and laid out during user intervention.
 676      * The default value of this property is look and feel dependent.
 677      * Some look and feels might not support continuous layout;
 678      * they will ignore this property.
 679      *
 680      * @param newContinuousLayout  <code>true</code> if the components
 681      *        should continuously be redrawn as the divider changes position
 682      * @beaninfo
 683      *        bound: true
 684      *  description: Whether the child components are
 685      *               continuously redisplayed and laid out during
 686      *               user intervention.
 687      * @see #isContinuousLayout
 688      */


 689     public void setContinuousLayout(boolean newContinuousLayout) {
 690         boolean           oldCD = continuousLayout;
 691 
 692         continuousLayout = newContinuousLayout;
 693         firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldCD,
 694                            newContinuousLayout);
 695     }
 696 
 697 
 698     /**
 699      * Gets the <code>continuousLayout</code> property.
 700      *
 701      * @return the value of the <code>continuousLayout</code> property
 702      * @see #setContinuousLayout
 703      */
 704     public boolean isContinuousLayout() {
 705         return continuousLayout;
 706     }
 707 
 708     /**
 709      * Specifies how to distribute extra space when the size of the split pane
 710      * changes. A value of 0, the default,
 711      * indicates the right/bottom component gets all the extra space (the
 712      * left/top component acts fixed), where as a value of 1 specifies the
 713      * left/top component gets all the extra space (the right/bottom component
 714      * acts fixed). Specifically, the left/top component gets (weight * diff)
 715      * extra space and the right/bottom component gets (1 - weight) * diff
 716      * extra space.
 717      *
 718      * @param value as described above
 719      * @exception IllegalArgumentException if <code>value</code> is &lt; 0 or &gt; 1
 720      * @since 1.3
 721      * @beaninfo
 722      *        bound: true
 723      *  description: Specifies how to distribute extra space when the split pane
 724      *               resizes.
 725      */


 726     public void setResizeWeight(double value) {
 727         if (value < 0 || value > 1) {
 728             throw new IllegalArgumentException("JSplitPane weight must be between 0 and 1");
 729         }
 730         double         oldWeight = resizeWeight;
 731 
 732         resizeWeight = value;
 733         firePropertyChange(RESIZE_WEIGHT_PROPERTY, oldWeight, value);
 734     }
 735 
 736     /**
 737      * Returns the number that determines how extra space is distributed.
 738      * @return how extra space is to be distributed on a resize of the
 739      *         split pane
 740      * @since 1.3
 741      */
 742     public double getResizeWeight() {
 743         return resizeWeight;
 744     }
 745 


 756         }
 757     }
 758 
 759 
 760     /**
 761      * Sets the divider location as a percentage of the
 762      * <code>JSplitPane</code>'s size.
 763      * <p>
 764      * This method is implemented in terms of
 765      * <code>setDividerLocation(int)</code>.
 766      * This method immediately changes the size of the split pane based on
 767      * its current size. If the split pane is not correctly realized and on
 768      * screen, this method will have no effect (new divider location will
 769      * become (current size * proportionalLocation) which is 0).
 770      *
 771      * @param proportionalLocation  a double-precision floating point value
 772      *        that specifies a percentage, from zero (top/left) to 1.0
 773      *        (bottom/right)
 774      * @exception IllegalArgumentException if the specified location is &lt; 0
 775      *            or &gt; 1.0
 776      * @beaninfo
 777      *  description: The location of the divider.
 778      */


 779     public void setDividerLocation(double proportionalLocation) {
 780         if (proportionalLocation < 0.0 ||
 781            proportionalLocation > 1.0) {
 782             throw new IllegalArgumentException("proportional location must " +
 783                                                "be between 0.0 and 1.0.");
 784         }
 785         if (getOrientation() == VERTICAL_SPLIT) {
 786             setDividerLocation((int)((double)(getHeight() - getDividerSize()) *
 787                                      proportionalLocation));
 788         } else {
 789             setDividerLocation((int)((double)(getWidth() - getDividerSize()) *
 790                                      proportionalLocation));
 791         }
 792     }
 793 
 794 
 795     /**
 796      * Sets the location of the divider. This is passed off to the
 797      * look and feel implementation, and then listeners are notified. A value
 798      * less than 0 implies the divider should be reset to a value that
 799      * attempts to honor the preferred size of the left/top component.
 800      * After notifying the listeners, the last divider location is updated,
 801      * via <code>setLastDividerLocation</code>.
 802      *
 803      * @param location an int specifying a UI-specific value (typically a
 804      *        pixel count)
 805      * @beaninfo
 806      *        bound: true
 807      *  description: The location of the divider.
 808      */


 809     public void setDividerLocation(int location) {
 810         int                 oldValue = dividerLocation;
 811 
 812         dividerLocation = location;
 813 
 814         // Notify UI.
 815         SplitPaneUI         ui = getUI();
 816 
 817         if (ui != null) {
 818             ui.setDividerLocation(this, location);
 819         }
 820 
 821         // Then listeners
 822         firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldValue, location);
 823 
 824         // And update the last divider location.
 825         setLastDividerLocation(oldValue);
 826     }
 827 
 828 
 829     /**
 830      * Returns the last value passed to <code>setDividerLocation</code>.
 831      * The value returned from this method may differ from the actual
 832      * divider location (if <code>setDividerLocation</code> was passed a
 833      * value bigger than the current size).
 834      *
 835      * @return an integer specifying the location of the divider
 836      */
 837     public int getDividerLocation() {
 838         return dividerLocation;
 839     }
 840 
 841 
 842     /**
 843      * Returns the minimum location of the divider from the look and feel
 844      * implementation.
 845      *
 846      * @return an integer specifying a UI-specific value for the minimum
 847      *          location (typically a pixel count); or -1 if the UI is
 848      *          <code>null</code>
 849      * @beaninfo
 850      *  description: The minimum location of the divider from the L&amp;F.
 851      */


 852     public int getMinimumDividerLocation() {
 853         SplitPaneUI         ui = getUI();
 854 
 855         if (ui != null) {
 856             return ui.getMinimumDividerLocation(this);
 857         }
 858         return -1;
 859     }
 860 
 861 
 862     /**
 863      * Returns the maximum location of the divider from the look and feel
 864      * implementation.
 865      *
 866      * @return an integer specifying a UI-specific value for the maximum
 867      *          location (typically a pixel count); or -1 if the  UI is
 868      *          <code>null</code>
 869      */

 870     public int getMaximumDividerLocation() {
 871         SplitPaneUI         ui = getUI();
 872 
 873         if (ui != null) {
 874             return ui.getMaximumDividerLocation(this);
 875         }
 876         return -1;
 877     }
 878 
 879 
 880     /**
 881      * Removes the child component, <code>component</code> from the
 882      * pane. Resets the <code>leftComponent</code> or
 883      * <code>rightComponent</code> instance variable, as necessary.
 884      *
 885      * @param component the <code>Component</code> to remove
 886      */
 887     public void remove(Component component) {
 888         if (component == leftComponent) {
 889             leftComponent = null;


 930      */
 931     public void removeAll() {
 932         leftComponent = rightComponent = null;
 933         super.removeAll();
 934 
 935         // Update the JSplitPane on the screen
 936         revalidate();
 937         repaint();
 938     }
 939 
 940 
 941     /**
 942      * Returns true, so that calls to <code>revalidate</code>
 943      * on any descendant of this <code>JSplitPane</code>
 944      * will cause a request to be queued that
 945      * will validate the <code>JSplitPane</code> and all its descendants.
 946      *
 947      * @return true
 948      * @see JComponent#revalidate
 949      * @see java.awt.Container#isValidateRoot
 950      *
 951      * @beaninfo
 952      *    hidden: true
 953      */
 954     @Override

 955     public boolean isValidateRoot() {
 956         return true;
 957     }
 958 
 959 
 960     /**
 961      * Adds the specified component to this split pane.
 962      * If <code>constraints</code> identifies the left/top or
 963      * right/bottom child component, and a component with that identifier
 964      * was previously added, it will be removed and then <code>comp</code>
 965      * will be added in its place. If <code>constraints</code> is not
 966      * one of the known identifiers the layout manager may throw an
 967      * <code>IllegalArgumentException</code>.
 968      * <p>
 969      * The possible constraints objects (Strings) are:
 970      * <ul>
 971      * <li>JSplitPane.TOP
 972      * <li>JSplitPane.LEFT
 973      * <li>JSplitPane.BOTTOM
 974      * <li>JSplitPane.RIGHT


1115         ",lastDividerLocation=" + lastDividerLocation +
1116         ",oneTouchExpandable=" + oneTouchExpandableString +
1117         ",orientation=" + orientationString;
1118     }
1119 
1120 
1121 
1122     ///////////////////////////
1123     // Accessibility support //
1124     ///////////////////////////
1125 
1126 
1127     /**
1128      * Gets the AccessibleContext associated with this JSplitPane.
1129      * For split panes, the AccessibleContext takes the form of an
1130      * AccessibleJSplitPane.
1131      * A new AccessibleJSplitPane instance is created if necessary.
1132      *
1133      * @return an AccessibleJSplitPane that serves as the
1134      *         AccessibleContext of this JSplitPane
1135      * @beaninfo
1136      *       expert: true
1137      *  description: The AccessibleContext associated with this SplitPane.
1138      */


1139     public AccessibleContext getAccessibleContext() {
1140         if (accessibleContext == null) {
1141             accessibleContext = new AccessibleJSplitPane();
1142         }
1143         return accessibleContext;
1144     }
1145 
1146 
1147     /**
1148      * This class implements accessibility support for the
1149      * <code>JSplitPane</code> class.  It provides an implementation of the
1150      * Java Accessibility API appropriate to split pane user-interface elements.
1151      * <p>
1152      * <strong>Warning:</strong>
1153      * Serialized objects of this class will not be compatible with
1154      * future Swing releases. The current serialization support is
1155      * appropriate for short term storage or RMI between applications running
1156      * the same version of Swing.  As of 1.4, support for long term storage
1157      * of all JavaBeans&trade;
1158      * has been added to the <code>java.beans</code> package.


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


  26 package javax.swing;
  27 
  28 import java.beans.JavaBean;
  29 import java.beans.BeanProperty;
  30 import java.beans.ConstructorProperties;
  31 import javax.swing.plaf.*;
  32 import javax.accessibility.*;
  33 
  34 import java.awt.*;
  35 
  36 import java.io.ObjectOutputStream;

  37 import java.io.IOException;
  38 


  39 /**
  40  * <code>JSplitPane</code> is used to divide two (and only two)
  41  * <code>Component</code>s. The two <code>Component</code>s
  42  * are graphically divided based on the look and feel
  43  * implementation, and the two <code>Component</code>s can then be
  44  * interactively resized by the user.
  45  * Information on using <code>JSplitPane</code> is in
  46  * <a
  47  href="http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html">How to Use Split Panes</a> in
  48  * <em>The Java Tutorial</em>.
  49  * <p>
  50  * The two <code>Component</code>s in a split pane can be aligned
  51  * left to right using
  52  * <code>JSplitPane.HORIZONTAL_SPLIT</code>, or top to bottom using
  53  * <code>JSplitPane.VERTICAL_SPLIT</code>.
  54  * The preferred way to change the size of the <code>Component</code>s
  55  * is to invoke
  56  * <code>setDividerLocation</code> where <code>location</code> is either
  57  * the new x or y position, depending on the orientation of the
  58  * <code>JSplitPane</code>.


  77  * <strong>Warning:</strong> Swing is not thread safe. For more
  78  * information see <a
  79  * href="package-summary.html#threading">Swing's Threading
  80  * Policy</a>.
  81  * <p>
  82  * <strong>Warning:</strong>
  83  * Serialized objects of this class will not be compatible with
  84  * future Swing releases. The current serialization support is
  85  * appropriate for short term storage or RMI between applications running
  86  * the same version of Swing.  As of 1.4, support for long term storage
  87  * of all JavaBeans&trade;
  88  * has been added to the <code>java.beans</code> package.
  89  * Please see {@link java.beans.XMLEncoder}.
  90  *
  91  * @see #setDividerLocation
  92  * @see #resetToPreferredSizes
  93  *
  94  * @author Scott Violet
  95  * @since 1.2
  96  */
  97 @JavaBean(defaultProperty = "UI")
  98 @SuppressWarnings("serial") // Same-version serialization only
  99 public class JSplitPane extends JComponent implements Accessible
 100 {
 101     /**
 102      * @see #getUIClassID
 103      * @see #readObject
 104      */
 105     private static final String uiClassID = "SplitPaneUI";
 106 
 107     /**
 108      * Vertical split indicates the <code>Component</code>s are
 109      * split along the y axis.  For example the two
 110      * <code>Component</code>s will be split one on top of the other.
 111      */
 112     public final static int VERTICAL_SPLIT = 0;
 113 
 114     /**
 115      * Horizontal split indicates the <code>Component</code>s are
 116      * split along the x axis.  For example the two
 117      * <code>Component</code>s will be split one to the left of the


 344         if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT)
 345             throw new IllegalArgumentException("cannot create JSplitPane, " +
 346                                                "orientation must be one of " +
 347                                                "JSplitPane.HORIZONTAL_SPLIT " +
 348                                                "or JSplitPane.VERTICAL_SPLIT");
 349         continuousLayout = newContinuousLayout;
 350         if (newLeftComponent != null)
 351             setLeftComponent(newLeftComponent);
 352         if (newRightComponent != null)
 353             setRightComponent(newRightComponent);
 354         updateUI();
 355 
 356     }
 357 
 358 
 359     /**
 360      * Sets the L&amp;F object that renders this component.
 361      *
 362      * @param ui  the <code>SplitPaneUI</code> L&amp;F object
 363      * @see UIDefaults#getUI





 364      */
 365     public void setUI(SplitPaneUI ui) {
 366         if ((SplitPaneUI)this.ui != ui) {
 367             super.setUI(ui);
 368             revalidate();
 369         }
 370     }
 371 
 372 
 373     /**
 374      * Returns the <code>SplitPaneUI</code> that is providing the
 375      * current look and feel.
 376      *
 377      * @return the <code>SplitPaneUI</code> object that renders this component



 378      */
 379     @BeanProperty(bound = false, expert = true, description
 380             = "The L&amp;F object that renders this component.")
 381     public SplitPaneUI getUI() {
 382         return (SplitPaneUI)ui;
 383     }
 384 
 385 
 386     /**
 387      * Notification from the <code>UIManager</code> that the L&amp;F has changed.
 388      * Replaces the current UI object with the latest version from the
 389      * <code>UIManager</code>.
 390      *
 391      * @see JComponent#updateUI
 392      */
 393     public void updateUI() {
 394         setUI((SplitPaneUI)UIManager.getUI(this));
 395         revalidate();
 396     }
 397 
 398 
 399     /**
 400      * Returns the name of the L&amp;F class that renders this component.
 401      *
 402      * @return the string "SplitPaneUI"
 403      * @see JComponent#getUIClassID
 404      * @see UIDefaults#getUI



 405      */
 406     @BeanProperty(bound = false, expert = true, description
 407             = "A string that specifies the name of the L&amp;F class.")
 408     public String getUIClassID() {
 409         return uiClassID;
 410     }
 411 
 412 
 413     /**
 414      * Sets the size of the divider.
 415      *
 416      * @param newSize an integer giving the size of the divider in pixels



 417      */
 418     @BeanProperty(description
 419             = "The size of the divider.")
 420     public void setDividerSize(int newSize) {
 421         int           oldSize = dividerSize;
 422 
 423         dividerSizeSet = true;
 424         if (oldSize != newSize) {
 425             dividerSize = newSize;
 426             firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, newSize);
 427         }
 428     }
 429 
 430 
 431     /**
 432      * Returns the size of the divider.
 433      *
 434      * @return an integer giving the size of the divider in pixels
 435      */
 436     public int getDividerSize() {
 437         return dividerSize;
 438     }
 439 


 442      * Sets the component to the left (or above) the divider.
 443      *
 444      * @param comp the <code>Component</code> to display in that position
 445      */
 446     public void setLeftComponent(Component comp) {
 447         if (comp == null) {
 448             if (leftComponent != null) {
 449                 remove(leftComponent);
 450                 leftComponent = null;
 451             }
 452         } else {
 453             add(comp, JSplitPane.LEFT);
 454         }
 455     }
 456 
 457 
 458     /**
 459      * Returns the component to the left (or above) the divider.
 460      *
 461      * @return the <code>Component</code> displayed in that position



 462      */
 463     @BeanProperty(bound = false, preferred = true, description
 464             = "The component to the left (or above) the divider.")
 465     public Component getLeftComponent() {
 466         return leftComponent;
 467     }
 468 
 469 
 470     /**
 471      * Sets the component above, or to the left of the divider.
 472      *
 473      * @param comp the <code>Component</code> to display in that position


 474      */
 475     @BeanProperty(bound = false, description
 476             = "The component above, or to the left of the divider.")
 477     public void setTopComponent(Component comp) {
 478         setLeftComponent(comp);
 479     }
 480 
 481 
 482     /**
 483      * Returns the component above, or to the left of the divider.
 484      *
 485      * @return the <code>Component</code> displayed in that position
 486      */
 487     public Component getTopComponent() {
 488         return leftComponent;
 489     }
 490 
 491 
 492     /**
 493      * Sets the component to the right (or below) the divider.
 494      *
 495      * @param comp the <code>Component</code> to display in that position



 496      */
 497     @BeanProperty(bound = false, preferred = true, description
 498             = "The component to the right (or below) the divider.")
 499     public void setRightComponent(Component comp) {
 500         if (comp == null) {
 501             if (rightComponent != null) {
 502                 remove(rightComponent);
 503                 rightComponent = null;
 504             }
 505         } else {
 506             add(comp, JSplitPane.RIGHT);
 507         }
 508     }
 509 
 510 
 511     /**
 512      * Returns the component to the right (or below) the divider.
 513      *
 514      * @return the <code>Component</code> displayed in that position
 515      */
 516     public Component getRightComponent() {
 517         return rightComponent;
 518     }
 519 
 520 
 521     /**
 522      * Sets the component below, or to the right of the divider.
 523      *
 524      * @param comp the <code>Component</code> to display in that position


 525      */
 526     @BeanProperty(bound = false, description
 527             = "The component below, or to the right of the divider.")
 528     public void setBottomComponent(Component comp) {
 529         setRightComponent(comp);
 530     }
 531 
 532 
 533     /**
 534      * Returns the component below, or to the right of the divider.
 535      *
 536      * @return the <code>Component</code> displayed in that position
 537      */
 538     public Component getBottomComponent() {
 539         return rightComponent;
 540     }
 541 
 542 
 543     /**
 544      * Sets the value of the <code>oneTouchExpandable</code> property,
 545      * which must be <code>true</code> for the
 546      * <code>JSplitPane</code> to provide a UI widget
 547      * on the divider to quickly expand/collapse the divider.
 548      * The default value of this property is <code>false</code>.
 549      * Some look and feels might not support one-touch expanding;
 550      * they will ignore this property.
 551      *
 552      * @param newValue <code>true</code> to specify that the split pane should provide a
 553      *        collapse/expand widget




 554      *
 555      * @see #isOneTouchExpandable
 556      */
 557     @BeanProperty(description
 558             = "UI widget on the divider to quickly expand/collapse the divider.")
 559     public void setOneTouchExpandable(boolean newValue) {
 560         boolean           oldValue = oneTouchExpandable;
 561 
 562         oneTouchExpandable = newValue;
 563         oneTouchExpandableSet = true;
 564         firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue, newValue);
 565         repaint();
 566     }
 567 
 568 
 569     /**
 570      * Gets the <code>oneTouchExpandable</code> property.
 571      *
 572      * @return the value of the <code>oneTouchExpandable</code> property
 573      * @see #setOneTouchExpandable
 574      */
 575     public boolean isOneTouchExpandable() {
 576         return oneTouchExpandable;
 577     }
 578 
 579 
 580     /**
 581      * Sets the last location the divider was at to
 582      * <code>newLastLocation</code>.
 583      *
 584      * @param newLastLocation an integer specifying the last divider location
 585      *        in pixels, from the left (or upper) edge of the pane to the
 586      *        left (or upper) edge of the divider



 587      */
 588     @BeanProperty(description
 589             = "The last location the divider was at.")
 590     public void setLastDividerLocation(int newLastLocation) {
 591         int               oldLocation = lastDividerLocation;
 592 
 593         lastDividerLocation = newLastLocation;
 594         firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldLocation,
 595                            newLastLocation);
 596     }
 597 
 598 
 599     /**
 600      * Returns the last location the divider was at.
 601      *
 602      * @return an integer specifying the last divider location as a count
 603      *       of pixels from the left (or upper) edge of the pane to the
 604      *       left (or upper) edge of the divider
 605      */
 606     public int getLastDividerLocation() {
 607         return lastDividerLocation;
 608     }
 609 
 610 
 611     /**
 612      * Sets the orientation, or how the splitter is divided. The options
 613      * are:<ul>
 614      * <li>JSplitPane.VERTICAL_SPLIT  (above/below orientation of components)
 615      * <li>JSplitPane.HORIZONTAL_SPLIT  (left/right orientation of components)
 616      * </ul>
 617      *
 618      * @param orientation an integer specifying the orientation
 619      * @exception IllegalArgumentException if orientation is not one of:
 620      *        HORIZONTAL_SPLIT or VERTICAL_SPLIT.





 621      */
 622     @BeanProperty(enumerationValues = {
 623             "JSplitPane.HORIZONTAL_SPLIT",
 624             "JSplitPane.VERTICAL_SPLIT"}, description
 625             = "The orientation, or how the splitter is divided.")
 626     public void setOrientation(int orientation) {
 627         if ((orientation != VERTICAL_SPLIT) &&
 628             (orientation != HORIZONTAL_SPLIT)) {
 629            throw new IllegalArgumentException("JSplitPane: orientation must " +
 630                                               "be one of " +
 631                                               "JSplitPane.VERTICAL_SPLIT or " +
 632                                               "JSplitPane.HORIZONTAL_SPLIT");
 633         }
 634 
 635         int           oldOrientation = this.orientation;
 636 
 637         this.orientation = orientation;
 638         firePropertyChange(ORIENTATION_PROPERTY, oldOrientation, orientation);
 639     }
 640 
 641 
 642     /**
 643      * Returns the orientation.
 644      *
 645      * @return an integer giving the orientation
 646      * @see #setOrientation
 647      */
 648     public int getOrientation() {
 649         return orientation;
 650     }
 651 
 652 
 653     /**
 654      * Sets the value of the <code>continuousLayout</code> property,
 655      * which must be <code>true</code> for the child components
 656      * to be continuously
 657      * redisplayed and laid out during user intervention.
 658      * The default value of this property is look and feel dependent.
 659      * Some look and feels might not support continuous layout;
 660      * they will ignore this property.
 661      *
 662      * @param newContinuousLayout  <code>true</code> if the components
 663      *        should continuously be redrawn as the divider changes position





 664      * @see #isContinuousLayout
 665      */
 666     @BeanProperty(description
 667             = "Whether the child components are continuously redisplayed and laid out during user intervention.")
 668     public void setContinuousLayout(boolean newContinuousLayout) {
 669         boolean           oldCD = continuousLayout;
 670 
 671         continuousLayout = newContinuousLayout;
 672         firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldCD,
 673                            newContinuousLayout);
 674     }
 675 
 676 
 677     /**
 678      * Gets the <code>continuousLayout</code> property.
 679      *
 680      * @return the value of the <code>continuousLayout</code> property
 681      * @see #setContinuousLayout
 682      */
 683     public boolean isContinuousLayout() {
 684         return continuousLayout;
 685     }
 686 
 687     /**
 688      * Specifies how to distribute extra space when the size of the split pane
 689      * changes. A value of 0, the default,
 690      * indicates the right/bottom component gets all the extra space (the
 691      * left/top component acts fixed), where as a value of 1 specifies the
 692      * left/top component gets all the extra space (the right/bottom component
 693      * acts fixed). Specifically, the left/top component gets (weight * diff)
 694      * extra space and the right/bottom component gets (1 - weight) * diff
 695      * extra space.
 696      *
 697      * @param value as described above
 698      * @exception IllegalArgumentException if <code>value</code> is &lt; 0 or &gt; 1
 699      * @since 1.3




 700      */
 701     @BeanProperty(description
 702             = "Specifies how to distribute extra space when the split pane resizes.")
 703     public void setResizeWeight(double value) {
 704         if (value < 0 || value > 1) {
 705             throw new IllegalArgumentException("JSplitPane weight must be between 0 and 1");
 706         }
 707         double         oldWeight = resizeWeight;
 708 
 709         resizeWeight = value;
 710         firePropertyChange(RESIZE_WEIGHT_PROPERTY, oldWeight, value);
 711     }
 712 
 713     /**
 714      * Returns the number that determines how extra space is distributed.
 715      * @return how extra space is to be distributed on a resize of the
 716      *         split pane
 717      * @since 1.3
 718      */
 719     public double getResizeWeight() {
 720         return resizeWeight;
 721     }
 722 


 733         }
 734     }
 735 
 736 
 737     /**
 738      * Sets the divider location as a percentage of the
 739      * <code>JSplitPane</code>'s size.
 740      * <p>
 741      * This method is implemented in terms of
 742      * <code>setDividerLocation(int)</code>.
 743      * This method immediately changes the size of the split pane based on
 744      * its current size. If the split pane is not correctly realized and on
 745      * screen, this method will have no effect (new divider location will
 746      * become (current size * proportionalLocation) which is 0).
 747      *
 748      * @param proportionalLocation  a double-precision floating point value
 749      *        that specifies a percentage, from zero (top/left) to 1.0
 750      *        (bottom/right)
 751      * @exception IllegalArgumentException if the specified location is &lt; 0
 752      *            or &gt; 1.0


 753      */
 754     @BeanProperty(description
 755             = "The location of the divider.")
 756     public void setDividerLocation(double proportionalLocation) {
 757         if (proportionalLocation < 0.0 ||
 758            proportionalLocation > 1.0) {
 759             throw new IllegalArgumentException("proportional location must " +
 760                                                "be between 0.0 and 1.0.");
 761         }
 762         if (getOrientation() == VERTICAL_SPLIT) {
 763             setDividerLocation((int)((double)(getHeight() - getDividerSize()) *
 764                                      proportionalLocation));
 765         } else {
 766             setDividerLocation((int)((double)(getWidth() - getDividerSize()) *
 767                                      proportionalLocation));
 768         }
 769     }
 770 
 771 
 772     /**
 773      * Sets the location of the divider. This is passed off to the
 774      * look and feel implementation, and then listeners are notified. A value
 775      * less than 0 implies the divider should be reset to a value that
 776      * attempts to honor the preferred size of the left/top component.
 777      * After notifying the listeners, the last divider location is updated,
 778      * via <code>setLastDividerLocation</code>.
 779      *
 780      * @param location an int specifying a UI-specific value (typically a
 781      *        pixel count)



 782      */
 783     @BeanProperty(description
 784             = "The location of the divider.")
 785     public void setDividerLocation(int location) {
 786         int                 oldValue = dividerLocation;
 787 
 788         dividerLocation = location;
 789 
 790         // Notify UI.
 791         SplitPaneUI         ui = getUI();
 792 
 793         if (ui != null) {
 794             ui.setDividerLocation(this, location);
 795         }
 796 
 797         // Then listeners
 798         firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldValue, location);
 799 
 800         // And update the last divider location.
 801         setLastDividerLocation(oldValue);
 802     }
 803 
 804 
 805     /**
 806      * Returns the last value passed to <code>setDividerLocation</code>.
 807      * The value returned from this method may differ from the actual
 808      * divider location (if <code>setDividerLocation</code> was passed a
 809      * value bigger than the current size).
 810      *
 811      * @return an integer specifying the location of the divider
 812      */
 813     public int getDividerLocation() {
 814         return dividerLocation;
 815     }
 816 
 817 
 818     /**
 819      * Returns the minimum location of the divider from the look and feel
 820      * implementation.
 821      *
 822      * @return an integer specifying a UI-specific value for the minimum
 823      *          location (typically a pixel count); or -1 if the UI is
 824      *          <code>null</code>


 825      */
 826     @BeanProperty(bound = false, description
 827             = "The minimum location of the divider from the L&amp;F.")
 828     public int getMinimumDividerLocation() {
 829         SplitPaneUI         ui = getUI();
 830 
 831         if (ui != null) {
 832             return ui.getMinimumDividerLocation(this);
 833         }
 834         return -1;
 835     }
 836 
 837 
 838     /**
 839      * Returns the maximum location of the divider from the look and feel
 840      * implementation.
 841      *
 842      * @return an integer specifying a UI-specific value for the maximum
 843      *          location (typically a pixel count); or -1 if the  UI is
 844      *          <code>null</code>
 845      */
 846     @BeanProperty(bound = false)
 847     public int getMaximumDividerLocation() {
 848         SplitPaneUI         ui = getUI();
 849 
 850         if (ui != null) {
 851             return ui.getMaximumDividerLocation(this);
 852         }
 853         return -1;
 854     }
 855 
 856 
 857     /**
 858      * Removes the child component, <code>component</code> from the
 859      * pane. Resets the <code>leftComponent</code> or
 860      * <code>rightComponent</code> instance variable, as necessary.
 861      *
 862      * @param component the <code>Component</code> to remove
 863      */
 864     public void remove(Component component) {
 865         if (component == leftComponent) {
 866             leftComponent = null;


 907      */
 908     public void removeAll() {
 909         leftComponent = rightComponent = null;
 910         super.removeAll();
 911 
 912         // Update the JSplitPane on the screen
 913         revalidate();
 914         repaint();
 915     }
 916 
 917 
 918     /**
 919      * Returns true, so that calls to <code>revalidate</code>
 920      * on any descendant of this <code>JSplitPane</code>
 921      * will cause a request to be queued that
 922      * will validate the <code>JSplitPane</code> and all its descendants.
 923      *
 924      * @return true
 925      * @see JComponent#revalidate
 926      * @see java.awt.Container#isValidateRoot



 927      */
 928     @Override
 929     @BeanProperty(hidden = true)
 930     public boolean isValidateRoot() {
 931         return true;
 932     }
 933 
 934 
 935     /**
 936      * Adds the specified component to this split pane.
 937      * If <code>constraints</code> identifies the left/top or
 938      * right/bottom child component, and a component with that identifier
 939      * was previously added, it will be removed and then <code>comp</code>
 940      * will be added in its place. If <code>constraints</code> is not
 941      * one of the known identifiers the layout manager may throw an
 942      * <code>IllegalArgumentException</code>.
 943      * <p>
 944      * The possible constraints objects (Strings) are:
 945      * <ul>
 946      * <li>JSplitPane.TOP
 947      * <li>JSplitPane.LEFT
 948      * <li>JSplitPane.BOTTOM
 949      * <li>JSplitPane.RIGHT


1090         ",lastDividerLocation=" + lastDividerLocation +
1091         ",oneTouchExpandable=" + oneTouchExpandableString +
1092         ",orientation=" + orientationString;
1093     }
1094 
1095 
1096 
1097     ///////////////////////////
1098     // Accessibility support //
1099     ///////////////////////////
1100 
1101 
1102     /**
1103      * Gets the AccessibleContext associated with this JSplitPane.
1104      * For split panes, the AccessibleContext takes the form of an
1105      * AccessibleJSplitPane.
1106      * A new AccessibleJSplitPane instance is created if necessary.
1107      *
1108      * @return an AccessibleJSplitPane that serves as the
1109      *         AccessibleContext of this JSplitPane



1110      */
1111     @BeanProperty(bound = false, expert = true, description
1112             = "The AccessibleContext associated with this SplitPane.")
1113     public AccessibleContext getAccessibleContext() {
1114         if (accessibleContext == null) {
1115             accessibleContext = new AccessibleJSplitPane();
1116         }
1117         return accessibleContext;
1118     }
1119 
1120 
1121     /**
1122      * This class implements accessibility support for the
1123      * <code>JSplitPane</code> class.  It provides an implementation of the
1124      * Java Accessibility API appropriate to split pane user-interface elements.
1125      * <p>
1126      * <strong>Warning:</strong>
1127      * Serialized objects of this class will not be compatible with
1128      * future Swing releases. The current serialization support is
1129      * appropriate for short term storage or RMI between applications running
1130      * the same version of Swing.  As of 1.4, support for long term storage
1131      * of all JavaBeans&trade;
1132      * has been added to the <code>java.beans</code> package.