1. /*
  2. * @(#)JSplitPane.java 1.64 01/02/09
  3. *
  4. * Copyright 1997-2001 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import javax.swing.border.Border;
  12. import javax.swing.plaf.*;
  13. import javax.accessibility.*;
  14. import java.awt.*;
  15. import java.io.ObjectOutputStream;
  16. import java.io.ObjectInputStream;
  17. import java.io.IOException;
  18. /**
  19. * <code>JSplitPane</code> is used to divide two (and only two)
  20. * <code>Component</code>s. The two <code>Component</code>s
  21. * are graphically divided based on the look and feel
  22. * implementation, and the two <code>Component</code>s can then be
  23. * interactively resized by the user.
  24. * Information on using <code>JSplitPane</code> is in
  25. * <a
  26. href="http://java.sun.com/docs/books/tutorial/uiswing/components/splitpane.html">How to Use Split Panes</a> in
  27. * <em>The Java Tutorial</em>.
  28. * <p>
  29. * The two <code>Component</code>s in a split pane can be aligned
  30. * left to right using
  31. * <code>JSplitPane.HORIZONTAL_SPLIT</code>, or top to bottom using
  32. * <code>JSplitPane.VERTICAL_SPLIT</code>.
  33. * The preferred way to change the size of the <code>Component</code>s
  34. * is to invoke
  35. * <code>setDividerLocation</code> where <code>location</code> is either
  36. * the new x or y position, depending on the orientation of the
  37. * <code>JSplitPane</code>.
  38. * <p>
  39. * To resize the <code>Component</code>s to their preferred sizes invoke
  40. * <code>resetToPreferredSizes</code>.
  41. * <p>
  42. * When the user is resizing the <code>Component</code>s the minimum
  43. * size of the <code>Components</code> is used to determine the
  44. * maximum/minimum position the <code>Component</code>s
  45. * can be set to. If the minimum size of the two
  46. * components is greater than the size of the split pane the divider
  47. * will not allow you to resize it. To alter the minimum size of a
  48. * <code>JComponent</code>, see {@link JComponent#setMinimumSize}.
  49. * <p>
  50. * When the user resizes the split pane the new space is distributed between
  51. * the two components based on the <code>resizeWeight</code> property.
  52. * A value of 0,
  53. * the default, indicates the right/bottom component gets all the space,
  54. * where as a value of 1 indicates the left/top component gets all the space.
  55. * <p>
  56. * For the keyboard keys used by this component in the standard Look and
  57. * Feel (L&F) renditions, see the
  58. * <a href="doc-files/Key-Index.html#JSplitPane">JSplitPane</a> key
  59. * assignments.
  60. * <p>
  61. * <strong>Warning:</strong>
  62. * Serialized objects of this class will not be compatible with
  63. * future Swing releases. The current serialization support is appropriate
  64. * for short term storage or RMI between applications running the same
  65. * version of Swing. A future release of Swing will provide support for
  66. * long term persistence.
  67. *
  68. * @see #setDividerLocation
  69. * @see #resetToPreferredSizes
  70. *
  71. * @version 1.64 02/09/01
  72. * @author Scott Violet
  73. */
  74. public class JSplitPane extends JComponent implements Accessible
  75. {
  76. /**
  77. * @see #getUIClassID
  78. * @see #readObject
  79. */
  80. private static final String uiClassID = "SplitPaneUI";
  81. /**
  82. * Vertical split indicates the <code>Component</code>s are
  83. * split along the y axis. For example the two
  84. * <code>Component</code>s will be split one on top of the other.
  85. */
  86. public final static int VERTICAL_SPLIT = 0;
  87. /**
  88. * Horizontal split indicates the <code>Component</code>s are
  89. * split along the x axis. For example the two
  90. * <code>Component</code>s will be split one to the left of the
  91. * other.
  92. */
  93. public final static int HORIZONTAL_SPLIT = 1;
  94. /**
  95. * Used to add a <code>Component</code> to the left of the other
  96. * <code>Component</code>.
  97. */
  98. public final static String LEFT = "left";
  99. /**
  100. * Used to add a <code>Component</code> to the right of the other
  101. * <code>Component</code>.
  102. */
  103. public final static String RIGHT = "right";
  104. /**
  105. * Used to add a <code>Component</code> above the other
  106. * <code>Component</code>.
  107. */
  108. public final static String TOP = "top";
  109. /**
  110. * Used to add a <code>Component</code> below the other
  111. * <code>Component</code>.
  112. */
  113. public final static String BOTTOM = "bottom";
  114. /**
  115. * Used to add a <code>Component</code> that will represent the divider.
  116. */
  117. public final static String DIVIDER = "divider";
  118. /**
  119. * Bound property name for orientation (horizontal or vertical).
  120. */
  121. public final static String ORIENTATION_PROPERTY = "orientation";
  122. /**
  123. * Bound property name for continuousLayout.
  124. */
  125. public final static String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout";
  126. /**
  127. * Bound property name for border.
  128. */
  129. public final static String DIVIDER_SIZE_PROPERTY = "dividerSize";
  130. /**
  131. * Bound property for oneTouchExpandable.
  132. */
  133. public final static String ONE_TOUCH_EXPANDABLE_PROPERTY =
  134. "oneTouchExpandable";
  135. /**
  136. * Bound property for lastLocation.
  137. */
  138. public final static String LAST_DIVIDER_LOCATION_PROPERTY =
  139. "lastDividerLocation";
  140. /**
  141. * Bound property for the dividerLocation.
  142. * @since 1.3
  143. */
  144. public final static String DIVIDER_LOCATION_PROPERTY = "dividerLocation";
  145. /**
  146. * Bound property for weight.
  147. * @since 1.3.
  148. */
  149. public final static String RESIZE_WEIGHT_PROPERTY = "resizeWeight";
  150. /**
  151. * How the views are split.
  152. */
  153. protected int orientation;
  154. /**
  155. * Whether or not the views are continuously redisplayed while
  156. * resizing.
  157. */
  158. protected boolean continuousLayout;
  159. /**
  160. * The left or top component.
  161. */
  162. protected Component leftComponent;
  163. /**
  164. * The right or bottom component.
  165. */
  166. protected Component rightComponent;
  167. /**
  168. * Size of the divider.
  169. */
  170. protected int dividerSize;
  171. /**
  172. * Is a little widget provided to quickly expand/collapse the
  173. * split pane?
  174. */
  175. protected boolean oneTouchExpandable;
  176. /**
  177. * Previous location of the split pane.
  178. */
  179. protected int lastDividerLocation;
  180. /**
  181. * How to distribute extra space.
  182. */
  183. private double resizeWeight;
  184. /**
  185. * Location of the divider, at least the value that was set, the UI may
  186. * have a different value.
  187. */
  188. private int dividerLocation;
  189. /**
  190. * Creates a new <code>JSplitPane</code> configured to arrange the child
  191. * components side-by-side horizontally with no continuous
  192. * layout, using two buttons for the components.
  193. */
  194. public JSplitPane() {
  195. this(JSplitPane.HORIZONTAL_SPLIT, false,
  196. new JButton(UIManager.getString("SplitPane.leftButtonText")),
  197. new JButton(UIManager.getString("SplitPane.rightButtonText")));
  198. }
  199. /**
  200. * Creates a new <code>JSplitPane</code> configured with the
  201. * specified orientation and no continuous layout.
  202. *
  203. * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
  204. * <code>JSplitPane.VERTICAL_SPLIT</code>
  205. * @exception IllegalArgumentException if <code>orientation</code>
  206. * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT.
  207. */
  208. public JSplitPane(int newOrientation) {
  209. this(newOrientation, false);
  210. }
  211. /**
  212. * Creates a new <code>JSplitPane</code> with the specified
  213. * orientation and redrawing style.
  214. *
  215. * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
  216. * <code>JSplitPane.VERTICAL_SPLIT</code>
  217. * @param newContinuousLayout a boolean, true for the components to
  218. * redraw continuously as the divider changes position, false
  219. * to wait until the divider position stops changing to redraw
  220. * @exception IllegalArgumentException if <code>orientation</code>
  221. * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT
  222. */
  223. public JSplitPane(int newOrientation,
  224. boolean newContinuousLayout) {
  225. this(newOrientation, newContinuousLayout, null, null);
  226. }
  227. /**
  228. * Creates a new <code>JSplitPane</code> with the specified
  229. * orientation and
  230. * with the specified components that do not do continuous
  231. * redrawing.
  232. *
  233. * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
  234. * <code>JSplitPane.VERTICAL_SPLIT</code>
  235. * @param newLeftComponent the <code>Component</code> that will
  236. * appear on the left
  237. * of a horizontally-split pane, or at the top of a
  238. * vertically-split pane
  239. * @param newRightComponent the <code>Component</code> that will
  240. * appear on the right
  241. * of a horizontally-split pane, or at the bottom of a
  242. * vertically-split pane
  243. * @exception IllegalArgumentException if <code>orientation</code>
  244. * is not one of: HORIZONTAL_SPLIT or VERTICAL_SPLIT
  245. */
  246. public JSplitPane(int newOrientation,
  247. Component newLeftComponent,
  248. Component newRightComponent){
  249. this(newOrientation, false, newLeftComponent, newRightComponent);
  250. }
  251. /**
  252. * Creates a new <code>JSplitPane</code> with the specified
  253. * orientation and
  254. * redrawing style, and with the specified components.
  255. *
  256. * @param newOrientation <code>JSplitPane.HORIZONTAL_SPLIT</code> or
  257. * <code>JSplitPane.VERTICAL_SPLIT</code>
  258. * @param newContinuousLayout a boolean, true for the components to
  259. * redraw continuously as the divider changes position, false
  260. * to wait until the divider position stops changing to redraw
  261. * @param newLeftComponent the <code>Component</code> that will
  262. * appear on the left
  263. * of a horizontally-split pane, or at the top of a
  264. * vertically-split pane
  265. * @param newRightComponent the <code>Component</code> that will
  266. * appear on the right
  267. * of a horizontally-split pane, or at the bottom of a
  268. * vertically-split pane
  269. * @exception IllegalArgumentException if <code>orientation</code>
  270. * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT
  271. */
  272. public JSplitPane(int newOrientation,
  273. boolean newContinuousLayout,
  274. Component newLeftComponent,
  275. Component newRightComponent){
  276. super();
  277. dividerLocation = -1;
  278. setLayout(null);
  279. setOpaque(true);
  280. orientation = newOrientation;
  281. if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT)
  282. throw new IllegalArgumentException("cannot create JSplitPane, " +
  283. "orientation must be one of " +
  284. "JSplitPane.HORIZONTAL_SPLIT " +
  285. "or JSplitPane.VERTICAL_SPLIT");
  286. continuousLayout = newContinuousLayout;
  287. if (newLeftComponent != null)
  288. setLeftComponent(newLeftComponent);
  289. if (newRightComponent != null)
  290. setRightComponent(newRightComponent);
  291. updateUI();
  292. }
  293. /**
  294. * Sets the L&F object that renders this component.
  295. *
  296. * @param ui the <code>SplitPaneUI</code> L&F object
  297. * @see UIDefaults#getUI
  298. */
  299. public void setUI(SplitPaneUI ui) {
  300. if ((SplitPaneUI)this.ui != ui) {
  301. super.setUI(ui);
  302. revalidate();
  303. }
  304. }
  305. /**
  306. * Returns the <code>SplitPaneUI</code> that is providing the
  307. * current look and feel.
  308. *
  309. * @return the <code>SplitPaneUI</code> object that renders this component
  310. * @beaninfo
  311. * expert: true
  312. * description: The L&F object that renders this component.
  313. */
  314. public SplitPaneUI getUI() {
  315. return (SplitPaneUI)ui;
  316. }
  317. /**
  318. * Notification from the <code>UIManager</code> that the L&F has changed.
  319. * Replaces the current UI object with the latest version from the
  320. * <code>UIManager</code>.
  321. *
  322. * @see JComponent#updateUI
  323. */
  324. public void updateUI() {
  325. setUI((SplitPaneUI)UIManager.getUI(this));
  326. revalidate();
  327. }
  328. /**
  329. * Returns the name of the L&F class that renders this component.
  330. *
  331. * @return the string "SplitPaneUI"
  332. * @see JComponent#getUIClassID
  333. * @see UIDefaults#getUI
  334. * @beaninfo
  335. * expert: true
  336. * description: A string that specifies the name of the L&F class.
  337. */
  338. public String getUIClassID() {
  339. return uiClassID;
  340. }
  341. /**
  342. * Sets the size of the divider.
  343. *
  344. * @param newSize an integer giving the size of the divider in pixels
  345. * @beaninfo
  346. * bound: true
  347. * description: The size of the divider.
  348. */
  349. public void setDividerSize(int newSize) {
  350. int oldSize = dividerSize;
  351. if (oldSize != newSize) {
  352. dividerSize = newSize;
  353. firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, newSize);
  354. }
  355. }
  356. /**
  357. * Returns the size of the divider.
  358. *
  359. * @return an integer giving the size of the divider in pixels
  360. */
  361. public int getDividerSize() {
  362. return dividerSize;
  363. }
  364. /**
  365. * Sets the component to the left (or above) the divider.
  366. *
  367. * @param comp the <code>Component</code> to display in that position
  368. */
  369. public void setLeftComponent(Component comp) {
  370. if (comp == null) {
  371. if (leftComponent != null) {
  372. remove(leftComponent);
  373. leftComponent = null;
  374. }
  375. } else {
  376. add(comp, JSplitPane.LEFT);
  377. }
  378. }
  379. /**
  380. * Returns the component to the left (or above) the divider.
  381. *
  382. * @return the <code>Component</code> displayed in that position
  383. * @beaninfo
  384. * preferred: true
  385. * description: The component to the left (or above) the divider.
  386. */
  387. public Component getLeftComponent() {
  388. return leftComponent;
  389. }
  390. /**
  391. * Sets the component above, or to the left of the divider.
  392. *
  393. * @param comp the <code>Component</code> to display in that position
  394. * @beaninfo
  395. * description: The component above, or to the left of the divider.
  396. */
  397. public void setTopComponent(Component comp) {
  398. setLeftComponent(comp);
  399. }
  400. /**
  401. * Returns the component above, or to the left of the divider.
  402. *
  403. * @return the <code>Component</code> displayed in that position
  404. */
  405. public Component getTopComponent() {
  406. return leftComponent;
  407. }
  408. /**
  409. * Sets the component to the right (or below) the divider.
  410. *
  411. * @param comp the <code>Component</code> to display in that position
  412. * @beaninfo
  413. * preferred: true
  414. * description: The component to the right (or below) the divider.
  415. */
  416. public void setRightComponent(Component comp) {
  417. if (comp == null) {
  418. if (rightComponent != null) {
  419. remove(rightComponent);
  420. rightComponent = null;
  421. }
  422. } else {
  423. add(comp, JSplitPane.RIGHT);
  424. }
  425. }
  426. /**
  427. * Returns the component to the right (or below) the divider.
  428. *
  429. * @return the <code>Component</code> displayed in that position
  430. */
  431. public Component getRightComponent() {
  432. return rightComponent;
  433. }
  434. /**
  435. * Sets the component below, or to the right of the divider.
  436. *
  437. * @param comp the <code>Component</code> to display in that position
  438. * @beaninfo
  439. * description: The component below, or to the right of the divider.
  440. */
  441. public void setBottomComponent(Component comp) {
  442. setRightComponent(comp);
  443. }
  444. /**
  445. * Returns the component below, or to the right of the divider.
  446. *
  447. * @return the <code>Component</code> displayed in that position
  448. */
  449. public Component getBottomComponent() {
  450. return rightComponent;
  451. }
  452. /**
  453. * Determines whether the <code>JSplitPane</code> provides a UI widget
  454. * on the divider to quickly expand/collapse the divider.
  455. *
  456. * @param newValue a boolean, where true means to provide a
  457. * collapse/expand widget
  458. * @beaninfo
  459. * bound: true
  460. * description: UI widget on the divider to quickly
  461. * expand/collapse the divider.
  462. */
  463. public void setOneTouchExpandable(boolean newValue) {
  464. boolean oldValue = oneTouchExpandable;
  465. oneTouchExpandable = newValue;
  466. firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue, newValue);
  467. repaint();
  468. }
  469. /**
  470. * Returns true if the pane provides a UI widget to collapse/expand
  471. * the divider.
  472. *
  473. * @return true if the split pane provides a collapse/expand widget
  474. */
  475. public boolean isOneTouchExpandable() {
  476. return oneTouchExpandable;
  477. }
  478. /**
  479. * Sets the last location the divider was at to
  480. * <code>newLastLocation</code>.
  481. *
  482. * @param newLastLocation an integer specifying the last divider location
  483. * in pixels, from the left (or upper) edge of the pane to the
  484. * left (or upper) edge of the divider
  485. * @beaninfo
  486. * bound: true
  487. * description: The last location the divider was at.
  488. */
  489. public void setLastDividerLocation(int newLastLocation) {
  490. int oldLocation = lastDividerLocation;
  491. lastDividerLocation = newLastLocation;
  492. firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldLocation,
  493. newLastLocation);
  494. }
  495. /**
  496. * Returns the last location the divider was at.
  497. *
  498. * @return an integer specifying the last divider location as a count
  499. * of pixels from the left (or upper) edge of the pane to the
  500. * left (or upper) edge of the divider
  501. */
  502. public int getLastDividerLocation() {
  503. return lastDividerLocation;
  504. }
  505. /**
  506. * Sets the orientation, or how the splitter is divided. The options
  507. * are:<ul>
  508. * <li>JSplitPane.VERTICAL_SPLIT (above/below orientation of components)
  509. * <li>JSplitPane.HORIZONTAL_SPLIT (left/right orientation of components)
  510. * </ul>
  511. *
  512. * @param orientation an integer specifying the orientation
  513. * @exception IllegalArgumentException if orientation is not one of:
  514. * HORIZONTAL_SPLIT or VERTICAL_SPLIT.
  515. * @beaninfo
  516. * bound: true
  517. * description: The orientation, or how the splitter is divided.
  518. * enum: HORIZONTAL_SPLIT JSplitPane.HORIZONTAL_SPLIT
  519. * VERTICAL_SPLIT JSplitPane.VERTICAL_SPLIT
  520. */
  521. public void setOrientation(int orientation) {
  522. if ((orientation != VERTICAL_SPLIT) &&
  523. (orientation != HORIZONTAL_SPLIT)) {
  524. throw new IllegalArgumentException("JSplitPane: orientation must " +
  525. "be one of " +
  526. "JSplitPane.VERTICAL_SPLIT or " +
  527. "JSplitPane.HORIZONTAL_SPLIT");
  528. }
  529. int oldOrientation = this.orientation;
  530. this.orientation = orientation;
  531. firePropertyChange(ORIENTATION_PROPERTY, oldOrientation, orientation);
  532. }
  533. /**
  534. * Returns the orientation.
  535. *
  536. * @return an integer giving the orientation
  537. * @see #setOrientation
  538. */
  539. public int getOrientation() {
  540. return orientation;
  541. }
  542. /**
  543. * Sets whether or not the child components are continuously
  544. * redisplayed and layed out during user intervention.
  545. *
  546. * @param newContinuousLayout a boolean, true if the components
  547. * are continuously redrawn as the divider changes position
  548. * @beaninfo
  549. * bound: true
  550. * description: Whether or not the child components are
  551. * continuously redisplayed and layed out during
  552. * user intervention.
  553. */
  554. public void setContinuousLayout(boolean newContinuousLayout) {
  555. boolean oldCD = continuousLayout;
  556. continuousLayout = newContinuousLayout;
  557. firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldCD,
  558. newContinuousLayout);
  559. }
  560. /**
  561. * Returns true if the child comopnents are continuously redisplayed and
  562. * layed out during user intervention.
  563. *
  564. * @return true if the components are continuously redrawn as the
  565. * divider changes position
  566. */
  567. public boolean isContinuousLayout() {
  568. return continuousLayout;
  569. }
  570. /**
  571. * Specifies how to distribute extra space when the size of the split pane
  572. * changes. A value of 0, the default,
  573. * indicates the right/bottom component gets all the extra space (the
  574. * left/top component acts fixed), where as a value of 1 specifies the
  575. * left/top component gets all the extra space (the right/bottom component
  576. * acts fixed). Specifically, the left/top component gets (weight * diff)
  577. * extra space and the right/bottom component gets (1 - weight) * diff
  578. * extra space.
  579. *
  580. * @param value as described above
  581. * @exception IllegalArgumentException if <code>value</code> is < 0 or > 1
  582. * @since 1.3
  583. * @beaninfo
  584. * bound: true
  585. * description: Specifies how to distribute extra space when the split pane
  586. * resizes.
  587. */
  588. public void setResizeWeight(double value) {
  589. if (value < 0 || value > 1) {
  590. throw new IllegalArgumentException("JSplitPane weight must be between 0 and 1");
  591. }
  592. double oldWeight = resizeWeight;
  593. resizeWeight = value;
  594. firePropertyChange(RESIZE_WEIGHT_PROPERTY, oldWeight, value);
  595. }
  596. /**
  597. * Returns the number that determines how extra space is distributed.
  598. * @return how extra space is to be distributed on a resize of the
  599. * split pane
  600. * @since 1.3
  601. */
  602. public double getResizeWeight() {
  603. return resizeWeight;
  604. }
  605. /**
  606. * Lays out the <code>JSplitPane</code> layout based on the preferred size
  607. * of the children components. This will likely result in changing
  608. * the divider location.
  609. */
  610. public void resetToPreferredSizes() {
  611. SplitPaneUI ui = getUI();
  612. if (ui != null) {
  613. ui.resetToPreferredSizes(this);
  614. }
  615. }
  616. /**
  617. * Sets the divider location as a percentage of the
  618. * <code>JSplitPane</code>'s size.
  619. * <p>
  620. * This method is implemented in terms of
  621. * <code>setDividerLocation(int)</code>.
  622. * This method immediately changes the size of the split pane based on
  623. * its current size. If the split pane is not correctly realized and on
  624. * screen, this method will have no effect (new divider location will
  625. * become (current size * proportionalLocation) which is 0).
  626. *
  627. * @param proportionalLocation a double-precision floating point value
  628. * that specifies a percentage, from zero (top/left) to 1.0
  629. * (bottom/right)
  630. * @exception IllegalArgumentException if the specified location is < 0
  631. * or > 1.0
  632. * @beaninfo
  633. * description: The location of the divider.
  634. */
  635. public void setDividerLocation(double proportionalLocation) {
  636. if (proportionalLocation < 0.0 ||
  637. proportionalLocation > 1.0) {
  638. throw new IllegalArgumentException("proportional location must " +
  639. "be between 0.0 and 1.0.");
  640. }
  641. if (getOrientation() == VERTICAL_SPLIT) {
  642. setDividerLocation((int)((double)(getHeight() - getDividerSize()) *
  643. proportionalLocation));
  644. } else {
  645. setDividerLocation((int)((double)(getWidth() - getDividerSize()) *
  646. proportionalLocation));
  647. }
  648. }
  649. /**
  650. * Sets the location of the divider. This is passed off to the
  651. * look and feel implementation, and then listeners are notified. A value
  652. * less than 0 implies the divider should be reset to a value that
  653. * attempts to honor the preferred size of the left/top component.
  654. * After notifying the listeners, the last divider location is updated,
  655. * via <code>setLastDividerLocation</code>.
  656. *
  657. * @param location an int specifying a UI-specific value (typically a
  658. * pixel count)
  659. * @beaninfo
  660. * bound: true
  661. * description: The location of the divider.
  662. */
  663. public void setDividerLocation(int location) {
  664. int oldValue = dividerLocation;
  665. dividerLocation = location;
  666. // Notify UI.
  667. SplitPaneUI ui = getUI();
  668. if (ui != null) {
  669. ui.setDividerLocation(this, location);
  670. }
  671. // Then listeners
  672. firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldValue, location);
  673. // And update the last divider location.
  674. setLastDividerLocation(oldValue);
  675. }
  676. /**
  677. * Returns the last value passed to <code>setDividerLocation</code>.
  678. * The value returned from this method may differ from the actual
  679. * divider location (if <code>setDividerLocation</code> was passed a
  680. * value bigger than the curent size).
  681. *
  682. * @return an integer specifying the location of the divider
  683. */
  684. public int getDividerLocation() {
  685. return dividerLocation;
  686. }
  687. /**
  688. * Returns the minimum location of the divider from the look and feel
  689. * implementation.
  690. *
  691. * @return an integer specifying a UI-specific value for the minimum
  692. * location (typically a pixel count); or -1 if the UI is
  693. * <code>null</code>
  694. * @beaninfo
  695. * description: The minimum location of the divider from the L&F.
  696. */
  697. public int getMinimumDividerLocation() {
  698. SplitPaneUI ui = getUI();
  699. if (ui != null) {
  700. return ui.getMinimumDividerLocation(this);
  701. }
  702. return -1;
  703. }
  704. /**
  705. * Returns the maximum location of the divider from the look and feel
  706. * implementation.
  707. *
  708. * @return an integer specifying a UI-specific value for the maximum
  709. * location (typically a pixel count); or -1 if the UI is
  710. * <code>null</code>
  711. */
  712. public int getMaximumDividerLocation() {
  713. SplitPaneUI ui = getUI();
  714. if (ui != null) {
  715. return ui.getMaximumDividerLocation(this);
  716. }
  717. return -1;
  718. }
  719. /**
  720. * Removes the child component, <code>component</code> from the
  721. * pane. Resets the <code>leftComponent</code> or
  722. * <code>rightComponent</code> instance variable, as necessary.
  723. *
  724. * @param component the <code>Component</code> to remove
  725. */
  726. public void remove(Component component) {
  727. if (component == leftComponent) {
  728. leftComponent = null;
  729. } else if (component == rightComponent) {
  730. rightComponent = null;
  731. }
  732. super.remove(component);
  733. // Update the JSplitPane on the screen
  734. revalidate();
  735. repaint();
  736. }
  737. /**
  738. * Removes the <code>Component</code> at the specified index.
  739. * Updates the <code>leftComponent</code> and <code>rightComponent</code>
  740. * instance variables as necessary, and then messages super.
  741. *
  742. * @param index an integer specifying the component to remove, where
  743. * 1 specifies the left/top component and 2 specifies the
  744. * bottom/right component
  745. */
  746. public void remove(int index) {
  747. Component comp = getComponent(index);
  748. if (comp == leftComponent) {
  749. leftComponent = null;
  750. } else if (comp == rightComponent) {
  751. rightComponent = null;
  752. }
  753. super.remove(index);
  754. // Update the JSplitPane on the screen
  755. revalidate();
  756. repaint();
  757. }
  758. /**
  759. * Removes all the child components from the split pane. Resets the
  760. * <code>leftComonent</code> and <code>rightComponent</code>
  761. * instance variables.
  762. */
  763. public void removeAll() {
  764. leftComponent = rightComponent = null;
  765. super.removeAll();
  766. // Update the JSplitPane on the screen
  767. revalidate();
  768. repaint();
  769. }
  770. /**
  771. * Returns true, so that calls to <code>revalidate</code>
  772. * on any descendant of this <code>JSplitPane</code>
  773. * will cause a request to be queued that
  774. * will validate the <code>JSplitPane</code> and all its descendants.
  775. *
  776. * @return true
  777. * @see JComponent#revalidate
  778. *
  779. * @beaninfo
  780. * hidden: true
  781. */
  782. public boolean isValidateRoot() {
  783. return true;
  784. }
  785. /**
  786. * Adds the specified component to this split pane.
  787. * If <code>constraints</code> identifies the left/top or
  788. * right/bottom child component, and a component with that identifier
  789. * was previously added, it will be removed and then <code>comp</code>
  790. * will be added in its place. If <code>constraints</code> is not
  791. * one of the known identifers the layout manager may throw an
  792. * IllegalArgumentException.
  793. * <p>
  794. * The possible constraints objects (Strings) are:
  795. * <ul>
  796. * <li>JSplitPane.TOP
  797. * <li>JSplitPane.LEFT
  798. * <li>JSplitPane.BOTTOM
  799. * <li>JSplitPane.RIGHT
  800. * </ul>
  801. * If the <code>constraints</code> object is <code>null</code>,
  802. * the component is added in the
  803. * first available position (left/top if open, else right/bottom).
  804. *
  805. * @param comp the component to add
  806. * @param constraints an <code>Object</code> specifying the
  807. * layout constraints
  808. * (position) for this component
  809. * @param index an integer specifying the index in the container's
  810. * list.
  811. * @exception IllegalArgumentException if the <code>constraints</code>
  812. * object does not match an existing component
  813. * @see java.awt.Container#addImpl(Component, Object, int)
  814. */
  815. protected void addImpl(Component comp, Object constraints, int index)
  816. {
  817. Component toRemove;
  818. if (constraints != null && !(constraints instanceof String)) {
  819. throw new IllegalArgumentException("cannot add to layout: " +
  820. "constraint must be a string " +
  821. "(or null)");
  822. }
  823. /* If the constraints are null and the left/right component is
  824. invalid, add it at the left/right component. */
  825. if (constraints == null) {
  826. if (getLeftComponent() == null) {
  827. constraints = JSplitPane.LEFT;
  828. } else if (getRightComponent() == null) {
  829. constraints = JSplitPane.RIGHT;
  830. }
  831. }
  832. /* Find the Component that already exists and remove it. */
  833. if (constraints != null && (constraints.equals(JSplitPane.LEFT) ||
  834. constraints.equals(JSplitPane.TOP))) {
  835. toRemove = getLeftComponent();
  836. if (toRemove != null) {
  837. remove(toRemove);
  838. }
  839. leftComponent = comp;
  840. index = -1;
  841. } else if (constraints != null &&
  842. (constraints.equals(JSplitPane.RIGHT) ||
  843. constraints.equals(JSplitPane.BOTTOM))) {
  844. toRemove = getRightComponent();
  845. if (toRemove != null) {
  846. remove(toRemove);
  847. }
  848. rightComponent = comp;
  849. index = -1;
  850. } else if (constraints != null &&
  851. constraints.equals(JSplitPane.DIVIDER)) {
  852. index = -1;
  853. }
  854. /* LayoutManager should raise for else condition here. */
  855. super.addImpl(comp, constraints, index);
  856. // Update the JSplitPane on the screen
  857. revalidate();
  858. repaint();
  859. }
  860. /**
  861. * Subclassed to message the UI with <code>finishedPaintingChildren</code>
  862. * after super has been messaged, as well as painting the border.
  863. *
  864. * @param g the <code>Graphics</code> context within which to paint
  865. */
  866. protected void paintChildren(Graphics g) {
  867. super.paintChildren(g);
  868. SplitPaneUI ui = getUI();
  869. if (ui != null) {
  870. Graphics tempG = SwingGraphics.createSwingGraphics(g);
  871. ui.finishedPaintingChildren(this, tempG);
  872. tempG.dispose();
  873. }
  874. }
  875. /**
  876. * See <code>readObject</code> and <code>writeObject</code> in
  877. * <code>JComponent</code> for more
  878. * information about serialization in Swing.
  879. */
  880. private void writeObject(ObjectOutputStream s) throws IOException {
  881. s.defaultWriteObject();
  882. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  883. ui.installUI(this);
  884. }
  885. }
  886. /**
  887. * Returns a string representation of this <code>JSplitPane</code>.
  888. * This method
  889. * is intended to be used only for debugging purposes, and the
  890. * content and format of the returned string may vary between
  891. * implementations. The returned string may be empty but may not
  892. * be <code>null</code>.
  893. *
  894. * @return a string representation of this <code>JSplitPane</code>.
  895. */
  896. protected String paramString() {
  897. String orientationString = (orientation == HORIZONTAL_SPLIT ?
  898. "HORIZONTAL_SPLIT" : "VERTICAL_SPLIT");
  899. String continuousLayoutString = (continuousLayout ?
  900. "true" : "false");
  901. String oneTouchExpandableString = (oneTouchExpandable ?
  902. "true" : "false");
  903. return super.paramString() +
  904. ",continuousLayout=" + continuousLayoutString +
  905. ",dividerSize=" + dividerSize +
  906. ",lastDividerLocation=" + lastDividerLocation +
  907. ",oneTouchExpandable=" + oneTouchExpandableString +
  908. ",orientation=" + orientationString;
  909. }
  910. ///////////////////////////
  911. // Accessibility support //
  912. ///////////////////////////
  913. /**
  914. * Gets the AccessibleContext associated with this JSplitPane.
  915. * For split panes, the AccessibleContext takes the form of an
  916. * AccessibleJSplitPane.
  917. * A new AccessibleJSplitPane instance is created if necessary.
  918. *
  919. * @return an AccessibleJSplitPane that serves as the
  920. * AccessibleContext of this JSplitPane
  921. * @beaninfo
  922. * expert: true
  923. * description: The AccessibleContext associated with this SplitPane.
  924. */
  925. public AccessibleContext getAccessibleContext() {
  926. if (accessibleContext == null) {
  927. accessibleContext = new AccessibleJSplitPane();
  928. }
  929. return accessibleContext;
  930. }
  931. /**
  932. * This class implements accessibility support for the
  933. * <code>JSplitPane</code> class. It provides an implementation of the
  934. * Java Accessibility API appropriate to split pane user-interface elements.
  935. * <p>
  936. * <strong>Warning:</strong>
  937. * Serialized objects of this class will not be compatible with
  938. * future Swing releases. The current serialization support is appropriate
  939. * for short term storage or RMI between applications running the same
  940. * version of Swing. A future release of Swing will provide support for
  941. * long term persistence.
  942. */
  943. protected class AccessibleJSplitPane extends AccessibleJComponent
  944. implements AccessibleValue {
  945. /**
  946. * Gets the state set of this object.
  947. *
  948. * @return an instance of AccessibleState containing the current state
  949. * of the object
  950. * @see AccessibleState
  951. */
  952. public AccessibleStateSet getAccessibleStateSet() {
  953. AccessibleStateSet states = super.getAccessibleStateSet();
  954. // FIXME: [[[WDW - Should also add BUSY if this implements
  955. // Adjustable at some point. If this happens, we probably
  956. // should also add actions.]]]
  957. if (getOrientation() == VERTICAL_SPLIT) {
  958. states.add(AccessibleState.VERTICAL);
  959. } else {
  960. states.add(AccessibleState.HORIZONTAL);
  961. }
  962. return states;
  963. }
  964. /**
  965. * Get the AccessibleValue associated with this object. In the
  966. * implementation of the Java Accessibility API for this class,
  967. * return this object, which is responsible for implementing the
  968. * AccessibleValue interface on behalf of itself.
  969. *
  970. * @return this object
  971. */
  972. public AccessibleValue getAccessibleValue() {
  973. return this;
  974. }
  975. /**
  976. * Gets the accessible value of this object.
  977. *
  978. * @return a localized String describing the value of this object
  979. */
  980. public Number getCurrentAccessibleValue() {
  981. return new Integer(getDividerLocation());
  982. }
  983. /**
  984. * Sets the value of this object as a Number.
  985. *
  986. * @return True if the value was set.
  987. */
  988. public boolean setCurrentAccessibleValue(Number n) {
  989. if (n instanceof Integer) {
  990. setDividerLocation(n.intValue());
  991. return true;
  992. } else {
  993. return false;
  994. }
  995. }
  996. /**
  997. * Gets the minimum accessible value of this object.
  998. *
  999. * @return The minimum value of this object.
  1000. */
  1001. public Number getMinimumAccessibleValue() {
  1002. return new Integer(getUI().getMinimumDividerLocation(
  1003. JSplitPane.this));
  1004. }
  1005. /**
  1006. * Gets the maximum accessible value of this object.
  1007. *
  1008. * @return The maximum value of this object.
  1009. */
  1010. public Number getMaximumAccessibleValue() {
  1011. return new Integer(getUI().getMaximumDividerLocation(
  1012. JSplitPane.this));
  1013. }
  1014. /**
  1015. * Gets the role of this object.
  1016. *
  1017. * @return an instance of AccessibleRole describing the role of
  1018. * the object
  1019. * @see AccessibleRole
  1020. */
  1021. public AccessibleRole getAccessibleRole() {
  1022. return AccessibleRole.SPLIT_PANE;
  1023. }
  1024. } // inner class AccessibleJSplitPane
  1025. }