Frames | No Frames |
1: /* BasicSplitPaneDivider.java -- 2: Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.plaf.basic; 40: 41: import java.awt.Color; 42: import java.awt.Component; 43: import java.awt.Container; 44: import java.awt.Dimension; 45: import java.awt.Graphics; 46: import java.awt.Insets; 47: import java.awt.LayoutManager; 48: import java.awt.event.ActionEvent; 49: import java.awt.event.ActionListener; 50: import java.awt.event.MouseAdapter; 51: import java.awt.event.MouseEvent; 52: import java.awt.event.MouseMotionListener; 53: import java.beans.PropertyChangeEvent; 54: import java.beans.PropertyChangeListener; 55: 56: import javax.swing.JButton; 57: import javax.swing.JSplitPane; 58: import javax.swing.UIManager; 59: import javax.swing.border.Border; 60: 61: /** 62: * The divider that separates the two parts of a JSplitPane in the Basic look 63: * and feel. 64: * 65: * <p> 66: * Implementation status: We do not have a real implementation yet. Currently, 67: * it is mostly a stub to allow compiling other parts of the 68: * javax.swing.plaf.basic package, although some parts are already 69: * functional. 70: * </p> 71: * 72: * @author Sascha Brawer (brawer_AT_dandelis.ch) 73: */ 74: public class BasicSplitPaneDivider extends Container 75: implements PropertyChangeListener 76: { 77: /** 78: * The buttons used as one touch buttons. 79: */ 80: private class BasicOneTouchButton 81: extends JButton 82: { 83: /** 84: * Denotes a left button. 85: */ 86: static final int LEFT = 0; 87: 88: /** 89: * Denotes a right button. 90: */ 91: static final int RIGHT = 1; 92: 93: /** 94: * The x points for the arrow. 95: */ 96: private int[] xpoints; 97: 98: /** 99: * The y points for the arrow. 100: */ 101: private int[] ypoints; 102: 103: /** 104: * Either LEFT or RIGHT. 105: */ 106: private int direction; 107: 108: /** 109: * Creates a new instance. 110: * 111: * @param dir either LEFT or RIGHT 112: */ 113: BasicOneTouchButton(int dir) 114: { 115: direction = dir; 116: xpoints = new int[3]; 117: ypoints = new int[3]; 118: } 119: 120: /** 121: * Never allow borders. 122: */ 123: public void setBorder(Border b) 124: { 125: } 126: 127: /** 128: * Never allow focus traversal. 129: */ 130: public boolean isFocusTraversable() 131: { 132: return false; 133: } 134: 135: /** 136: * Paints the one touch button. 137: */ 138: public void paint(Graphics g) 139: { 140: if (splitPane != null) 141: { 142: // Fill background. 143: g.setColor(splitPane.getBackground()); 144: g.fillRect(0, 0, getWidth(), getHeight()); 145: 146: // Draw arrow. 147: int size; 148: if (direction == LEFT) 149: { 150: if (orientation == JSplitPane.VERTICAL_SPLIT) 151: { 152: size = Math.min(getHeight(), ONE_TOUCH_SIZE); 153: xpoints[0] = 0; 154: xpoints[1] = size / 2; 155: xpoints[2] = size; 156: ypoints[0] = size; 157: ypoints[1] = 0; 158: ypoints[2] = size; 159: } 160: else 161: { 162: size = Math.min(getWidth(), ONE_TOUCH_SIZE); 163: xpoints[0] = size; 164: xpoints[1] = 0; 165: xpoints[2] = size; 166: ypoints[0] = 0; 167: ypoints[1] = size / 2; 168: ypoints[2] = size; 169: } 170: } 171: else 172: { 173: if (orientation == JSplitPane.VERTICAL_SPLIT) 174: { 175: size = Math.min(getHeight(), ONE_TOUCH_SIZE); 176: xpoints[0] = 0; 177: xpoints[1] = size / 2; 178: xpoints[2] = size; 179: ypoints[0] = 0; 180: ypoints[1] = size; 181: ypoints[2] = 0; 182: } 183: else 184: { 185: size = Math.min(getWidth(), ONE_TOUCH_SIZE); 186: xpoints[0] = 0; 187: xpoints[1] = size; 188: xpoints[2] = 0; 189: ypoints[0] = 0; 190: ypoints[1] = size / 2; 191: ypoints[2] = size; 192: } 193: } 194: g.setColor(Color.BLACK); 195: g.fillPolygon(xpoints, ypoints, 3); 196: } 197: } 198: } 199: 200: /** 201: * Listens for actions on the one touch buttons. 202: */ 203: private class OneTouchAction 204: implements ActionListener 205: { 206: 207: public void actionPerformed(ActionEvent ev) 208: { 209: Insets insets = splitPane.getInsets(); 210: int lastLoc = splitPane.getLastDividerLocation(); 211: int currentLoc = splitPaneUI.getDividerLocation(splitPane); 212: int newLoc; 213: 214: if (ev.getSource() == leftButton) 215: { 216: if (orientation == JSplitPane.VERTICAL_SPLIT) 217: { 218: if (currentLoc 219: >= splitPane.getHeight() - insets.bottom - getHeight()) 220: { 221: newLoc = Math.min(splitPane.getMaximumDividerLocation(), 222: lastLoc); 223: } 224: else 225: { 226: newLoc = insets.top; 227: } 228: } 229: else 230: { 231: if (currentLoc 232: >= splitPane.getWidth() - insets.right - getWidth()) 233: { 234: newLoc = Math.min(splitPane.getMaximumDividerLocation(), 235: lastLoc); 236: } 237: else 238: { 239: newLoc = insets.left; 240: } 241: } 242: } 243: else 244: { 245: if (orientation == JSplitPane.VERTICAL_SPLIT) 246: { 247: if (currentLoc == insets.top) 248: { 249: newLoc = Math.min(splitPane.getMaximumDividerLocation(), 250: lastLoc); 251: } 252: else 253: { 254: newLoc = splitPane.getHeight() - insets.top - getHeight(); 255: } 256: } 257: else 258: { 259: if (currentLoc == insets.left) 260: { 261: newLoc = Math.min(splitPane.getMaximumDividerLocation(), 262: lastLoc); 263: } 264: else 265: { 266: newLoc = splitPane.getWidth() - insets.left - getWidth(); 267: } 268: } 269: } 270: if (currentLoc != newLoc) 271: { 272: splitPane.setDividerLocation(newLoc); 273: splitPane.setLastDividerLocation(currentLoc); 274: } 275: } 276: } 277: 278: /** 279: * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1 280: * on MacOS X 10.1.5. 281: */ 282: static final long serialVersionUID = 1463404307042803342L; 283: 284: /** 285: * The width and height of the little buttons for showing and hiding parts 286: * of a JSplitPane in a single mouse click. 287: */ 288: protected static final int ONE_TOUCH_SIZE = 6; 289: 290: /** The distance the one touch buttons will sit from the divider's edges. */ 291: protected static final int ONE_TOUCH_OFFSET = 2; 292: 293: /** 294: * An object that performs the tasks associated with an ongoing drag 295: * operation, or <code>null</code> if the user is currently not dragging 296: * the divider. 297: */ 298: protected DragController dragger; 299: 300: /** 301: * The delegate object that is responsible for the UI of the 302: * <code>JSplitPane</code> that contains this divider. 303: */ 304: protected BasicSplitPaneUI splitPaneUI; 305: 306: /** The thickness of the divider in pixels. */ 307: protected int dividerSize; 308: 309: /** A divider that is used for layout purposes. */ 310: protected Component hiddenDivider; 311: 312: /** The JSplitPane containing this divider. */ 313: protected JSplitPane splitPane; 314: 315: /** 316: * The listener for handling mouse events from both the divider and the 317: * containing <code>JSplitPane</code>. 318: * 319: * <p> 320: * The reason for also handling MouseEvents from the containing 321: * <code>JSplitPane</code> is that users should be able to start a drag 322: * gesture from inside the JSplitPane, but slightly outisde the divider. 323: * </p> 324: */ 325: protected MouseHandler mouseHandler = new MouseHandler(); 326: 327: /** 328: * The current orientation of the containing <code>JSplitPane</code>, which 329: * is either {@link javax.swing.JSplitPane#HORIZONTAL_SPLIT} or {@link 330: * javax.swing.JSplitPane#VERTICAL_SPLIT}. 331: */ 332: protected int orientation; 333: 334: /** 335: * The button for showing and hiding the left (or top) component of the 336: * <code>JSplitPane</code>. 337: */ 338: protected JButton leftButton; 339: 340: /** 341: * The button for showing and hiding the right (or bottom) component of the 342: * <code>JSplitPane</code>. 343: */ 344: protected JButton rightButton; 345: 346: /** 347: * The border of this divider. Typically, this will be an instance of {@link 348: * javax.swing.plaf.basic.BasicBorders.SplitPaneDividerBorder}. 349: * 350: * @see #getBorder() 351: * @see #setBorder(javax.swing.border.Border) 352: */ 353: private Border border; 354: 355: // This is not a pixel count. 356: // This int should be able to take 3 values. 357: // left (top), middle, right(bottom) 358: // 0 1 2 359: 360: /** 361: * Keeps track of where the divider should be placed when using one touch 362: * expand buttons. 363: * This is package-private to avoid an accessor method. 364: */ 365: transient int currentDividerLocation = 1; 366: 367: /** 368: * Indicates if the ont touch buttons are laid out centered or at the 369: * top/left. 370: * 371: * Package private to avoid accessor method. 372: */ 373: boolean centerOneTouchButtons; 374: 375: /** 376: * Constructs a new divider. 377: * 378: * @param ui the UI delegate of the enclosing <code>JSplitPane</code>. 379: */ 380: public BasicSplitPaneDivider(BasicSplitPaneUI ui) 381: { 382: setLayout(new DividerLayout()); 383: setBasicSplitPaneUI(ui); 384: setDividerSize(splitPane.getDividerSize()); 385: centerOneTouchButtons = 386: UIManager.getBoolean("SplitPane.centerOneTouchButtons"); 387: } 388: 389: /** 390: * Sets the delegate object that is responsible for the UI of the {@link 391: * javax.swing.JSplitPane} containing this divider. 392: * 393: * @param newUI the UI delegate, or <code>null</code> to release the 394: * connection to the current delegate. 395: */ 396: public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) 397: { 398: /* Remove the connection to the existing JSplitPane. */ 399: if (splitPane != null) 400: { 401: splitPane.removePropertyChangeListener(this); 402: removeMouseListener(mouseHandler); 403: removeMouseMotionListener(mouseHandler); 404: splitPane = null; 405: hiddenDivider = null; 406: } 407: 408: /* Establish the connection to the new JSplitPane. */ 409: splitPaneUI = newUI; 410: if (splitPaneUI != null) 411: splitPane = newUI.getSplitPane(); 412: if (splitPane != null) 413: { 414: splitPane.addPropertyChangeListener(this); 415: addMouseListener(mouseHandler); 416: addMouseMotionListener(mouseHandler); 417: hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider(); 418: orientation = splitPane.getOrientation(); 419: if (splitPane.isOneTouchExpandable()) 420: oneTouchExpandableChanged(); 421: } 422: } 423: 424: /** 425: * Returns the delegate object that is responsible for the UI of the {@link 426: * javax.swing.JSplitPane} containing this divider. 427: * 428: * @return The UI for the JSplitPane. 429: */ 430: public BasicSplitPaneUI getBasicSplitPaneUI() 431: { 432: return splitPaneUI; 433: } 434: 435: /** 436: * Sets the thickness of the divider. 437: * 438: * @param newSize the new width or height in pixels. 439: */ 440: public void setDividerSize(int newSize) 441: { 442: this.dividerSize = newSize; 443: } 444: 445: /** 446: * Retrieves the thickness of the divider. 447: * 448: * @return The thickness of the divider. 449: */ 450: public int getDividerSize() 451: { 452: return dividerSize; 453: } 454: 455: /** 456: * Sets the border of this divider. 457: * 458: * @param border the new border. Typically, this will be an instance of 459: * {@link 460: * javax.swing.plaf.basic.BasicBorders.SplitPaneBorder}. 461: * 462: * @since 1.3 463: */ 464: public void setBorder(Border border) 465: { 466: if (border != this.border) 467: { 468: Border oldValue = this.border; 469: this.border = border; 470: firePropertyChange("border", oldValue, border); 471: } 472: } 473: 474: /** 475: * Retrieves the border of this divider. 476: * 477: * @return the current border, or <code>null</code> if no border has been 478: * set. 479: * 480: * @since 1.3 481: */ 482: public Border getBorder() 483: { 484: return border; 485: } 486: 487: /** 488: * Retrieves the insets of the divider. If a border has been installed on 489: * the divider, the result of calling its <code>getBorderInsets</code> 490: * method is returned. Otherwise, the inherited implementation will be 491: * invoked. 492: * 493: * @see javax.swing.border.Border#getBorderInsets(java.awt.Component) 494: */ 495: public Insets getInsets() 496: { 497: if (border != null) 498: return border.getBorderInsets(this); 499: else 500: return super.getInsets(); 501: } 502: 503: /** 504: * Returns the preferred size of this divider, which is 505: * <code>dividerSize</code> by <code>dividerSize</code> pixels. 506: * 507: * @return The preferred size of the divider. 508: */ 509: public Dimension getPreferredSize() 510: { 511: Dimension d; 512: if (orientation == JSplitPane.HORIZONTAL_SPLIT) 513: d = new Dimension(getDividerSize(), 1); 514: else 515: d = new Dimension(1, getDividerSize()); 516: return d; 517: } 518: 519: /** 520: * Returns the minimal size of this divider, which is 521: * <code>dividerSize</code> by <code>dividerSize</code> pixels. 522: * 523: * @return The minimal size of the divider. 524: */ 525: public Dimension getMinimumSize() 526: { 527: return getPreferredSize(); 528: } 529: 530: /** 531: * Processes events from the <code>JSplitPane</code> that contains this 532: * divider. 533: * 534: * @param e The PropertyChangeEvent. 535: */ 536: public void propertyChange(PropertyChangeEvent e) 537: { 538: if (e.getPropertyName().equals(JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY)) 539: oneTouchExpandableChanged(); 540: else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) 541: { 542: orientation = splitPane.getOrientation(); 543: invalidate(); 544: if (splitPane != null) 545: splitPane.revalidate(); 546: } 547: else if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY)) 548: dividerSize = splitPane.getDividerSize(); 549: } 550: 551: /** 552: * Paints the divider by painting its border. 553: * 554: * @param g The Graphics Object to paint with. 555: */ 556: public void paint(Graphics g) 557: { 558: Dimension dividerSize; 559: 560: super.paint(g); 561: if (border != null) 562: { 563: dividerSize = getSize(); 564: border.paintBorder(this, g, 0, 0, dividerSize.width, dividerSize.height); 565: } 566: } 567: 568: /** 569: * Reacts to changes of the <code>oneToughExpandable</code> property of the 570: * containing <code>JSplitPane</code>. 571: */ 572: protected void oneTouchExpandableChanged() 573: { 574: if (splitPane.isOneTouchExpandable()) 575: { 576: leftButton = createLeftOneTouchButton(); 577: if (leftButton != null) 578: leftButton.addActionListener(new OneTouchAction()); 579: 580: rightButton = createRightOneTouchButton(); 581: if (rightButton != null) 582: rightButton.addActionListener(new OneTouchAction()); 583: 584: // Only add them when both are non-null. 585: if (leftButton != null && rightButton != null) 586: { 587: add(leftButton); 588: add(rightButton); 589: } 590: } 591: invalidate(); 592: if (splitPane != null) 593: splitPane.revalidate(); 594: } 595: 596: /** 597: * Creates a button for showing and hiding the left (or top) part of a 598: * <code>JSplitPane</code>. 599: * 600: * @return The left one touch button. 601: */ 602: protected JButton createLeftOneTouchButton() 603: { 604: JButton button = new BasicOneTouchButton(BasicOneTouchButton.LEFT); 605: button.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE)); 606: button.setRequestFocusEnabled(false); 607: return button; 608: } 609: 610: /** 611: * Creates a button for showing and hiding the right (or bottom) part of a 612: * <code>JSplitPane</code>. 613: * 614: * @return The right one touch button. 615: */ 616: protected JButton createRightOneTouchButton() 617: { 618: JButton button = new BasicOneTouchButton(BasicOneTouchButton.RIGHT); 619: button.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE)); 620: button.setRequestFocusEnabled(false); 621: return button; 622: } 623: 624: /** 625: * Prepares the divider for dragging by calling the 626: * <code>startDragging</code> method of the UI delegate of the enclosing 627: * <code>JSplitPane</code>. 628: * 629: * @see BasicSplitPaneUI#startDragging() 630: */ 631: protected void prepareForDragging() 632: { 633: if (splitPaneUI != null) 634: splitPaneUI.startDragging(); 635: } 636: 637: /** 638: * Drags the divider to a given location by calling the 639: * <code>dragDividerTo</code> method of the UI delegate of the enclosing 640: * <code>JSplitPane</code>. 641: * 642: * @param location the new location of the divider. 643: * 644: * @see BasicSplitPaneUI#dragDividerTo(int location) 645: */ 646: protected void dragDividerTo(int location) 647: { 648: if (splitPaneUI != null) 649: splitPaneUI.dragDividerTo(location); 650: } 651: 652: /** 653: * Finishes a dragging gesture by calling the <code>finishDraggingTo</code> 654: * method of the UI delegate of the enclosing <code>JSplitPane</code>. 655: * 656: * @param location the new, final location of the divider. 657: * 658: * @see BasicSplitPaneUI#finishDraggingTo(int location) 659: */ 660: protected void finishDraggingTo(int location) 661: { 662: if (splitPaneUI != null) 663: splitPaneUI.finishDraggingTo(location); 664: } 665: 666: /** 667: * This helper method moves the divider to one of the three locations when 668: * using one touch expand buttons. Location 0 is the left (or top) most 669: * location. Location 1 is the middle. Location 2 is the right (or bottom) 670: * most location. 671: * This is package-private to avoid an accessor method. 672: * 673: * @param locationIndex The location to move to. 674: */ 675: void moveDividerTo(int locationIndex) 676: { 677: Insets insets = splitPane.getInsets(); 678: switch (locationIndex) 679: { 680: case 1: 681: splitPane.setDividerLocation(splitPane.getLastDividerLocation()); 682: break; 683: case 0: 684: int top = (orientation == JSplitPane.HORIZONTAL_SPLIT) ? insets.left 685: : insets.top; 686: splitPane.setDividerLocation(top); 687: break; 688: case 2: 689: int bottom; 690: if (orientation == JSplitPane.HORIZONTAL_SPLIT) 691: bottom = splitPane.getBounds().width - insets.right - dividerSize; 692: else 693: bottom = splitPane.getBounds().height - insets.bottom - dividerSize; 694: splitPane.setDividerLocation(bottom); 695: break; 696: } 697: } 698: 699: /** 700: * The listener for handling mouse events from both the divider and the 701: * containing <code>JSplitPane</code>. 702: * 703: * <p> 704: * The reason for also handling MouseEvents from the containing 705: * <code>JSplitPane</code> is that users should be able to start a drag 706: * gesture from inside the JSplitPane, but slightly outisde the divider. 707: * </p> 708: * 709: * @author Sascha Brawer (brawer_AT_dandelis.ch) 710: */ 711: protected class MouseHandler extends MouseAdapter 712: implements MouseMotionListener 713: { 714: /** Keeps track of whether a drag is occurring. */ 715: private transient boolean isDragging; 716: 717: /** 718: * This method is called when the mouse is pressed. 719: * 720: * @param e The MouseEvent. 721: */ 722: public void mousePressed(MouseEvent e) 723: { 724: isDragging = true; 725: currentDividerLocation = 1; 726: if (orientation == JSplitPane.HORIZONTAL_SPLIT) 727: dragger = new DragController(e); 728: else 729: dragger = new VerticalDragController(e); 730: prepareForDragging(); 731: } 732: 733: /** 734: * This method is called when the mouse is released. 735: * 736: * @param e The MouseEvent. 737: */ 738: public void mouseReleased(MouseEvent e) 739: { 740: if (isDragging) 741: dragger.completeDrag(e); 742: isDragging = false; 743: } 744: 745: /** 746: * Repeatedly invoked when the user is dragging the mouse cursor while 747: * having pressed a mouse button. 748: * 749: * @param e The MouseEvent. 750: */ 751: public void mouseDragged(MouseEvent e) 752: { 753: if (dragger != null) 754: dragger.continueDrag(e); 755: } 756: 757: /** 758: * Repeatedly invoked when the user is dragging the mouse cursor without 759: * having pressed a mouse button. 760: * 761: * @param e The MouseEvent. 762: */ 763: public void mouseMoved(MouseEvent e) 764: { 765: // Do nothing. 766: } 767: } 768: 769: /** 770: * Performs the tasks associated with an ongoing drag operation. 771: * 772: * @author Sascha Brawer (brawer_AT_dandelis.ch) 773: */ 774: protected class DragController 775: { 776: /** 777: * The difference between where the mouse is clicked and the initial 778: * divider location. 779: */ 780: transient int offset; 781: 782: /** 783: * Creates a new DragController object. 784: * 785: * @param e The MouseEvent to initialize with. 786: */ 787: protected DragController(MouseEvent e) 788: { 789: offset = e.getX(); 790: } 791: 792: /** 793: * This method returns true if the divider can move. 794: * 795: * @return True if dragging is allowed. 796: */ 797: protected boolean isValid() 798: { 799: // Views can always be resized? 800: return true; 801: } 802: 803: /** 804: * Returns a position for the divider given the MouseEvent. 805: * 806: * @param e MouseEvent. 807: * 808: * @return The position for the divider to move to. 809: */ 810: protected int positionForMouseEvent(MouseEvent e) 811: { 812: return e.getX() + getX() - offset; 813: } 814: 815: /** 816: * This method returns one of the two paramters for the orientation. In 817: * this case, it returns x. 818: * 819: * @param x The x coordinate. 820: * @param y The y coordinate. 821: * 822: * @return The x coordinate. 823: */ 824: protected int getNeededLocation(int x, int y) 825: { 826: return x; 827: } 828: 829: /** 830: * This method is called to pass on the drag information to the UI through 831: * dragDividerTo. 832: * 833: * @param newX The x coordinate of the MouseEvent. 834: * @param newY The y coordinate of the MouseEvent. 835: */ 836: protected void continueDrag(int newX, int newY) 837: { 838: if (isValid()) 839: dragDividerTo(adjust(newX, newY)); 840: } 841: 842: /** 843: * This method is called to pass on the drag information to the UI 844: * through dragDividerTo. 845: * 846: * @param e The MouseEvent. 847: */ 848: protected void continueDrag(MouseEvent e) 849: { 850: if (isValid()) 851: dragDividerTo(positionForMouseEvent(e)); 852: } 853: 854: /** 855: * This method is called to finish the drag session by calling 856: * finishDraggingTo. 857: * 858: * @param x The x coordinate of the MouseEvent. 859: * @param y The y coordinate of the MouseEvent. 860: */ 861: protected void completeDrag(int x, int y) 862: { 863: finishDraggingTo(adjust(x, y)); 864: } 865: 866: /** 867: * This method is called to finish the drag session by calling 868: * finishDraggingTo. 869: * 870: * @param e The MouseEvent. 871: */ 872: protected void completeDrag(MouseEvent e) 873: { 874: finishDraggingTo(positionForMouseEvent(e)); 875: } 876: 877: /** 878: * This is a helper method that includes the offset in the needed 879: * location. 880: * 881: * @param x The x coordinate of the MouseEvent. 882: * @param y The y coordinate of the MouseEvent. 883: * 884: * @return The needed location adjusted by the offsets. 885: */ 886: int adjust(int x, int y) 887: { 888: return getNeededLocation(x, y) + getX() - offset; 889: } 890: } 891: 892: /** 893: * This is a helper class that controls dragging when the orientation is 894: * VERTICAL_SPLIT. 895: */ 896: protected class VerticalDragController extends DragController 897: { 898: /** 899: * Creates a new VerticalDragController object. 900: * 901: * @param e The MouseEvent to initialize with. 902: */ 903: protected VerticalDragController(MouseEvent e) 904: { 905: super(e); 906: offset = e.getY(); 907: } 908: 909: /** 910: * This method returns one of the two parameters given the orientation. In 911: * this case, it returns y. 912: * 913: * @param x The x coordinate of the MouseEvent. 914: * @param y The y coordinate of the MouseEvent. 915: * 916: * @return The y coordinate. 917: */ 918: protected int getNeededLocation(int x, int y) 919: { 920: return y; 921: } 922: 923: /** 924: * This method returns the new location of the divider given a MouseEvent. 925: * 926: * @param e The MouseEvent. 927: * 928: * @return The new location of the divider. 929: */ 930: protected int positionForMouseEvent(MouseEvent e) 931: { 932: return e.getY() + getY() - offset; 933: } 934: 935: /** 936: * This is a helper method that includes the offset in the needed 937: * location. 938: * 939: * @param x The x coordinate of the MouseEvent. 940: * @param y The y coordinate of the MouseEvent. 941: * 942: * @return The needed location adjusted by the offsets. 943: */ 944: int adjust(int x, int y) 945: { 946: return getNeededLocation(x, y) + getY() - offset; 947: } 948: } 949: 950: /** 951: * This helper class acts as the Layout Manager for the divider. 952: */ 953: protected class DividerLayout implements LayoutManager 954: { 955: /** 956: * Creates a new DividerLayout object. 957: */ 958: protected DividerLayout() 959: { 960: // Nothing to do here. 961: } 962: 963: /** 964: * This method is called when a Component is added. 965: * 966: * @param string The constraints string. 967: * @param c The Component to add. 968: */ 969: public void addLayoutComponent(String string, Component c) 970: { 971: // Do nothing. 972: } 973: 974: /** 975: * This method is called to lay out the container. 976: * 977: * @param c The container to lay out. 978: */ 979: public void layoutContainer(Container c) 980: { 981: if (leftButton != null && rightButton != null 982: && c == BasicSplitPaneDivider.this) 983: { 984: if (splitPane.isOneTouchExpandable()) 985: { 986: Insets insets = getInsets(); 987: if (orientation == JSplitPane.HORIZONTAL_SPLIT) 988: { 989: int size = getWidth() - insets.left - insets.right; 990: size = Math.max(size, 0); 991: size = Math.min(size, ONE_TOUCH_SIZE); 992: int x, y; 993: if (centerOneTouchButtons) 994: { 995: y = insets.top; 996: x = (getWidth() - size) / 2; 997: } 998: else 999: { 1000: x = insets.left; 1001: y = 0; 1002: } 1003: 1004: leftButton.setBounds(x, y + ONE_TOUCH_OFFSET, size, 1005: size * 2); 1006: rightButton.setBounds(x, y + ONE_TOUCH_OFFSET 1007: + ONE_TOUCH_SIZE * 2, size, size * 2); 1008: } 1009: else 1010: { 1011: int size = getHeight() - insets.top - insets.bottom; 1012: size = Math.max(size, 0); 1013: size = Math.min(size, ONE_TOUCH_SIZE); 1014: int x, y; 1015: if (centerOneTouchButtons) 1016: { 1017: x = insets.left; 1018: y = (getHeight() - size) / 2; 1019: } 1020: else 1021: { 1022: x = 0; 1023: y = insets.top; 1024: } 1025: leftButton.setBounds(x + ONE_TOUCH_OFFSET, y, size * 2, 1026: size); 1027: rightButton.setBounds(x + ONE_TOUCH_OFFSET 1028: + ONE_TOUCH_SIZE * 2, y, size * 2, 1029: size); 1030: } 1031: } 1032: else 1033: { 1034: // The JDK sets this bounds for disabled one touch buttons, so 1035: // do we. 1036: leftButton.setBounds(-5, -5, 1, 1); 1037: rightButton.setBounds(-5, -5, 1, 1); 1038: } 1039: } 1040: } 1041: 1042: /** 1043: * This method returns the minimum layout size. 1044: * 1045: * @param c The container to calculate for. 1046: * 1047: * @return The minimum layout size. 1048: */ 1049: public Dimension minimumLayoutSize(Container c) 1050: { 1051: return preferredLayoutSize(c); 1052: } 1053: 1054: /** 1055: * This method returns the preferred layout size. 1056: * 1057: * @param c The container to calculate for. 1058: * 1059: * @return The preferred layout size. 1060: */ 1061: public Dimension preferredLayoutSize(Container c) 1062: { 1063: return new Dimension(dividerSize, dividerSize); 1064: } 1065: 1066: /** 1067: * This method is called when a component is removed. 1068: * 1069: * @param c The component to remove. 1070: */ 1071: public void removeLayoutComponent(Component c) 1072: { 1073: // Do nothing. 1074: } 1075: 1076: } 1077: }