1. /*
  2. * @(#)BasicSplitPaneUI.java 1.51 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.basic;
  8. import javax.swing.*;
  9. import javax.swing.border.Border;
  10. import javax.swing.event.*;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import java.awt.peer.ComponentPeer;
  14. import java.beans.*;
  15. import java.util.*;
  16. import javax.swing.plaf.SplitPaneUI;
  17. import javax.swing.plaf.ComponentUI;
  18. /**
  19. * A Basic L&F implementation of the SplitPaneUI.
  20. *
  21. * @version 1.51 11/29/01
  22. * @author Scott Violet
  23. * @author Steve Wilson
  24. * @author Ralph Kar
  25. */
  26. public class BasicSplitPaneUI extends SplitPaneUI
  27. {
  28. /**
  29. * The divider used for non-continuous layout is added to the split pane
  30. * with this object.
  31. */
  32. protected static final String NON_CONTINUOUS_DIVIDER =
  33. "nonContinuousDivider";
  34. /**
  35. * How far (relativ) the divider does move when it is moved around by
  36. * the cursor keys on the keyboard.
  37. */
  38. protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;
  39. /**
  40. * JSplitPane instance this instance is providing
  41. * the look and feel for.
  42. */
  43. protected JSplitPane splitPane;
  44. /**
  45. * LayoutManager that is created and placed into the split pane.
  46. */
  47. protected BasicHorizontalLayoutManager layoutManager;
  48. /**
  49. * Instance of the divider for this JSplitPane.
  50. */
  51. protected BasicSplitPaneDivider divider;
  52. /**
  53. * Instance of the PropertyChangeListener for this JSplitPane.
  54. */
  55. protected PropertyChangeListener propertyChangeListener;
  56. /**
  57. * Instance of the FocusListener for this JSplitPane.
  58. */
  59. protected FocusListener focusListener;
  60. /**
  61. * The size of the divider while the dragging session is valid.
  62. */
  63. protected int dividerSize;
  64. /**
  65. * Instance for the shadow of the divider when non continuous layout
  66. * is being used.
  67. */
  68. protected Component nonContinuousLayoutDivider;
  69. /**
  70. * Set to true in startDragging if any of the children
  71. * (not including the nonContinuousLayoutDivider) are heavy weights.
  72. */
  73. protected boolean draggingHW;
  74. /**
  75. * Location of the divider when the dragging session began.
  76. */
  77. protected int beginDragDividerLocation;
  78. /**
  79. * The keystrokes that the JSplitPane is supposed to handle.
  80. */
  81. protected KeyStroke upKey;
  82. protected KeyStroke downKey;
  83. protected KeyStroke leftKey;
  84. protected KeyStroke rightKey;
  85. protected KeyStroke homeKey;
  86. protected KeyStroke endKey;
  87. protected KeyStroke dividerResizeToggleKey;
  88. // hania 10/29/98: if the above (upKey, etc) need to be
  89. // protected fields (and I don't really understand why they do), then so
  90. // do the ones below (kpUpKey, etc). I am making them private
  91. // until we can make a release where API changes are allowed.
  92. private KeyStroke kpUpKey;
  93. private KeyStroke kpDownKey;
  94. private KeyStroke kpLeftKey;
  95. private KeyStroke kpRightKey;
  96. /**
  97. * The handlers that are handling the keystrokes for keyboard navigation.
  98. */
  99. protected ActionListener keyboardUpLeftListener;
  100. protected ActionListener keyboardDownRightListener;
  101. protected ActionListener keyboardHomeListener;
  102. protected ActionListener keyboardEndListener;
  103. protected ActionListener keyboardResizeToggleListener;
  104. // Private data of the instance
  105. private int orientation;
  106. private int lastDragLocation;
  107. private boolean continuousLayout;
  108. private boolean dividerKeyboardResize;
  109. private boolean dividerLocationIsSet; // needed for tracking
  110. // the first occurence of
  111. // setDividerLocation()
  112. /**
  113. * Creates a new BasicSplitPaneUI instance
  114. */
  115. public static ComponentUI createUI(JComponent x) {
  116. return new BasicSplitPaneUI();
  117. }
  118. /**
  119. * Installs the UI.
  120. */
  121. public void installUI(JComponent c) {
  122. splitPane = (JSplitPane) c;
  123. dividerLocationIsSet = false;
  124. dividerKeyboardResize = false;
  125. installDefaults();
  126. installListeners();
  127. installKeyboardActions();
  128. setLastDragLocation(-1);
  129. }
  130. /**
  131. * Installs the UI defaults.
  132. */
  133. protected void installDefaults(){
  134. LookAndFeel.installBorder(splitPane, "SplitPane.border");
  135. if (divider == null) divider = createDefaultDivider();
  136. divider.setBasicSplitPaneUI(this);
  137. splitPane.setDividerSize(((Integer) (UIManager.get(
  138. "SplitPane.dividerSize"))).intValue());
  139. divider.setDividerSize(splitPane.getDividerSize());
  140. splitPane.add(divider, JSplitPane.DIVIDER);
  141. setOrientation(splitPane.getOrientation());
  142. setContinuousLayout(splitPane.isContinuousLayout());
  143. resetLayoutManager();
  144. /* Install the nonContinuousLayoutDivider here to avoid having to
  145. add/remove everything later. */
  146. if(nonContinuousLayoutDivider == null) {
  147. setNonContinuousLayoutDivider(
  148. createDefaultNonContinuousLayoutDivider(),
  149. true);
  150. } else {
  151. setNonContinuousLayoutDivider(nonContinuousLayoutDivider, true);
  152. }
  153. }
  154. /**
  155. * Installs the event listeners for the UI.
  156. */
  157. protected void installListeners() {
  158. if ((propertyChangeListener = createPropertyChangeListener()) !=
  159. null) {
  160. splitPane.addPropertyChangeListener(propertyChangeListener);
  161. }
  162. if ((focusListener = createFocusListener()) != null) {
  163. splitPane.addFocusListener(focusListener);
  164. }
  165. keyboardUpLeftListener = createKeyboardUpLeftListener();
  166. keyboardDownRightListener = createKeyboardDownRightListener();
  167. keyboardHomeListener = createKeyboardHomeListener();
  168. keyboardEndListener = createKeyboardEndListener();
  169. keyboardResizeToggleListener = createKeyboardResizeToggleListener();
  170. }
  171. /**
  172. * Installs the keyboard actions for the UI.
  173. */
  174. protected void installKeyboardActions() {
  175. upKey = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
  176. splitPane.registerKeyboardAction(
  177. keyboardUpLeftListener,
  178. upKey,
  179. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  180. downKey = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
  181. splitPane.registerKeyboardAction(
  182. keyboardDownRightListener,
  183. downKey,
  184. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  185. leftKey = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
  186. splitPane.registerKeyboardAction(
  187. keyboardUpLeftListener,
  188. leftKey,
  189. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  190. rightKey = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
  191. splitPane.registerKeyboardAction(
  192. keyboardDownRightListener,
  193. rightKey,
  194. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  195. kpUpKey = KeyStroke.getKeyStroke( "KP_UP" );
  196. splitPane.registerKeyboardAction(
  197. keyboardUpLeftListener,
  198. kpUpKey,
  199. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  200. kpDownKey = KeyStroke.getKeyStroke("KP_DOWN");
  201. splitPane.registerKeyboardAction(
  202. keyboardDownRightListener,
  203. kpDownKey,
  204. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  205. kpLeftKey = KeyStroke.getKeyStroke("KP_LEFT");
  206. splitPane.registerKeyboardAction(
  207. keyboardUpLeftListener,
  208. kpLeftKey,
  209. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  210. kpRightKey = KeyStroke.getKeyStroke("KP_RIGHT");
  211. splitPane.registerKeyboardAction(
  212. keyboardDownRightListener,
  213. kpRightKey,
  214. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  215. homeKey = KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0);
  216. splitPane.registerKeyboardAction(
  217. keyboardHomeListener,
  218. homeKey,
  219. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  220. endKey = KeyStroke.getKeyStroke(KeyEvent.VK_END, 0);
  221. splitPane.registerKeyboardAction(
  222. keyboardEndListener,
  223. endKey,
  224. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  225. dividerResizeToggleKey = KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0);
  226. splitPane.registerKeyboardAction(
  227. keyboardResizeToggleListener,
  228. dividerResizeToggleKey,
  229. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  230. splitPane.registerKeyboardAction(new ToggleSideFocusHandler(),
  231. KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0),
  232. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  233. }
  234. /**
  235. * Uninstalls the UI.
  236. */
  237. public void uninstallUI(JComponent c) {
  238. uninstallKeyboardActions();
  239. uninstallListeners();
  240. uninstallDefaults();
  241. dividerLocationIsSet = false;
  242. dividerKeyboardResize = false;
  243. splitPane = null;
  244. }
  245. /**
  246. * Uninstalls the UI defaults.
  247. */
  248. protected void uninstallDefaults() {
  249. if(splitPane.getLayout() == layoutManager) {
  250. splitPane.setLayout(null);
  251. }
  252. if(nonContinuousLayoutDivider != null) {
  253. splitPane.remove(nonContinuousLayoutDivider);
  254. }
  255. LookAndFeel.uninstallBorder(splitPane);
  256. splitPane.remove(divider);
  257. divider.setBasicSplitPaneUI(null);
  258. layoutManager = null;
  259. divider = null;
  260. nonContinuousLayoutDivider = null;
  261. setNonContinuousLayoutDivider(null);
  262. }
  263. /**
  264. * Uninstalls the event listeners for the UI.
  265. */
  266. protected void uninstallListeners() {
  267. if (propertyChangeListener != null) {
  268. splitPane.removePropertyChangeListener(propertyChangeListener);
  269. propertyChangeListener = null;
  270. }
  271. if (focusListener != null) {
  272. splitPane.removeFocusListener(focusListener);
  273. focusListener = null;
  274. }
  275. keyboardUpLeftListener = null;
  276. keyboardDownRightListener = null;
  277. keyboardHomeListener = null;
  278. keyboardEndListener = null;
  279. keyboardResizeToggleListener = null;
  280. }
  281. /**
  282. * Uninstalls the keyboard actions for the UI.
  283. */
  284. protected void uninstallKeyboardActions() {
  285. splitPane.unregisterKeyboardAction(upKey);
  286. splitPane.unregisterKeyboardAction(downKey);
  287. splitPane.unregisterKeyboardAction(leftKey);
  288. splitPane.unregisterKeyboardAction(rightKey);
  289. splitPane.unregisterKeyboardAction(homeKey);
  290. splitPane.unregisterKeyboardAction(endKey);
  291. splitPane.unregisterKeyboardAction(dividerResizeToggleKey);
  292. splitPane.unregisterKeyboardAction
  293. (KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0));
  294. splitPane.unregisterKeyboardAction(kpUpKey);
  295. splitPane.unregisterKeyboardAction(kpDownKey);
  296. splitPane.unregisterKeyboardAction(kpLeftKey);
  297. splitPane.unregisterKeyboardAction(kpRightKey);
  298. kpUpKey = kpDownKey = kpLeftKey = kpRightKey = null;
  299. upKey = null;
  300. downKey = null;
  301. leftKey = null;
  302. rightKey = null;
  303. homeKey = null;
  304. endKey = null;
  305. dividerResizeToggleKey = null;
  306. }
  307. /**
  308. * Creates a PropertyChangeListener for the JSplitPane UI.
  309. */
  310. protected PropertyChangeListener createPropertyChangeListener() {
  311. return new PropertyHandler();
  312. }
  313. /**
  314. * Creates a FocusListener for the JSplitPane UI.
  315. */
  316. protected FocusListener createFocusListener() {
  317. return new FocusHandler();
  318. }
  319. /**
  320. * Creates a ActionListener for the JSplitPane UI that listens for
  321. * specific key presses.
  322. */
  323. protected ActionListener createKeyboardUpLeftListener() {
  324. return new KeyboardUpLeftHandler();
  325. }
  326. /**
  327. * Creates a ActionListener for the JSplitPane UI that listens for
  328. * specific key presses.
  329. */
  330. protected ActionListener createKeyboardDownRightListener() {
  331. return new KeyboardDownRightHandler();
  332. }
  333. /**
  334. * Creates a ActionListener for the JSplitPane UI that listens for
  335. * specific key presses.
  336. */
  337. protected ActionListener createKeyboardHomeListener() {
  338. return new KeyboardHomeHandler();
  339. }
  340. /**
  341. * Creates a ActionListener for the JSplitPane UI that listens for
  342. * specific key presses.
  343. */
  344. protected ActionListener createKeyboardEndListener() {
  345. return new KeyboardEndHandler();
  346. }
  347. /**
  348. * Creates a ActionListener for the JSplitPane UI that listens for
  349. * specific key presses.
  350. */
  351. protected ActionListener createKeyboardResizeToggleListener() {
  352. return new KeyboardResizeToggleHandler();
  353. }
  354. /**
  355. * Returns the orientation for the JSplitPane.
  356. */
  357. public int getOrientation() {
  358. return orientation;
  359. }
  360. /**
  361. * Set the orientation for the JSplitPane.
  362. */
  363. public void setOrientation(int orientation) {
  364. this.orientation = orientation;
  365. }
  366. /**
  367. * Determines wether the JSplitPane is set to use a continuous layout.
  368. */
  369. public boolean isContinuousLayout() {
  370. return continuousLayout;
  371. }
  372. /**
  373. * Turn continuous layout on/off.
  374. */
  375. public void setContinuousLayout(boolean b) {
  376. continuousLayout = b;
  377. }
  378. /**
  379. * Returns the last drag location of the JSplitPane.
  380. */
  381. public int getLastDragLocation() {
  382. return lastDragLocation;
  383. }
  384. /**
  385. * Set the last drag location of the JSplitPane.
  386. */
  387. public void setLastDragLocation(int l) {
  388. lastDragLocation = l;
  389. }
  390. /**
  391. * Implementation of the PropertyChangeListener
  392. * that the JSplitPane UI uses.
  393. * <p>
  394. * This inner class is marked "public" due to a compiler bug.
  395. * This class should be treated as a "protected" inner class.
  396. * Instantiate it only within subclasses of BasicSplitPaneUI.
  397. */
  398. public class PropertyHandler implements PropertyChangeListener
  399. {
  400. /**
  401. * Messaged from the JSplitPane the reciever is contained in.
  402. * May potentially reset the layout manager and cause a
  403. * validate() to be sent.
  404. */
  405. public void propertyChange(PropertyChangeEvent e) {
  406. if(e.getSource() == splitPane) {
  407. String changeName = e.getPropertyName();
  408. if(changeName.equals(JSplitPane.ORIENTATION_PROPERTY)) {
  409. orientation = splitPane.getOrientation();
  410. resetLayoutManager();
  411. } else if(changeName.equals(
  412. JSplitPane.CONTINUOUS_LAYOUT_PROPERTY)) {
  413. setContinuousLayout(splitPane.isContinuousLayout());
  414. if(!isContinuousLayout()) {
  415. if(nonContinuousLayoutDivider == null) {
  416. setNonContinuousLayoutDivider(
  417. createDefaultNonContinuousLayoutDivider(),
  418. true);
  419. } else if(nonContinuousLayoutDivider.getParent() ==
  420. null) {
  421. setNonContinuousLayoutDivider(
  422. nonContinuousLayoutDivider,
  423. true);
  424. }
  425. }
  426. } else if(changeName.equals(JSplitPane.DIVIDER_SIZE_PROPERTY)){
  427. divider.setDividerSize(splitPane.getDividerSize());
  428. layoutManager.resetSizeAt(2);
  429. splitPane.revalidate();
  430. }
  431. }
  432. }
  433. }
  434. /**
  435. * Implementation of the FocusListener that the JSplitPane UI uses.
  436. * <p>
  437. * This inner class is marked "public" due to a compiler bug.
  438. * This class should be treated as a "protected" inner class.
  439. * Instantiate it only within subclasses of BasicSplitPaneUI.
  440. */
  441. public class FocusHandler extends FocusAdapter
  442. {
  443. public void focusLost(FocusEvent ev) {
  444. dividerKeyboardResize = false;
  445. splitPane.repaint();
  446. }
  447. }
  448. /**
  449. * Implementation of an ActionListener that the JSplitPane UI uses for
  450. * handling specific key presses.
  451. * <p>
  452. * This inner class is marked "public" due to a compiler bug.
  453. * This class should be treated as a "protected" inner class.
  454. * Instantiate it only within subclasses of BasicSplitPaneUI.
  455. */
  456. public class KeyboardUpLeftHandler implements ActionListener
  457. {
  458. public void actionPerformed(ActionEvent ev) {
  459. if (dividerKeyboardResize) {
  460. setDividerLocation(splitPane,
  461. getDividerLocation(splitPane) -
  462. KEYBOARD_DIVIDER_MOVE_OFFSET);
  463. }
  464. }
  465. }
  466. /**
  467. * Implementation of an ActionListener that the JSplitPane UI uses for
  468. * handling specific key presses.
  469. * <p>
  470. * This inner class is marked "public" due to a compiler bug.
  471. * This class should be treated as a "protected" inner class.
  472. * Instantiate it only within subclasses of BasicSplitPaneUI.
  473. */
  474. public class KeyboardDownRightHandler implements ActionListener
  475. {
  476. public void actionPerformed(ActionEvent ev) {
  477. if (dividerKeyboardResize) {
  478. setDividerLocation(splitPane,
  479. getDividerLocation(splitPane) +
  480. KEYBOARD_DIVIDER_MOVE_OFFSET);
  481. }
  482. }
  483. }
  484. /**
  485. * Implementation of an ActionListener that the JSplitPane UI uses for
  486. * handling specific key presses.
  487. * <p>
  488. * This inner class is marked "public" due to a compiler bug.
  489. * This class should be treated as a "protected" inner class.
  490. * Instantiate it only within subclasses of BasicSplitPaneUI.
  491. */
  492. public class KeyboardHomeHandler implements ActionListener
  493. {
  494. public void actionPerformed(ActionEvent ev) {
  495. if (dividerKeyboardResize) {
  496. setDividerLocation(splitPane, 0);
  497. }
  498. }
  499. }
  500. /**
  501. * Implementation of an ActionListener that the JSplitPane UI uses for
  502. * handling specific key presses.
  503. * <p>
  504. * This inner class is marked "public" due to a compiler bug.
  505. * This class should be treated as a "protected" inner class.
  506. * Instantiate it only within subclasses of BasicSplitPaneUI.
  507. */
  508. public class KeyboardEndHandler implements ActionListener
  509. {
  510. public void actionPerformed(ActionEvent ev) {
  511. if (dividerKeyboardResize) {
  512. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  513. setDividerLocation(splitPane, splitPane.getHeight() -
  514. splitPane.getInsets().bottom);
  515. }
  516. else {
  517. setDividerLocation(splitPane, splitPane.getWidth() -
  518. splitPane.getInsets().right);
  519. }
  520. }
  521. }
  522. }
  523. /**
  524. * Implementation of an ActionListener that the JSplitPane UI uses for
  525. * handling specific key presses.
  526. * <p>
  527. * This inner class is marked "public" due to a compiler bug.
  528. * This class should be treated as a "protected" inner class.
  529. * Instantiate it only within subclasses of BasicSplitPaneUI.
  530. */
  531. public class KeyboardResizeToggleHandler implements ActionListener
  532. {
  533. public void actionPerformed(ActionEvent ev) {
  534. if (!dividerKeyboardResize) {
  535. splitPane.requestFocus();
  536. dividerKeyboardResize = true;
  537. splitPane.repaint();
  538. }
  539. }
  540. }
  541. /**
  542. * ActionListener that will focus on the opposite component that
  543. * has focus. EG if the left side has focus, this will transfer focus
  544. * to the right component.
  545. */
  546. class ToggleSideFocusHandler implements ActionListener {
  547. public void actionPerformed(ActionEvent ae) {
  548. // Determine which side currently has focus. If there is only
  549. // one component, don't change the focus.
  550. Component left = splitPane.getLeftComponent();
  551. Component right = splitPane.getRightComponent();
  552. Component focus = SwingUtilities.findFocusOwner(left);
  553. Component focusOn;
  554. if (focus == null) {
  555. focusOn = SwingUtilities.findFocusOwner(right);
  556. if (focusOn != null) {
  557. if (left != null) {
  558. focusOn = left;
  559. }
  560. else {
  561. focusOn = null;
  562. }
  563. }
  564. else if (left != null) {
  565. focusOn = left;
  566. }
  567. else if (right != null) {
  568. focusOn = right;
  569. }
  570. }
  571. else if (right != null) {
  572. focusOn = right;
  573. }
  574. else {
  575. focusOn = left;
  576. }
  577. if (focusOn != null) {
  578. // Found the component to request focus on.
  579. if (focusOn instanceof JComponent) {
  580. if (!((JComponent)focusOn).requestDefaultFocus() &&
  581. focusOn.isFocusTraversable()) {
  582. focusOn.requestFocus();
  583. }
  584. }
  585. else {
  586. focusOn.requestFocus();
  587. }
  588. }
  589. }
  590. }
  591. /**
  592. * Returns the divider between the top Components.
  593. */
  594. public BasicSplitPaneDivider getDivider() {
  595. return divider;
  596. }
  597. /**
  598. * Returns the default non continuous layout divider, which is an
  599. * instanceof Canvas that fills the background in dark gray.
  600. */
  601. protected Component createDefaultNonContinuousLayoutDivider() {
  602. return new Canvas() {
  603. public void paint(Graphics g) {
  604. if(!isContinuousLayout() && getLastDragLocation() != -1) {
  605. Dimension size = splitPane.getSize();
  606. g.setColor(Color.darkGray);
  607. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  608. g.fillRect(0, 0, dividerSize - 1, size.height - 1);
  609. } else {
  610. g.fillRect(0, 0, size.width - 1, dividerSize - 1);
  611. }
  612. }
  613. }
  614. };
  615. }
  616. /**
  617. * Sets the divider to use when the splitPane is configured to
  618. * not continuously layout. This divider will only be used during a
  619. * dragging session. It is recommended that the passed in component
  620. * be a heavy weight.
  621. */
  622. protected void setNonContinuousLayoutDivider(Component newDivider) {
  623. setNonContinuousLayoutDivider(newDivider, true);
  624. }
  625. /**
  626. * Sets the divider to use.
  627. */
  628. protected void setNonContinuousLayoutDivider(Component newDivider,
  629. boolean rememberSizes) {
  630. if(nonContinuousLayoutDivider != null && splitPane != null) {
  631. splitPane.remove(nonContinuousLayoutDivider);
  632. }
  633. nonContinuousLayoutDivider = newDivider;
  634. if(nonContinuousLayoutDivider != null && splitPane != null) {
  635. nonContinuousLayoutDivider.setLocation(-1000, -1000);
  636. /* Needs to remove all the components and readd them! YECK! */
  637. Component leftC = splitPane.getLeftComponent();
  638. Component rightC = splitPane.getRightComponent();
  639. int[] sizes = layoutManager.getSizes();
  640. if(leftC != null)
  641. splitPane.setLeftComponent(null);
  642. if(rightC != null)
  643. splitPane.setRightComponent(null);
  644. splitPane.remove(divider);
  645. splitPane.add(nonContinuousLayoutDivider, BasicSplitPaneUI.
  646. NON_CONTINUOUS_DIVIDER,
  647. splitPane.getComponentCount());
  648. splitPane.setLeftComponent(leftC);
  649. splitPane.setRightComponent(rightC);
  650. splitPane.add(divider, JSplitPane.DIVIDER);
  651. if(rememberSizes)
  652. layoutManager.setSizes(sizes);
  653. splitPane.revalidate();
  654. splitPane.paintImmediately(splitPane.getX(),
  655. splitPane.getY(),
  656. splitPane.getWidth(),
  657. splitPane.getHeight());
  658. }
  659. }
  660. /**
  661. * Returns the divider to use when the splitPane is configured to
  662. * not continuously layout. This divider will only be used during a
  663. * dragging session.
  664. */
  665. public Component getNonContinuousLayoutDivider() {
  666. return nonContinuousLayoutDivider;
  667. }
  668. /**
  669. * Returns the splitpane this instance is currently contained
  670. * in.
  671. */
  672. public JSplitPane getSplitPane() {
  673. return splitPane;
  674. }
  675. /**
  676. * Creates the default divider.
  677. */
  678. public BasicSplitPaneDivider createDefaultDivider() {
  679. return new BasicSplitPaneDivider(this);
  680. }
  681. /**
  682. * Messaged to reset the preferred sizes.
  683. */
  684. public void resetToPreferredSizes(JSplitPane jc) {
  685. if(splitPane != null) {
  686. layoutManager.resetToPreferredSizes();
  687. splitPane.revalidate();
  688. layoutManager.layoutContainer(splitPane);
  689. }
  690. }
  691. /**
  692. * Sets the location of the divider to location.
  693. */
  694. public void setDividerLocation(JSplitPane jc, int location) {
  695. Component leftC = splitPane.getLeftComponent();
  696. Component rightC = splitPane.getRightComponent();
  697. if(leftC != null && rightC != null) {
  698. Insets insets = splitPane.getInsets();
  699. // Since location describes the size of the left/top component
  700. // and not really the divider location the actual divider location
  701. // that can be retrieved via JSplitPane.getDividerLocation() ends
  702. // up to be location + getDividerborderSize().
  703. // That's why we subtract getDividerBorderSize() in the
  704. // calculations with location so that getDividerLocation()
  705. // returns the correct value.
  706. if(insets != null) {
  707. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  708. leftC.setSize(Math.max(0, location -
  709. getDividerBorderSize() -
  710. insets.left), 10);
  711. } else {
  712. leftC.setSize(10, Math.max(0, location -
  713. getDividerBorderSize() -
  714. insets.top));
  715. }
  716. } else {
  717. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  718. leftC.setSize(Math.max(0, location -
  719. getDividerBorderSize()), 10);
  720. } else {
  721. leftC.setSize(10, Math.max(0, location -
  722. getDividerBorderSize()));
  723. }
  724. }
  725. if (!dividerLocationIsSet) dividerLocationIsSet = true;
  726. splitPane.revalidate();
  727. splitPane.repaint();
  728. }
  729. }
  730. /**
  731. * Returns the location of the divider.
  732. */
  733. public int getDividerLocation(JSplitPane jc) {
  734. if(orientation == JSplitPane.HORIZONTAL_SPLIT)
  735. return divider.getLocation().x;
  736. return divider.getLocation().y;
  737. }
  738. /**
  739. * Gets the minimum location of the divider.
  740. */
  741. public int getMinimumDividerLocation(JSplitPane jc) {
  742. int minLoc = 0;
  743. Component leftC = splitPane.getLeftComponent();
  744. if ((leftC != null) && (leftC.isVisible())) {
  745. Insets insets = splitPane.getInsets();
  746. Dimension minSize = leftC.getMinimumSize();
  747. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  748. minLoc = minSize.width;
  749. } else {
  750. minLoc = minSize.height;
  751. }
  752. minLoc += getDividerBorderSize();
  753. if(insets != null) {
  754. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  755. minLoc += insets.left;
  756. } else {
  757. minLoc += insets.top;
  758. }
  759. }
  760. }
  761. return minLoc;
  762. }
  763. /**
  764. * Gets the maximum location of the divider.
  765. */
  766. public int getMaximumDividerLocation(JSplitPane jc) {
  767. Dimension splitPaneSize = splitPane.getSize();
  768. int maxLoc = 0;
  769. Component rightC = splitPane.getRightComponent();
  770. if (rightC != null) {
  771. Insets insets = splitPane.getInsets();
  772. Dimension minSize = new Dimension(0, 0);
  773. if (rightC.isVisible()) {
  774. minSize = rightC.getMinimumSize();
  775. }
  776. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  777. maxLoc = splitPaneSize.width - minSize.width;
  778. } else {
  779. maxLoc = splitPaneSize.height - minSize.height;
  780. }
  781. maxLoc -= (dividerSize + getDividerBorderSize());
  782. if(insets != null) {
  783. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  784. maxLoc += insets.left;
  785. } else {
  786. maxLoc += insets.top;
  787. }
  788. }
  789. }
  790. return Math.max(getMinimumDividerLocation(splitPane), maxLoc);
  791. }
  792. /**
  793. * Messaged after the JSplitPane the receiver is providing the look
  794. * and feel for paints its children.
  795. */
  796. public void finishedPaintingChildren(JSplitPane jc, Graphics g) {
  797. if(jc == splitPane && getLastDragLocation() != -1 &&
  798. !isContinuousLayout() && !draggingHW) {
  799. Dimension size = splitPane.getSize();
  800. g.setColor(Color.darkGray);
  801. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  802. g.fillRect(getLastDragLocation(), 0, dividerSize - 1,
  803. size.height - 1);
  804. } else {
  805. g.fillRect(0, lastDragLocation, size.width - 1,
  806. dividerSize - 1);
  807. }
  808. }
  809. }
  810. /**
  811. * Messaged to paint the look and feel.
  812. */
  813. public void paint(Graphics g, JComponent jc) {
  814. }
  815. /**
  816. * Returns the preferred size for the passed in component,
  817. * This is passed off to the current layoutmanager.
  818. */
  819. public Dimension getPreferredSize(JComponent jc) {
  820. if(splitPane != null)
  821. return layoutManager.preferredLayoutSize(splitPane);
  822. return new Dimension(0, 0);
  823. }
  824. /**
  825. * Returns the minimum size for the passed in component,
  826. * This is passed off to the current layoutmanager.
  827. */
  828. public Dimension getMinimumSize(JComponent jc) {
  829. if(splitPane != null)
  830. return layoutManager.minimumLayoutSize(splitPane);
  831. return new Dimension(0, 0);
  832. }
  833. /**
  834. * Returns the maximum size for the passed in component,
  835. * This is passed off to the current layoutmanager.
  836. */
  837. public Dimension getMaximumSize(JComponent jc) {
  838. if(splitPane != null)
  839. return layoutManager.maximumLayoutSize(splitPane);
  840. return new Dimension(0, 0);
  841. }
  842. /**
  843. * Returns the insets. The insets are returned from the broder insets
  844. * of the current border.
  845. */
  846. public Insets getInsets(JComponent jc) {
  847. return null;
  848. }
  849. /**
  850. * Resets the layout manager based on orientation and messages it
  851. * with invalidateLayout to pull in appropriate Components.
  852. */
  853. protected void resetLayoutManager() {
  854. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  855. layoutManager = new BasicHorizontalLayoutManager();
  856. } else {
  857. layoutManager = new BasicVerticalLayoutManager();
  858. }
  859. splitPane.setLayout(layoutManager);
  860. layoutManager.updateComponents();
  861. splitPane.revalidate();
  862. splitPane.repaint();
  863. }
  864. /**
  865. * Should be messaged before the dragging session starts, resets
  866. * lastDragLocation and dividerSize.
  867. */
  868. protected void startDragging() {
  869. Component leftC = splitPane.getLeftComponent();
  870. Component rightC = splitPane.getRightComponent();
  871. ComponentPeer cPeer;
  872. beginDragDividerLocation = getDividerLocation(splitPane);
  873. draggingHW = false;
  874. if(leftC != null && (cPeer = leftC.getPeer()) != null &&
  875. !(cPeer instanceof java.awt.peer.LightweightPeer)) {
  876. draggingHW = true;
  877. } else if(rightC != null && (cPeer = rightC.getPeer()) != null
  878. && !(cPeer instanceof java.awt.peer.LightweightPeer)) {
  879. draggingHW = true;
  880. }
  881. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  882. setLastDragLocation(divider.getBounds().x);
  883. dividerSize = divider.getSize().width + 2 * getDividerBorderSize();
  884. if(!isContinuousLayout() && draggingHW) {
  885. nonContinuousLayoutDivider.setBounds
  886. (getLastDragLocation(), 0, dividerSize,
  887. splitPane.getHeight());
  888. }
  889. } else {
  890. setLastDragLocation(divider.getBounds().y);
  891. dividerSize = divider.getSize().height + 2 *
  892. getDividerBorderSize();
  893. if(!isContinuousLayout() && draggingHW) {
  894. nonContinuousLayoutDivider.setBounds
  895. (0, getLastDragLocation(), splitPane.getWidth(),
  896. dividerSize);
  897. }
  898. }
  899. }
  900. /**
  901. * Messaged during a dragging session to move the divider to the
  902. * passed in location. If continuousLayout is true the location is
  903. * reset and the splitPane validated.
  904. */
  905. protected void dragDividerTo(int location) {
  906. if(getLastDragLocation() != location) {
  907. if(isContinuousLayout()) {
  908. setDividerLocation(splitPane, location);
  909. setLastDragLocation(location);
  910. } else {
  911. int lastLoc = getLastDragLocation();
  912. setLastDragLocation(location);
  913. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  914. int splitHeight = splitPane.getSize().height;
  915. if(draggingHW) {
  916. nonContinuousLayoutDivider.setLocation(
  917. getLastDragLocation(), 0);
  918. } else {
  919. splitPane.repaint(lastLoc, 0, dividerSize,
  920. splitHeight);
  921. splitPane.repaint(location, 0, dividerSize,
  922. splitHeight);
  923. }
  924. } else {
  925. int splitWidth = splitPane.getSize().width;
  926. if(draggingHW) {
  927. nonContinuousLayoutDivider.setLocation(0,
  928. getLastDragLocation());
  929. } else {
  930. splitPane.repaint(0, lastLoc, splitWidth,
  931. dividerSize);
  932. splitPane.repaint(0, location, splitWidth,
  933. dividerSize);
  934. }
  935. }
  936. }
  937. }
  938. }
  939. /**
  940. * Messaged to finish the dragging session. If not continuous display
  941. * the dividers location will be reset.
  942. */
  943. protected void finishDraggingTo(int location) {
  944. dragDividerTo(location);
  945. setLastDragLocation(-1);
  946. if(!isContinuousLayout()) {
  947. Component leftC = splitPane.getLeftComponent();
  948. Rectangle leftBounds = leftC.getBounds();
  949. if(orientation == JSplitPane.HORIZONTAL_SPLIT) {
  950. int splitHeight = splitPane.getSize().height;
  951. leftC.setSize(location - leftBounds.x - getDividerBorderSize(),
  952. leftBounds.height);
  953. if(draggingHW)
  954. nonContinuousLayoutDivider.setLocation(-dividerSize, 0);
  955. splitPane.paintImmediately(location, 0, dividerSize,
  956. splitHeight);
  957. } else {
  958. int splitWidth = splitPane.getSize().width;
  959. leftC.setSize(leftBounds.width,
  960. location - leftBounds.y -
  961. getDividerBorderSize());
  962. if(draggingHW)
  963. nonContinuousLayoutDivider.setLocation(0, -dividerSize);
  964. splitPane.paintImmediately(0, location, splitWidth,
  965. dividerSize);
  966. }
  967. /* Do the layout. */
  968. splitPane.revalidate();
  969. // Note: The following is only necessary because of a bug in
  970. // the LightweightDispatcher, refer to bug 4201465 for more info,
  971. // when it is fixed this will be removed.
  972. RepaintManager.currentManager(splitPane).
  973. validateInvalidComponents();
  974. splitPane.repaint();
  975. }
  976. splitPane.setLastDividerLocation(beginDragDividerLocation);
  977. }
  978. /**
  979. * Returns the width of one side of the divider border.
  980. */
  981. protected int getDividerBorderSize() {
  982. return 1;
  983. }
  984. /**
  985. * LayoutManager for JSplitPanes that have an orientation of
  986. * HORIZONTAL_SPLIT.
  987. * <p>
  988. * This inner class is marked "public" due to a compiler bug.
  989. * This class should be treated as a "protected" inner class.
  990. * Instantiate it only within subclasses of BasicSplitPaneUI.
  991. */
  992. public class BasicHorizontalLayoutManager implements LayoutManager2
  993. {
  994. /* left, right, divider. (in this exact order) */
  995. protected int[] sizes;
  996. protected Component[] components;
  997. BasicHorizontalLayoutManager() {
  998. components = new Component[3];
  999. components[0] = components[1] = components[2] = null;
  1000. sizes = new int[3];
  1001. }
  1002. /**
  1003. * Resets the size of the Component at the passed in location.
  1004. */
  1005. protected void resetSizeAt(int index) {
  1006. sizes[index] = -1;
  1007. }
  1008. /**
  1009. * Sets the sizes to <code>newSizes</code>.
  1010. */
  1011. protected void setSizes(int[] newSizes) {
  1012. System.arraycopy(newSizes, 0, sizes, 0, 3);
  1013. }
  1014. /**
  1015. * Returns the sizes of the components.
  1016. */
  1017. protected int[] getSizes() {
  1018. int[] retSizes = new int[3];
  1019. System.arraycopy(sizes, 0, retSizes, 0, 3);
  1020. return retSizes;
  1021. }
  1022. /**
  1023. * Returns the width of the passed in Components preferred size.
  1024. */
  1025. protected int getPreferredSizeOfComponent(Component c) {
  1026. return c.getPreferredSize().width;
  1027. }
  1028. /**
  1029. * Returns the width of the passed in Components minimum size.
  1030. */
  1031. int getMinimumSizeOfComponent(Component c) {
  1032. return c.getMinimumSize().width;
  1033. }
  1034. /**
  1035. * Returns the width of the passed in component.
  1036. */
  1037. protected int getSizeOfComponent(Component c) {
  1038. return c.getSize().width;
  1039. }
  1040. /**
  1041. * Returns the available width based on the container size and
  1042. * Insets.
  1043. */
  1044. protected int getAvailableSize(Dimension containerSize,
  1045. Insets insets) {
  1046. if(insets == null)
  1047. return containerSize.width;
  1048. return (containerSize.width - (insets.left + insets.right + 2 *
  1049. getDividerBorderSize()));
  1050. }
  1051. /**
  1052. * Returns the left inset, unless the Insets or null in which case
  1053. * 0 is returned.
  1054. */
  1055. protected int getInitialLocation(Insets insets) {
  1056. if(insets != null)
  1057. return insets.left;
  1058. return 0;
  1059. }
  1060. /**
  1061. * Sets the width of the component c to be size, placing its
  1062. * x location at location, y to the insets.top and height
  1063. * to the containersize.height less the top and bottom insets.
  1064. */
  1065. protected void setComponentToSize(Component c, int size,
  1066. int location, Insets insets,
  1067. Dimension containerSize) {
  1068. if(insets != null) {
  1069. c.setBounds(location, insets.top, size, containerSize.height -
  1070. (insets.top + insets.bottom));
  1071. } else {
  1072. c.setBounds(location, 0, size, containerSize.height);
  1073. }
  1074. }
  1075. /**
  1076. * Calculates the actual layout.
  1077. */
  1078. public void layoutContainer(Container container) {
  1079. Dimension containerSize = container.getSize();
  1080. // If the splitpane has a zero size then no op out of here.
  1081. // If we execute this function now, we're going to cause ourselves
  1082. // much grief.
  1083. if (containerSize.height <= 0 || containerSize.width <= 0 ) {
  1084. return;
  1085. }
  1086. Insets insets = splitPane.getInsets();
  1087. int counter;
  1088. int newSize;
  1089. int totalSize = 0;
  1090. int availableSize = getAvailableSize(containerSize, insets);
  1091. int beginLocation;
  1092. // Set the last location
  1093. beginLocation = splitPane.getDividerLocation();
  1094. // Check to see if the size of something has changed and
  1095. // adjust the other Component if it has
  1096. for (counter=0; counter<3; counter++) {
  1097. if (components[counter] != null) {
  1098. // -1 signifies this is the first time this component
  1099. // is being layed out and that the preferred size (if
  1100. // possible) should be asked for
  1101. if (sizes[counter] == -1) {
  1102. if ((dividerLocationIsSet) && (counter == 0)) {
  1103. // If setDividerLocation() was already called
  1104. // before validation, then the actually set size
  1105. // has to be used for the upper/left component
  1106. // instead of the preferred size
  1107. sizes[counter] = Math.min(availableSize,
  1108. getSizeOfComponent(
  1109. components[counter]));
  1110. }
  1111. else {
  1112. // Retrieve the preferred size of each component
  1113. sizes[counter] = Math.min(availableSize,
  1114. getPreferredSizeOfComponent(
  1115. components[counter]));
  1116. if (counter == 2) {
  1117. // Is the size of the top/left component plus
  1118. // the size of the divider bigger than the
  1119. // minimum size of the bottom/right component?
  1120. // If so set the top/left component to its
  1121. // minimum size, but only if the minimum size
  1122. // is greater than 0 (zero).
  1123. if ((components[0] != null) &&
  1124. (components[1] != null)) {
  1125. if ((sizes[0] + sizes[counter] +
  1126. getMinimumSizeOfComponent(
  1127. components[1])) > availableSize) {
  1128. sizes[0] =
  1129. (getMinimumSizeOfComponent(
  1130. components[0]) > 0) ?
  1131. getMinimumSizeOfComponent(
  1132. components[0]) :
  1133. getPreferredSizeOfComponent(
  1134. components[0]);
  1135. }
  1136. }
  1137. }
  1138. // Set the size of the components to 0 if it is
  1139. // not visible.
  1140. if (!((components[counter]).isVisible())) {
  1141. sizes[counter] = 0;
  1142. }
  1143. }
  1144. } else {
  1145. newSize = getSizeOfComponent(components[counter]);
  1146. if (sizes[counter] != newSize) {
  1147. if (counter == 0) {
  1148. if (components[1] != null) {
  1149. sizes[1] = Math.max(0, sizes[1] +
  1150. (sizes[counter] - newSize));
  1151. }
  1152. } else if (counter == 1) {
  1153. if (components[0] != null) {
  1154. sizes[0] = Math.max(0, sizes[0] +
  1155. (sizes[counter] - newSize));
  1156. }
  1157. }
  1158. sizes[counter] = newSize;
  1159. // Do this to not adjust the next one, but adjust
  1160. // the divider
  1161. if (counter == 0) counter = 1;
  1162. }
  1163. }
  1164. }
  1165. }
  1166. for (counter=0; counter<3; counter++) totalSize += sizes[counter];
  1167. // If the width has changed, adjust the right, and then left
  1168. // component (if necessary)
  1169. if (totalSize != availableSize) {
  1170. int toDiff = (availableSize - totalSize);
  1171. if (components[1] != null) {
  1172. newSize = Math.max(0, sizes[1] + toDiff);
  1173. if (newSize == 0) {
  1174. toDiff += sizes[1];
  1175. sizes[1] = 0;
  1176. if (components[0] != null)
  1177. sizes[0] = Math.max(0, sizes[0] + toDiff);
  1178. } else {
  1179. sizes[1] = newSize;
  1180. }
  1181. } else if (components[0] != null) {
  1182. sizes[0] = Math.max(0, sizes[0] + toDiff);
  1183. }
  1184. }
  1185. // Reset the bounds of each component
  1186. int nextLocation = getInitialLocation(insets);
  1187. int bdSize = getDividerBorderSize();
  1188. counter = 0;
  1189. while (counter < 3) {
  1190. if (components[counter] != null) {
  1191. setComponentToSize(components[counter], sizes[counter],
  1192. nextLocation, insets, containerSize);
  1193. nextLocation += sizes[counter];
  1194. }
  1195. switch (counter) {
  1196. case 0:
  1197. counter = 2;
  1198. nextLocation += bdSize;
  1199. break;
  1200. case 2:
  1201. counter = 1;
  1202. nextLocation += bdSize;
  1203. break;
  1204. case 1:
  1205. counter = 3;
  1206. break;
  1207. }
  1208. }
  1209. if (beginLocation != splitPane.getDividerLocation()) {
  1210. splitPane.setLastDividerLocation(beginLocation);
  1211. }
  1212. }
  1213. /**
  1214. * Adds the component at place. Place must be one of
  1215. * JSplitPane.LEFT, RIGHT, TOP, BOTTOM, or null (for the
  1216. * divider).
  1217. */
  1218. public void addLayoutComponent(String place, Component component) {
  1219. boolean isValid = true;
  1220. if(place != null) {
  1221. if(place.equals(JSplitPane.DIVIDER)) {
  1222. /* Divider. */
  1223. components[2] = component;
  1224. sizes[2] = -1;
  1225. } else if(place.equals(JSplitPane.LEFT) ||
  1226. place.equals(JSplitPane.TOP)) {
  1227. components[0] = component;
  1228. sizes[0] = -1;
  1229. } else if(place.equals(JSplitPane.RIGHT) ||
  1230. place.equals(JSplitPane.BOTTOM)) {
  1231. components[1] = component;
  1232. sizes[1] = -1;
  1233. } else if(!place.equals(
  1234. BasicSplitPaneUI.NON_CONTINUOUS_DIVIDER))
  1235. isValid = false;
  1236. } else {
  1237. isValid = false;
  1238. }
  1239. if(!isValid)
  1240. throw new IllegalArgumentException("cannot add to layout: " +
  1241. "unknown constraint: " +
  1242. place);
  1243. }
  1244. /**
  1245. * Returns the minimum size needed to contain the children.
  1246. * The width is the sum of all the childrens min widths and
  1247. * the height is the largest of the childrens minimum heights.
  1248. */
  1249. public Dimension minimumLayoutSize(Container container) {
  1250. Dimension minSize;
  1251. int minX = 0;
  1252. int minY = 0;
  1253. Insets insets = splitPane.getInsets();
  1254. for (int counter=0; counter<3; counter++) {
  1255. if(components[counter] != null) {
  1256. minSize = components[counter].getMinimumSize();
  1257. minX += minSize.width;
  1258. if(minSize.height > minY)
  1259. minY = minSize.height;
  1260. }
  1261. }
  1262. if(insets != null) {
  1263. minX += insets.left + insets.right;
  1264. minY += insets.bottom + insets.top;
  1265. }
  1266. if (components[0] != null && components[1] != null) {
  1267. minX += (2 * getDividerBorderSize());
  1268. }
  1269. return new Dimension(minX, minY);
  1270. }
  1271. /**
  1272. * Returns the preferred size needed to contain the children.
  1273. * The width is the sum of all the childrens preferred widths and
  1274. * the height is the largest of the childrens preferred heights.
  1275. */
  1276. public Dimension preferredLayoutSize(Container container) {
  1277. Dimension preSize;
  1278. int preX = 0;
  1279. int preY = 0;
  1280. Insets insets = splitPane.getInsets();
  1281. for(int counter = 0; counter < 3; counter++) {
  1282. if(components[counter] != null) {
  1283. preSize = components[counter].getPreferredSize();
  1284. preX += preSize.width;
  1285. if(preSize.height > preY)
  1286. preY = preSize.height;
  1287. }
  1288. }
  1289. if(insets != null) {
  1290. preX += insets.left + insets.right;
  1291. preY += insets.bottom + insets.top;
  1292. }
  1293. if (components[0] != null && components[1] != null) {
  1294. preX += (2 * getDividerBorderSize());
  1295. }
  1296. return new Dimension(preX, preY);
  1297. }
  1298. /**
  1299. * Removes the specified component from our knowledge.
  1300. */
  1301. public void removeLayoutComponent(Component component) {
  1302. for(int counter = 0; counter < 3; counter++) {
  1303. if(components[counter] == component) {
  1304. components[counter] = null;
  1305. sizes[counter] = 0;
  1306. }
  1307. }
  1308. }
  1309. //
  1310. // LayoutManager2
  1311. //
  1312. /**
  1313. * Adds the specified component to the layout, using the specified
  1314. * constraint object.
  1315. * @param comp the component to be added
  1316. * @param constraints where/how the component is added to the layout.
  1317. */
  1318. public void addLayoutComponent(Component comp, Object constraints) {
  1319. if ((constraints == null) || (constraints instanceof String)) {
  1320. addLayoutComponent((String)constraints, comp);
  1321. } else {
  1322. throw new IllegalArgumentException("cannot add to layout: " +
  1323. "constraint must be a " +
  1324. "string (or null)");
  1325. }
  1326. }
  1327. /**
  1328. * Returns the alignment along the x axis. This specifies how
  1329. * the component would like to be aligned relative to other
  1330. * components. The value should be a number between 0 and 1
  1331. * where 0 represents alignment along the origin, 1 is aligned
  1332. * the furthest away from the origin, 0.5 is centered, etc.
  1333. */
  1334. public float getLayoutAlignmentX(Container target) {
  1335. return 0.0f;
  1336. }
  1337. /**
  1338. * Returns the alignment along the y axis. This specifies how
  1339. * the component would like to be aligned relative to other
  1340. * components. The value should be a number between 0 and 1
  1341. * where 0 represents alignment along the origin, 1 is aligned
  1342. * the furthest away from the origin, 0.5 is centered, etc.
  1343. */
  1344. public float getLayoutAlignmentY(Container target) {
  1345. return 0.0f;
  1346. }
  1347. /**
  1348. * Does nothing. If the developer really wants to change the
  1349. * size of one of the views JSplitPane.resetToPreferredSizes should
  1350. * be messaged.
  1351. */
  1352. public void invalidateLayout(Container c) {
  1353. }
  1354. /**
  1355. * Returns the maximum layout size, which is Integer.MAX_VALUE
  1356. * in both directions.
  1357. */
  1358. public Dimension maximumLayoutSize(Container target) {
  1359. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  1360. }
  1361. /**
  1362. * Resets the cached sizes so that next time this instance is
  1363. * layed out it'll ask for the preferred sizes.
  1364. */
  1365. public void resetToPreferredSizes() {
  1366. for(int counter = 0; counter < 3; counter++)
  1367. sizes[counter] = -1;
  1368. }
  1369. /**
  1370. * Determines the components. This should be called whenever
  1371. * a new instance of this is installed into an existing
  1372. * SplitPane.
  1373. */
  1374. protected void updateComponents() {
  1375. Component comp;
  1376. comp = splitPane.getLeftComponent();
  1377. if(components[0] != comp) {
  1378. components[0] = comp;
  1379. if(comp == null) {
  1380. sizes[0] = 0;
  1381. } else {
  1382. sizes[0] = -1;
  1383. }
  1384. }
  1385. comp = splitPane.getRightComponent();
  1386. if(components[1] != comp) {
  1387. components[1] = comp;
  1388. if(comp == null) {
  1389. sizes[1] = 0;
  1390. } else {
  1391. sizes[1] = -1;
  1392. }
  1393. }
  1394. /* Find the divider. */
  1395. Component[] children = splitPane.getComponents();
  1396. Component oldDivider = components[2];
  1397. components[2] = null;
  1398. for(int counter = children.length - 1; counter >= 0; counter--) {
  1399. if(children[counter] != components[0] &&
  1400. children[counter] != components[1] &&
  1401. children[counter] != nonContinuousLayoutDivider) {
  1402. if(oldDivider != children[counter]) {
  1403. components[2] = children[counter];
  1404. if(children[counter] == null) {
  1405. sizes[2] = 0;
  1406. } else {
  1407. sizes[2] = -1;
  1408. }
  1409. } else {
  1410. components[2] = oldDivider;
  1411. }
  1412. break;
  1413. }
  1414. }
  1415. if(components[2] == null) sizes[2] = 0;
  1416. }
  1417. }
  1418. /**
  1419. * LayoutManager used for JSplitPanes with an orientation of
  1420. * VERTICAL_SPLIT.
  1421. * <p>
  1422. * This inner class is marked "public" due to a compiler bug.
  1423. * This class should be treated as a "protected" inner class.
  1424. * Instantiate it only within subclasses of BasicSplitPaneUI.
  1425. */
  1426. public class BasicVerticalLayoutManager extends
  1427. BasicHorizontalLayoutManager
  1428. {
  1429. /**
  1430. * Returns the height of the passed in Components preferred size.
  1431. */
  1432. protected int getPreferredSizeOfComponent(Component c) {
  1433. return c.getPreferredSize().height;
  1434. }
  1435. /**
  1436. * Returns the height of the passed in Components minimum size.
  1437. */
  1438. int getMinimumSizeOfComponent(Component c) {
  1439. return c.getMinimumSize().height;
  1440. }
  1441. /**
  1442. * Returns the height of the passed in component.
  1443. */
  1444. protected int getSizeOfComponent(Component c) {
  1445. return c.getSize().height;
  1446. }
  1447. /**
  1448. * Returns the available height based on the container size and
  1449. * Insets.
  1450. */
  1451. protected int getAvailableSize(Dimension containerSize,
  1452. Insets insets) {
  1453. if(insets == null)
  1454. return containerSize.height;
  1455. return (containerSize.height - (insets.bottom + insets.top + 2 *
  1456. getDividerBorderSize()));
  1457. }
  1458. /**
  1459. * Returns the top inset, unless the Insets or null in which case
  1460. * 0 is returned.
  1461. */
  1462. protected int getInitialLocation(Insets insets) {
  1463. if(insets != null)
  1464. return insets.top;
  1465. return 0;
  1466. }
  1467. /**
  1468. * Sets the height of the component c to be size, placing its
  1469. * x location to insets.left, y to location and width
  1470. * to the containersize.width less the left and right insets.
  1471. */
  1472. protected void setComponentToSize(Component c, int size,
  1473. int location, Insets insets,
  1474. Dimension containerSize) {
  1475. if(insets != null) {
  1476. c.setBounds(insets.left, location, containerSize.width -
  1477. (insets.left + insets.right), size);
  1478. } else {
  1479. c.setBounds(0, location, containerSize.width, size);
  1480. }
  1481. }
  1482. /**
  1483. * Returns the minimum size needed to contain the children.
  1484. * The height is the sum of all the childrens min heights and
  1485. * the width is the largest of the childrens minimum widths.
  1486. */
  1487. public Dimension minimumLayoutSize(Container container) {
  1488. Dimension minSize;
  1489. int minX = 0;
  1490. int minY = 0;
  1491. Insets insets = splitPane.getInsets();
  1492. for(int counter = 0; counter < 3; counter++) {
  1493. if(components[counter] != null) {
  1494. minSize = components[counter].getMinimumSize();
  1495. minY += minSize.height;
  1496. if(minSize.width > minX)
  1497. minX = minSize.width;
  1498. }
  1499. }
  1500. if(insets != null) {
  1501. minX += insets.left + insets.right;
  1502. minY += insets.bottom + insets.top;
  1503. }
  1504. if (components[0] != null && components[1] != null) {
  1505. minY += (2 * getDividerBorderSize());
  1506. }
  1507. return new Dimension(minX, minY);
  1508. }
  1509. /**
  1510. * Returns the preferred size needed to contain the children.
  1511. * The height is the sum of all the childrens preferred heights and
  1512. * the width is the largest of the childrens preferred widths.
  1513. */
  1514. public Dimension preferredLayoutSize(Container container) {
  1515. Dimension preSize;
  1516. int preX = 0;
  1517. int preY = 0;
  1518. Insets insets = splitPane.getInsets();
  1519. for(int counter = 0; counter < 3; counter++) {
  1520. if(components[counter] != null) {
  1521. preSize = components[counter].getPreferredSize();
  1522. preY += preSize.height;
  1523. if(preSize.width > preX)
  1524. preX = preSize.width;
  1525. }
  1526. }
  1527. if(insets != null) {
  1528. preX += insets.left + insets.right;
  1529. preY += insets.bottom + insets.top;
  1530. }
  1531. if (components[0] != null && components[1] != null) {
  1532. preY += (2 * getDividerBorderSize());
  1533. }
  1534. return new Dimension(preX, preY);
  1535. }
  1536. }
  1537. }