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>. 64 * <p> 65 * To resize the <code>Component</code>s to their preferred sizes invoke 66 * <code>resetToPreferredSizes</code>. 67 * <p> 68 * When the user is resizing the <code>Component</code>s the minimum 69 * size of the <code>Components</code> is used to determine the 70 * maximum/minimum position the <code>Component</code>s 71 * can be set to. If the minimum size of the two 72 * components is greater than the size of the split pane the divider 73 * will not allow you to resize it. To alter the minimum size of a 74 * <code>JComponent</code>, see {@link JComponent#setMinimumSize}. 75 * <p> 76 * When the user resizes the split pane the new space is distributed between 77 * the two components based on the <code>resizeWeight</code> property. 78 * A value of 0, 79 * the default, indicates the right/bottom component gets all the space, 80 * where as a value of 1 indicates the left/top component gets all the space. 81 * <p> 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™ 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 */ 101 @SuppressWarnings("serial") // Same-version serialization only 102 public class JSplitPane extends JComponent implements Accessible 103 { 104 /** 105 * @see #getUIClassID 106 * @see #readObject 107 */ 108 private static final String uiClassID = "SplitPaneUI"; 109 110 /** 111 * Vertical split indicates the <code>Component</code>s are 112 * split along the y axis. For example the two 113 * <code>Component</code>s will be split one on top of the other. 114 */ 115 public final static int VERTICAL_SPLIT = 0; 116 117 /** 118 * Horizontal split indicates the <code>Component</code>s are 119 * split along the x axis. For example the two 120 * <code>Component</code>s will be split one to the left of the 121 * other. 122 */ 123 public final static int HORIZONTAL_SPLIT = 1; 124 125 /** 126 * Used to add a <code>Component</code> to the left of the other 127 * <code>Component</code>. 128 */ 129 public final static String LEFT = "left"; 130 131 /** 132 * Used to add a <code>Component</code> to the right of the other 133 * <code>Component</code>. 134 */ 135 public final static String RIGHT = "right"; 136 137 /** 138 * Used to add a <code>Component</code> above the other 139 * <code>Component</code>. 140 */ 141 public final static String TOP = "top"; 142 143 /** 144 * Used to add a <code>Component</code> below the other 145 * <code>Component</code>. 146 */ 147 public final static String BOTTOM = "bottom"; 148 149 /** 150 * Used to add a <code>Component</code> that will represent the divider. 151 */ 152 public final static String DIVIDER = "divider"; 153 154 /** 155 * Bound property name for orientation (horizontal or vertical). 156 */ 157 public final static String ORIENTATION_PROPERTY = "orientation"; 158 159 /** 160 * Bound property name for continuousLayout. 161 */ 162 public final static String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout"; 163 164 /** 165 * Bound property name for border. 166 */ 167 public final static String DIVIDER_SIZE_PROPERTY = "dividerSize"; 168 169 /** 170 * Bound property for oneTouchExpandable. 171 */ 172 public final static String ONE_TOUCH_EXPANDABLE_PROPERTY = 173 "oneTouchExpandable"; 174 175 /** 176 * Bound property for lastLocation. 177 */ 178 public final static String LAST_DIVIDER_LOCATION_PROPERTY = 179 "lastDividerLocation"; 180 181 /** 182 * Bound property for the dividerLocation. 183 * @since 1.3 184 */ 185 public final static String DIVIDER_LOCATION_PROPERTY = "dividerLocation"; 186 187 /** 188 * Bound property for weight. 189 * @since 1.3 190 */ 191 public final static String RESIZE_WEIGHT_PROPERTY = "resizeWeight"; 192 193 /** 194 * How the views are split. 195 */ 196 protected int orientation; 197 198 /** 199 * Whether or not the views are continuously redisplayed while 200 * resizing. 201 */ 202 protected boolean continuousLayout; 203 204 /** 205 * The left or top component. 206 */ 207 protected Component leftComponent; 208 209 /** 210 * The right or bottom component. 211 */ 212 protected Component rightComponent; 213 214 /** 215 * Size of the divider. 216 */ 217 protected int dividerSize; 218 private boolean dividerSizeSet = false; 219 220 /** 221 * Is a little widget provided to quickly expand/collapse the 222 * split pane? 223 */ 224 protected boolean oneTouchExpandable; 225 private boolean oneTouchExpandableSet; 226 227 /** 228 * Previous location of the split pane. 229 */ 230 protected int lastDividerLocation; 231 232 /** 233 * How to distribute extra space. 234 */ 235 private double resizeWeight; 236 237 /** 238 * Location of the divider, at least the value that was set, the UI may 239 * have a different value. 240 */ 241 private int dividerLocation; 242 243 244 /** 245 * Creates a new <code>JSplitPane</code> configured to arrange the child 246 * components side-by-side horizontally, using two buttons for the components. 247 */ 248 public JSplitPane() { 249 this(JSplitPane.HORIZONTAL_SPLIT, 250 UIManager.getBoolean("SplitPane.continuousLayout"), 251 new JButton(UIManager.getString("SplitPane.leftButtonText")), 252 new JButton(UIManager.getString("SplitPane.rightButtonText"))); 253 } 254 255 256 /** 257 * Creates a new <code>JSplitPane</code> configured with the 258 * specified orientation. 259 * 260 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or 261 * <code>JSplitPane.VERTICAL_SPLIT</code> 262 * @exception IllegalArgumentException if <code>orientation</code> 263 * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT. 264 */ 265 @ConstructorProperties({"orientation"}) 266 public JSplitPane(int newOrientation) { 267 this(newOrientation, 268 UIManager.getBoolean("SplitPane.continuousLayout")); 269 } 270 271 272 /** 273 * Creates a new <code>JSplitPane</code> with the specified 274 * orientation and redrawing style. 275 * 276 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or 277 * <code>JSplitPane.VERTICAL_SPLIT</code> 278 * @param newContinuousLayout a boolean, true for the components to 279 * redraw continuously as the divider changes position, false 280 * to wait until the divider position stops changing to redraw 281 * @exception IllegalArgumentException if <code>orientation</code> 282 * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT 283 */ 284 public JSplitPane(int newOrientation, 285 boolean newContinuousLayout) { 286 this(newOrientation, newContinuousLayout, null, null); 287 } 288 289 290 /** 291 * Creates a new <code>JSplitPane</code> with the specified 292 * orientation and the specified components. 293 * 294 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or 295 * <code>JSplitPane.VERTICAL_SPLIT</code> 296 * @param newLeftComponent the <code>Component</code> that will 297 * appear on the left 298 * of a horizontally-split pane, or at the top of a 299 * vertically-split pane 300 * @param newRightComponent the <code>Component</code> that will 301 * appear on the right 302 * of a horizontally-split pane, or at the bottom of a 303 * vertically-split pane 304 * @exception IllegalArgumentException if <code>orientation</code> 305 * is not one of: HORIZONTAL_SPLIT or VERTICAL_SPLIT 306 */ 307 public JSplitPane(int newOrientation, 308 Component newLeftComponent, 309 Component newRightComponent){ 310 this(newOrientation, 311 UIManager.getBoolean("SplitPane.continuousLayout"), 312 newLeftComponent, newRightComponent); 313 } 314 315 316 /** 317 * Creates a new <code>JSplitPane</code> with the specified 318 * orientation and 319 * redrawing style, and with the specified components. 320 * 321 * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or 322 * <code>JSplitPane.VERTICAL_SPLIT</code> 323 * @param newContinuousLayout a boolean, true for the components to 324 * redraw continuously as the divider changes position, false 325 * to wait until the divider position stops changing to redraw 326 * @param newLeftComponent the <code>Component</code> that will 327 * appear on the left 328 * of a horizontally-split pane, or at the top of a 329 * vertically-split pane 330 * @param newRightComponent the <code>Component</code> that will 331 * appear on the right 332 * of a horizontally-split pane, or at the bottom of a 333 * vertically-split pane 334 * @exception IllegalArgumentException if <code>orientation</code> 335 * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT 336 */ 337 public JSplitPane(int newOrientation, 338 boolean newContinuousLayout, 339 Component newLeftComponent, 340 Component newRightComponent){ 341 super(); 342 343 dividerLocation = -1; 344 setLayout(null); 345 setUIProperty("opaque", Boolean.TRUE); 346 orientation = newOrientation; 347 if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT) 348 throw new IllegalArgumentException("cannot create JSplitPane, " + 349 "orientation must be one of " + 350 "JSplitPane.HORIZONTAL_SPLIT " + 351 "or JSplitPane.VERTICAL_SPLIT"); 352 continuousLayout = newContinuousLayout; 353 if (newLeftComponent != null) 354 setLeftComponent(newLeftComponent); 355 if (newRightComponent != null) 356 setRightComponent(newRightComponent); 357 updateUI(); 358 359 } 360 361 362 /** 363 * Sets the L&F object that renders this component. 364 * 365 * @param ui the <code>SplitPaneUI</code> L&F object 366 * @see UIDefaults#getUI 367 * @beaninfo 368 * bound: true 369 * hidden: true 370 * attribute: visualUpdate true 371 * description: The UI object that implements the Component's LookAndFeel. 372 */ 373 public void setUI(SplitPaneUI ui) { 374 if ((SplitPaneUI)this.ui != ui) { 375 super.setUI(ui); 376 revalidate(); 377 } 378 } 379 380 381 /** 382 * Returns the <code>SplitPaneUI</code> that is providing the 383 * current look and feel. 384 * 385 * @return the <code>SplitPaneUI</code> object that renders this component 386 * @beaninfo 387 * expert: true 388 * description: The L&F object that renders this component. 389 */ 390 public SplitPaneUI getUI() { 391 return (SplitPaneUI)ui; 392 } 393 394 395 /** 396 * Notification from the <code>UIManager</code> that the L&F has changed. 397 * Replaces the current UI object with the latest version from the 398 * <code>UIManager</code>. 399 * 400 * @see JComponent#updateUI 401 */ 402 public void updateUI() { 403 setUI((SplitPaneUI)UIManager.getUI(this)); 404 revalidate(); 405 } 406 407 408 /** 409 * Returns the name of the L&F class that renders this component. 410 * 411 * @return the string "SplitPaneUI" 412 * @see JComponent#getUIClassID 413 * @see UIDefaults#getUI 414 * @beaninfo 415 * expert: true 416 * description: A string that specifies the name of the L&F class. 417 */ 418 public String getUIClassID() { 419 return uiClassID; 420 } 421 422 423 /** 424 * Sets the size of the divider. 425 * 426 * @param newSize an integer giving the size of the divider in pixels 427 * @beaninfo 428 * bound: true 429 * description: The size of the divider. 430 */ 431 public void setDividerSize(int newSize) { 432 int oldSize = dividerSize; 433 434 dividerSizeSet = true; 435 if (oldSize != newSize) { 436 dividerSize = newSize; 437 firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, newSize); 438 } 439 } 440 441 442 /** 443 * Returns the size of the divider. 444 * 445 * @return an integer giving the size of the divider in pixels 446 */ 447 public int getDividerSize() { 448 return dividerSize; 449 } 450 451 452 /** 453 * Sets the component to the left (or above) the divider. 454 * 455 * @param comp the <code>Component</code> to display in that position 456 */ 457 public void setLeftComponent(Component comp) { 458 if (comp == null) { 459 if (leftComponent != null) { 460 remove(leftComponent); 461 leftComponent = null; 462 } 463 } else { 464 add(comp, JSplitPane.LEFT); 465 } 466 } 467 468 469 /** 470 * Returns the component to the left (or above) the divider. 471 * 472 * @return the <code>Component</code> displayed in that position 473 * @beaninfo 474 * preferred: true 475 * description: The component to the left (or above) the divider. 476 */ 477 public Component getLeftComponent() { 478 return leftComponent; 479 } 480 481 482 /** 483 * Sets the component above, or to the left of the divider. 484 * 485 * @param comp the <code>Component</code> to display in that position 486 * @beaninfo 487 * description: The component above, or to the left of the divider. 488 */ 489 public void setTopComponent(Component comp) { 490 setLeftComponent(comp); 491 } 492 493 494 /** 495 * Returns the component above, or to the left of the divider. 496 * 497 * @return the <code>Component</code> displayed in that position 498 */ 499 public Component getTopComponent() { 500 return leftComponent; 501 } 502 503 504 /** 505 * Sets the component to the right (or below) the divider. 506 * 507 * @param comp the <code>Component</code> to display in that position 508 * @beaninfo 509 * preferred: true 510 * description: The component to the right (or below) the divider. 511 */ 512 public void setRightComponent(Component comp) { 513 if (comp == null) { 514 if (rightComponent != null) { 515 remove(rightComponent); 516 rightComponent = null; 517 } 518 } else { 519 add(comp, JSplitPane.RIGHT); 520 } 521 } 522 523 524 /** 525 * Returns the component to the right (or below) the divider. 526 * 527 * @return the <code>Component</code> displayed in that position 528 */ 529 public Component getRightComponent() { 530 return rightComponent; 531 } 532 533 534 /** 535 * Sets the component below, or to the right of the divider. 536 * 537 * @param comp the <code>Component</code> to display in that position 538 * @beaninfo 539 * description: The component below, or to the right of the divider. 540 */ 541 public void setBottomComponent(Component comp) { 542 setRightComponent(comp); 543 } 544 545 546 /** 547 * Returns the component below, or to the right of the divider. 548 * 549 * @return the <code>Component</code> displayed in that position 550 */ 551 public Component getBottomComponent() { 552 return rightComponent; 553 } 554 555 556 /** 557 * Sets the value of the <code>oneTouchExpandable</code> property, 558 * which must be <code>true</code> for the 559 * <code>JSplitPane</code> to provide a UI widget 560 * on the divider to quickly expand/collapse the divider. 561 * The default value of this property is <code>false</code>. 562 * Some look and feels might not support one-touch expanding; 563 * they will ignore this property. 564 * 565 * @param newValue <code>true</code> to specify that the split pane should provide a 566 * collapse/expand widget 567 * @beaninfo 568 * bound: true 569 * description: UI widget on the divider to quickly 570 * expand/collapse the divider. 571 * 572 * @see #isOneTouchExpandable 573 */ 574 public void setOneTouchExpandable(boolean newValue) { 575 boolean oldValue = oneTouchExpandable; 576 577 oneTouchExpandable = newValue; 578 oneTouchExpandableSet = true; 579 firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue, newValue); 580 repaint(); 581 } 582 583 584 /** 585 * Gets the <code>oneTouchExpandable</code> property. 586 * 587 * @return the value of the <code>oneTouchExpandable</code> property 588 * @see #setOneTouchExpandable 589 */ 590 public boolean isOneTouchExpandable() { 591 return oneTouchExpandable; 592 } 593 594 595 /** 596 * Sets the last location the divider was at to 597 * <code>newLastLocation</code>. 598 * 599 * @param newLastLocation an integer specifying the last divider location 600 * in pixels, from the left (or upper) edge of the pane to the 601 * left (or upper) edge of the divider 602 * @beaninfo 603 * bound: true 604 * description: The last location the divider was at. 605 */ 606 public void setLastDividerLocation(int newLastLocation) { 607 int oldLocation = lastDividerLocation; 608 609 lastDividerLocation = newLastLocation; 610 firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldLocation, 611 newLastLocation); 612 } 613 614 615 /** 616 * Returns the last location the divider was at. 617 * 618 * @return an integer specifying the last divider location as a count 619 * of pixels from the left (or upper) edge of the pane to the 620 * left (or upper) edge of the divider 621 */ 622 public int getLastDividerLocation() { 623 return lastDividerLocation; 624 } 625 626 627 /** 628 * Sets the orientation, or how the splitter is divided. The options 629 * are:<ul> 630 * <li>JSplitPane.VERTICAL_SPLIT (above/below orientation of components) 631 * <li>JSplitPane.HORIZONTAL_SPLIT (left/right orientation of components) 632 * </ul> 633 * 634 * @param orientation an integer specifying the orientation 635 * @exception IllegalArgumentException if orientation is not one of: 636 * HORIZONTAL_SPLIT or VERTICAL_SPLIT. 637 * @beaninfo 638 * bound: true 639 * description: The orientation, or how the splitter is divided. 640 * enum: HORIZONTAL_SPLIT JSplitPane.HORIZONTAL_SPLIT 641 * VERTICAL_SPLIT JSplitPane.VERTICAL_SPLIT 642 */ 643 public void setOrientation(int orientation) { 644 if ((orientation != VERTICAL_SPLIT) && 645 (orientation != HORIZONTAL_SPLIT)) { 646 throw new IllegalArgumentException("JSplitPane: orientation must " + 647 "be one of " + 648 "JSplitPane.VERTICAL_SPLIT or " + 649 "JSplitPane.HORIZONTAL_SPLIT"); 650 } 651 652 int oldOrientation = this.orientation; 653 654 this.orientation = orientation; 655 firePropertyChange(ORIENTATION_PROPERTY, oldOrientation, orientation); 656 } 657 658 659 /** 660 * Returns the orientation. 661 * 662 * @return an integer giving the orientation 663 * @see #setOrientation 664 */ 665 public int getOrientation() { 666 return orientation; 667 } 668 669 670 /** 671 * Sets the value of the <code>continuousLayout</code> property, 672 * which must be <code>true</code> for the child components 673 * to be continuously 674 * redisplayed and laid out during user intervention. 675 * The default value of this property is look and feel dependent. 676 * Some look and feels might not support continuous layout; 677 * they will ignore this property. 678 * 679 * @param newContinuousLayout <code>true</code> if the components 680 * should continuously be redrawn as the divider changes position 681 * @beaninfo 682 * bound: true 683 * description: Whether the child components are 684 * continuously redisplayed and laid out during 685 * user intervention. 686 * @see #isContinuousLayout 687 */ 688 public void setContinuousLayout(boolean newContinuousLayout) { 689 boolean oldCD = continuousLayout; 690 691 continuousLayout = newContinuousLayout; 692 firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldCD, 693 newContinuousLayout); 694 } 695 696 697 /** 698 * Gets the <code>continuousLayout</code> property. 699 * 700 * @return the value of the <code>continuousLayout</code> property 701 * @see #setContinuousLayout 702 */ 703 public boolean isContinuousLayout() { 704 return continuousLayout; 705 } 706 707 /** 708 * Specifies how to distribute extra space when the size of the split pane 709 * changes. A value of 0, the default, 710 * indicates the right/bottom component gets all the extra space (the 711 * left/top component acts fixed), where as a value of 1 specifies the 712 * left/top component gets all the extra space (the right/bottom component 713 * acts fixed). Specifically, the left/top component gets (weight * diff) 714 * extra space and the right/bottom component gets (1 - weight) * diff 715 * extra space. 716 * 717 * @param value as described above 718 * @exception IllegalArgumentException if <code>value</code> is < 0 or > 1 719 * @since 1.3 720 * @beaninfo 721 * bound: true 722 * description: Specifies how to distribute extra space when the split pane 723 * resizes. 724 */ 725 public void setResizeWeight(double value) { 726 if (value < 0 || value > 1) { 727 throw new IllegalArgumentException("JSplitPane weight must be between 0 and 1"); 728 } 729 double oldWeight = resizeWeight; 730 731 resizeWeight = value; 732 firePropertyChange(RESIZE_WEIGHT_PROPERTY, oldWeight, value); 733 } 734 735 /** 736 * Returns the number that determines how extra space is distributed. 737 * @return how extra space is to be distributed on a resize of the 738 * split pane 739 * @since 1.3 740 */ 741 public double getResizeWeight() { 742 return resizeWeight; 743 } 744 745 /** 746 * Lays out the <code>JSplitPane</code> layout based on the preferred size 747 * of the children components. This will likely result in changing 748 * the divider location. 749 */ 750 public void resetToPreferredSizes() { 751 SplitPaneUI ui = getUI(); 752 753 if (ui != null) { 754 ui.resetToPreferredSizes(this); 755 } 756 } 757 758 759 /** 760 * Sets the divider location as a percentage of the 761 * <code>JSplitPane</code>'s size. 762 * <p> 763 * This method is implemented in terms of 764 * <code>setDividerLocation(int)</code>. 765 * This method immediately changes the size of the split pane based on 766 * its current size. If the split pane is not correctly realized and on 767 * screen, this method will have no effect (new divider location will 768 * become (current size * proportionalLocation) which is 0). 769 * 770 * @param proportionalLocation a double-precision floating point value 771 * that specifies a percentage, from zero (top/left) to 1.0 772 * (bottom/right) 773 * @exception IllegalArgumentException if the specified location is < 0 774 * or > 1.0 775 * @beaninfo 776 * description: The location of the divider. 777 */ 778 public void setDividerLocation(double proportionalLocation) { 779 if (proportionalLocation < 0.0 || 780 proportionalLocation > 1.0) { 781 throw new IllegalArgumentException("proportional location must " + 782 "be between 0.0 and 1.0."); 783 } 784 if (getOrientation() == VERTICAL_SPLIT) { 785 setDividerLocation((int)((double)(getHeight() - getDividerSize()) * 786 proportionalLocation)); 787 } else { 788 setDividerLocation((int)((double)(getWidth() - getDividerSize()) * 789 proportionalLocation)); 790 } 791 } 792 793 794 /** 795 * Sets the location of the divider. This is passed off to the 796 * look and feel implementation, and then listeners are notified. A value 797 * less than 0 implies the divider should be reset to a value that 798 * attempts to honor the preferred size of the left/top component. 799 * After notifying the listeners, the last divider location is updated, 800 * via <code>setLastDividerLocation</code>. 801 * 802 * @param location an int specifying a UI-specific value (typically a 803 * pixel count) 804 * @beaninfo 805 * bound: true 806 * description: The location of the divider. 807 */ 808 public void setDividerLocation(int location) { 809 int oldValue = dividerLocation; 810 811 dividerLocation = location; 812 813 // Notify UI. 814 SplitPaneUI ui = getUI(); 815 816 if (ui != null) { 817 ui.setDividerLocation(this, location); 818 } 819 820 // Then listeners 821 firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldValue, location); 822 823 // And update the last divider location. 824 setLastDividerLocation(oldValue); 825 } 826 827 828 /** 829 * Returns the last value passed to <code>setDividerLocation</code>. 830 * The value returned from this method may differ from the actual 831 * divider location (if <code>setDividerLocation</code> was passed a 832 * value bigger than the current size). 833 * 834 * @return an integer specifying the location of the divider 835 */ 836 public int getDividerLocation() { 837 return dividerLocation; 838 } 839 840 841 /** 842 * Returns the minimum location of the divider from the look and feel 843 * implementation. 844 * 845 * @return an integer specifying a UI-specific value for the minimum 846 * location (typically a pixel count); or -1 if the UI is 847 * <code>null</code> 848 * @beaninfo 849 * description: The minimum location of the divider from the L&F. 850 */ 851 public int getMinimumDividerLocation() { 852 SplitPaneUI ui = getUI(); 853 854 if (ui != null) { 855 return ui.getMinimumDividerLocation(this); 856 } 857 return -1; 858 } 859 860 861 /** 862 * Returns the maximum location of the divider from the look and feel 863 * implementation. 864 * 865 * @return an integer specifying a UI-specific value for the maximum 866 * location (typically a pixel count); or -1 if the UI is 867 * <code>null</code> 868 */ 869 public int getMaximumDividerLocation() { 870 SplitPaneUI ui = getUI(); 871 872 if (ui != null) { 873 return ui.getMaximumDividerLocation(this); 874 } 875 return -1; 876 } 877 878 879 /** 880 * Removes the child component, <code>component</code> from the 881 * pane. Resets the <code>leftComponent</code> or 882 * <code>rightComponent</code> instance variable, as necessary. 883 * 884 * @param component the <code>Component</code> to remove 885 */ 886 public void remove(Component component) { 887 if (component == leftComponent) { 888 leftComponent = null; 889 } else if (component == rightComponent) { 890 rightComponent = null; 891 } 892 super.remove(component); 893 894 // Update the JSplitPane on the screen 895 revalidate(); 896 repaint(); 897 } 898 899 900 /** 901 * Removes the <code>Component</code> at the specified index. 902 * Updates the <code>leftComponent</code> and <code>rightComponent</code> 903 * instance variables as necessary, and then messages super. 904 * 905 * @param index an integer specifying the component to remove, where 906 * 1 specifies the left/top component and 2 specifies the 907 * bottom/right component 908 */ 909 public void remove(int index) { 910 Component comp = getComponent(index); 911 912 if (comp == leftComponent) { 913 leftComponent = null; 914 } else if (comp == rightComponent) { 915 rightComponent = null; 916 } 917 super.remove(index); 918 919 // Update the JSplitPane on the screen 920 revalidate(); 921 repaint(); 922 } 923 924 925 /** 926 * Removes all the child components from the split pane. Resets the 927 * <code>leftComonent</code> and <code>rightComponent</code> 928 * instance variables. 929 */ 930 public void removeAll() { 931 leftComponent = rightComponent = null; 932 super.removeAll(); 933 934 // Update the JSplitPane on the screen 935 revalidate(); 936 repaint(); 937 } 938 939 940 /** 941 * Returns true, so that calls to <code>revalidate</code> 942 * on any descendant of this <code>JSplitPane</code> 943 * will cause a request to be queued that 944 * will validate the <code>JSplitPane</code> and all its descendants. 945 * 946 * @return true 947 * @see JComponent#revalidate 948 * @see java.awt.Container#isValidateRoot 949 * 950 * @beaninfo 951 * hidden: true 952 */ 953 @Override 954 public boolean isValidateRoot() { 955 return true; 956 } 957 958 959 /** 960 * Adds the specified component to this split pane. 961 * If <code>constraints</code> identifies the left/top or 962 * right/bottom child component, and a component with that identifier 963 * was previously added, it will be removed and then <code>comp</code> 964 * will be added in its place. If <code>constraints</code> is not 965 * one of the known identifiers the layout manager may throw an 966 * <code>IllegalArgumentException</code>. 967 * <p> 968 * The possible constraints objects (Strings) are: 969 * <ul> 970 * <li>JSplitPane.TOP 971 * <li>JSplitPane.LEFT 972 * <li>JSplitPane.BOTTOM 973 * <li>JSplitPane.RIGHT 974 * </ul> 975 * If the <code>constraints</code> object is <code>null</code>, 976 * the component is added in the 977 * first available position (left/top if open, else right/bottom). 978 * 979 * @param comp the component to add 980 * @param constraints an <code>Object</code> specifying the 981 * layout constraints 982 * (position) for this component 983 * @param index an integer specifying the index in the container's 984 * list. 985 * @exception IllegalArgumentException if the <code>constraints</code> 986 * object does not match an existing component 987 * @see java.awt.Container#addImpl(Component, Object, int) 988 */ 989 protected void addImpl(Component comp, Object constraints, int index) 990 { 991 Component toRemove; 992 993 if (constraints != null && !(constraints instanceof String)) { 994 throw new IllegalArgumentException("cannot add to layout: " + 995 "constraint must be a string " + 996 "(or null)"); 997 } 998 999 /* If the constraints are null and the left/right component is 1000 invalid, add it at the left/right component. */ 1001 if (constraints == null) { 1002 if (getLeftComponent() == null) { 1003 constraints = JSplitPane.LEFT; 1004 } else if (getRightComponent() == null) { 1005 constraints = JSplitPane.RIGHT; 1006 } 1007 } 1008 1009 /* Find the Component that already exists and remove it. */ 1010 if (constraints != null && (constraints.equals(JSplitPane.LEFT) || 1011 constraints.equals(JSplitPane.TOP))) { 1012 toRemove = getLeftComponent(); 1013 if (toRemove != null) { 1014 remove(toRemove); 1015 } 1016 leftComponent = comp; 1017 index = -1; 1018 } else if (constraints != null && 1019 (constraints.equals(JSplitPane.RIGHT) || 1020 constraints.equals(JSplitPane.BOTTOM))) { 1021 toRemove = getRightComponent(); 1022 if (toRemove != null) { 1023 remove(toRemove); 1024 } 1025 rightComponent = comp; 1026 index = -1; 1027 } else if (constraints != null && 1028 constraints.equals(JSplitPane.DIVIDER)) { 1029 index = -1; 1030 } 1031 /* LayoutManager should raise for else condition here. */ 1032 1033 super.addImpl(comp, constraints, index); 1034 1035 // Update the JSplitPane on the screen 1036 revalidate(); 1037 repaint(); 1038 } 1039 1040 1041 /** 1042 * Subclassed to message the UI with <code>finishedPaintingChildren</code> 1043 * after super has been messaged, as well as painting the border. 1044 * 1045 * @param g the <code>Graphics</code> context within which to paint 1046 */ 1047 protected void paintChildren(Graphics g) { 1048 super.paintChildren(g); 1049 1050 SplitPaneUI ui = getUI(); 1051 1052 if (ui != null) { 1053 Graphics tempG = g.create(); 1054 ui.finishedPaintingChildren(this, tempG); 1055 tempG.dispose(); 1056 } 1057 } 1058 1059 1060 /** 1061 * See <code>readObject</code> and <code>writeObject</code> in 1062 * <code>JComponent</code> for more 1063 * information about serialization in Swing. 1064 */ 1065 private void writeObject(ObjectOutputStream s) throws IOException { 1066 s.defaultWriteObject(); 1067 if (getUIClassID().equals(uiClassID)) { 1068 byte count = JComponent.getWriteObjCounter(this); 1069 JComponent.setWriteObjCounter(this, --count); 1070 if (count == 0 && ui != null) { 1071 ui.installUI(this); 1072 } 1073 } 1074 } 1075 1076 void setUIProperty(String propertyName, Object value) { 1077 if (propertyName == "dividerSize") { 1078 if (!dividerSizeSet) { 1079 setDividerSize(((Number)value).intValue()); 1080 dividerSizeSet = false; 1081 } 1082 } else if (propertyName == "oneTouchExpandable") { 1083 if (!oneTouchExpandableSet) { 1084 setOneTouchExpandable(((Boolean)value).booleanValue()); 1085 oneTouchExpandableSet = false; 1086 } 1087 } else { 1088 super.setUIProperty(propertyName, value); 1089 } 1090 } 1091 1092 1093 /** 1094 * Returns a string representation of this <code>JSplitPane</code>. 1095 * This method 1096 * is intended to be used only for debugging purposes, and the 1097 * content and format of the returned string may vary between 1098 * implementations. The returned string may be empty but may not 1099 * be <code>null</code>. 1100 * 1101 * @return a string representation of this <code>JSplitPane</code>. 1102 */ 1103 protected String paramString() { 1104 String orientationString = (orientation == HORIZONTAL_SPLIT ? 1105 "HORIZONTAL_SPLIT" : "VERTICAL_SPLIT"); 1106 String continuousLayoutString = (continuousLayout ? 1107 "true" : "false"); 1108 String oneTouchExpandableString = (oneTouchExpandable ? 1109 "true" : "false"); 1110 1111 return super.paramString() + 1112 ",continuousLayout=" + continuousLayoutString + 1113 ",dividerSize=" + dividerSize + 1114 ",lastDividerLocation=" + lastDividerLocation + 1115 ",oneTouchExpandable=" + oneTouchExpandableString + 1116 ",orientation=" + orientationString; 1117 } 1118 1119 1120 1121 /////////////////////////// 1122 // Accessibility support // 1123 /////////////////////////// 1124 1125 1126 /** 1127 * Gets the AccessibleContext associated with this JSplitPane. 1128 * For split panes, the AccessibleContext takes the form of an 1129 * AccessibleJSplitPane. 1130 * A new AccessibleJSplitPane instance is created if necessary. 1131 * 1132 * @return an AccessibleJSplitPane that serves as the 1133 * AccessibleContext of this JSplitPane 1134 * @beaninfo 1135 * expert: true 1136 * description: The AccessibleContext associated with this SplitPane. 1137 */ 1138 public AccessibleContext getAccessibleContext() { 1139 if (accessibleContext == null) { 1140 accessibleContext = new AccessibleJSplitPane(); 1141 } 1142 return accessibleContext; 1143 } 1144 1145 1146 /** 1147 * This class implements accessibility support for the 1148 * <code>JSplitPane</code> class. It provides an implementation of the 1149 * Java Accessibility API appropriate to split pane user-interface elements. 1150 * <p> 1151 * <strong>Warning:</strong> 1152 * Serialized objects of this class will not be compatible with 1153 * future Swing releases. The current serialization support is 1154 * appropriate for short term storage or RMI between applications running 1155 * the same version of Swing. As of 1.4, support for long term storage 1156 * of all JavaBeans™ 1157 * has been added to the <code>java.beans</code> package. 1158 * Please see {@link java.beans.XMLEncoder}. 1159 */ 1160 @SuppressWarnings("serial") // Same-version serialization only 1161 protected class AccessibleJSplitPane extends AccessibleJComponent 1162 implements AccessibleValue { 1163 /** 1164 * Gets the state set of this object. 1165 * 1166 * @return an instance of AccessibleState containing the current state 1167 * of the object 1168 * @see AccessibleState 1169 */ 1170 public AccessibleStateSet getAccessibleStateSet() { 1171 AccessibleStateSet states = super.getAccessibleStateSet(); 1172 // FIXME: [[[WDW - Should also add BUSY if this implements 1173 // Adjustable at some point. If this happens, we probably 1174 // should also add actions.]]] 1175 if (getOrientation() == VERTICAL_SPLIT) { 1176 states.add(AccessibleState.VERTICAL); 1177 } else { 1178 states.add(AccessibleState.HORIZONTAL); 1179 } 1180 return states; 1181 } 1182 1183 1184 /** 1185 * Get the AccessibleValue associated with this object. In the 1186 * implementation of the Java Accessibility API for this class, 1187 * return this object, which is responsible for implementing the 1188 * AccessibleValue interface on behalf of itself. 1189 * 1190 * @return this object 1191 */ 1192 public AccessibleValue getAccessibleValue() { 1193 return this; 1194 } 1195 1196 1197 /** 1198 * Gets the accessible value of this object. 1199 * 1200 * @return a localized String describing the value of this object 1201 */ 1202 public Number getCurrentAccessibleValue() { 1203 return Integer.valueOf(getDividerLocation()); 1204 } 1205 1206 1207 /** 1208 * Sets the value of this object as a Number. 1209 * 1210 * @return True if the value was set. 1211 */ 1212 public boolean setCurrentAccessibleValue(Number n) { 1213 // TIGER - 4422535 1214 if (n == null) { 1215 return false; 1216 } 1217 setDividerLocation(n.intValue()); 1218 return true; 1219 } 1220 1221 1222 /** 1223 * Gets the minimum accessible value of this object. 1224 * 1225 * @return The minimum value of this object. 1226 */ 1227 public Number getMinimumAccessibleValue() { 1228 return Integer.valueOf(getUI().getMinimumDividerLocation( 1229 JSplitPane.this)); 1230 } 1231 1232 1233 /** 1234 * Gets the maximum accessible value of this object. 1235 * 1236 * @return The maximum value of this object. 1237 */ 1238 public Number getMaximumAccessibleValue() { 1239 return Integer.valueOf(getUI().getMaximumDividerLocation( 1240 JSplitPane.this)); 1241 } 1242 1243 1244 /** 1245 * Gets the role of this object. 1246 * 1247 * @return an instance of AccessibleRole describing the role of 1248 * the object 1249 * @see AccessibleRole 1250 */ 1251 public AccessibleRole getAccessibleRole() { 1252 return AccessibleRole.SPLIT_PANE; 1253 } 1254 } // inner class AccessibleJSplitPane 1255 }