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