1. /*
  2. * @(#)BasicSplitPaneDivider.java 1.38 00/02/02
  3. *
  4. * Copyright 1997-2000 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.plaf.basic;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import javax.swing.*;
  14. import javax.swing.event.*;
  15. import javax.swing.plaf.*;
  16. import javax.swing.border.Border;
  17. import java.beans.*;
  18. import java.io.*;
  19. /**
  20. * Divider used by BasicSplitPaneUI. Subclassers may wish to override
  21. * paint to do something more interesting.
  22. * The border effect is drawn in BasicSplitPaneUI, so if you don't like
  23. * that border, reset it there.
  24. * To conditionally drag from certain areas subclass mousePressed and
  25. * call super when you wish the dragging to begin.
  26. * <p>
  27. * <strong>Warning:</strong>
  28. * Serialized objects of this class will not be compatible with
  29. * future Swing releases. The current serialization support is appropriate
  30. * for short term storage or RMI between applications running the same
  31. * version of Swing. A future release of Swing will provide support for
  32. * long term persistence.
  33. *
  34. * @version 1.38 02/02/00
  35. * @author Scott Violet
  36. */
  37. public class BasicSplitPaneDivider extends Container
  38. implements PropertyChangeListener
  39. {
  40. /**
  41. * Width or height of the divider based on orientation
  42. * BasicSplitPaneUI adds two to this.
  43. */
  44. protected static final int ONE_TOUCH_SIZE = 6;
  45. protected static final int ONE_TOUCH_OFFSET = 2;
  46. /**
  47. * Handles mouse dragging message to do the actual dragging.
  48. */
  49. protected DragController dragger;
  50. /**
  51. * UI this instance was created from.
  52. */
  53. protected BasicSplitPaneUI splitPaneUI;
  54. /**
  55. * Size of the divider.
  56. */
  57. protected int dividerSize = 0; // default - SET TO 0???
  58. /**
  59. * Divider that is used for noncontinuous layout mode.
  60. */
  61. protected Component hiddenDivider;
  62. /**
  63. * JSplitPane the receiver is contained in.
  64. */
  65. protected JSplitPane splitPane;
  66. /**
  67. * Handles mouse events from both this class, and the split pane.
  68. * Mouse events are handled for the splitpane since you want to be able
  69. * to drag when clicking on the border of the divider, which is not
  70. * drawn by the divider.
  71. */
  72. protected MouseHandler mouseHandler;
  73. /**
  74. * Orientation of the JSplitPane.
  75. */
  76. protected int orientation;
  77. /**
  78. * Button for quickly toggling the left component.
  79. */
  80. protected JButton leftButton;
  81. /**
  82. * Button for quickly toggling the right component.
  83. */
  84. protected JButton rightButton;
  85. /**
  86. * Cursor used for HORIZONTAL_SPLIT splitpanes.
  87. */
  88. static final Cursor horizontalCursor =
  89. Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
  90. /**
  91. * Cursor used for VERTICAL_SPLIT splitpanes.
  92. */
  93. static final Cursor verticalCursor =
  94. Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
  95. /**
  96. * Default cursor.
  97. */
  98. static final Cursor defaultCursor =
  99. Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  100. /** Border. */
  101. private Border border;
  102. /**
  103. * Creates an instance of BasicSplitPaneDivider. Registers this
  104. * instance for mouse events and mouse dragged events.
  105. */
  106. public BasicSplitPaneDivider(BasicSplitPaneUI ui) {
  107. setLayout(new DividerLayout());
  108. setBasicSplitPaneUI(ui);
  109. orientation = splitPane.getOrientation();
  110. setBackground(UIManager.getColor("SplitPane.background"));
  111. }
  112. /**
  113. * Sets the SplitPaneUI that is using the receiver.
  114. */
  115. public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) {
  116. if (splitPane != null) {
  117. splitPane.removePropertyChangeListener(this);
  118. if (mouseHandler != null) {
  119. splitPane.removeMouseListener(mouseHandler);
  120. splitPane.removeMouseMotionListener(mouseHandler);
  121. removeMouseListener(mouseHandler);
  122. removeMouseMotionListener(mouseHandler);
  123. mouseHandler = null;
  124. }
  125. }
  126. splitPaneUI = newUI;
  127. if (newUI != null) {
  128. splitPane = newUI.getSplitPane();
  129. if (splitPane != null) {
  130. if (mouseHandler == null) mouseHandler = new MouseHandler();
  131. splitPane.addMouseListener(mouseHandler);
  132. splitPane.addMouseMotionListener(mouseHandler);
  133. addMouseListener(mouseHandler);
  134. addMouseMotionListener(mouseHandler);
  135. splitPane.addPropertyChangeListener(this);
  136. if (splitPane.isOneTouchExpandable()) {
  137. oneTouchExpandableChanged();
  138. }
  139. }
  140. }
  141. else {
  142. splitPane = null;
  143. }
  144. }
  145. /**
  146. * Returns the <code>SplitPaneUI</code> the receiver is currently
  147. * in.
  148. */
  149. public BasicSplitPaneUI getBasicSplitPaneUI() {
  150. return splitPaneUI;
  151. }
  152. /**
  153. * Sets the size of the divider to <code>newSize</code>. That is
  154. * the width if the splitpane is <code>HORIZONTAL_SPLIT</code>, or
  155. * the height of <code>VERTICAL_SPLIT</code>.
  156. */
  157. public void setDividerSize(int newSize) {
  158. dividerSize = newSize;
  159. }
  160. /**
  161. * Returns the size of the divider, that is the width if the splitpane
  162. * is HORIZONTAL_SPLIT, or the height of VERTICAL_SPLIT.
  163. */
  164. public int getDividerSize() {
  165. return dividerSize;
  166. }
  167. /**
  168. * Sets the border of this component.
  169. * @since 1.3
  170. */
  171. public void setBorder(Border border) {
  172. Border oldBorder = this.border;
  173. this.border = border;
  174. }
  175. /**
  176. * Returns the border of this component or null if no border is
  177. * currently set.
  178. *
  179. * @return the border object for this component
  180. * @see #setBorder
  181. * @since 1.3
  182. */
  183. public Border getBorder() {
  184. return border;
  185. }
  186. /**
  187. * If a border has been set on this component, returns the
  188. * border's insets, else calls super.getInsets.
  189. *
  190. * @return the value of the insets property.
  191. * @see #setBorder
  192. */
  193. public Insets getInsets() {
  194. Border border = getBorder();
  195. if (border != null) {
  196. return border.getBorderInsets(this);
  197. }
  198. return super.getInsets();
  199. }
  200. /**
  201. * Returns dividerSize x dividerSize
  202. */
  203. public Dimension getPreferredSize() {
  204. return new Dimension(getDividerSize(), getDividerSize());
  205. }
  206. /**
  207. * Returns dividerSize x dividerSize
  208. */
  209. public Dimension getMinimumSize() {
  210. return getPreferredSize();
  211. }
  212. /**
  213. * Property change event, presumably from the JSplitPane, will message
  214. * updateOrientation if necessary.
  215. */
  216. public void propertyChange(PropertyChangeEvent e) {
  217. if (e.getSource() == splitPane) {
  218. if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) {
  219. orientation = splitPane.getOrientation();
  220. invalidate();
  221. validate();
  222. }
  223. else if (e.getPropertyName().equals(JSplitPane.
  224. ONE_TOUCH_EXPANDABLE_PROPERTY)) {
  225. oneTouchExpandableChanged();
  226. }
  227. }
  228. }
  229. /**
  230. * Paints the divider.
  231. */
  232. public void paint(Graphics g) {
  233. super.paint(g);
  234. // Paint the border.
  235. Border border = getBorder();
  236. if (border != null) {
  237. Dimension size = getSize();
  238. border.paintBorder(this, g, 0, 0, size.width, size.height);
  239. }
  240. }
  241. /**
  242. * Messaged when the oneTouchExpandable value of the JSplitPane the
  243. * receiver is contained in changes. Will create the
  244. * <code>leftButton</code> and <code>rightButton</code> if they
  245. * are null. invalidates the receiver as well.
  246. */
  247. protected void oneTouchExpandableChanged() {
  248. if (splitPane.isOneTouchExpandable() &&
  249. leftButton == null &&
  250. rightButton == null) {
  251. /* Create the left button and add an action listener to
  252. expand/collapse it. */
  253. leftButton = createLeftOneTouchButton();
  254. if (leftButton != null)
  255. leftButton.addActionListener(new OneTouchActionHandler(true));
  256. /* Create the right button and add an action listener to
  257. expand/collapse it. */
  258. rightButton = createRightOneTouchButton();
  259. if (rightButton != null)
  260. rightButton.addActionListener(new OneTouchActionHandler
  261. (false));
  262. if (leftButton != null && rightButton != null) {
  263. add(leftButton);
  264. add(rightButton);
  265. }
  266. }
  267. invalidate();
  268. validate();
  269. }
  270. /**
  271. * Creates and return an instance of JButton that can be used to
  272. * collapse the left component in the split pane.
  273. */
  274. protected JButton createLeftOneTouchButton() {
  275. JButton b = new JButton() {
  276. public void setBorder(Border b) {
  277. }
  278. public void paint(Graphics g) {
  279. if (splitPane != null) {
  280. int[] xs = new int[3];
  281. int[] ys = new int[3];
  282. int blockSize = Math.min(getDividerSize(),
  283. ONE_TOUCH_SIZE);
  284. // Fill the background first ...
  285. g.setColor(this.getBackground());
  286. g.fillRect(0, 0, this.getWidth(),
  287. this.getHeight());
  288. // ... then draw the arrow.
  289. g.setColor(Color.black);
  290. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  291. xs[0] = blockSize;
  292. xs[1] = 0;
  293. xs[2] = blockSize << 1;
  294. ys[0] = 0;
  295. ys[1] = ys[2] = blockSize;
  296. g.drawPolygon(xs, ys, 3); // Little trick to make the
  297. // arrows of equal size
  298. }
  299. else {
  300. xs[0] = xs[2] = blockSize;
  301. xs[1] = 0;
  302. ys[0] = 0;
  303. ys[1] = blockSize;
  304. ys[2] = blockSize << 1;
  305. }
  306. g.fillPolygon(xs, ys, 3);
  307. }
  308. }
  309. // Don't want the button to participate in focus traversable.
  310. public boolean isFocusTraversable() {
  311. return false;
  312. }
  313. };
  314. b.setCursor(defaultCursor);
  315. b.setFocusPainted(false);
  316. b.setBorderPainted(false);
  317. return b;
  318. }
  319. /**
  320. * Creates and return an instance of JButton that can be used to
  321. * collapse the right component in the split pane.
  322. */
  323. protected JButton createRightOneTouchButton() {
  324. JButton b = new JButton() {
  325. public void setBorder(Border border) {
  326. }
  327. public void paint(Graphics g) {
  328. if (splitPane != null) {
  329. int[] xs = new int[3];
  330. int[] ys = new int[3];
  331. int blockSize = Math.min(getDividerSize(),
  332. ONE_TOUCH_SIZE);
  333. // Fill the background first ...
  334. g.setColor(this.getBackground());
  335. g.fillRect(0, 0, this.getWidth(),
  336. this.getHeight());
  337. // ... then draw the arrow.
  338. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  339. xs[0] = blockSize;
  340. xs[1] = blockSize << 1;
  341. xs[2] = 0;
  342. ys[0] = blockSize;
  343. ys[1] = ys[2] = 0;
  344. }
  345. else {
  346. xs[0] = xs[2] = 0;
  347. xs[1] = blockSize;
  348. ys[0] = 0;
  349. ys[1] = blockSize;
  350. ys[2] = blockSize << 1;
  351. }
  352. g.setColor(Color.black);
  353. g.fillPolygon(xs, ys, 3);
  354. }
  355. }
  356. // Don't want the button to participate in focus traversable.
  357. public boolean isFocusTraversable() {
  358. return false;
  359. }
  360. };
  361. b.setCursor(defaultCursor);
  362. b.setFocusPainted(false);
  363. b.setBorderPainted(false);
  364. return b;
  365. }
  366. /**
  367. * Message to prepare for dragging. This messages the BasicSplitPaneUI
  368. * with startDragging.
  369. */
  370. protected void prepareForDragging() {
  371. splitPaneUI.startDragging();
  372. }
  373. /**
  374. * Messages the BasicSplitPaneUI with dragDividerTo that this instance
  375. * is contained in.
  376. */
  377. protected void dragDividerTo(int location) {
  378. splitPaneUI.dragDividerTo(location);
  379. }
  380. /**
  381. * Messages the BasicSplitPaneUI with finishDraggingTo that this instance
  382. * is contained in.
  383. */
  384. protected void finishDraggingTo(int location) {
  385. splitPaneUI.finishDraggingTo(location);
  386. }
  387. /**
  388. * MouseHandler is responsible for converting mouse events
  389. * (released, dragged...) into the appropriate DragController
  390. * methods.
  391. * <p>
  392. */
  393. protected class MouseHandler extends MouseAdapter
  394. implements MouseMotionListener
  395. {
  396. /**
  397. * Starts the dragging session by creating the appropriate instance
  398. * of DragController.
  399. */
  400. public void mousePressed(MouseEvent e) {
  401. if ((e.getSource() == BasicSplitPaneDivider.this ||
  402. e.getSource() == splitPane) &&
  403. dragger == null &&splitPane.isEnabled()) {
  404. Component newHiddenDivider = splitPaneUI.
  405. getNonContinuousLayoutDivider();
  406. if (hiddenDivider != newHiddenDivider) {
  407. if (hiddenDivider != null) {
  408. hiddenDivider.removeMouseListener(this);
  409. hiddenDivider.removeMouseMotionListener(this);
  410. }
  411. hiddenDivider = newHiddenDivider;
  412. if (hiddenDivider != null) {
  413. hiddenDivider.addMouseMotionListener(this);
  414. hiddenDivider.addMouseListener(this);
  415. }
  416. }
  417. if (splitPane.getLeftComponent() != null &&
  418. splitPane.getRightComponent() != null) {
  419. if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
  420. dragger = new DragController(e);
  421. }
  422. else {
  423. dragger = new VerticalDragController(e);
  424. }
  425. if (!dragger.isValid()) {
  426. dragger = null;
  427. }
  428. else {
  429. prepareForDragging();
  430. dragger.continueDrag(e);
  431. }
  432. }
  433. e.consume();
  434. }
  435. }
  436. /**
  437. * If dragger is not null it is messaged with completeDrag.
  438. */
  439. public void mouseReleased(MouseEvent e) {
  440. if (dragger != null) {
  441. if (e.getSource() == splitPane) {
  442. dragger.completeDrag(e.getX(), e.getY());
  443. }
  444. else if (e.getSource() == BasicSplitPaneDivider.this) {
  445. Point ourLoc = getLocation();
  446. dragger.completeDrag(e.getX() + ourLoc.x,
  447. e.getY() + ourLoc.y);
  448. }
  449. else if (e.getSource() == hiddenDivider) {
  450. Point hDividerLoc = hiddenDivider.getLocation();
  451. int ourX = e.getX() + hDividerLoc.x;
  452. int ourY = e.getY() + hDividerLoc.y;
  453. dragger.completeDrag(ourX, ourY);
  454. }
  455. dragger = null;
  456. e.consume();
  457. }
  458. }
  459. //
  460. // MouseMotionListener
  461. //
  462. /**
  463. * If dragger is not null it is messaged with continueDrag.
  464. */
  465. public void mouseDragged(MouseEvent e) {
  466. if (dragger != null) {
  467. if (e.getSource() == splitPane) {
  468. dragger.continueDrag(e.getX(), e.getY());
  469. }
  470. else if (e.getSource() == BasicSplitPaneDivider.this) {
  471. Point ourLoc = getLocation();
  472. dragger.continueDrag(e.getX() + ourLoc.x,
  473. e.getY() + ourLoc.y);
  474. }
  475. else if (e.getSource() == hiddenDivider) {
  476. Point hDividerLoc = hiddenDivider.getLocation();
  477. int ourX = e.getX() + hDividerLoc.x;
  478. int ourY = e.getY() + hDividerLoc.y;
  479. dragger.continueDrag(ourX, ourY);
  480. }
  481. e.consume();
  482. }
  483. }
  484. /**
  485. * Resets the cursor based on the orientation.
  486. */
  487. public void mouseMoved(MouseEvent e) {
  488. if (dragger != null) return;
  489. int eventX = e.getX();
  490. int eventY = e.getY();
  491. Rectangle bounds = getBounds();
  492. Cursor newCursor;
  493. if (e.getSource() == BasicSplitPaneDivider.this) {
  494. if (eventX >= 0 && eventX < bounds.width &&
  495. eventY >= 0 && eventY < bounds.height) {
  496. newCursor = (orientation == JSplitPane.HORIZONTAL_SPLIT) ?
  497. horizontalCursor : verticalCursor;
  498. }
  499. else {
  500. newCursor = defaultCursor;
  501. }
  502. }
  503. else {
  504. if (eventX >= bounds.x &&
  505. eventX < (bounds.x + bounds.width) &&
  506. eventY >= bounds.y &&
  507. eventY < (bounds.y + bounds.height)) {
  508. newCursor = (orientation == JSplitPane.HORIZONTAL_SPLIT) ?
  509. horizontalCursor : verticalCursor;
  510. }
  511. else {
  512. newCursor = defaultCursor;
  513. }
  514. }
  515. if (getCursor() != newCursor) {
  516. setCursor(newCursor);
  517. }
  518. }
  519. }
  520. /**
  521. * Handles the events during a dragging session for a
  522. * HORIZONTAL_SPLIT orientated split pane. This continually
  523. * messages dragDividerTo and then when done messages
  524. * finishDraggingTo. When an instance is created it should be
  525. * messaged with isValid() to insure that dragging can happen
  526. * (dragging won't be allowed if the two views can not be resized).
  527. * <p>
  528. * <strong>Warning:</strong>
  529. * Serialized objects of this class will not be compatible with
  530. * future Swing releases. The current serialization support is appropriate
  531. * for short term storage or RMI between applications running the same
  532. * version of Swing. A future release of Swing will provide support for
  533. * long term persistence.
  534. */
  535. protected class DragController
  536. {
  537. /**
  538. * Initial location of the divider.
  539. */
  540. int initialX;
  541. /**
  542. * Maximum and minimum positions to drag to.
  543. */
  544. int maxX, minX;
  545. /**
  546. * Initial location the mouse down happened at.
  547. */
  548. int offset;
  549. protected DragController(MouseEvent e) {
  550. JSplitPane splitPane = splitPaneUI.getSplitPane();
  551. Component leftC = splitPane.getLeftComponent();
  552. Component rightC = splitPane.getRightComponent();
  553. initialX = getLocation().x;
  554. if (e.getSource() == BasicSplitPaneDivider.this) {
  555. offset = e.getX();
  556. }
  557. else { // splitPane
  558. offset = e.getX() - initialX;
  559. }
  560. if (leftC == null || rightC == null || offset < -1 ||
  561. offset > getSize().width) {
  562. // Don't allow dragging.
  563. maxX = -1;
  564. }
  565. else {
  566. Insets insets = splitPane.getInsets();
  567. if (leftC.isVisible()) {
  568. minX = leftC.getMinimumSize().width;
  569. if (insets != null) {
  570. minX += insets.left;
  571. }
  572. }
  573. else {
  574. minX = 0;
  575. }
  576. if (rightC.isVisible()) {
  577. int right = (insets != null) ? insets.right : 0;
  578. maxX = Math.max(0, splitPane.getSize().width -
  579. (getSize().width + right) -
  580. rightC.getMinimumSize().width);
  581. }
  582. else {
  583. int right = (insets != null) ? insets.right : 0;
  584. maxX = Math.max(0, splitPane.getSize().width -
  585. (getSize().width + right));
  586. }
  587. if (maxX < minX) minX = maxX = 0;
  588. }
  589. }
  590. /**
  591. * Returns true if the dragging session is valid.
  592. */
  593. protected boolean isValid() {
  594. return (maxX > 0);
  595. }
  596. /**
  597. * Returns the new position to put the divider at based on
  598. * the passed in MouseEvent.
  599. */
  600. protected int positionForMouseEvent(MouseEvent e) {
  601. int newX = (e.getSource() == BasicSplitPaneDivider.this) ?
  602. (e.getX() + getLocation().x) : e.getX();
  603. newX = Math.min(maxX, Math.max(minX, newX - offset));
  604. return newX;
  605. }
  606. /**
  607. * Returns the x argument, since this is used for horizontal
  608. * splits.
  609. */
  610. protected int getNeededLocation(int x, int y) {
  611. int newX;
  612. newX = Math.min(maxX, Math.max(minX, x - offset));
  613. return newX;
  614. }
  615. protected void continueDrag(int newX, int newY) {
  616. dragDividerTo(getNeededLocation(newX, newY));
  617. }
  618. /**
  619. * Messages dragDividerTo with the new location for the mouse
  620. * event.
  621. */
  622. protected void continueDrag(MouseEvent e) {
  623. dragDividerTo(positionForMouseEvent(e));
  624. }
  625. protected void completeDrag(int x, int y) {
  626. finishDraggingTo(getNeededLocation(x, y));
  627. }
  628. /**
  629. * Messages finishDraggingTo with the new location for the mouse
  630. * event.
  631. */
  632. protected void completeDrag(MouseEvent e) {
  633. finishDraggingTo(positionForMouseEvent(e));
  634. }
  635. } // End of BasicSplitPaneDivider.DragController
  636. /**
  637. * Handles the events during a dragging session for a
  638. * VERTICAL_SPLIT orientated split pane. This continually
  639. * messages dragDividerTo and then when done messages
  640. * finishDraggingTo. When an instance is created it should be
  641. * messaged with isValid() to insure that dragging can happen
  642. * (dragging won't be allowed if the two views can not be resized).
  643. */
  644. protected class VerticalDragController extends DragController
  645. {
  646. /* DragControllers ivars are now in terms of y, not x. */
  647. protected VerticalDragController(MouseEvent e) {
  648. super(e);
  649. JSplitPane splitPane = splitPaneUI.getSplitPane();
  650. Component leftC = splitPane.getLeftComponent();
  651. Component rightC = splitPane.getRightComponent();
  652. initialX = getLocation().y;
  653. if (e.getSource() == BasicSplitPaneDivider.this) {
  654. offset = e.getY();
  655. }
  656. else {
  657. offset = e.getY() - initialX;
  658. }
  659. if (leftC == null || rightC == null || offset < -1 ||
  660. offset > getSize().height) {
  661. // Don't allow dragging.
  662. maxX = -1;
  663. }
  664. else {
  665. Insets insets = splitPane.getInsets();
  666. if (leftC.isVisible()) {
  667. minX = leftC.getMinimumSize().height;
  668. if (insets != null) {
  669. minX += insets.top;
  670. }
  671. }
  672. else {
  673. minX = 0;
  674. }
  675. if (rightC.isVisible()) {
  676. int bottom = (insets != null) ? insets.bottom : 0;
  677. maxX = Math.max(0, splitPane.getSize().height -
  678. (getSize().height + bottom) -
  679. rightC.getMinimumSize().height);
  680. }
  681. else {
  682. int bottom = (insets != null) ? insets.bottom : 0;
  683. maxX = Math.max(0, splitPane.getSize().height -
  684. (getSize().height + bottom));
  685. }
  686. if (maxX < minX) minX = maxX = 0;
  687. }
  688. }
  689. /**
  690. * Returns the y argument, since this is used for vertical
  691. * splits.
  692. */
  693. protected int getNeededLocation(int x, int y) {
  694. int newY;
  695. newY = Math.min(maxX, Math.max(minX, y - offset));
  696. return newY;
  697. }
  698. /**
  699. * Returns the new position to put the divider at based on
  700. * the passed in MouseEvent.
  701. */
  702. protected int positionForMouseEvent(MouseEvent e) {
  703. int newY = (e.getSource() == BasicSplitPaneDivider.this) ?
  704. (e.getY() + getLocation().y) : e.getY();
  705. newY = Math.min(maxX, Math.max(minX, newY - offset));
  706. return newY;
  707. }
  708. } // End of BasicSplitPaneDividier.VerticalDragController
  709. /**
  710. * Used to layout a BasicSplitPaneDivider. Layout for the divider
  711. * involves appropraitely moving the left/right buttons around.
  712. * <p>
  713. */
  714. protected class DividerLayout implements LayoutManager
  715. {
  716. public void layoutContainer(Container c) {
  717. if (leftButton != null && rightButton != null &&
  718. c == BasicSplitPaneDivider.this) {
  719. if (splitPane.isOneTouchExpandable()) {
  720. Insets insets = getInsets();
  721. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  722. int extraX = (insets != null) ? insets.left : 0;
  723. int blockSize = getDividerSize();
  724. if (insets != null) {
  725. blockSize -= (insets.top + insets.bottom);
  726. }
  727. blockSize = Math.min(blockSize, ONE_TOUCH_SIZE);
  728. int y = (c.getSize().height - blockSize) / 2;
  729. leftButton.setBounds(extraX + ONE_TOUCH_OFFSET, y,
  730. blockSize * 2, blockSize);
  731. rightButton.setBounds(extraX + ONE_TOUCH_OFFSET +
  732. ONE_TOUCH_SIZE * 2, y,
  733. blockSize * 2, blockSize);
  734. }
  735. else {
  736. int extraY = (insets != null) ? insets.top : 0;
  737. int blockSize = getDividerSize();
  738. if (insets != null) {
  739. blockSize -= (insets.left + insets.right);
  740. }
  741. blockSize = Math.min(blockSize, ONE_TOUCH_SIZE);
  742. int x = (c.getSize().width - blockSize) / 2;
  743. leftButton.setBounds(x, extraY + ONE_TOUCH_OFFSET,
  744. blockSize, blockSize * 2);
  745. rightButton.setBounds(x, extraY + ONE_TOUCH_OFFSET +
  746. ONE_TOUCH_SIZE * 2, blockSize,
  747. blockSize * 2);
  748. }
  749. }
  750. else {
  751. leftButton.setBounds(-5, -5, 1, 1);
  752. rightButton.setBounds(-5, -5, 1, 1);
  753. }
  754. }
  755. }
  756. public Dimension minimumLayoutSize(Container c) {
  757. return new Dimension(0,0);
  758. }
  759. public Dimension preferredLayoutSize(Container c) {
  760. return new Dimension(0, 0);
  761. }
  762. public void removeLayoutComponent(Component c) {}
  763. public void addLayoutComponent(String string, Component c) {}
  764. } // End of class BasicSplitPaneDivider.DividerLayout
  765. /**
  766. * Listeners installed on the one touch expandable buttons.
  767. */
  768. private class OneTouchActionHandler implements ActionListener {
  769. /** True indicates the resize should go the minimum (top or left)
  770. * vs false which indicates the resize should go to the maximum.
  771. */
  772. private boolean toMinimum;
  773. OneTouchActionHandler(boolean toMinimum) {
  774. this.toMinimum = toMinimum;
  775. }
  776. public void actionPerformed(ActionEvent e) {
  777. Insets insets = splitPane.getInsets();
  778. int lastLoc = splitPane.getLastDividerLocation();
  779. int currentLoc = splitPaneUI.getDividerLocation(splitPane);
  780. int newLoc;
  781. // We use the location from the UI directly, as the location the
  782. // JSplitPane itself maintains is not necessarly correct.
  783. if (toMinimum) {
  784. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  785. if (currentLoc >= (splitPane.getHeight() -
  786. insets.bottom - getDividerSize()))
  787. newLoc = lastLoc;
  788. else
  789. newLoc = insets.top;
  790. }
  791. else {
  792. if (currentLoc >= (splitPane.getWidth() -
  793. insets.right - getDividerSize()))
  794. newLoc = lastLoc;
  795. else
  796. newLoc = insets.left;
  797. }
  798. }
  799. else {
  800. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  801. if (currentLoc == insets.top)
  802. newLoc = lastLoc;
  803. else
  804. newLoc = splitPane.getHeight() - getHeight() -
  805. insets.top;
  806. }
  807. else {
  808. if (currentLoc == insets.left)
  809. newLoc = lastLoc;
  810. else
  811. newLoc = splitPane.getWidth() - getWidth() -
  812. insets.left;
  813. }
  814. }
  815. if (currentLoc != newLoc) {
  816. splitPane.setDividerLocation(newLoc);
  817. // We do this in case the dividers notion of the location
  818. // differs from the real location.
  819. splitPane.setLastDividerLocation(currentLoc);
  820. }
  821. }
  822. } // End of class BasicSplitPaneDivider.LeftActionListener
  823. }