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