Frames | No Frames |
1: /* BasicSplitPaneUI.java -- 2: Copyright (C) 2003, 2004, 2005, 2006, 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.Canvas; 42: import java.awt.Color; 43: import java.awt.Component; 44: import java.awt.Container; 45: import java.awt.Dimension; 46: import java.awt.Graphics; 47: import java.awt.Insets; 48: import java.awt.LayoutManager2; 49: import java.awt.Point; 50: import java.awt.event.ActionEvent; 51: import java.awt.event.ActionListener; 52: import java.awt.event.FocusAdapter; 53: import java.awt.event.FocusEvent; 54: import java.awt.event.FocusListener; 55: import java.beans.PropertyChangeEvent; 56: import java.beans.PropertyChangeListener; 57: 58: import javax.swing.AbstractAction; 59: import javax.swing.ActionMap; 60: import javax.swing.InputMap; 61: import javax.swing.JComponent; 62: import javax.swing.JSlider; 63: import javax.swing.JSplitPane; 64: import javax.swing.KeyStroke; 65: import javax.swing.LookAndFeel; 66: import javax.swing.SwingUtilities; 67: import javax.swing.UIManager; 68: import javax.swing.plaf.ActionMapUIResource; 69: import javax.swing.plaf.ComponentUI; 70: import javax.swing.plaf.SplitPaneUI; 71: import javax.swing.plaf.UIResource; 72: 73: /** 74: * This is the Basic Look and Feel implementation of the SplitPaneUI class. 75: */ 76: public class BasicSplitPaneUI extends SplitPaneUI 77: { 78: /** 79: * This Layout Manager controls the position and size of the components when 80: * the JSplitPane's orientation is HORIZONTAL_SPLIT. 81: * 82: * @specnote Apparently this class was intended to be protected, 83: * but was made public by a compiler bug and is now 84: * public for compatibility. 85: */ 86: public class BasicHorizontalLayoutManager implements LayoutManager2 87: { 88: // 3 components at a time. 89: // LEFT/TOP = 0 90: // RIGHT/BOTTOM = 1 91: // DIVIDER = 2 92: 93: /** 94: * This array contains the components in the JSplitPane. The left/top 95: * component is at index 0, the right/bottom is at 1, and the divider is 96: * at 2. 97: */ 98: protected Component[] components = new Component[3]; 99: 100: // These are the _current_ widths of the associated component. 101: 102: /** 103: * This array contains the current width (for HORIZONTAL_SPLIT) or height 104: * (for VERTICAL_SPLIT) of the components. The indices are the same as 105: * for components. 106: */ 107: protected int[] sizes = new int[3]; 108: 109: /** 110: * Creates a new instance. This is package private because the reference 111: * implementation has no public constructor either. Still, we need to 112: * call it from BasicVerticalLayoutManager. 113: */ 114: BasicHorizontalLayoutManager() 115: { 116: // Nothing to do here. 117: } 118: 119: /** 120: * This method adds the component given to the JSplitPane. The position of 121: * the component is given by the constraints object. 122: * 123: * @param comp The Component to add. 124: * @param constraints The constraints that bind the object. 125: */ 126: public void addLayoutComponent(Component comp, Object constraints) 127: { 128: addLayoutComponent((String) constraints, comp); 129: } 130: 131: /** 132: * This method is called to add a Component to the JSplitPane. The 133: * placement string determines where the Component will be placed. The 134: * string should be one of LEFT, RIGHT, TOP, BOTTOM or null (signals that 135: * the component is the divider). 136: * 137: * @param place The placement of the Component. 138: * @param component The Component to add. 139: * 140: * @throws IllegalArgumentException DOCUMENT ME! 141: */ 142: public void addLayoutComponent(String place, Component component) 143: { 144: int i = 0; 145: if (place == null) 146: i = 2; 147: else if (place.equals(JSplitPane.TOP) || place.equals(JSplitPane.LEFT)) 148: i = 0; 149: else if (place.equals(JSplitPane.BOTTOM) 150: || place.equals(JSplitPane.RIGHT)) 151: i = 1; 152: else 153: throw new IllegalArgumentException("Illegal placement in JSplitPane"); 154: components[i] = component; 155: resetSizeAt(i); 156: splitPane.revalidate(); 157: splitPane.repaint(); 158: } 159: 160: /** 161: * This method returns the width of the JSplitPane minus the insets. 162: * 163: * @param containerSize The Dimensions of the JSplitPane. 164: * @param insets The Insets of the JSplitPane. 165: * 166: * @return The width of the JSplitPane minus the insets. 167: */ 168: protected int getAvailableSize(Dimension containerSize, Insets insets) 169: { 170: return containerSize.width - insets.left - insets.right; 171: } 172: 173: /** 174: * This method returns the given insets left value. If the given inset is 175: * null, then 0 is returned. 176: * 177: * @param insets The Insets to use with the JSplitPane. 178: * 179: * @return The inset's left value. 180: */ 181: protected int getInitialLocation(Insets insets) 182: { 183: if (insets != null) 184: return insets.left; 185: return 0; 186: } 187: 188: /** 189: * This specifies how a component is aligned with respect to other 190: * components in the x fdirection. 191: * 192: * @param target The container. 193: * 194: * @return The component's alignment. 195: */ 196: public float getLayoutAlignmentX(Container target) 197: { 198: return target.getAlignmentX(); 199: } 200: 201: /** 202: * This specifies how a component is aligned with respect to other 203: * components in the y direction. 204: * 205: * @param target The container. 206: * 207: * @return The component's alignment. 208: */ 209: public float getLayoutAlignmentY(Container target) 210: { 211: return target.getAlignmentY(); 212: } 213: 214: /** 215: * This method returns the preferred width of the component. 216: * 217: * @param c The component to measure. 218: * 219: * @return The preferred width of the component. 220: */ 221: protected int getPreferredSizeOfComponent(Component c) 222: { 223: Dimension dims = c.getPreferredSize(); 224: if (dims != null) 225: return dims.width; 226: return 0; 227: } 228: 229: /** 230: * This method returns the current width of the component. 231: * 232: * @param c The component to measure. 233: * 234: * @return The width of the component. 235: */ 236: protected int getSizeOfComponent(Component c) 237: { 238: return c.getWidth(); 239: } 240: 241: /** 242: * This method returns the sizes array. 243: * 244: * @return The sizes array. 245: */ 246: protected int[] getSizes() 247: { 248: return sizes; 249: } 250: 251: /** 252: * This method invalidates the layout. It does nothing. 253: * 254: * @param c The container to invalidate. 255: */ 256: public void invalidateLayout(Container c) 257: { 258: // DO NOTHING 259: } 260: 261: /** 262: * This method lays out the components in the container. 263: * 264: * @param container The container to lay out. 265: */ 266: public void layoutContainer(Container container) 267: { 268: if (container instanceof JSplitPane) 269: { 270: JSplitPane split = (JSplitPane) container; 271: distributeExtraSpace(); 272: Insets insets = split.getInsets(); 273: Dimension dims = split.getSize(); 274: int loc = getInitialLocation(insets); 275: int available = getAvailableSize(dims, insets); 276: sizes[0] = getDividerLocation(split) - loc; 277: sizes[1] = available - sizes[0] - sizes[2]; 278: // The size of the divider won't change. 279: 280: // Layout component#1. 281: setComponentToSize(components[0], sizes[0], loc, insets, dims); 282: // Layout divider. 283: loc += sizes[0]; 284: setComponentToSize(components[2], sizes[2], loc, insets, dims); 285: // Layout component#2. 286: loc += sizes[2]; 287: setComponentToSize(components[1], sizes[1], loc, insets, dims); 288: } 289: } 290: 291: /** 292: * This method returns the maximum size for the container given the 293: * components. It returns a new Dimension object that has width and 294: * height equal to Integer.MAX_VALUE. 295: * 296: * @param target The container to measure. 297: * 298: * @return The maximum size. 299: */ 300: public Dimension maximumLayoutSize(Container target) 301: { 302: return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 303: } 304: 305: /** 306: * This method returns the container's minimum size. The minimum width is 307: * the sum of all the component's minimum widths. The minimum height is 308: * the maximum of all the components' minimum heights. 309: * 310: * @param target The container to measure. 311: * 312: * @return The minimum size. 313: */ 314: public Dimension minimumLayoutSize(Container target) 315: { 316: if (target instanceof JSplitPane) 317: { 318: JSplitPane split = (JSplitPane) target; 319: Insets insets = target.getInsets(); 320: 321: int height = 0; 322: int width = 0; 323: for (int i = 0; i < components.length; i++) 324: { 325: if (components[i] == null) 326: continue; 327: Dimension dims = components[i].getMinimumSize(); 328: if (dims != null) 329: { 330: width += dims.width; 331: height = Math.max(height, dims.height); 332: } 333: } 334: return new Dimension(width, height); 335: } 336: return null; 337: } 338: 339: /** 340: * This method returns the container's preferred size. The preferred width 341: * is the sum of all the component's preferred widths. The preferred 342: * height is the maximum of all the components' preferred heights. 343: * 344: * @param target The container to measure. 345: * 346: * @return The preferred size. 347: */ 348: public Dimension preferredLayoutSize(Container target) 349: { 350: if (target instanceof JSplitPane) 351: { 352: JSplitPane split = (JSplitPane) target; 353: Insets insets = target.getInsets(); 354: 355: int height = 0; 356: int width = 0; 357: for (int i = 0; i < components.length; i++) 358: { 359: if (components[i] == null) 360: continue; 361: Dimension dims = components[i].getPreferredSize(); 362: if (dims != null) 363: { 364: width += dims.width; 365: if (!(components[i] instanceof BasicSplitPaneDivider)) 366: height = Math.max(height, dims.height); 367: } 368: } 369: return new Dimension(width, height); 370: } 371: return null; 372: } 373: 374: /** 375: * This method removes the component from the layout. 376: * 377: * @param component The component to remove from the layout. 378: */ 379: public void removeLayoutComponent(Component component) 380: { 381: for (int i = 0; i < components.length; i++) 382: { 383: if (component == components[i]) 384: { 385: components[i] = null; 386: sizes[i] = 0; 387: } 388: } 389: } 390: 391: /** 392: * This method resets the size of Component to the preferred size. 393: * 394: * @param index The index of the component to reset. 395: */ 396: protected void resetSizeAt(int index) 397: { 398: if (components[index] != null) 399: sizes[index] = getPreferredSizeOfComponent(components[index]); 400: } 401: 402: /** 403: * This method resets the sizes of all the components. 404: */ 405: public void resetToPreferredSizes() 406: { 407: for (int i = 0; i < components.length; i++) 408: resetSizeAt(i); 409: setDividerLocation(splitPane, 410: getInitialLocation(splitPane.getInsets()) + sizes[0]); 411: } 412: 413: /** 414: * This methods sets the bounds of the given component. The width is the 415: * size. The height is the container size minus the top and bottom 416: * inset. The x coordinate is the location given. The y coordinate is 417: * the top inset. 418: * 419: * @param c The component to set. 420: * @param size The width of the component. 421: * @param location The x coordinate. 422: * @param insets The insets to use. 423: * @param containerSize The height of the container. 424: */ 425: protected void setComponentToSize(Component c, int size, int location, 426: Insets insets, Dimension containerSize) 427: { 428: int w = size; 429: int h = containerSize.height - insets.top - insets.bottom; 430: int x = location; 431: int y = insets.top; 432: c.setBounds(x, y, w, h); 433: } 434: 435: /** 436: * This method stores the given int array as the new sizes array. 437: * 438: * @param newSizes The array to use as sizes. 439: */ 440: protected void setSizes(int[] newSizes) 441: { 442: sizes = newSizes; 443: } 444: 445: /** 446: * This method determines the size of each component. It should be called 447: * when a new Layout Manager is created for an existing JSplitPane. 448: */ 449: protected void updateComponents() 450: { 451: Component left = splitPane.getLeftComponent(); 452: Component right = splitPane.getRightComponent(); 453: 454: if (left != null) 455: { 456: components[0] = left; 457: resetSizeAt(0); 458: } 459: if (right != null) 460: { 461: components[1] = right; 462: resetSizeAt(1); 463: } 464: components[2] = divider; 465: resetSizeAt(2); 466: } 467: 468: /** 469: * This method resizes the left and right components to fit inside the 470: * JSplitPane when there is extra space. 471: */ 472: void distributeExtraSpace() 473: { 474: // FIXME: This needs to be reimplemented correctly. 475: } 476: 477: /** 478: * This method returns the minimum width of the component at the given 479: * index. 480: * 481: * @param index The index to check. 482: * 483: * @return The minimum width. 484: */ 485: int minimumSizeOfComponent(int index) 486: { 487: Dimension dims = components[index].getMinimumSize(); 488: if (dims != null) 489: return dims.width; 490: else 491: return 0; 492: } 493: } //end BasicHorizontalLayoutManager 494: 495: /** 496: * This class is the Layout Manager for the JSplitPane when the orientation 497: * is VERTICAL_SPLIT. 498: * 499: * @specnote Apparently this class was intended to be protected, 500: * but was made public by a compiler bug and is now 501: * public for compatibility. 502: */ 503: public class BasicVerticalLayoutManager 504: extends BasicHorizontalLayoutManager 505: { 506: /** 507: * This method returns the height of the container minus the top and 508: * bottom inset. 509: * 510: * @param containerSize The size of the container. 511: * @param insets The insets of the container. 512: * 513: * @return The height minus top and bottom inset. 514: */ 515: protected int getAvailableSize(Dimension containerSize, Insets insets) 516: { 517: return containerSize.height - insets.top - insets.bottom; 518: } 519: 520: /** 521: * This method returns the top inset. 522: * 523: * @param insets The Insets to use. 524: * 525: * @return The top inset. 526: */ 527: protected int getInitialLocation(Insets insets) 528: { 529: return insets.top; 530: } 531: 532: /** 533: * This method returns the preferred height of the component. 534: * 535: * @param c The component to measure. 536: * 537: * @return The preferred height of the component. 538: */ 539: protected int getPreferredSizeOfComponent(Component c) 540: { 541: Dimension dims = c.getPreferredSize(); 542: if (dims != null) 543: return dims.height; 544: return 0; 545: } 546: 547: /** 548: * This method returns the current height of the component. 549: * 550: * @param c The component to measure. 551: * 552: * @return The current height of the component. 553: */ 554: protected int getSizeOfComponent(Component c) 555: { 556: return c.getHeight(); 557: } 558: 559: /** 560: * This method returns the minimum layout size. The minimum height is the 561: * sum of all the components' minimum heights. The minimum width is the 562: * maximum of all the components' minimum widths. 563: * 564: * @param container The container to measure. 565: * 566: * @return The minimum size. 567: */ 568: public Dimension minimumLayoutSize(Container container) 569: { 570: if (container instanceof JSplitPane) 571: { 572: JSplitPane split = (JSplitPane) container; 573: Insets insets = container.getInsets(); 574: 575: int height = 0; 576: int width = 0; 577: for (int i = 0; i < components.length; i++) 578: { 579: if (components[i] == null) 580: continue; 581: Dimension dims = components[i].getMinimumSize(); 582: if (dims != null) 583: { 584: height += dims.height; 585: width = Math.max(width, dims.width); 586: } 587: } 588: return new Dimension(width, height); 589: } 590: return null; 591: } 592: 593: /** 594: * This method returns the preferred layout size. The preferred height is 595: * the sum of all the components' preferred heights. The preferred width 596: * is the maximum of all the components' preferred widths. 597: * 598: * @param container The container to measure. 599: * 600: * @return The preferred size. 601: */ 602: public Dimension preferredLayoutSize(Container container) 603: { 604: if (container instanceof JSplitPane) 605: { 606: JSplitPane split = (JSplitPane) container; 607: Insets insets = container.getInsets(); 608: 609: int height = 0; 610: int width = 0; 611: for (int i = 0; i < components.length; i++) 612: { 613: if (components[i] == null) 614: continue; 615: Dimension dims = components[i].getPreferredSize(); 616: if (dims != null) 617: { 618: height += dims.height; 619: width = Math.max(width, dims.width); 620: } 621: } 622: return new Dimension(width, height); 623: } 624: return null; 625: } 626: 627: /** 628: * This method sets the bounds of the given component. The y coordinate is 629: * the location given. The x coordinate is the left inset. The height is 630: * the size given. The width is the container size minus the left and 631: * right inset. 632: * 633: * @param c The component to set bounds for. 634: * @param size The height. 635: * @param location The y coordinate. 636: * @param insets The insets to use. 637: * @param containerSize The container's size. 638: */ 639: protected void setComponentToSize(Component c, int size, int location, 640: Insets insets, Dimension containerSize) 641: { 642: int y = location; 643: int x = insets.left; 644: int h = size; 645: int w = containerSize.width - insets.left - insets.right; 646: c.setBounds(x, y, w, h); 647: } 648: 649: /** 650: * This method returns the minimum height of the component at the given 651: * index. 652: * 653: * @param index The index of the component to check. 654: * 655: * @return The minimum height of the given component. 656: */ 657: int minimumSizeOfComponent(int index) 658: { 659: Dimension dims = components[index].getMinimumSize(); 660: if (dims != null) 661: return dims.height; 662: else 663: return 0; 664: } 665: } 666: 667: /** 668: * This class handles FocusEvents from the JComponent. 669: * 670: * @specnote Apparently this class was intended to be protected, 671: * but was made public by a compiler bug and is now 672: * public for compatibility. 673: */ 674: public class FocusHandler extends FocusAdapter 675: { 676: /** 677: * This method is called when the JSplitPane gains focus. 678: * 679: * @param ev The FocusEvent. 680: */ 681: public void focusGained(FocusEvent ev) 682: { 683: // repaint the divider because its background color may change due to 684: // the focus state... 685: divider.repaint(); 686: } 687: 688: /** 689: * This method is called when the JSplitPane loses focus. 690: * 691: * @param ev The FocusEvent. 692: */ 693: public void focusLost(FocusEvent ev) 694: { 695: // repaint the divider because its background color may change due to 696: // the focus state... 697: divider.repaint(); 698: } 699: } 700: 701: /** 702: * This is a deprecated class. It is supposed to be used for handling down 703: * and right key presses. 704: * 705: * @specnote Apparently this class was intended to be protected, 706: * but was made public by a compiler bug and is now 707: * public for compatibility. 708: */ 709: public class KeyboardDownRightHandler implements ActionListener 710: { 711: /** 712: * This method is called when the down or right keys are pressed. 713: * 714: * @param ev The ActionEvent 715: */ 716: public void actionPerformed(ActionEvent ev) 717: { 718: // FIXME: implement. 719: } 720: } 721: 722: /** 723: * This is a deprecated class. It is supposed to be used for handling end 724: * key presses. 725: * 726: * @specnote Apparently this class was intended to be protected, 727: * but was made public by a compiler bug and is now 728: * public for compatibility. 729: */ 730: public class KeyboardEndHandler implements ActionListener 731: { 732: /** 733: * This method is called when the end key is pressed. 734: * 735: * @param ev The ActionEvent. 736: */ 737: public void actionPerformed(ActionEvent ev) 738: { 739: // FIXME: implement. 740: } 741: } 742: 743: /** 744: * This is a deprecated class. It is supposed to be used for handling home 745: * key presses. 746: * 747: * @specnote Apparently this class was intended to be protected, 748: * but was made public by a compiler bug and is now 749: * public for compatibility. 750: */ 751: public class KeyboardHomeHandler implements ActionListener 752: { 753: /** 754: * This method is called when the home key is pressed. 755: * 756: * @param ev The ActionEvent. 757: */ 758: public void actionPerformed(ActionEvent ev) 759: { 760: // FIXME: implement. 761: } 762: } 763: 764: /** 765: * This is a deprecated class. It is supposed to be used for handling resize 766: * toggles. 767: * 768: * @specnote Apparently this class was intended to be protected, 769: * but was made public by a compiler bug and is now 770: * public for compatibility. 771: */ 772: public class KeyboardResizeToggleHandler implements ActionListener 773: { 774: /** 775: * This method is called when a resize is toggled. 776: * 777: * @param ev The ActionEvent. 778: */ 779: public void actionPerformed(ActionEvent ev) 780: { 781: // FIXME: implement. 782: } 783: } 784: 785: /** 786: * This is a deprecated class. It is supposed to be used for handler up and 787: * left key presses. 788: * 789: * @specnote Apparently this class was intended to be protected, 790: * but was made public by a compiler bug and is now 791: * public for compatibility. 792: */ 793: public class KeyboardUpLeftHandler implements ActionListener 794: { 795: /** 796: * This method is called when the left or up keys are pressed. 797: * 798: * @param ev The ActionEvent. 799: */ 800: public void actionPerformed(ActionEvent ev) 801: { 802: // FIXME: implement. 803: } 804: } 805: 806: /** 807: * This helper class handles PropertyChangeEvents from the JSplitPane. When 808: * a property changes, this will update the UI accordingly. 809: * 810: * @specnote Apparently this class was intended to be protected, 811: * but was made public by a compiler bug and is now 812: * public for compatibility. 813: */ 814: public class PropertyHandler implements PropertyChangeListener 815: { 816: /** 817: * This method is called whenever one of the JSplitPane's properties 818: * change. 819: * 820: * @param e DOCUMENT ME! 821: */ 822: public void propertyChange(PropertyChangeEvent e) 823: { 824: if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY)) 825: { 826: int newSize = splitPane.getDividerSize(); 827: int[] tmpSizes = layoutManager.getSizes(); 828: dividerSize = tmpSizes[2]; 829: int newSpace = newSize - tmpSizes[2]; 830: tmpSizes[2] = newSize; 831: 832: tmpSizes[0] += newSpace / 2; 833: tmpSizes[1] += newSpace / 2; 834: 835: layoutManager.setSizes(tmpSizes); 836: } 837: else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) 838: { 839: int max = layoutManager.getAvailableSize(splitPane.getSize(), 840: splitPane.getInsets()); 841: int dividerLoc = getDividerLocation(splitPane); 842: double prop = ((double) dividerLoc) / max; 843: 844: resetLayoutManager(); 845: if (prop <= 1 && prop >= 0) 846: splitPane.setDividerLocation(prop); 847: } 848: // Don't have to deal with continuous_layout - only 849: // necessary in dragging modes (and it's checked 850: // every time you drag there) 851: // Don't have to deal with resize_weight (as there 852: // will be no extra space associated with this 853: // event - the changes to the weighting will 854: // be taken into account the next time the 855: // sizes change.) 856: // Don't have to deal with divider_location 857: // The method in JSplitPane calls our setDividerLocation 858: // so we'll know about those anyway. 859: // Don't have to deal with last_divider_location 860: // Although I'm not sure why, it doesn't seem to 861: // have any effect on Sun's JSplitPane. 862: // one_touch_expandable changes are dealt with 863: // by our divider. 864: } 865: } 866: 867: /** The location of the divider when dragging began. */ 868: protected int beginDragDividerLocation; 869: 870: /** The size of the divider while dragging. */ 871: protected int dividerSize; 872: 873: /** The location where the last drag location ended. */ 874: transient int lastDragLocation = -1; 875: 876: /** The distance the divider is moved when moved by keyboard actions. */ 877: // Sun defines this as 3 878: protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3; 879: 880: /** The divider that divides this JSplitPane. */ 881: protected BasicSplitPaneDivider divider; 882: 883: /** The listener that listens for PropertyChangeEvents from the JSplitPane. */ 884: protected PropertyChangeListener propertyChangeListener; 885: 886: /** The JSplitPane's focus handler. */ 887: protected FocusListener focusListener; 888: 889: /** @deprecated The handler for down and right key presses. */ 890: protected ActionListener keyboardDownRightListener; 891: 892: /** @deprecated The handler for end key presses. */ 893: protected ActionListener keyboardEndListener; 894: 895: /** @deprecated The handler for home key presses. */ 896: protected ActionListener keyboardHomeListener; 897: 898: /** @deprecated The handler for toggling resizes. */ 899: protected ActionListener keyboardResizeToggleListener; 900: 901: /** @deprecated The handler for up and left key presses. */ 902: protected ActionListener keyboardUpLeftListener; 903: 904: /** The JSplitPane's current layout manager. */ 905: protected BasicHorizontalLayoutManager layoutManager; 906: 907: /** @deprecated The divider resize toggle key. */ 908: protected KeyStroke dividerResizeToggleKey; 909: 910: /** @deprecated The down key. */ 911: protected KeyStroke downKey; 912: 913: /** @deprecated The end key. */ 914: protected KeyStroke endKey; 915: 916: /** @deprecated The home key. */ 917: protected KeyStroke homeKey; 918: 919: /** @deprecated The left key. */ 920: protected KeyStroke leftKey; 921: 922: /** @deprecated The right key. */ 923: protected KeyStroke rightKey; 924: 925: /** @deprecated The up key. */ 926: protected KeyStroke upKey; 927: 928: /** Set to true when dragging heavy weight components. */ 929: protected boolean draggingHW; 930: 931: /** 932: * The constraints object used when adding the non-continuous divider to the 933: * JSplitPane. 934: */ 935: protected static final String NON_CONTINUOUS_DIVIDER 936: = "nonContinuousDivider"; 937: 938: /** The dark divider used when dragging in non-continuous layout mode. */ 939: protected Component nonContinuousLayoutDivider; 940: 941: /** The JSplitPane that this UI draws. */ 942: protected JSplitPane splitPane; 943: 944: private int dividerLocation; 945: 946: /** 947: * Creates a new BasicSplitPaneUI object. 948: */ 949: public BasicSplitPaneUI() 950: { 951: // Nothing to do here. 952: } 953: 954: /** 955: * This method creates a new BasicSplitPaneUI for the given JComponent. 956: * 957: * @param x The JComponent to create a UI for. 958: * 959: * @return A new BasicSplitPaneUI. 960: */ 961: public static ComponentUI createUI(JComponent x) 962: { 963: return new BasicSplitPaneUI(); 964: } 965: 966: /** 967: * This method installs the BasicSplitPaneUI for the given JComponent. 968: * 969: * @param c The JComponent to install the UI for. 970: */ 971: public void installUI(JComponent c) 972: { 973: if (c instanceof JSplitPane) 974: { 975: splitPane = (JSplitPane) c; 976: installDefaults(); 977: installListeners(); 978: installKeyboardActions(); 979: } 980: } 981: 982: /** 983: * This method uninstalls the BasicSplitPaneUI for the given JComponent. 984: * 985: * @param c The JComponent to uninstall the UI for. 986: */ 987: public void uninstallUI(JComponent c) 988: { 989: uninstallKeyboardActions(); 990: uninstallListeners(); 991: uninstallDefaults(); 992: 993: splitPane = null; 994: } 995: 996: /** 997: * This method installs the defaults given by the Look and Feel. 998: */ 999: protected void installDefaults() 1000: { 1001: LookAndFeel.installColors(splitPane, "SplitPane.background", 1002: "SplitPane.foreground"); 1003: LookAndFeel.installBorder(splitPane, "SplitPane.border"); 1004: divider = createDefaultDivider(); 1005: divider.setBorder(UIManager.getBorder("SplitPaneDivider.border")); 1006: resetLayoutManager(); 1007: nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); 1008: splitPane.add(divider, JSplitPane.DIVIDER); 1009: 1010: // There is no need to add the nonContinuousLayoutDivider 1011: splitPane.setDividerSize(UIManager.getInt("SplitPane.dividerSize")); 1012: splitPane.setOpaque(true); 1013: } 1014: 1015: /** 1016: * This method uninstalls the defaults and nulls any objects created during 1017: * install. 1018: */ 1019: protected void uninstallDefaults() 1020: { 1021: layoutManager = null; 1022: splitPane.remove(divider); 1023: divider = null; 1024: nonContinuousLayoutDivider = null; 1025: 1026: if (splitPane.getBackground() instanceof UIResource) 1027: splitPane.setBackground(null); 1028: if (splitPane.getBorder() instanceof UIResource) 1029: splitPane.setBorder(null); 1030: } 1031: 1032: /** 1033: * This method installs the listeners needed for this UI to function. 1034: */ 1035: protected void installListeners() 1036: { 1037: propertyChangeListener = createPropertyChangeListener(); 1038: focusListener = createFocusListener(); 1039: 1040: splitPane.addPropertyChangeListener(propertyChangeListener); 1041: splitPane.addFocusListener(focusListener); 1042: } 1043: 1044: /** 1045: * This method uninstalls all listeners registered for the UI. 1046: */ 1047: protected void uninstallListeners() 1048: { 1049: splitPane.removePropertyChangeListener(propertyChangeListener); 1050: splitPane.removeFocusListener(focusListener); 1051: 1052: focusListener = null; 1053: propertyChangeListener = null; 1054: } 1055: 1056: /** 1057: * Returns the input map for the specified condition. 1058: * 1059: * @param condition the condition. 1060: * 1061: * @return The input map. 1062: */ 1063: InputMap getInputMap(int condition) 1064: { 1065: if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) 1066: return (InputMap) UIManager.get("SplitPane.ancestorInputMap"); 1067: return null; 1068: } 1069: 1070: /** 1071: * Returns the action map for the {@link JSplitPane}. All sliders share 1072: * a single action map which is created the first time this method is 1073: * called, then stored in the UIDefaults table for subsequent access. 1074: * 1075: * @return The shared action map. 1076: */ 1077: ActionMap getActionMap() 1078: { 1079: ActionMap map = (ActionMap) UIManager.get("SplitPane.actionMap"); 1080: 1081: if (map == null) // first time here 1082: { 1083: map = createActionMap(); 1084: if (map != null) 1085: UIManager.put("SplitPane.actionMap", map); 1086: } 1087: return map; 1088: } 1089: 1090: /** 1091: * Creates the action map shared by all {@link JSlider} instances. 1092: * This method is called once by {@link #getActionMap()} when it 1093: * finds no action map in the UIDefaults table...after the map is 1094: * created, it gets added to the defaults table so that subsequent 1095: * calls to {@link #getActionMap()} will return the same shared 1096: * instance. 1097: * 1098: * @return The action map. 1099: */ 1100: ActionMap createActionMap() 1101: { 1102: ActionMap map = new ActionMapUIResource(); 1103: map.put("toggleFocus", 1104: new AbstractAction("toggleFocus") { 1105: public void actionPerformed(ActionEvent event) 1106: { 1107: // FIXME: What to do here? 1108: } 1109: } 1110: ); 1111: map.put("startResize", 1112: new AbstractAction("startResize") { 1113: public void actionPerformed(ActionEvent event) 1114: { 1115: splitPane.requestFocus(); 1116: } 1117: } 1118: ); 1119: map.put("selectMax", 1120: new AbstractAction("selectMax") { 1121: public void actionPerformed(ActionEvent event) 1122: { 1123: splitPane.setDividerLocation(1.0); 1124: } 1125: } 1126: ); 1127: map.put("selectMin", 1128: new AbstractAction("selectMin") { 1129: public void actionPerformed(ActionEvent event) 1130: { 1131: splitPane.setDividerLocation(0.0); 1132: } 1133: } 1134: ); 1135: map.put("negativeIncrement", 1136: new AbstractAction("negativeIncrement") { 1137: public void actionPerformed(ActionEvent event) 1138: { 1139: setDividerLocation(splitPane, Math.max(dividerLocation 1140: - KEYBOARD_DIVIDER_MOVE_OFFSET, 0)); 1141: } 1142: } 1143: ); 1144: map.put("positiveIncrement", 1145: new AbstractAction("positiveIncrement") { 1146: public void actionPerformed(ActionEvent event) 1147: { 1148: setDividerLocation(splitPane, dividerLocation 1149: + KEYBOARD_DIVIDER_MOVE_OFFSET); 1150: } 1151: } 1152: ); 1153: map.put("focusOutBackward", 1154: new AbstractAction("focusOutBackward") { 1155: public void actionPerformed(ActionEvent event) 1156: { 1157: // FIXME: implement this 1158: } 1159: } 1160: ); 1161: map.put("focusOutForward", 1162: new AbstractAction("focusOutForward") { 1163: public void actionPerformed(ActionEvent event) 1164: { 1165: // FIXME: implement this 1166: } 1167: } 1168: ); 1169: return map; 1170: } 1171: 1172: /** 1173: * Installs any keyboard actions. The list of keys that need to be bound are 1174: * listed in Basic look and feel's defaults. 1175: */ 1176: protected void installKeyboardActions() 1177: { 1178: InputMap keyMap = getInputMap( 1179: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 1180: SwingUtilities.replaceUIInputMap(splitPane, 1181: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap); 1182: ActionMap map = getActionMap(); 1183: SwingUtilities.replaceUIActionMap(splitPane, map); 1184: } 1185: 1186: /** 1187: * This method reverses the work done in installKeyboardActions. 1188: */ 1189: protected void uninstallKeyboardActions() 1190: { 1191: SwingUtilities.replaceUIActionMap(splitPane, null); 1192: SwingUtilities.replaceUIInputMap(splitPane, 1193: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); 1194: } 1195: 1196: /** 1197: * This method creates a new PropertyChangeListener. 1198: * 1199: * @return A new PropertyChangeListener. 1200: */ 1201: protected PropertyChangeListener createPropertyChangeListener() 1202: { 1203: return new PropertyHandler(); 1204: } 1205: 1206: /** 1207: * This method creates a new FocusListener. 1208: * 1209: * @return A new FocusListener. 1210: */ 1211: protected FocusListener createFocusListener() 1212: { 1213: return new FocusHandler(); 1214: } 1215: 1216: /** 1217: * This method creates a new ActionListener for up and left key presses. 1218: * 1219: * @return A new ActionListener for up and left keys. 1220: * 1221: * @deprecated 1.3 1222: */ 1223: protected ActionListener createKeyboardUpLeftListener() 1224: { 1225: return new KeyboardUpLeftHandler(); 1226: } 1227: 1228: /** 1229: * This method creates a new ActionListener for down and right key presses. 1230: * 1231: * @return A new ActionListener for down and right keys. 1232: * 1233: * @deprecated 1.3 1234: */ 1235: protected ActionListener createKeyboardDownRightListener() 1236: { 1237: return new KeyboardDownRightHandler(); 1238: } 1239: 1240: /** 1241: * This method creates a new ActionListener for home key presses. 1242: * 1243: * @return A new ActionListener for home keys. 1244: * 1245: * @deprecated 1246: */ 1247: protected ActionListener createKeyboardHomeListener() 1248: { 1249: return new KeyboardHomeHandler(); 1250: } 1251: 1252: /** 1253: * This method creates a new ActionListener for end key presses.i 1254: * 1255: * @return A new ActionListener for end keys. 1256: * 1257: * @deprecated 1.3 1258: */ 1259: protected ActionListener createKeyboardEndListener() 1260: { 1261: return new KeyboardEndHandler(); 1262: } 1263: 1264: /** 1265: * This method creates a new ActionListener for resize toggle key events. 1266: * 1267: * @return A new ActionListener for resize toggle keys. 1268: * 1269: * @deprecated 1.3 1270: */ 1271: protected ActionListener createKeyboardResizeToggleListener() 1272: { 1273: return new KeyboardResizeToggleHandler(); 1274: } 1275: 1276: /** 1277: * This method returns the orientation of the JSplitPane. 1278: * 1279: * @return The orientation of the JSplitPane. 1280: */ 1281: public int getOrientation() 1282: { 1283: return splitPane.getOrientation(); 1284: } 1285: 1286: /** 1287: * This method sets the orientation of the JSplitPane. 1288: * 1289: * @param orientation The new orientation of the JSplitPane. 1290: */ 1291: public void setOrientation(int orientation) 1292: { 1293: splitPane.setOrientation(orientation); 1294: } 1295: 1296: /** 1297: * This method returns true if the JSplitPane is using continuous layout. 1298: * 1299: * @return True if the JSplitPane is using continuous layout. 1300: */ 1301: public boolean isContinuousLayout() 1302: { 1303: return splitPane.isContinuousLayout(); 1304: } 1305: 1306: /** 1307: * This method sets the continuous layout property of the JSplitPane. 1308: * 1309: * @param b True if the JsplitPane is to use continuous layout. 1310: */ 1311: public void setContinuousLayout(boolean b) 1312: { 1313: splitPane.setContinuousLayout(b); 1314: } 1315: 1316: /** 1317: * This method returns the last location the divider was dragged to. 1318: * 1319: * @return The last location the divider was dragged to. 1320: */ 1321: public int getLastDragLocation() 1322: { 1323: return lastDragLocation; 1324: } 1325: 1326: /** 1327: * This method sets the last location the divider was dragged to. 1328: * 1329: * @param l The last location the divider was dragged to. 1330: */ 1331: public void setLastDragLocation(int l) 1332: { 1333: lastDragLocation = l; 1334: } 1335: 1336: /** 1337: * This method returns the BasicSplitPaneDivider that divides this 1338: * JSplitPane. 1339: * 1340: * @return The divider for the JSplitPane. 1341: */ 1342: public BasicSplitPaneDivider getDivider() 1343: { 1344: return divider; 1345: } 1346: 1347: /** 1348: * This method creates a nonContinuousLayoutDivider for use with the 1349: * JSplitPane in nonContinousLayout mode. The default divider is a gray 1350: * Canvas. 1351: * 1352: * @return The default nonContinousLayoutDivider. 1353: */ 1354: protected Component createDefaultNonContinuousLayoutDivider() 1355: { 1356: if (nonContinuousLayoutDivider == null) 1357: { 1358: nonContinuousLayoutDivider = new Canvas(); 1359: Color c = UIManager.getColor("SplitPaneDivider.draggingColor"); 1360: nonContinuousLayoutDivider.setBackground(c); 1361: } 1362: return nonContinuousLayoutDivider; 1363: } 1364: 1365: /** 1366: * This method sets the component to use as the nonContinuousLayoutDivider. 1367: * 1368: * @param newDivider The component to use as the nonContinuousLayoutDivider. 1369: */ 1370: protected void setNonContinuousLayoutDivider(Component newDivider) 1371: { 1372: setNonContinuousLayoutDivider(newDivider, true); 1373: } 1374: 1375: /** 1376: * This method sets the component to use as the nonContinuousLayoutDivider. 1377: * 1378: * @param newDivider The component to use as the nonContinuousLayoutDivider. 1379: * @param rememberSizes FIXME: document. 1380: */ 1381: protected void setNonContinuousLayoutDivider(Component newDivider, 1382: boolean rememberSizes) 1383: { 1384: // FIXME: use rememberSizes for something 1385: nonContinuousLayoutDivider = newDivider; 1386: } 1387: 1388: /** 1389: * This method returns the nonContinuousLayoutDivider. 1390: * 1391: * @return The nonContinuousLayoutDivider. 1392: */ 1393: public Component getNonContinuousLayoutDivider() 1394: { 1395: return nonContinuousLayoutDivider; 1396: } 1397: 1398: /** 1399: * This method returns the JSplitPane that this BasicSplitPaneUI draws. 1400: * 1401: * @return The JSplitPane. 1402: */ 1403: public JSplitPane getSplitPane() 1404: { 1405: return splitPane; 1406: } 1407: 1408: /** 1409: * This method creates the divider used normally with the JSplitPane. 1410: * 1411: * @return The default divider. 1412: */ 1413: public BasicSplitPaneDivider createDefaultDivider() 1414: { 1415: if (divider == null) 1416: divider = new BasicSplitPaneDivider(this); 1417: return divider; 1418: } 1419: 1420: /** 1421: * This method is called when JSplitPane's resetToPreferredSizes is called. 1422: * It resets the sizes of all components in the JSplitPane. 1423: * 1424: * @param jc The JSplitPane to reset. 1425: */ 1426: public void resetToPreferredSizes(JSplitPane jc) 1427: { 1428: layoutManager.resetToPreferredSizes(); 1429: } 1430: 1431: /** 1432: * This method sets the location of the divider. 1433: * 1434: * @param jc The JSplitPane to set the divider location in. 1435: * @param location The new location of the divider. 1436: */ 1437: public void setDividerLocation(JSplitPane jc, int location) 1438: { 1439: dividerLocation = location; 1440: splitPane.revalidate(); 1441: splitPane.repaint(); 1442: } 1443: 1444: /** 1445: * This method returns the location of the divider. 1446: * 1447: * @param jc The JSplitPane to retrieve the location for. 1448: * 1449: * @return The location of the divider. 1450: */ 1451: public int getDividerLocation(JSplitPane jc) 1452: { 1453: return dividerLocation; 1454: } 1455: 1456: /** 1457: * This method returns the smallest value possible for the location of the 1458: * divider. 1459: * 1460: * @param jc The JSplitPane. 1461: * 1462: * @return The minimum divider location. 1463: */ 1464: public int getMinimumDividerLocation(JSplitPane jc) 1465: { 1466: int value = layoutManager.getInitialLocation(jc.getInsets()); 1467: if (layoutManager.components[0] != null) 1468: value += layoutManager.minimumSizeOfComponent(0); 1469: return value; 1470: } 1471: 1472: /** 1473: * This method returns the largest value possible for the location of the 1474: * divider. 1475: * 1476: * @param jc The JSplitPane. 1477: * 1478: * @return The maximum divider location. 1479: */ 1480: public int getMaximumDividerLocation(JSplitPane jc) 1481: { 1482: int value = layoutManager.getInitialLocation(jc.getInsets()) 1483: + layoutManager.getAvailableSize(jc.getSize(), jc.getInsets()) 1484: - splitPane.getDividerSize(); 1485: if (layoutManager.components[1] != null) 1486: value -= layoutManager.minimumSizeOfComponent(1); 1487: return value; 1488: } 1489: 1490: /** 1491: * This method is called after the children of the JSplitPane are painted. 1492: * 1493: * @param jc The JSplitPane. 1494: * @param g The Graphics object to paint with. 1495: */ 1496: public void finishedPaintingChildren(JSplitPane jc, Graphics g) 1497: { 1498: if (! splitPane.isContinuousLayout() && nonContinuousLayoutDivider != null 1499: && nonContinuousLayoutDivider.isVisible()) 1500: javax.swing.SwingUtilities.paintComponent(g, nonContinuousLayoutDivider, 1501: null, 1502: nonContinuousLayoutDivider 1503: .getBounds()); 1504: } 1505: 1506: /** 1507: * This method is called to paint the JSplitPane. 1508: * 1509: * @param g The Graphics object to paint with. 1510: * @param jc The JSplitPane to paint. 1511: */ 1512: public void paint(Graphics g, JComponent jc) 1513: { 1514: // TODO: What should be done here? 1515: } 1516: 1517: /** 1518: * This method returns the preferred size of the JSplitPane. 1519: * 1520: * @param jc The JSplitPane. 1521: * 1522: * @return The preferred size of the JSplitPane. 1523: */ 1524: public Dimension getPreferredSize(JComponent jc) 1525: { 1526: return layoutManager.preferredLayoutSize((Container) jc); 1527: } 1528: 1529: /** 1530: * This method returns the minimum size of the JSplitPane. 1531: * 1532: * @param jc The JSplitPane. 1533: * 1534: * @return The minimum size of the JSplitPane. 1535: */ 1536: public Dimension getMinimumSize(JComponent jc) 1537: { 1538: return layoutManager.minimumLayoutSize((Container) jc); 1539: } 1540: 1541: /** 1542: * This method returns the maximum size of the JSplitPane. 1543: * 1544: * @param jc The JSplitPane. 1545: * 1546: * @return The maximum size of the JSplitPane. 1547: */ 1548: public Dimension getMaximumSize(JComponent jc) 1549: { 1550: return layoutManager.maximumLayoutSize((Container) jc); 1551: } 1552: 1553: /** 1554: * This method returns the border insets of the current border. 1555: * 1556: * @param jc The JSplitPane. 1557: * 1558: * @return The current border insets. 1559: */ 1560: public Insets getInsets(JComponent jc) 1561: { 1562: return splitPane.getBorder().getBorderInsets(splitPane); 1563: } 1564: 1565: /** 1566: * This method resets the current layout manager. The type of layout manager 1567: * is dependent on the current orientation. 1568: */ 1569: protected void resetLayoutManager() 1570: { 1571: if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) 1572: layoutManager = new BasicHorizontalLayoutManager(); 1573: else 1574: layoutManager = new BasicVerticalLayoutManager(); 1575: getSplitPane().setLayout(layoutManager); 1576: layoutManager.updateComponents(); 1577: 1578: // invalidating by itself does not invalidate the layout. 1579: getSplitPane().revalidate(); 1580: } 1581: 1582: /** 1583: * This method is called when dragging starts. It resets lastDragLocation 1584: * and dividerSize. 1585: */ 1586: protected void startDragging() 1587: { 1588: Component left = splitPane.getLeftComponent(); 1589: Component right = splitPane.getRightComponent(); 1590: dividerSize = divider.getDividerSize(); 1591: setLastDragLocation(-1); 1592: 1593: if ((left != null && !left.isLightweight()) 1594: || (right != null && !right.isLightweight())) 1595: draggingHW = true; 1596: 1597: if (splitPane.isContinuousLayout()) 1598: nonContinuousLayoutDivider.setVisible(false); 1599: else 1600: { 1601: nonContinuousLayoutDivider.setVisible(true); 1602: nonContinuousLayoutDivider.setBounds(divider.getBounds()); 1603: } 1604: } 1605: 1606: /** 1607: * This method is called whenever the divider is dragged. If the JSplitPane 1608: * is in continuousLayout mode, the divider needs to be moved and the 1609: * JSplitPane needs to be laid out. 1610: * 1611: * @param location The new location of the divider. 1612: */ 1613: protected void dragDividerTo(int location) 1614: { 1615: location = validLocation(location); 1616: if (beginDragDividerLocation == -1) 1617: beginDragDividerLocation = location; 1618: 1619: if (splitPane.isContinuousLayout()) 1620: splitPane.setDividerLocation(location); 1621: else 1622: { 1623: Point p = nonContinuousLayoutDivider.getLocation(); 1624: if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) 1625: p.x = location; 1626: else 1627: p.y = location; 1628: nonContinuousLayoutDivider.setLocation(p); 1629: } 1630: setLastDragLocation(location); 1631: splitPane.repaint(); 1632: } 1633: 1634: /** 1635: * This method is called when the dragging is finished. 1636: * 1637: * @param location The location where the drag finished. 1638: */ 1639: protected void finishDraggingTo(int location) 1640: { 1641: if (nonContinuousLayoutDivider != null) 1642: nonContinuousLayoutDivider.setVisible(false); 1643: draggingHW = false; 1644: location = validLocation(location); 1645: splitPane.setDividerLocation(location); 1646: splitPane.setLastDividerLocation(beginDragDividerLocation); 1647: beginDragDividerLocation = -1; 1648: } 1649: 1650: /** 1651: * This method returns the width of one of the sides of the divider's border. 1652: * 1653: * @return The width of one side of the divider's border. 1654: * 1655: * @deprecated 1.3 1656: */ 1657: protected int getDividerBorderSize() 1658: { 1659: if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) 1660: return divider.getBorder().getBorderInsets(divider).left; 1661: else 1662: return divider.getBorder().getBorderInsets(divider).top; 1663: } 1664: 1665: /** 1666: * This is a helper method that returns a valid location for the divider 1667: * when dragging. 1668: * 1669: * @param location The location to check. 1670: * 1671: * @return A valid location. 1672: */ 1673: private int validLocation(int location) 1674: { 1675: int min = getMinimumDividerLocation(splitPane); 1676: int max = getMaximumDividerLocation(splitPane); 1677: if (min > 0 && location < min) 1678: return min; 1679: if (max > 0 && location > max) 1680: return max; 1681: return location; 1682: } 1683: }