GNU Classpath (0.20) | |
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.LookAndFeel; 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: c.setBounds(x, y, w, h); 641: } 642: 643: /** 644: * This method returns the minimum height of the component at the given 645: * index. 646: * 647: * @param index The index of the component to check. 648: * 649: * @return The minimum height of the given component. 650: */ 651: int minimumSizeOfComponent(int index) 652: { 653: Dimension dims = components[index].getMinimumSize(); 654: if (dims != null) 655: return dims.height; 656: else 657: return 0; 658: } 659: } 660: 661: /** 662: * This class handles FocusEvents from the JComponent. 663: * 664: * @specnote Apparently this class was intended to be protected, 665: * but was made public by a compiler bug and is now 666: * public for compatibility. 667: */ 668: public class FocusHandler extends FocusAdapter 669: { 670: /** 671: * This method is called when the JSplitPane gains focus. 672: * 673: * @param ev The FocusEvent. 674: */ 675: public void focusGained(FocusEvent ev) 676: { 677: // FIXME: implement. 678: } 679: 680: /** 681: * This method is called when the JSplitPane loses focus. 682: * 683: * @param ev The FocusEvent. 684: */ 685: public void focusLost(FocusEvent ev) 686: { 687: // FIXME: implement. 688: } 689: } 690: 691: /** 692: * This is a deprecated class. It is supposed to be used for handling down 693: * and right key presses. 694: * 695: * @specnote Apparently this class was intended to be protected, 696: * but was made public by a compiler bug and is now 697: * public for compatibility. 698: */ 699: public class KeyboardDownRightHandler implements ActionListener 700: { 701: /** 702: * This method is called when the down or right keys are pressed. 703: * 704: * @param ev The ActionEvent 705: */ 706: public void actionPerformed(ActionEvent ev) 707: { 708: // FIXME: implement. 709: } 710: } 711: 712: /** 713: * This is a deprecated class. It is supposed to be used for handling end 714: * key presses. 715: * 716: * @specnote Apparently this class was intended to be protected, 717: * but was made public by a compiler bug and is now 718: * public for compatibility. 719: */ 720: public class KeyboardEndHandler implements ActionListener 721: { 722: /** 723: * This method is called when the end key is pressed. 724: * 725: * @param ev The ActionEvent. 726: */ 727: public void actionPerformed(ActionEvent ev) 728: { 729: // FIXME: implement. 730: } 731: } 732: 733: /** 734: * This is a deprecated class. It is supposed to be used for handling home 735: * key presses. 736: * 737: * @specnote Apparently this class was intended to be protected, 738: * but was made public by a compiler bug and is now 739: * public for compatibility. 740: */ 741: public class KeyboardHomeHandler implements ActionListener 742: { 743: /** 744: * This method is called when the home key is pressed. 745: * 746: * @param ev The ActionEvent. 747: */ 748: public void actionPerformed(ActionEvent ev) 749: { 750: // FIXME: implement. 751: } 752: } 753: 754: /** 755: * This is a deprecated class. It is supposed to be used for handling resize 756: * toggles. 757: * 758: * @specnote Apparently this class was intended to be protected, 759: * but was made public by a compiler bug and is now 760: * public for compatibility. 761: */ 762: public class KeyboardResizeToggleHandler implements ActionListener 763: { 764: /** 765: * This method is called when a resize is toggled. 766: * 767: * @param ev The ActionEvent. 768: */ 769: public void actionPerformed(ActionEvent ev) 770: { 771: // FIXME: implement. 772: } 773: } 774: 775: /** 776: * This is a deprecated class. It is supposed to be used for handler up and 777: * left key presses. 778: * 779: * @specnote Apparently this class was intended to be protected, 780: * but was made public by a compiler bug and is now 781: * public for compatibility. 782: */ 783: public class KeyboardUpLeftHandler implements ActionListener 784: { 785: /** 786: * This method is called when the left or up keys are pressed. 787: * 788: * @param ev The ActionEvent. 789: */ 790: public void actionPerformed(ActionEvent ev) 791: { 792: // FIXME: implement. 793: } 794: } 795: 796: /** 797: * This helper class handles PropertyChangeEvents from the JSplitPane. When 798: * a property changes, this will update the UI accordingly. 799: * 800: * @specnote Apparently this class was intended to be protected, 801: * but was made public by a compiler bug and is now 802: * public for compatibility. 803: */ 804: public class PropertyHandler implements PropertyChangeListener 805: { 806: /** 807: * This method is called whenever one of the JSplitPane's properties 808: * change. 809: * 810: * @param e DOCUMENT ME! 811: */ 812: public void propertyChange(PropertyChangeEvent e) 813: { 814: if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY)) 815: { 816: int newSize = splitPane.getDividerSize(); 817: int[] tmpSizes = layoutManager.getSizes(); 818: dividerSize = tmpSizes[2]; 819: int newSpace = newSize - tmpSizes[2]; 820: tmpSizes[2] = newSize; 821: 822: tmpSizes[0] += newSpace / 2; 823: tmpSizes[1] += newSpace / 2; 824: 825: layoutManager.setSizes(tmpSizes); 826: } 827: else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) 828: { 829: int max = layoutManager.getAvailableSize(splitPane.getSize(), 830: splitPane.getInsets()); 831: int dividerLoc = getDividerLocation(splitPane); 832: double prop = ((double) dividerLoc) / max; 833: 834: resetLayoutManager(); 835: if (prop <= 1 && prop >= 0) 836: splitPane.setDividerLocation(prop); 837: } 838: layoutManager.layoutContainer(splitPane); 839: splitPane.repaint(); 840: // Don't have to deal with continuous_layout - only 841: // necessary in dragging modes (and it's checked 842: // every time you drag there) 843: // Don't have to deal with resize_weight (as there 844: // will be no extra space associated with this 845: // event - the changes to the weighting will 846: // be taken into account the next time the 847: // sizes change.) 848: // Don't have to deal with divider_location 849: // The method in JSplitPane calls our setDividerLocation 850: // so we'll know about those anyway. 851: // Don't have to deal with last_divider_location 852: // Although I'm not sure why, it doesn't seem to 853: // have any effect on Sun's JSplitPane. 854: // one_touch_expandable changes are dealt with 855: // by our divider. 856: } 857: } 858: 859: /** The location of the divider when dragging began. */ 860: protected int beginDragDividerLocation; 861: 862: /** The size of the divider while dragging. */ 863: protected int dividerSize; 864: 865: /** The location where the last drag location ended. */ 866: transient int lastDragLocation = -1; 867: 868: /** The distance the divider is moved when moved by keyboard actions. */ 869: // Sun defines this as 3 870: protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3; 871: 872: /** The divider that divides this JSplitPane. */ 873: protected BasicSplitPaneDivider divider; 874: 875: /** The listener that listens for PropertyChangeEvents from the JSplitPane. */ 876: protected PropertyChangeListener propertyChangeListener; 877: 878: /** The JSplitPane's focus handler. */ 879: protected FocusListener focusListener; 880: 881: /** @deprecated The handler for down and right key presses. */ 882: protected ActionListener keyboardDownRightListener; 883: 884: /** @deprecated The handler for end key presses. */ 885: protected ActionListener keyboardEndListener; 886: 887: /** @deprecated The handler for home key presses. */ 888: protected ActionListener keyboardHomeListener; 889: 890: /** @deprecated The handler for toggling resizes. */ 891: protected ActionListener keyboardResizeToggleListener; 892: 893: /** @deprecated The handler for up and left key presses. */ 894: protected ActionListener keyboardUpLeftListener; 895: 896: /** The JSplitPane's current layout manager. */ 897: protected BasicHorizontalLayoutManager layoutManager; 898: 899: /** @deprecated The divider resize toggle key. */ 900: protected KeyStroke dividerResizeToggleKey; 901: 902: /** @deprecated The down key. */ 903: protected KeyStroke downKey; 904: 905: /** @deprecated The end key. */ 906: protected KeyStroke endKey; 907: 908: /** @deprecated The home key. */ 909: protected KeyStroke homeKey; 910: 911: /** @deprecated The left key. */ 912: protected KeyStroke leftKey; 913: 914: /** @deprecated The right key. */ 915: protected KeyStroke rightKey; 916: 917: /** @deprecated The up key. */ 918: protected KeyStroke upKey; 919: 920: /** Set to true when dragging heavy weight components. */ 921: protected boolean draggingHW; 922: 923: /** 924: * The constraints object used when adding the non-continuous divider to the 925: * JSplitPane. 926: */ 927: protected static final String NON_CONTINUOUS_DIVIDER 928: = "nonContinuousDivider"; 929: 930: /** The dark divider used when dragging in non-continuous layout mode. */ 931: protected Component nonContinuousLayoutDivider; 932: 933: /** The JSplitPane that this UI draws. */ 934: protected JSplitPane splitPane; 935: 936: /** 937: * Creates a new BasicSplitPaneUI object. 938: */ 939: public BasicSplitPaneUI() 940: { 941: // Nothing to do here. 942: } 943: 944: /** 945: * This method creates a new BasicSplitPaneUI for the given JComponent. 946: * 947: * @param x The JComponent to create a UI for. 948: * 949: * @return A new BasicSplitPaneUI. 950: */ 951: public static ComponentUI createUI(JComponent x) 952: { 953: return new BasicSplitPaneUI(); 954: } 955: 956: /** 957: * This method installs the BasicSplitPaneUI for the given JComponent. 958: * 959: * @param c The JComponent to install the UI for. 960: */ 961: public void installUI(JComponent c) 962: { 963: if (c instanceof JSplitPane) 964: { 965: splitPane = (JSplitPane) c; 966: installDefaults(); 967: installListeners(); 968: installKeyboardActions(); 969: } 970: } 971: 972: /** 973: * This method uninstalls the BasicSplitPaneUI for the given JComponent. 974: * 975: * @param c The JComponent to uninstall the UI for. 976: */ 977: public void uninstallUI(JComponent c) 978: { 979: uninstallKeyboardActions(); 980: uninstallListeners(); 981: uninstallDefaults(); 982: 983: splitPane = null; 984: } 985: 986: /** 987: * This method installs the defaults given by the Look and Feel. 988: */ 989: protected void installDefaults() 990: { 991: LookAndFeel.installColors(splitPane, "SplitPane.background", 992: "SplitPane.foreground"); 993: LookAndFeel.installBorder(splitPane, "SplitPane.border"); 994: divider = createDefaultDivider(); 995: resetLayoutManager(); 996: nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); 997: splitPane.add(divider, JSplitPane.DIVIDER); 998: 999: // There is no need to add the nonContinuousLayoutDivider 1000: splitPane.setDividerSize(UIManager.getInt("SplitPane.dividerSize")); 1001: splitPane.setOpaque(true); 1002: } 1003: 1004: /** 1005: * This method uninstalls the defaults and nulls any objects created during 1006: * install. 1007: */ 1008: protected void uninstallDefaults() 1009: { 1010: layoutManager = null; 1011: splitPane.remove(divider); 1012: divider = null; 1013: nonContinuousLayoutDivider = null; 1014: 1015: splitPane.setBackground(null); 1016: splitPane.setBorder(null); 1017: } 1018: 1019: /** 1020: * This method installs the listeners needed for this UI to function. 1021: */ 1022: protected void installListeners() 1023: { 1024: propertyChangeListener = createPropertyChangeListener(); 1025: focusListener = createFocusListener(); 1026: 1027: splitPane.addPropertyChangeListener(propertyChangeListener); 1028: splitPane.addFocusListener(focusListener); 1029: } 1030: 1031: /** 1032: * This method uninstalls all listeners registered for the UI. 1033: */ 1034: protected void uninstallListeners() 1035: { 1036: splitPane.removePropertyChangeListener(propertyChangeListener); 1037: splitPane.removeFocusListener(focusListener); 1038: 1039: focusListener = null; 1040: propertyChangeListener = null; 1041: } 1042: 1043: /** 1044: * This method installs the keyboard actions for the JSplitPane. 1045: */ 1046: protected void installKeyboardActions() 1047: { 1048: // FIXME: implement. 1049: } 1050: 1051: /** 1052: * This method reverses the work done in installKeyboardActions. 1053: */ 1054: protected void uninstallKeyboardActions() 1055: { 1056: // FIXME: implement. 1057: } 1058: 1059: /** 1060: * This method creates a new PropertyChangeListener. 1061: * 1062: * @return A new PropertyChangeListener. 1063: */ 1064: protected PropertyChangeListener createPropertyChangeListener() 1065: { 1066: return new PropertyHandler(); 1067: } 1068: 1069: /** 1070: * This method creates a new FocusListener. 1071: * 1072: * @return A new FocusListener. 1073: */ 1074: protected FocusListener createFocusListener() 1075: { 1076: return new FocusHandler(); 1077: } 1078: 1079: /** 1080: * This method creates a new ActionListener for up and left key presses. 1081: * 1082: * @return A new ActionListener for up and left keys. 1083: * 1084: * @deprecated 1.3 1085: */ 1086: protected ActionListener createKeyboardUpLeftListener() 1087: { 1088: return new KeyboardUpLeftHandler(); 1089: } 1090: 1091: /** 1092: * This method creates a new ActionListener for down and right key presses. 1093: * 1094: * @return A new ActionListener for down and right keys. 1095: * 1096: * @deprecated 1.3 1097: */ 1098: protected ActionListener createKeyboardDownRightListener() 1099: { 1100: return new KeyboardDownRightHandler(); 1101: } 1102: 1103: /** 1104: * This method creates a new ActionListener for home key presses. 1105: * 1106: * @return A new ActionListener for home keys. 1107: * 1108: * @deprecated 1109: */ 1110: protected ActionListener createKeyboardHomeListener() 1111: { 1112: return new KeyboardHomeHandler(); 1113: } 1114: 1115: /** 1116: * This method creates a new ActionListener for end key presses.i 1117: * 1118: * @return A new ActionListener for end keys. 1119: * 1120: * @deprecated 1.3 1121: */ 1122: protected ActionListener createKeyboardEndListener() 1123: { 1124: return new KeyboardEndHandler(); 1125: } 1126: 1127: /** 1128: * This method creates a new ActionListener for resize toggle key events. 1129: * 1130: * @return A new ActionListener for resize toggle keys. 1131: * 1132: * @deprecated 1.3 1133: */ 1134: protected ActionListener createKeyboardResizeToggleListener() 1135: { 1136: return new KeyboardResizeToggleHandler(); 1137: } 1138: 1139: /** 1140: * This method returns the orientation of the JSplitPane. 1141: * 1142: * @return The orientation of the JSplitPane. 1143: */ 1144: public int getOrientation() 1145: { 1146: return splitPane.getOrientation(); 1147: } 1148: 1149: /** 1150: * This method sets the orientation of the JSplitPane. 1151: * 1152: * @param orientation The new orientation of the JSplitPane. 1153: */ 1154: public void setOrientation(int orientation) 1155: { 1156: splitPane.setOrientation(orientation); 1157: } 1158: 1159: /** 1160: * This method returns true if the JSplitPane is using continuous layout. 1161: * 1162: * @return True if the JSplitPane is using continuous layout. 1163: */ 1164: public boolean isContinuousLayout() 1165: { 1166: return splitPane.isContinuousLayout(); 1167: } 1168: 1169: /** 1170: * This method sets the continuous layout property of the JSplitPane. 1171: * 1172: * @param b True if the JsplitPane is to use continuous layout. 1173: */ 1174: public void setContinuousLayout(boolean b) 1175: { 1176: splitPane.setContinuousLayout(b); 1177: } 1178: 1179: /** 1180: * This method returns the last location the divider was dragged to. 1181: * 1182: * @return The last location the divider was dragged to. 1183: */ 1184: public int getLastDragLocation() 1185: { 1186: return lastDragLocation; 1187: } 1188: 1189: /** 1190: * This method sets the last location the divider was dragged to. 1191: * 1192: * @param l The last location the divider was dragged to. 1193: */ 1194: public void setLastDragLocation(int l) 1195: { 1196: lastDragLocation = l; 1197: } 1198: 1199: /** 1200: * This method returns the BasicSplitPaneDivider that divides this 1201: * JSplitPane. 1202: * 1203: * @return The divider for the JSplitPane. 1204: */ 1205: public BasicSplitPaneDivider getDivider() 1206: { 1207: return divider; 1208: } 1209: 1210: /** 1211: * This method creates a nonContinuousLayoutDivider for use with the 1212: * JSplitPane in nonContinousLayout mode. The default divider is a gray 1213: * Canvas. 1214: * 1215: * @return The default nonContinousLayoutDivider. 1216: */ 1217: protected Component createDefaultNonContinuousLayoutDivider() 1218: { 1219: if (nonContinuousLayoutDivider == null) 1220: { 1221: nonContinuousLayoutDivider = new Canvas(); 1222: nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY); 1223: } 1224: return nonContinuousLayoutDivider; 1225: } 1226: 1227: /** 1228: * This method sets the component to use as the nonContinuousLayoutDivider. 1229: * 1230: * @param newDivider The component to use as the nonContinuousLayoutDivider. 1231: */ 1232: protected void setNonContinuousLayoutDivider(Component newDivider) 1233: { 1234: setNonContinuousLayoutDivider(newDivider, true); 1235: } 1236: 1237: /** 1238: * This method sets the component to use as the nonContinuousLayoutDivider. 1239: * 1240: * @param newDivider The component to use as the nonContinuousLayoutDivider. 1241: * @param rememberSizes FIXME: document. 1242: */ 1243: protected void setNonContinuousLayoutDivider(Component newDivider, 1244: boolean rememberSizes) 1245: { 1246: // FIXME: use rememberSizes for something 1247: nonContinuousLayoutDivider = newDivider; 1248: } 1249: 1250: /** 1251: * This method returns the nonContinuousLayoutDivider. 1252: * 1253: * @return The nonContinuousLayoutDivider. 1254: */ 1255: public Component getNonContinuousLayoutDivider() 1256: { 1257: return nonContinuousLayoutDivider; 1258: } 1259: 1260: /** 1261: * This method returns the JSplitPane that this BasicSplitPaneUI draws. 1262: * 1263: * @return The JSplitPane. 1264: */ 1265: public JSplitPane getSplitPane() 1266: { 1267: return splitPane; 1268: } 1269: 1270: /** 1271: * This method creates the divider used normally with the JSplitPane. 1272: * 1273: * @return The default divider. 1274: */ 1275: public BasicSplitPaneDivider createDefaultDivider() 1276: { 1277: if (divider == null) 1278: divider = new BasicSplitPaneDivider(this); 1279: return divider; 1280: } 1281: 1282: /** 1283: * This method is called when JSplitPane's resetToPreferredSizes is called. 1284: * It resets the sizes of all components in the JSplitPane. 1285: * 1286: * @param jc The JSplitPane to reset. 1287: */ 1288: public void resetToPreferredSizes(JSplitPane jc) 1289: { 1290: layoutManager.resetToPreferredSizes(); 1291: } 1292: 1293: /** 1294: * This method sets the location of the divider. 1295: * 1296: * @param jc The JSplitPane to set the divider location in. 1297: * @param location The new location of the divider. 1298: */ 1299: public void setDividerLocation(JSplitPane jc, int location) 1300: { 1301: location = validLocation(location); 1302: Container p = jc.getParent(); 1303: Component right = jc.getRightComponent(); 1304: Dimension rightPrefSize = right == null ? new Dimension(0, 0) 1305: : right.getPreferredSize(); 1306: Dimension size = jc.getSize(); 1307: // check if the size has been set for the splitpane 1308: if (size.width == 0 && size.height == 0) 1309: size = jc.getPreferredSize(); 1310: 1311: if (getOrientation() == 0 && location > size.height) 1312: { 1313: location = size.height; 1314: while (p != null) 1315: { 1316: p.setSize(p.getWidth(), p.getHeight() + rightPrefSize.height); 1317: p = p.getParent(); 1318: } 1319: } 1320: else if (location > size.width) 1321: { 1322: location = size.width; 1323: while (p != null) 1324: { 1325: p.setSize(p.getWidth() + rightPrefSize.width, p.getHeight()); 1326: p = p.getParent(); 1327: } 1328: } 1329: 1330: setLastDragLocation(getDividerLocation(splitPane)); 1331: splitPane.setLastDividerLocation(getDividerLocation(splitPane)); 1332: int[] tmpSizes = layoutManager.getSizes(); 1333: tmpSizes[0] = location 1334: - layoutManager.getInitialLocation(splitPane.getInsets()); 1335: tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(), 1336: splitPane.getInsets()) 1337: - tmpSizes[0]; 1338: layoutManager.setSizes(tmpSizes); 1339: splitPane.revalidate(); 1340: splitPane.repaint(); 1341: } 1342: 1343: /** 1344: * This method returns the location of the divider. 1345: * 1346: * @param jc The JSplitPane to retrieve the location for. 1347: * 1348: * @return The location of the divider. 1349: */ 1350: public int getDividerLocation(JSplitPane jc) 1351: { 1352: return layoutManager.sizes[0] 1353: + layoutManager.getInitialLocation(splitPane.getInsets()); 1354: } 1355: 1356: /** 1357: * This method returns the smallest value possible for the location of the 1358: * divider. 1359: * 1360: * @param jc The JSplitPane. 1361: * 1362: * @return The minimum divider location. 1363: */ 1364: public int getMinimumDividerLocation(JSplitPane jc) 1365: { 1366: int value = layoutManager.getInitialLocation(jc.getInsets()); 1367: if (layoutManager.components[0] != null) 1368: value -= layoutManager.minimumSizeOfComponent(0); 1369: return value; 1370: } 1371: 1372: /** 1373: * This method returns the largest value possible for the location of the 1374: * divider. 1375: * 1376: * @param jc The JSplitPane. 1377: * 1378: * @return The maximum divider location. 1379: */ 1380: public int getMaximumDividerLocation(JSplitPane jc) 1381: { 1382: int value = layoutManager.getInitialLocation(jc.getInsets()) 1383: + layoutManager.getAvailableSize(jc.getSize(), jc.getInsets()) 1384: - splitPane.getDividerSize(); 1385: if (layoutManager.components[1] != null) 1386: value -= layoutManager.minimumSizeOfComponent(1); 1387: return value; 1388: } 1389: 1390: /** 1391: * This method is called after the children of the JSplitPane are painted. 1392: * 1393: * @param jc The JSplitPane. 1394: * @param g The Graphics object to paint with. 1395: */ 1396: public void finishedPaintingChildren(JSplitPane jc, Graphics g) 1397: { 1398: if (! splitPane.isContinuousLayout() && nonContinuousLayoutDivider != null 1399: && nonContinuousLayoutDivider.isVisible()) 1400: javax.swing.SwingUtilities.paintComponent(g, nonContinuousLayoutDivider, 1401: null, 1402: nonContinuousLayoutDivider 1403: .getBounds()); 1404: } 1405: 1406: /** 1407: * This method is called to paint the JSplitPane. 1408: * 1409: * @param g The Graphics object to paint with. 1410: * @param jc The JSplitPane to paint. 1411: */ 1412: public void paint(Graphics g, JComponent jc) 1413: { 1414: // TODO: What should be done here? 1415: } 1416: 1417: /** 1418: * This method returns the preferred size of the JSplitPane. 1419: * 1420: * @param jc The JSplitPane. 1421: * 1422: * @return The preferred size of the JSplitPane. 1423: */ 1424: public Dimension getPreferredSize(JComponent jc) 1425: { 1426: return layoutManager.preferredLayoutSize((Container) jc); 1427: } 1428: 1429: /** 1430: * This method returns the minimum size of the JSplitPane. 1431: * 1432: * @param jc The JSplitPane. 1433: * 1434: * @return The minimum size of the JSplitPane. 1435: */ 1436: public Dimension getMinimumSize(JComponent jc) 1437: { 1438: return layoutManager.minimumLayoutSize((Container) jc); 1439: } 1440: 1441: /** 1442: * This method returns the maximum size of the JSplitPane. 1443: * 1444: * @param jc The JSplitPane. 1445: * 1446: * @return The maximum size of the JSplitPane. 1447: */ 1448: public Dimension getMaximumSize(JComponent jc) 1449: { 1450: return layoutManager.maximumLayoutSize((Container) jc); 1451: } 1452: 1453: /** 1454: * This method returns the border insets of the current border. 1455: * 1456: * @param jc The JSplitPane. 1457: * 1458: * @return The current border insets. 1459: */ 1460: public Insets getInsets(JComponent jc) 1461: { 1462: return splitPane.getBorder().getBorderInsets(splitPane); 1463: } 1464: 1465: /** 1466: * This method resets the current layout manager. The type of layout manager 1467: * is dependent on the current orientation. 1468: */ 1469: protected void resetLayoutManager() 1470: { 1471: if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) 1472: layoutManager = new BasicHorizontalLayoutManager(); 1473: else 1474: layoutManager = new BasicVerticalLayoutManager(); 1475: getSplitPane().setLayout(layoutManager); 1476: layoutManager.updateComponents(); 1477: 1478: // invalidating by itself does not invalidate the layout. 1479: getSplitPane().revalidate(); 1480: } 1481: 1482: /** 1483: * This method is called when dragging starts. It resets lastDragLocation 1484: * and dividerSize. 1485: */ 1486: protected void startDragging() 1487: { 1488: Component left = splitPane.getLeftComponent(); 1489: Component right = splitPane.getRightComponent(); 1490: dividerSize = divider.getDividerSize(); 1491: setLastDragLocation(-1); 1492: 1493: if ((left != null && !left.isLightweight()) 1494: || (right != null && !right.isLightweight())) 1495: draggingHW = true; 1496: 1497: if (splitPane.isContinuousLayout()) 1498: nonContinuousLayoutDivider.setVisible(false); 1499: else 1500: { 1501: nonContinuousLayoutDivider.setVisible(true); 1502: nonContinuousLayoutDivider.setBounds(divider.getBounds()); 1503: } 1504: splitPane.revalidate(); 1505: splitPane.repaint(); 1506: } 1507: 1508: /** 1509: * This method is called whenever the divider is dragged. If the JSplitPane 1510: * is in continuousLayout mode, the divider needs to be moved and the 1511: * JSplitPane needs to be laid out. 1512: * 1513: * @param location The new location of the divider. 1514: */ 1515: protected void dragDividerTo(int location) 1516: { 1517: location = validLocation(location); 1518: if (beginDragDividerLocation == -1) 1519: beginDragDividerLocation = location; 1520: 1521: if (splitPane.isContinuousLayout()) 1522: splitPane.setDividerLocation(location); 1523: else 1524: { 1525: Point p = nonContinuousLayoutDivider.getLocation(); 1526: if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) 1527: p.x = location; 1528: else 1529: p.y = location; 1530: nonContinuousLayoutDivider.setLocation(p); 1531: } 1532: setLastDragLocation(location); 1533: splitPane.repaint(); 1534: } 1535: 1536: /** 1537: * This method is called when the dragging is finished. 1538: * 1539: * @param location The location where the drag finished. 1540: */ 1541: protected void finishDraggingTo(int location) 1542: { 1543: if (nonContinuousLayoutDivider != null) 1544: nonContinuousLayoutDivider.setVisible(false); 1545: draggingHW = false; 1546: location = validLocation(location); 1547: dragDividerTo(location); 1548: splitPane.setDividerLocation(location); 1549: splitPane.setLastDividerLocation(beginDragDividerLocation); 1550: beginDragDividerLocation = -1; 1551: splitPane.repaint(); 1552: } 1553: 1554: /** 1555: * This method returns the width of one of the sides of the divider's border. 1556: * 1557: * @return The width of one side of the divider's border. 1558: * 1559: * @deprecated 1.3 1560: */ 1561: protected int getDividerBorderSize() 1562: { 1563: if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) 1564: return divider.getBorder().getBorderInsets(divider).left; 1565: else 1566: return divider.getBorder().getBorderInsets(divider).top; 1567: } 1568: 1569: /** 1570: * This is a helper method that returns a valid location for the divider 1571: * when dragging. 1572: * 1573: * @param location The location to check. 1574: * 1575: * @return A valid location. 1576: */ 1577: private int validLocation(int location) 1578: { 1579: int min = getMinimumDividerLocation(splitPane); 1580: int max = getMaximumDividerLocation(splitPane); 1581: if (min > 0 && location < min) 1582: return min; 1583: if (max > 0 && location > max) 1584: return max; 1585: return location; 1586: } 1587: }
GNU Classpath (0.20) |