Source for javax.swing.plaf.basic.BasicSplitPaneUI

   1: /* BasicSplitPaneUI.java --
   2:    Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import java.awt.Canvas;
  42: import java.awt.Color;
  43: import java.awt.Component;
  44: import java.awt.Container;
  45: import java.awt.Dimension;
  46: import java.awt.Graphics;
  47: import java.awt.Insets;
  48: import java.awt.LayoutManager2;
  49: import java.awt.Point;
  50: import java.awt.event.ActionEvent;
  51: import java.awt.event.ActionListener;
  52: import java.awt.event.FocusAdapter;
  53: import java.awt.event.FocusEvent;
  54: import java.awt.event.FocusListener;
  55: import java.beans.PropertyChangeEvent;
  56: import java.beans.PropertyChangeListener;
  57: 
  58: import javax.swing.AbstractAction;
  59: import javax.swing.ActionMap;
  60: import javax.swing.InputMap;
  61: import javax.swing.JComponent;
  62: import javax.swing.JSlider;
  63: import javax.swing.JSplitPane;
  64: import javax.swing.KeyStroke;
  65: import javax.swing.LookAndFeel;
  66: import javax.swing.SwingConstants;
  67: import javax.swing.SwingUtilities;
  68: import javax.swing.UIManager;
  69: import javax.swing.plaf.ActionMapUIResource;
  70: import javax.swing.plaf.ComponentUI;
  71: import javax.swing.plaf.SplitPaneUI;
  72: import javax.swing.plaf.UIResource;
  73: 
  74: /**
  75:  * This is the Basic Look and Feel implementation of the SplitPaneUI  class.
  76:  */
  77: public class BasicSplitPaneUI extends SplitPaneUI
  78: {
  79:   /**
  80:    * This Layout Manager controls the position and size of the components when
  81:    * the JSplitPane's orientation is HORIZONTAL_SPLIT.
  82:    *
  83:    * @specnote Apparently this class was intended to be protected,
  84:    *           but was made public by a compiler bug and is now
  85:    *           public for compatibility.
  86:    */
  87:   public class BasicHorizontalLayoutManager implements LayoutManager2
  88:   {
  89:     // 3 components at a time.
  90:     // LEFT/TOP = 0
  91:     // RIGHT/BOTTOM = 1
  92:     // DIVIDER = 2    
  93: 
  94:     /**
  95:      * This array contains the components in the JSplitPane. The  left/top
  96:      * component is at index 0, the right/bottom is at 1, and the divider is
  97:      * at 2.
  98:      */
  99:     protected Component[] components = new Component[3];
 100: 
 101:     // These are the _current_ widths of the associated component.
 102: 
 103:     /**
 104:      * This array contains the current width (for HORIZONTAL_SPLIT) or height
 105:      * (for VERTICAL_SPLIT) of the components. The indices are the same as
 106:      * for components.
 107:      */
 108:     protected int[] sizes = new int[3];
 109: 
 110:     /**
 111:      * This is used to determine if we are vertical or horizontal layout.
 112:      * In the JDK, the BasicVerticalLayoutManager seems to have no more
 113:      * methods implemented (as of JDK5), so we keep this state here.
 114:      */
 115:     private int axis;
 116: 
 117:     /**
 118:      * Creates a new instance. This is package private because the reference
 119:      * implementation has no public constructor either. Still, we need to
 120:      * call it from BasicVerticalLayoutManager.
 121:      */
 122:     BasicHorizontalLayoutManager()
 123:     {
 124:       this(SwingConstants.HORIZONTAL);
 125:     }
 126: 
 127:     /**
 128:      * Creates a new instance for a specified axis. This is provided for
 129:      * compatibility, since the BasicVerticalLayoutManager seems to have
 130:      * no more implementation in the RI, according to the specs. So
 131:      * we handle all the axis specific stuff here.
 132:      *
 133:      * @param a the axis, either SwingConstants#HORIZONTAL,
 134:      *        or SwingConstants#VERTICAL
 135:      */
 136:     BasicHorizontalLayoutManager(int a)
 137:     {
 138:       axis = a;
 139:     }
 140: 
 141:     /**
 142:      * This method adds the component given to the JSplitPane. The position of
 143:      * the component is given by the constraints object.
 144:      *
 145:      * @param comp The Component to add.
 146:      * @param constraints The constraints that bind the object.
 147:      */
 148:     public void addLayoutComponent(Component comp, Object constraints)
 149:     {
 150:       addLayoutComponent((String) constraints, comp);
 151:     }
 152: 
 153:     /**
 154:      * This method is called to add a Component to the JSplitPane. The
 155:      * placement string determines where the Component will be placed. The
 156:      * string should be one of LEFT, RIGHT, TOP, BOTTOM or null (signals that
 157:      * the component is the divider).
 158:      *
 159:      * @param place The placement of the Component.
 160:      * @param component The Component to add.
 161:      *
 162:      * @throws IllegalArgumentException DOCUMENT ME!
 163:      */
 164:     public void addLayoutComponent(String place, Component component)
 165:     {
 166:       int i = 0;
 167:       if (place == null)
 168:         i = 2;
 169:       else if (place.equals(JSplitPane.TOP) || place.equals(JSplitPane.LEFT))
 170:         i = 0;
 171:       else if (place.equals(JSplitPane.BOTTOM)
 172:                || place.equals(JSplitPane.RIGHT))
 173:         i = 1;
 174:       else
 175:         throw new IllegalArgumentException("Illegal placement in JSplitPane");
 176:       components[i] = component;
 177:       resetSizeAt(i);
 178:       splitPane.revalidate();
 179:       splitPane.repaint();
 180:     }
 181: 
 182:     /**
 183:      * This method returns the width of the JSplitPane minus the insets.
 184:      *
 185:      * @param containerSize The Dimensions of the JSplitPane.
 186:      * @param insets The Insets of the JSplitPane.
 187:      *
 188:      * @return The width of the JSplitPane minus the insets.
 189:      */
 190:     protected int getAvailableSize(Dimension containerSize, Insets insets)
 191:     {
 192:       int size;
 193:       if (axis == SwingConstants.HORIZONTAL)
 194:         size = containerSize.width - insets.left - insets.right;
 195:       else
 196:         size = containerSize.height - insets.top - insets.bottom;
 197:       return size;
 198:     }
 199: 
 200:     /**
 201:      * This method returns the given insets left value. If the  given inset is
 202:      * null, then 0 is returned.
 203:      *
 204:      * @param insets The Insets to use with the JSplitPane.
 205:      *
 206:      * @return The inset's left value.
 207:      */
 208:     protected int getInitialLocation(Insets insets)
 209:     {
 210:       int loc = 0;
 211:       if (insets != null)
 212:         {
 213:           if (axis == SwingConstants.HORIZONTAL)
 214:             loc = insets.left;
 215:           else
 216:             loc = insets.top;
 217:         }
 218:       return loc;
 219:     }
 220: 
 221:     /**
 222:      * This specifies how a component is aligned with respect to  other
 223:      * components in the x fdirection.
 224:      *
 225:      * @param target The container.
 226:      *
 227:      * @return The component's alignment.
 228:      */
 229:     public float getLayoutAlignmentX(Container target)
 230:     {
 231:       return 0.0f;
 232:     }
 233: 
 234:     /**
 235:      * This specifies how a component is aligned with respect to  other
 236:      * components in the y direction.
 237:      *
 238:      * @param target The container.
 239:      *
 240:      * @return The component's alignment.
 241:      */
 242:     public float getLayoutAlignmentY(Container target)
 243:     {
 244:       return 0.0f;
 245:     }
 246: 
 247:     /**
 248:      * This method returns the preferred width of the component.
 249:      *
 250:      * @param c The component to measure.
 251:      *
 252:      * @return The preferred width of the component.
 253:      */
 254:     protected int getPreferredSizeOfComponent(Component c)
 255:     {
 256:       int size = 0;
 257:       Dimension dims = c.getPreferredSize();
 258:       if (axis == SwingConstants.HORIZONTAL)
 259:         {
 260:           if (dims != null)
 261:             size = dims.width;
 262:         }
 263:       else
 264:         {
 265:           if (dims != null)
 266:             size = dims.height;
 267:         }
 268:       return size;
 269:     }
 270: 
 271:     /**
 272:      * This method returns the current width of the component.
 273:      *
 274:      * @param c The component to measure.
 275:      *
 276:      * @return The width of the component.
 277:      */
 278:     protected int getSizeOfComponent(Component c)
 279:     {
 280:       int size;
 281:       if (axis == SwingConstants.HORIZONTAL)
 282:         size = c.getHeight();
 283:       else
 284:         size = c.getWidth();
 285:       return size;
 286:     }
 287: 
 288:     /**
 289:      * This method returns the sizes array.
 290:      *
 291:      * @return The sizes array.
 292:      */
 293:     protected int[] getSizes()
 294:     {
 295:       return sizes;
 296:     }
 297: 
 298:     /**
 299:      * This method invalidates the layout. It does nothing.
 300:      *
 301:      * @param c The container to invalidate.
 302:      */
 303:     public void invalidateLayout(Container c)
 304:     {
 305:       // DO NOTHING
 306:     }
 307: 
 308:     /**
 309:      * This method lays out the components in the container.
 310:      *
 311:      * @param container The container to lay out.
 312:      */
 313:     public void layoutContainer(Container container)
 314:     {
 315:       if (container instanceof JSplitPane)
 316:         {
 317:           JSplitPane split = (JSplitPane) container;
 318:           distributeExtraSpace();
 319:           Insets insets = split.getInsets();
 320:           Dimension dims = split.getSize();
 321:           int loc = getInitialLocation(insets);
 322:           int available = getAvailableSize(dims, insets);
 323:           sizes[0] = split.getDividerLocation();
 324:           sizes[1] = available - sizes[0] - sizes[2];
 325: 
 326:           // According to a Mauve test we only honour the minimum
 327:           // size of the components, when the dividerLocation hasn't
 328:           // been excplicitly set.
 329:           if (! dividerLocationSet)
 330:             {
 331:               sizes[0] = Math.max(sizes[0], minimumSizeOfComponent(0));
 332:               sizes[1] = Math.max(sizes[1], minimumSizeOfComponent(1));
 333:             }
 334:           // The size of the divider won't change.
 335: 
 336:           // Layout component#1.
 337:           setComponentToSize(components[0], sizes[0], loc, insets, dims);
 338:           // Layout divider.
 339:           loc += sizes[0];
 340:           setComponentToSize(components[2], sizes[2], loc, insets, dims);
 341:           // Layout component#2. 
 342:           loc += sizes[2];
 343:           setComponentToSize(components[1], sizes[1], loc, insets, dims);
 344:         }
 345:     }
 346: 
 347:     /**
 348:      * This method returns the maximum size for the container given the
 349:      * components. It returns a new Dimension object that has width and
 350:      * height equal to Integer.MAX_VALUE.
 351:      *
 352:      * @param target The container to measure.
 353:      *
 354:      * @return The maximum size.
 355:      */
 356:     public Dimension maximumLayoutSize(Container target)
 357:     {
 358:       return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 359:     }
 360: 
 361:     /**
 362:      * This method returns the container's minimum size. The  minimum width is
 363:      * the sum of all the component's minimum widths. The minimum height is
 364:      * the maximum of  all the components' minimum heights.
 365:      *
 366:      * @param target The container to measure.
 367:      *
 368:      * @return The minimum size.
 369:      */
 370:     public Dimension minimumLayoutSize(Container target)
 371:     {
 372:       Dimension dim = new Dimension();
 373:       if (target instanceof JSplitPane)
 374:         {
 375:           int primary = 0;
 376:           int secondary = 0;
 377:           for (int i = 0; i < components.length; i++)
 378:             {
 379:               if (components[i] != null)
 380:                 {
 381:                   Dimension dims = components[i].getMinimumSize();
 382:                   primary += axis == SwingConstants.HORIZONTAL ? dims.width
 383:                                                                : dims.height;
 384:                   int sec = axis == SwingConstants.HORIZONTAL ? dims.height
 385:                                                               : dims.width;
 386:                   secondary = Math.max(sec, secondary);
 387:                 }
 388:             }
 389:           int width = axis == SwingConstants.HORIZONTAL ? primary : secondary;
 390:           int height = axis == SwingConstants.VERTICAL ? secondary : primary;
 391: 
 392:           Insets i = splitPane.getInsets();
 393:           dim.setSize(width + i.left + i.right, height + i.top + i.bottom);
 394:         }
 395:       return dim;
 396:     }
 397: 
 398:     /**
 399:      * This method returns the container's preferred size. The preferred width
 400:      * is the sum of all the component's preferred widths. The preferred
 401:      * height is the maximum of all the components' preferred heights.
 402:      *
 403:      * @param target The container to measure.
 404:      *
 405:      * @return The preferred size.
 406:      */
 407:     public Dimension preferredLayoutSize(Container target)
 408:     {
 409:       Dimension dim = new Dimension();
 410:       if (target instanceof JSplitPane)
 411:         {
 412:           int primary = 0;
 413:           int secondary = 0;
 414:           for (int i = 0; i < components.length; i++)
 415:             {
 416:               if (components[i] != null)
 417:                 {
 418:                   Dimension dims = components[i].getPreferredSize();
 419:                   primary += axis == SwingConstants.HORIZONTAL ? dims.width
 420:                                                                : dims.height;
 421:                   int sec = axis == SwingConstants.HORIZONTAL ? dims.height
 422:                                                               : dims.width;
 423:                   secondary = Math.max(sec, secondary);
 424:                 }
 425:             }
 426:           int width = axis == SwingConstants.HORIZONTAL ? primary : secondary;
 427:           int height = axis == SwingConstants.VERTICAL ? secondary : primary;
 428: 
 429:           Insets i = splitPane.getInsets();
 430:           dim.setSize(width + i.left + i.right, height + i.top + i.bottom);
 431:         }
 432:       return dim;
 433:     }
 434: 
 435:     /**
 436:      * This method removes the component from the layout.
 437:      *
 438:      * @param component The component to remove from the layout.
 439:      */
 440:     public void removeLayoutComponent(Component component)
 441:     {
 442:       for (int i = 0; i < components.length; i++)
 443:         {
 444:           if (component == components[i])
 445:             {
 446:               components[i] = null;
 447:               sizes[i] = 0;
 448:             }
 449:         }
 450:     }
 451: 
 452:     /**
 453:      * This method resets the size of Component to the preferred size.
 454:      *
 455:      * @param index The index of the component to reset.
 456:      */
 457:     protected void resetSizeAt(int index)
 458:     {
 459:       if (components[index] != null)
 460:         sizes[index] = getPreferredSizeOfComponent(components[index]);
 461:     }
 462: 
 463:     /**
 464:      * This method resets the sizes of all the components.
 465:      */
 466:     public void resetToPreferredSizes()
 467:     {
 468:       for (int i = 0; i < components.length; i++)
 469:         resetSizeAt(i);
 470:     }
 471: 
 472:     /**
 473:      * This methods sets the bounds of the given component. The width is the
 474:      * size. The height is the container size minus the  top and bottom
 475:      * inset. The x coordinate is the location given.  The y coordinate is
 476:      * the top inset.
 477:      *
 478:      * @param c The component to set.
 479:      * @param size The width of the component.
 480:      * @param location The x coordinate.
 481:      * @param insets The insets to use.
 482:      * @param containerSize The height of the container.
 483:      */
 484:     protected void setComponentToSize(Component c, int size, int location,
 485:                                       Insets insets, Dimension containerSize)
 486:     { 
 487:       if (insets != null)
 488:         {
 489:           if (axis == SwingConstants.HORIZONTAL)
 490:             c.setBounds(location, insets.top, size,
 491:                         containerSize.height - insets.top - insets.bottom);
 492:           else
 493:             c.setBounds(insets.left, location,
 494:                         containerSize.width - insets.left - insets.right,
 495:                         size);
 496:         }
 497:       else
 498:         {
 499:           if (axis == SwingConstants.HORIZONTAL)
 500:             c.setBounds(location, 0, size, containerSize.height);
 501:           else
 502:             c.setBounds(0, location, containerSize.width, size);
 503:         }
 504:     }
 505: 
 506:     /**
 507:      * This method stores the given int array as the new sizes array.
 508:      *
 509:      * @param newSizes The array to use as sizes.
 510:      */
 511:     protected void setSizes(int[] newSizes)
 512:     {
 513:       sizes = newSizes;
 514:     }
 515: 
 516:     /**
 517:      * This method determines the size of each  component. It should be called
 518:      * when a new Layout Manager is created for an existing JSplitPane.
 519:      */
 520:     protected void updateComponents()
 521:     {
 522:       Component left = splitPane.getLeftComponent();
 523:       Component right = splitPane.getRightComponent();
 524: 
 525:       if (left != null)
 526:         {
 527:           components[0] = left;
 528:           resetSizeAt(0);
 529:         }
 530:       if (right != null)
 531:         {
 532:           components[1] = right;
 533:           resetSizeAt(1);
 534:         }
 535:       components[2] = divider;
 536:     }
 537: 
 538:     /**
 539:      * This method resizes the left and right components to fit inside the
 540:      * JSplitPane when there is extra space.
 541:      */
 542:     void distributeExtraSpace()
 543:     {
 544:       // FIXME: This needs to be reimplemented correctly.
 545:     }
 546: 
 547:     /**
 548:      * This method returns the minimum width of the  component at the given
 549:      * index.
 550:      *
 551:      * @param index The index to check.
 552:      *
 553:      * @return The minimum width.
 554:      */
 555:     int minimumSizeOfComponent(int index)
 556:     {
 557:       Dimension dims = components[index].getMinimumSize();
 558:       int size = 0;
 559:       if (dims != null)
 560:         if (axis == SwingConstants.HORIZONTAL)
 561:           size = dims.width;
 562:         else
 563:           size = dims.height;
 564:         return size;
 565:     }
 566:   } //end BasicHorizontalLayoutManager
 567: 
 568:   /**
 569:    * This class is the Layout Manager for the JSplitPane when the orientation
 570:    * is VERTICAL_SPLIT.
 571:    *
 572:    * @specnote Apparently this class was intended to be protected,
 573:    *           but was made public by a compiler bug and is now
 574:    *           public for compatibility.
 575:    */
 576:   public class BasicVerticalLayoutManager
 577:     extends BasicHorizontalLayoutManager
 578:   {
 579:     /**
 580:      * Creates a new instance.
 581:      */
 582:     public BasicVerticalLayoutManager()
 583:     {
 584:       super(SwingConstants.VERTICAL);
 585:     }
 586:   }
 587: 
 588:   /**
 589:    * This class handles FocusEvents from the JComponent.
 590:    *
 591:    * @specnote Apparently this class was intended to be protected,
 592:    *           but was made public by a compiler bug and is now
 593:    *           public for compatibility.
 594:    */
 595:   public class FocusHandler extends FocusAdapter
 596:   {
 597:     /**
 598:      * This method is called when the JSplitPane gains focus.
 599:      *
 600:      * @param ev The FocusEvent.
 601:      */
 602:     public void focusGained(FocusEvent ev)
 603:     {
 604:       // repaint the divider because its background color may change due to
 605:       // the focus state...
 606:       divider.repaint();
 607:     }
 608: 
 609:     /**
 610:      * This method is called when the JSplitPane loses focus.
 611:      *
 612:      * @param ev The FocusEvent.
 613:      */
 614:     public void focusLost(FocusEvent ev)
 615:     {
 616:       // repaint the divider because its background color may change due to
 617:       // the focus state...
 618:       divider.repaint();
 619:     }
 620:   }
 621: 
 622:   /**
 623:    * This is a deprecated class. It is supposed to be used for handling down
 624:    * and right key presses.
 625:    *
 626:    * @specnote Apparently this class was intended to be protected,
 627:    *           but was made public by a compiler bug and is now
 628:    *           public for compatibility.
 629:    */
 630:   public class KeyboardDownRightHandler implements ActionListener
 631:   {
 632:     /**
 633:      * This method is called when the down or right keys are pressed.
 634:      *
 635:      * @param ev The ActionEvent
 636:      */
 637:     public void actionPerformed(ActionEvent ev)
 638:     {
 639:       // FIXME: implement.
 640:     }
 641:   }
 642: 
 643:   /**
 644:    * This is a deprecated class. It is supposed to be used for handling end
 645:    * key presses.
 646:    *
 647:    * @specnote Apparently this class was intended to be protected,
 648:    *           but was made public by a compiler bug and is now
 649:    *           public for compatibility.
 650:    */
 651:   public class KeyboardEndHandler implements ActionListener
 652:   {
 653:     /**
 654:      * This method is called when the end key is pressed.
 655:      *
 656:      * @param ev The ActionEvent.
 657:      */
 658:     public void actionPerformed(ActionEvent ev)
 659:     {
 660:       // FIXME: implement.
 661:     }
 662:   }
 663: 
 664:   /**
 665:    * This is a deprecated class. It is supposed to be used for handling home
 666:    * key presses.
 667:    *
 668:    * @specnote Apparently this class was intended to be protected,
 669:    *           but was made public by a compiler bug and is now
 670:    *           public for compatibility.
 671:    */
 672:   public class KeyboardHomeHandler implements ActionListener
 673:   {
 674:     /**
 675:      * This method is called when the home key is pressed.
 676:      *
 677:      * @param ev The ActionEvent.
 678:      */
 679:     public void actionPerformed(ActionEvent ev)
 680:     {
 681:       // FIXME: implement.
 682:     }
 683:   }
 684: 
 685:   /**
 686:    * This is a deprecated class. It is supposed to be used for handling resize
 687:    * toggles.
 688:    *
 689:    * @specnote Apparently this class was intended to be protected,
 690:    *           but was made public by a compiler bug and is now
 691:    *           public for compatibility.
 692:    */
 693:   public class KeyboardResizeToggleHandler implements ActionListener
 694:   {
 695:     /**
 696:      * This method is called when a resize is toggled.
 697:      *
 698:      * @param ev The ActionEvent.
 699:      */
 700:     public void actionPerformed(ActionEvent ev)
 701:     {
 702:       // FIXME: implement.
 703:     }
 704:   }
 705: 
 706:   /**
 707:    * This is a deprecated class. It is supposed to be used for handler up and
 708:    * left key presses.
 709:    *
 710:    * @specnote Apparently this class was intended to be protected,
 711:    *           but was made public by a compiler bug and is now
 712:    *           public for compatibility.
 713:    */
 714:   public class KeyboardUpLeftHandler implements ActionListener
 715:   {
 716:     /**
 717:      * This method is called when the left or up keys are pressed.
 718:      *
 719:      * @param ev The ActionEvent.
 720:      */
 721:     public void actionPerformed(ActionEvent ev)
 722:     {
 723:       // FIXME: implement.
 724:     }
 725:   }
 726: 
 727:   /**
 728:    * This helper class handles PropertyChangeEvents from the JSplitPane. When
 729:    * a property changes, this will update the UI accordingly.
 730:    *
 731:    * @specnote Apparently this class was intended to be protected,
 732:    *           but was made public by a compiler bug and is now
 733:    *           public for compatibility.
 734:    */
 735:   public class PropertyHandler implements PropertyChangeListener
 736:   {
 737:     /**
 738:      * This method is called whenever one of the JSplitPane's properties
 739:      * change.
 740:      *
 741:      * @param e DOCUMENT ME!
 742:      */
 743:     public void propertyChange(PropertyChangeEvent e)
 744:     {
 745:       if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY))
 746:         {
 747:           int newSize = splitPane.getDividerSize();
 748:           int[] tmpSizes = layoutManager.getSizes();
 749:           dividerSize = tmpSizes[2];
 750:           int newSpace = newSize - tmpSizes[2];
 751:           tmpSizes[2] = newSize;
 752: 
 753:           tmpSizes[0] += newSpace / 2;
 754:           tmpSizes[1] += newSpace / 2;
 755:       
 756:           layoutManager.setSizes(tmpSizes);
 757:         }
 758:       else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY))
 759:         {
 760:           int max = layoutManager.getAvailableSize(splitPane.getSize(),
 761:                                                    splitPane.getInsets());
 762:           int dividerLoc = getDividerLocation(splitPane);
 763:           double prop = ((double) dividerLoc) / max;
 764: 
 765:           resetLayoutManager();
 766:           if (prop <= 1 && prop >= 0)
 767:             splitPane.setDividerLocation(prop);
 768:         }
 769:       // Don't have to deal with continuous_layout - only
 770:       // necessary in dragging modes (and it's checked
 771:       // every time you drag there)
 772:       // Don't have to deal with resize_weight (as there
 773:       // will be no extra space associated with this
 774:       // event - the changes to the weighting will
 775:       // be taken into account the next time the
 776:       // sizes change.)
 777:       // Don't have to deal with divider_location
 778:       // The method in JSplitPane calls our setDividerLocation
 779:       // so we'll know about those anyway.
 780:       // Don't have to deal with last_divider_location
 781:       // Although I'm not sure why, it doesn't seem to
 782:       // have any effect on Sun's JSplitPane.
 783:       // one_touch_expandable changes are dealt with
 784:       // by our divider.
 785:     }
 786:   }
 787: 
 788:   /** The location of the divider when dragging began. */
 789:   protected int beginDragDividerLocation;
 790: 
 791:   /** The size of the divider while dragging. */
 792:   protected int dividerSize;
 793: 
 794:   /** The location where the last drag location ended. */
 795:   transient int lastDragLocation = -1;
 796: 
 797:   /** The distance the divider is moved when moved by keyboard actions. */
 798:   // Sun defines this as 3
 799:   protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3;
 800: 
 801:   /** The divider that divides this JSplitPane. */
 802:   protected BasicSplitPaneDivider divider;
 803: 
 804:   /** The listener that listens for PropertyChangeEvents from the JSplitPane. */
 805:   protected PropertyChangeListener propertyChangeListener;
 806: 
 807:   /** The JSplitPane's focus handler. */
 808:   protected FocusListener focusListener;
 809: 
 810:   /** @deprecated The handler for down and right key presses. */
 811:   protected ActionListener keyboardDownRightListener;
 812: 
 813:   /** @deprecated The handler for end key presses. */
 814:   protected ActionListener keyboardEndListener;
 815: 
 816:   /** @deprecated The handler for home key presses. */
 817:   protected ActionListener keyboardHomeListener;
 818: 
 819:   /** @deprecated The handler for toggling resizes. */
 820:   protected ActionListener keyboardResizeToggleListener;
 821: 
 822:   /** @deprecated The handler for up and left key presses. */
 823:   protected ActionListener keyboardUpLeftListener;
 824: 
 825:   /** The JSplitPane's current layout manager. */
 826:   protected BasicHorizontalLayoutManager layoutManager;
 827: 
 828:   /** @deprecated The divider resize toggle key. */
 829:   protected KeyStroke dividerResizeToggleKey;
 830: 
 831:   /** @deprecated The down key. */
 832:   protected KeyStroke downKey;
 833: 
 834:   /** @deprecated The end key. */
 835:   protected KeyStroke endKey;
 836: 
 837:   /** @deprecated The home key. */
 838:   protected KeyStroke homeKey;
 839: 
 840:   /** @deprecated The left key. */
 841:   protected KeyStroke leftKey;
 842: 
 843:   /** @deprecated The right key. */
 844:   protected KeyStroke rightKey;
 845: 
 846:   /** @deprecated The up key. */
 847:   protected KeyStroke upKey;
 848: 
 849:   /** Set to true when dragging heavy weight components. */
 850:   protected boolean draggingHW;
 851: 
 852:   /**
 853:    * The constraints object used when adding the non-continuous divider to the
 854:    * JSplitPane.
 855:    */
 856:   protected static final String NON_CONTINUOUS_DIVIDER
 857:     = "nonContinuousDivider";
 858: 
 859:   /** The dark divider used when dragging in non-continuous layout mode. */
 860:   protected Component nonContinuousLayoutDivider;
 861: 
 862:   /** The JSplitPane that this UI draws. */
 863:   protected JSplitPane splitPane;
 864: 
 865:   /**
 866:    * True, when setDividerLocation() has been called at least
 867:    * once on the JSplitPane, false otherwise.
 868:    *
 869:    * This is package private to avoid a synthetic accessor method.
 870:    */
 871:   boolean dividerLocationSet;
 872: 
 873:   /**
 874:    * Creates a new BasicSplitPaneUI object.
 875:    */
 876:   public BasicSplitPaneUI()
 877:   {
 878:     // Nothing to do here.
 879:   }
 880: 
 881:   /**
 882:    * This method creates a new BasicSplitPaneUI for the given JComponent.
 883:    *
 884:    * @param x The JComponent to create a UI for.
 885:    *
 886:    * @return A new BasicSplitPaneUI.
 887:    */
 888:   public static ComponentUI createUI(JComponent x)
 889:   {
 890:     return new BasicSplitPaneUI();
 891:   }
 892: 
 893:   /**
 894:    * This method installs the BasicSplitPaneUI for the given JComponent.
 895:    *
 896:    * @param c The JComponent to install the UI for.
 897:    */
 898:   public void installUI(JComponent c)
 899:   {
 900:     if (c instanceof JSplitPane)