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